From: Mark Brown Date: Fri, 4 Oct 2013 23:23:12 +0000 (+0100) Subject: spi: Provide per-message prepare and unprepare operations X-Git-Url: https://git.karo-electronics.de/?a=commitdiff_plain;h=2841a5fc375e9c573d10b82db30fa8a4cc25301c;p=linux-beck.git spi: Provide per-message prepare and unprepare operations Many SPI drivers perform setup and tear down on every message, usually doing things like DMA mapping the message. Provide hooks for them to use to provide such operations. This is of limited value for drivers that implement transfer_one_message() but will be of much greater utility with future factoring out of standard implementations of that function. Signed-off-by: Mark Brown --- diff --git a/drivers/spi/spi.c b/drivers/spi/spi.c index 8bef0c9a7233..8a30c6b66a64 100644 --- a/drivers/spi/spi.c +++ b/drivers/spi/spi.c @@ -606,6 +606,18 @@ static void spi_pump_messages(struct kthread_work *work) trace_spi_message_start(master->cur_msg); + if (master->prepare_message) { + ret = master->prepare_message(master, master->cur_msg); + if (ret) { + dev_err(&master->dev, + "failed to prepare message: %d\n", ret); + master->cur_msg->status = ret; + spi_finalize_current_message(master); + return; + } + master->cur_msg_prepared = true; + } + ret = master->transfer_one_message(master, master->cur_msg); if (ret) { dev_err(&master->dev, @@ -687,6 +699,7 @@ void spi_finalize_current_message(struct spi_master *master) { struct spi_message *mesg; unsigned long flags; + int ret; spin_lock_irqsave(&master->queue_lock, flags); mesg = master->cur_msg; @@ -695,6 +708,15 @@ void spi_finalize_current_message(struct spi_master *master) queue_kthread_work(&master->kworker, &master->pump_messages); spin_unlock_irqrestore(&master->queue_lock, flags); + if (master->cur_msg_prepared && master->unprepare_message) { + ret = master->unprepare_message(master, mesg); + if (ret) { + dev_err(&master->dev, + "failed to unprepare message: %d\n", ret); + } + } + master->cur_msg_prepared = false; + mesg->state = NULL; if (mesg->complete) mesg->complete(mesg->context); diff --git a/include/linux/spi/spi.h b/include/linux/spi/spi.h index 887116dbce2c..000b50bee6c0 100644 --- a/include/linux/spi/spi.h +++ b/include/linux/spi/spi.h @@ -257,6 +257,8 @@ static inline void spi_unregister_driver(struct spi_driver *sdrv) * @queue_lock: spinlock to syncronise access to message queue * @queue: message queue * @cur_msg: the currently in-flight message + * @cur_msg_prepared: spi_prepare_message was called for the currently + * in-flight message * @busy: message pump is busy * @running: message pump is running * @rt: whether this queue is set to run as a realtime task @@ -274,6 +276,10 @@ static inline void spi_unregister_driver(struct spi_driver *sdrv) * @unprepare_transfer_hardware: there are currently no more messages on the * queue so the subsystem notifies the driver that it may relax the * hardware by issuing this call + * @prepare_message: set up the controller to transfer a single message, + * for example doing DMA mapping. Called from threaded + * context. + * @unprepare_message: undo any work done by prepare_message(). * @cs_gpios: Array of GPIOs to use as chip select lines; one per CS * number. Any individual value may be -ENOENT for CS lines that * are not GPIOs (driven by the SPI controller itself). @@ -388,11 +394,16 @@ struct spi_master { bool running; bool rt; bool auto_runtime_pm; + bool cur_msg_prepared; int (*prepare_transfer_hardware)(struct spi_master *master); int (*transfer_one_message)(struct spi_master *master, struct spi_message *mesg); int (*unprepare_transfer_hardware)(struct spi_master *master); + int (*prepare_message)(struct spi_master *master, + struct spi_message *message); + int (*unprepare_message)(struct spi_master *master, + struct spi_message *message); /* gpio chip select */ int *cs_gpios;