Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 7dd2af10 authored by Linux Build Service Account's avatar Linux Build Service Account Committed by Gerrit - the friendly Code Review server
Browse files

Merge "spi_qsd: Add core message queue feature"

parents d6e4e157 fee1e816
Loading
Loading
Loading
Loading
+4 −0
Original line number Original line Diff line number Diff line
@@ -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
@@ -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;
	};
	};
+4 −0
Original line number Original line Diff line number Diff line
@@ -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;
@@ -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;
};
};
+66 −59
Original line number Original line Diff line number Diff line
@@ -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);


@@ -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);


@@ -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;
}
}


@@ -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},
		};
		};


@@ -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);


@@ -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) {
@@ -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)) {
@@ -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:
@@ -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);
+0 −3
Original line number Original line Diff line number Diff line
@@ -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;