Loading Documentation/devicetree/bindings/spi/spi_qsd.txt +4 −0 Original line number Original line Diff line number Diff line Loading @@ -33,6 +33,9 @@ Optional properties: When this entry is not present, voting is done by the runtime-pm callbacks. When this entry is not present, voting is done by the runtime-pm callbacks. - qcom,master-id : Master endpoint number used for voting on clocks using the - qcom,master-id : Master endpoint number used for voting on clocks using the bus-scaling driver. bus-scaling driver. - qcom,rt-priority : whether spi message queue is set to run as a realtime task. With this spi transaction message pump with high (realtime) priority to reduce the transfer latency on the bus by minimising the delay between a transfer request Optional properties which are required for support of BAM-mode: Optional properties which are required for support of BAM-mode: - qcom,ver-reg-exists : Boolean. When present, allows driver to verify if HW - qcom,ver-reg-exists : Boolean. When present, allows driver to verify if HW Loading Loading @@ -92,4 +95,5 @@ Example: qcom,bam-producer-pipe-index = <13>; qcom,bam-producer-pipe-index = <13>; qcom,ver-reg-exists; qcom,ver-reg-exists; qcom,master-id = <86>; qcom,master-id = <86>; qcom,rt-priority; }; }; arch/arm/mach-msm/include/mach/msm_spi.h +4 −0 Original line number Original line Diff line number Diff line Loading @@ -22,6 +22,9 @@ * runtime pm (optimizes for power). * runtime pm (optimizes for power). * @master_id master id number of the controller's wrapper (BLSP or GSBI). * @master_id master id number of the controller's wrapper (BLSP or GSBI). * When zero, clock path voting is disabled. * When zero, clock path voting is disabled. * @rt when set, spi will pump transaction messages with high (realtime) * priority to reduce the transfer latency on the bus by minimising * the delay between a transfer request. */ */ struct msm_spi_platform_data { struct msm_spi_platform_data { u32 max_clock_speed; u32 max_clock_speed; Loading @@ -37,4 +40,5 @@ struct msm_spi_platform_data { bool use_bam; bool use_bam; u32 bam_consumer_pipe_index; u32 bam_consumer_pipe_index; u32 bam_producer_pipe_index; u32 bam_producer_pipe_index; bool rt_priority; }; }; drivers/spi/spi_qsd.c +66 −59 Original line number Original line Diff line number Diff line Loading @@ -1959,15 +1959,40 @@ error: } } } } /* workqueue - pull messages from queue & process */ /** static void msm_spi_workq(struct work_struct *work) * msm_spi_transfer_one_message: To process one spi message at a time * @master: spi master controller reference * @msg: one multi-segment SPI transaction * @return zero on success or negative error value * */ static int msm_spi_transfer_one_message(struct spi_master *master, struct spi_message *msg) { { struct msm_spi *dd = struct msm_spi *dd; container_of(work, struct msm_spi, work_data); struct spi_transfer *tr; unsigned long flags; unsigned long flags; u32 status_error = 0; u32 status_error = 0; pm_runtime_get_sync(dd->dev); dd = spi_master_get_devdata(master); if (list_empty(&msg->transfers) || !msg->complete) return -EINVAL; list_for_each_entry(tr, &msg->transfers, transfer_list) { /* Check message parameters */ if (tr->speed_hz > dd->pdata->max_clock_speed || (tr->bits_per_word && (tr->bits_per_word < 4 || tr->bits_per_word > 32)) || (tr->tx_buf == NULL && tr->rx_buf == NULL)) { dev_err(dd->dev, "Invalid transfer: %d Hz, %d bpw tx=%p, rx=%p\n", tr->speed_hz, tr->bits_per_word, tr->tx_buf, tr->rx_buf); status_error = -EINVAL; goto out; } } mutex_lock(&dd->core_lock); mutex_lock(&dd->core_lock); Loading @@ -1990,19 +2015,15 @@ static void msm_spi_workq(struct work_struct *work) spin_lock_irqsave(&dd->queue_lock, flags); spin_lock_irqsave(&dd->queue_lock, flags); dd->transfer_pending = 1; dd->transfer_pending = 1; while (!list_empty(&dd->queue)) { dd->cur_msg = msg; dd->cur_msg = list_entry(dd->queue.next, struct spi_message, queue); list_del_init(&dd->cur_msg->queue); spin_unlock_irqrestore(&dd->queue_lock, flags); spin_unlock_irqrestore(&dd->queue_lock, flags); if (status_error) if (status_error) dd->cur_msg->status = -EIO; dd->cur_msg->status = -EIO; else else msm_spi_process_message(dd); msm_spi_process_message(dd); if (dd->cur_msg->complete) dd->cur_msg->complete(dd->cur_msg->context); spin_lock_irqsave(&dd->queue_lock, flags); spin_lock_irqsave(&dd->queue_lock, flags); } dd->transfer_pending = 0; dd->transfer_pending = 0; spin_unlock_irqrestore(&dd->queue_lock, flags); spin_unlock_irqrestore(&dd->queue_lock, flags); Loading @@ -2011,44 +2032,33 @@ static void msm_spi_workq(struct work_struct *work) mutex_unlock(&dd->core_lock); mutex_unlock(&dd->core_lock); pm_runtime_mark_last_busy(dd->dev); /* pm_runtime_put_autosuspend(dd->dev); * If needed, this can be done after the current message is complete, * and work can be continued upon resume. No motivation for now. /* If needed, this can be done after the current message is complete, */ and work can be continued upon resume. No motivation for now. */ if (dd->suspended) if (dd->suspended) wake_up_interruptible(&dd->continue_suspend); wake_up_interruptible(&dd->continue_suspend); out: dd->cur_msg->status = status_error; spi_finalize_current_message(master); return 0; } } static int msm_spi_transfer(struct spi_device *spi, struct spi_message *msg) static int msm_spi_prepare_transfer_hardware(struct spi_master *master) { { struct msm_spi *dd; struct msm_spi *dd = spi_master_get_devdata(master); unsigned long flags; struct spi_transfer *tr; dd = spi_master_get_devdata(spi->master); if (list_empty(&msg->transfers) || !msg->complete) return -EINVAL; list_for_each_entry(tr, &msg->transfers, transfer_list) { pm_runtime_get_sync(dd->dev); /* Check message parameters */ return 0; if (tr->speed_hz > dd->pdata->max_clock_speed || (tr->bits_per_word && (tr->bits_per_word < 4 || tr->bits_per_word > 32)) || (tr->tx_buf == NULL && tr->rx_buf == NULL)) { dev_err(&spi->dev, "Invalid transfer: %d Hz, %d bpw" "tx=%p, rx=%p\n", tr->speed_hz, tr->bits_per_word, tr->tx_buf, tr->rx_buf); return -EINVAL; } } } spin_lock_irqsave(&dd->queue_lock, flags); static int msm_spi_unprepare_transfer_hardware(struct spi_master *master) list_add_tail(&msg->queue, &dd->queue); { spin_unlock_irqrestore(&dd->queue_lock, flags); struct msm_spi *dd = spi_master_get_devdata(master); queue_work(dd->workqueue, &dd->work_data); pm_runtime_mark_last_busy(dd->dev); pm_runtime_put_autosuspend(dd->dev); return 0; return 0; } } Loading Loading @@ -2700,6 +2710,8 @@ struct msm_spi_platform_data * __init msm_spi_dt_to_pdata( &dd->cs_gpios[2].gpio_num, DT_OPT, DT_GPIO, -1}, &dd->cs_gpios[2].gpio_num, DT_OPT, DT_GPIO, -1}, {"qcom,gpio-cs3", {"qcom,gpio-cs3", &dd->cs_gpios[3].gpio_num, DT_OPT, DT_GPIO, -1}, &dd->cs_gpios[3].gpio_num, DT_OPT, DT_GPIO, -1}, {"qcom,rt-priority", &pdata->rt_priority, DT_OPT, DT_BOOL, 0}, {NULL, NULL, 0, 0, 0}, {NULL, NULL, 0, 0, 0}, }; }; Loading Loading @@ -2793,7 +2805,11 @@ static int __init msm_spi_probe(struct platform_device *pdev) master->mode_bits = SPI_SUPPORTED_MODES; master->mode_bits = SPI_SUPPORTED_MODES; master->num_chipselect = SPI_NUM_CHIPSELECTS; master->num_chipselect = SPI_NUM_CHIPSELECTS; master->setup = msm_spi_setup; master->setup = msm_spi_setup; master->transfer = msm_spi_transfer; master->prepare_transfer_hardware = msm_spi_prepare_transfer_hardware; master->transfer_one_message = msm_spi_transfer_one_message; master->unprepare_transfer_hardware = msm_spi_unprepare_transfer_hardware; platform_set_drvdata(pdev, master); platform_set_drvdata(pdev, master); dd = spi_master_get_devdata(master); dd = spi_master_get_devdata(master); Loading Loading @@ -2833,6 +2849,7 @@ static int __init msm_spi_probe(struct platform_device *pdev) for (i = 0; i < ARRAY_SIZE(spi_cs_rsrcs); ++i) for (i = 0; i < ARRAY_SIZE(spi_cs_rsrcs); ++i) dd->cs_gpios[i].valid = 0; dd->cs_gpios[i].valid = 0; master->rt = pdata->rt_priority; dd->pdata = pdata; dd->pdata = pdata; resource = platform_get_resource(pdev, IORESOURCE_MEM, 0); resource = platform_get_resource(pdev, IORESOURCE_MEM, 0); if (!resource) { if (!resource) { Loading Loading @@ -2894,13 +2911,6 @@ skip_dma_resources: spin_lock_init(&dd->queue_lock); spin_lock_init(&dd->queue_lock); mutex_init(&dd->core_lock); mutex_init(&dd->core_lock); INIT_LIST_HEAD(&dd->queue); INIT_WORK(&dd->work_data, msm_spi_workq); init_waitqueue_head(&dd->continue_suspend); dd->workqueue = create_singlethread_workqueue( dev_name(master->dev.parent)); if (!dd->workqueue) goto err_probe_workq; if (!devm_request_mem_region(&pdev->dev, dd->mem_phys_addr, if (!devm_request_mem_region(&pdev->dev, dd->mem_phys_addr, dd->mem_size, SPI_DRV_NAME)) { dd->mem_size, SPI_DRV_NAME)) { Loading Loading @@ -3080,8 +3090,6 @@ err_probe_clk_get: } } err_probe_rlock_init: err_probe_rlock_init: err_probe_reqmem: err_probe_reqmem: destroy_workqueue(dd->workqueue); err_probe_workq: err_probe_res: err_probe_res: spi_master_put(master); spi_master_put(master); err_probe_exit: err_probe_exit: Loading Loading @@ -3244,7 +3252,6 @@ static int msm_spi_remove(struct platform_device *pdev) clk_put(dd->clk); clk_put(dd->clk); clk_put(dd->pclk); clk_put(dd->pclk); msm_spi_clk_path_teardown(dd); msm_spi_clk_path_teardown(dd); destroy_workqueue(dd->workqueue); platform_set_drvdata(pdev, 0); platform_set_drvdata(pdev, 0); spi_unregister_master(master); spi_unregister_master(master); spi_master_put(master); spi_master_put(master); Loading drivers/spi/spi_qsd.h +0 −3 Original line number Original line Diff line number Diff line Loading @@ -300,9 +300,6 @@ struct msm_spi { struct device *dev; struct device *dev; spinlock_t queue_lock; spinlock_t queue_lock; struct mutex core_lock; struct mutex core_lock; struct list_head queue; struct workqueue_struct *workqueue; struct work_struct work_data; struct spi_message *cur_msg; struct spi_message *cur_msg; struct spi_transfer *cur_transfer; struct spi_transfer *cur_transfer; struct completion transfer_complete; struct completion transfer_complete; Loading Loading
Documentation/devicetree/bindings/spi/spi_qsd.txt +4 −0 Original line number Original line Diff line number Diff line Loading @@ -33,6 +33,9 @@ Optional properties: When this entry is not present, voting is done by the runtime-pm callbacks. When this entry is not present, voting is done by the runtime-pm callbacks. - qcom,master-id : Master endpoint number used for voting on clocks using the - qcom,master-id : Master endpoint number used for voting on clocks using the bus-scaling driver. bus-scaling driver. - qcom,rt-priority : whether spi message queue is set to run as a realtime task. With this spi transaction message pump with high (realtime) priority to reduce the transfer latency on the bus by minimising the delay between a transfer request Optional properties which are required for support of BAM-mode: Optional properties which are required for support of BAM-mode: - qcom,ver-reg-exists : Boolean. When present, allows driver to verify if HW - qcom,ver-reg-exists : Boolean. When present, allows driver to verify if HW Loading Loading @@ -92,4 +95,5 @@ Example: qcom,bam-producer-pipe-index = <13>; qcom,bam-producer-pipe-index = <13>; qcom,ver-reg-exists; qcom,ver-reg-exists; qcom,master-id = <86>; qcom,master-id = <86>; qcom,rt-priority; }; };
arch/arm/mach-msm/include/mach/msm_spi.h +4 −0 Original line number Original line Diff line number Diff line Loading @@ -22,6 +22,9 @@ * runtime pm (optimizes for power). * runtime pm (optimizes for power). * @master_id master id number of the controller's wrapper (BLSP or GSBI). * @master_id master id number of the controller's wrapper (BLSP or GSBI). * When zero, clock path voting is disabled. * When zero, clock path voting is disabled. * @rt when set, spi will pump transaction messages with high (realtime) * priority to reduce the transfer latency on the bus by minimising * the delay between a transfer request. */ */ struct msm_spi_platform_data { struct msm_spi_platform_data { u32 max_clock_speed; u32 max_clock_speed; Loading @@ -37,4 +40,5 @@ struct msm_spi_platform_data { bool use_bam; bool use_bam; u32 bam_consumer_pipe_index; u32 bam_consumer_pipe_index; u32 bam_producer_pipe_index; u32 bam_producer_pipe_index; bool rt_priority; }; };
drivers/spi/spi_qsd.c +66 −59 Original line number Original line Diff line number Diff line Loading @@ -1959,15 +1959,40 @@ error: } } } } /* workqueue - pull messages from queue & process */ /** static void msm_spi_workq(struct work_struct *work) * msm_spi_transfer_one_message: To process one spi message at a time * @master: spi master controller reference * @msg: one multi-segment SPI transaction * @return zero on success or negative error value * */ static int msm_spi_transfer_one_message(struct spi_master *master, struct spi_message *msg) { { struct msm_spi *dd = struct msm_spi *dd; container_of(work, struct msm_spi, work_data); struct spi_transfer *tr; unsigned long flags; unsigned long flags; u32 status_error = 0; u32 status_error = 0; pm_runtime_get_sync(dd->dev); dd = spi_master_get_devdata(master); if (list_empty(&msg->transfers) || !msg->complete) return -EINVAL; list_for_each_entry(tr, &msg->transfers, transfer_list) { /* Check message parameters */ if (tr->speed_hz > dd->pdata->max_clock_speed || (tr->bits_per_word && (tr->bits_per_word < 4 || tr->bits_per_word > 32)) || (tr->tx_buf == NULL && tr->rx_buf == NULL)) { dev_err(dd->dev, "Invalid transfer: %d Hz, %d bpw tx=%p, rx=%p\n", tr->speed_hz, tr->bits_per_word, tr->tx_buf, tr->rx_buf); status_error = -EINVAL; goto out; } } mutex_lock(&dd->core_lock); mutex_lock(&dd->core_lock); Loading @@ -1990,19 +2015,15 @@ static void msm_spi_workq(struct work_struct *work) spin_lock_irqsave(&dd->queue_lock, flags); spin_lock_irqsave(&dd->queue_lock, flags); dd->transfer_pending = 1; dd->transfer_pending = 1; while (!list_empty(&dd->queue)) { dd->cur_msg = msg; dd->cur_msg = list_entry(dd->queue.next, struct spi_message, queue); list_del_init(&dd->cur_msg->queue); spin_unlock_irqrestore(&dd->queue_lock, flags); spin_unlock_irqrestore(&dd->queue_lock, flags); if (status_error) if (status_error) dd->cur_msg->status = -EIO; dd->cur_msg->status = -EIO; else else msm_spi_process_message(dd); msm_spi_process_message(dd); if (dd->cur_msg->complete) dd->cur_msg->complete(dd->cur_msg->context); spin_lock_irqsave(&dd->queue_lock, flags); spin_lock_irqsave(&dd->queue_lock, flags); } dd->transfer_pending = 0; dd->transfer_pending = 0; spin_unlock_irqrestore(&dd->queue_lock, flags); spin_unlock_irqrestore(&dd->queue_lock, flags); Loading @@ -2011,44 +2032,33 @@ static void msm_spi_workq(struct work_struct *work) mutex_unlock(&dd->core_lock); mutex_unlock(&dd->core_lock); pm_runtime_mark_last_busy(dd->dev); /* pm_runtime_put_autosuspend(dd->dev); * If needed, this can be done after the current message is complete, * and work can be continued upon resume. No motivation for now. /* If needed, this can be done after the current message is complete, */ and work can be continued upon resume. No motivation for now. */ if (dd->suspended) if (dd->suspended) wake_up_interruptible(&dd->continue_suspend); wake_up_interruptible(&dd->continue_suspend); out: dd->cur_msg->status = status_error; spi_finalize_current_message(master); return 0; } } static int msm_spi_transfer(struct spi_device *spi, struct spi_message *msg) static int msm_spi_prepare_transfer_hardware(struct spi_master *master) { { struct msm_spi *dd; struct msm_spi *dd = spi_master_get_devdata(master); unsigned long flags; struct spi_transfer *tr; dd = spi_master_get_devdata(spi->master); if (list_empty(&msg->transfers) || !msg->complete) return -EINVAL; list_for_each_entry(tr, &msg->transfers, transfer_list) { pm_runtime_get_sync(dd->dev); /* Check message parameters */ return 0; if (tr->speed_hz > dd->pdata->max_clock_speed || (tr->bits_per_word && (tr->bits_per_word < 4 || tr->bits_per_word > 32)) || (tr->tx_buf == NULL && tr->rx_buf == NULL)) { dev_err(&spi->dev, "Invalid transfer: %d Hz, %d bpw" "tx=%p, rx=%p\n", tr->speed_hz, tr->bits_per_word, tr->tx_buf, tr->rx_buf); return -EINVAL; } } } spin_lock_irqsave(&dd->queue_lock, flags); static int msm_spi_unprepare_transfer_hardware(struct spi_master *master) list_add_tail(&msg->queue, &dd->queue); { spin_unlock_irqrestore(&dd->queue_lock, flags); struct msm_spi *dd = spi_master_get_devdata(master); queue_work(dd->workqueue, &dd->work_data); pm_runtime_mark_last_busy(dd->dev); pm_runtime_put_autosuspend(dd->dev); return 0; return 0; } } Loading Loading @@ -2700,6 +2710,8 @@ struct msm_spi_platform_data * __init msm_spi_dt_to_pdata( &dd->cs_gpios[2].gpio_num, DT_OPT, DT_GPIO, -1}, &dd->cs_gpios[2].gpio_num, DT_OPT, DT_GPIO, -1}, {"qcom,gpio-cs3", {"qcom,gpio-cs3", &dd->cs_gpios[3].gpio_num, DT_OPT, DT_GPIO, -1}, &dd->cs_gpios[3].gpio_num, DT_OPT, DT_GPIO, -1}, {"qcom,rt-priority", &pdata->rt_priority, DT_OPT, DT_BOOL, 0}, {NULL, NULL, 0, 0, 0}, {NULL, NULL, 0, 0, 0}, }; }; Loading Loading @@ -2793,7 +2805,11 @@ static int __init msm_spi_probe(struct platform_device *pdev) master->mode_bits = SPI_SUPPORTED_MODES; master->mode_bits = SPI_SUPPORTED_MODES; master->num_chipselect = SPI_NUM_CHIPSELECTS; master->num_chipselect = SPI_NUM_CHIPSELECTS; master->setup = msm_spi_setup; master->setup = msm_spi_setup; master->transfer = msm_spi_transfer; master->prepare_transfer_hardware = msm_spi_prepare_transfer_hardware; master->transfer_one_message = msm_spi_transfer_one_message; master->unprepare_transfer_hardware = msm_spi_unprepare_transfer_hardware; platform_set_drvdata(pdev, master); platform_set_drvdata(pdev, master); dd = spi_master_get_devdata(master); dd = spi_master_get_devdata(master); Loading Loading @@ -2833,6 +2849,7 @@ static int __init msm_spi_probe(struct platform_device *pdev) for (i = 0; i < ARRAY_SIZE(spi_cs_rsrcs); ++i) for (i = 0; i < ARRAY_SIZE(spi_cs_rsrcs); ++i) dd->cs_gpios[i].valid = 0; dd->cs_gpios[i].valid = 0; master->rt = pdata->rt_priority; dd->pdata = pdata; dd->pdata = pdata; resource = platform_get_resource(pdev, IORESOURCE_MEM, 0); resource = platform_get_resource(pdev, IORESOURCE_MEM, 0); if (!resource) { if (!resource) { Loading Loading @@ -2894,13 +2911,6 @@ skip_dma_resources: spin_lock_init(&dd->queue_lock); spin_lock_init(&dd->queue_lock); mutex_init(&dd->core_lock); mutex_init(&dd->core_lock); INIT_LIST_HEAD(&dd->queue); INIT_WORK(&dd->work_data, msm_spi_workq); init_waitqueue_head(&dd->continue_suspend); dd->workqueue = create_singlethread_workqueue( dev_name(master->dev.parent)); if (!dd->workqueue) goto err_probe_workq; if (!devm_request_mem_region(&pdev->dev, dd->mem_phys_addr, if (!devm_request_mem_region(&pdev->dev, dd->mem_phys_addr, dd->mem_size, SPI_DRV_NAME)) { dd->mem_size, SPI_DRV_NAME)) { Loading Loading @@ -3080,8 +3090,6 @@ err_probe_clk_get: } } err_probe_rlock_init: err_probe_rlock_init: err_probe_reqmem: err_probe_reqmem: destroy_workqueue(dd->workqueue); err_probe_workq: err_probe_res: err_probe_res: spi_master_put(master); spi_master_put(master); err_probe_exit: err_probe_exit: Loading Loading @@ -3244,7 +3252,6 @@ static int msm_spi_remove(struct platform_device *pdev) clk_put(dd->clk); clk_put(dd->clk); clk_put(dd->pclk); clk_put(dd->pclk); msm_spi_clk_path_teardown(dd); msm_spi_clk_path_teardown(dd); destroy_workqueue(dd->workqueue); platform_set_drvdata(pdev, 0); platform_set_drvdata(pdev, 0); spi_unregister_master(master); spi_unregister_master(master); spi_master_put(master); spi_master_put(master); Loading
drivers/spi/spi_qsd.h +0 −3 Original line number Original line Diff line number Diff line Loading @@ -300,9 +300,6 @@ struct msm_spi { struct device *dev; struct device *dev; spinlock_t queue_lock; spinlock_t queue_lock; struct mutex core_lock; struct mutex core_lock; struct list_head queue; struct workqueue_struct *workqueue; struct work_struct work_data; struct spi_message *cur_msg; struct spi_message *cur_msg; struct spi_transfer *cur_transfer; struct spi_transfer *cur_transfer; struct completion transfer_complete; struct completion transfer_complete; Loading