Patchwork [01/11] spi: Provide core support for runtime PM during transfers

login
register
mail settings
Submitter Mark Brown
Date July 28, 2013, 2:43 p.m.
Message ID <1375022606-7576-1-git-send-email-broonie@kernel.org>
Download mbox | patch
Permalink /patch/2834694/
State New, archived
Headers show

Comments

Mark Brown - July 28, 2013, 2:43 p.m.
From: Mark Brown <broonie@linaro.org>

Most SPI drivers that implement runtime PM support use identical code to
do so: they acquire a runtime PM lock in prepare_transfer_hardware() and
then they release it in unprepare_transfer_hardware(). The variations in
this are mostly missing error checking and the choice to use autosuspend.

Since these runtime PM calls are normally the only thing in the prepare
and unprepare callbacks and the autosuspend API transparently does the
right thing on devices with autosuspend disabled factor all of this out
into the core with a flag to enable the behaviour.

Signed-off-by: Mark Brown <broonie@linaro.org>
---
 drivers/spi/spi.c       | 16 ++++++++++++++++
 include/linux/spi/spi.h |  4 ++++
 2 files changed, 20 insertions(+)
Linus Walleij - July 28, 2013, 8:51 p.m.
On Sun, Jul 28, 2013 at 4:43 PM, Mark Brown <broonie@kernel.org> wrote:

> Most SPI drivers that implement runtime PM support use identical code to
> do so: they acquire a runtime PM lock in prepare_transfer_hardware() and
> then they release it in unprepare_transfer_hardware(). The variations in
> this are mostly missing error checking and the choice to use autosuspend.
>
> Since these runtime PM calls are normally the only thing in the prepare
> and unprepare callbacks and the autosuspend API transparently does the
> right thing on devices with autosuspend disabled factor all of this out
> into the core with a flag to enable the behaviour.
>
> Signed-off-by: Mark Brown <broonie@linaro.org>

Acked-by: Linus Walleij <linus.walleij@linaro.org>

> + * @auto_runtime_pm: the core should ensure a runtime PM reference is held
> + *                   while the hardware is prepared

I'd mention here that the reference is taken on the parent
device of the SPI master, i.e. the very platform or AMBA
device, so that it will hit upwards to the bus.

Yours,
Linus Walleij
--
To unsubscribe from this list: send the line "unsubscribe linux-omap" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Mark Brown - July 29, 2013, 5:56 a.m.
On Sun, Jul 28, 2013 at 10:51:31PM +0200, Linus Walleij wrote:
> On Sun, Jul 28, 2013 at 4:43 PM, Mark Brown <broonie@kernel.org> wrote:

> > + * @auto_runtime_pm: the core should ensure a runtime PM reference is held
> > + *                   while the hardware is prepared

> I'd mention here that the reference is taken on the parent
> device of the SPI master, i.e. the very platform or AMBA
> device, so that it will hit upwards to the bus.

Yeah, I was actually contemplating changing that to use the spidev
though I think I'm going to stich with what's there.  On the one hand
runtime PM does do the right thing with children but really the way it's
set up at the minute is more obvious for users.
Stephen Warren - July 29, 2013, 4:56 p.m.
On 07/28/2013 08:43 AM, Mark Brown wrote:
> From: Mark Brown <broonie@linaro.org>
> 
> Most SPI drivers that implement runtime PM support use identical code to
> do so: they acquire a runtime PM lock in prepare_transfer_hardware() and
> then they release it in unprepare_transfer_hardware(). The variations in
> this are mostly missing error checking and the choice to use autosuspend.
> 
> Since these runtime PM calls are normally the only thing in the prepare
> and unprepare callbacks and the autosuspend API transparently does the
> right thing on devices with autosuspend disabled factor all of this out
> into the core with a flag to enable the behaviour.

Patch 1, 9, 10, 11,
Reviewed-by: Stephen Warren <swarren@nvidia.com>
--
To unsubscribe from this list: send the line "unsubscribe linux-omap" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

Patch

diff --git a/drivers/spi/spi.c b/drivers/spi/spi.c
index 46c3f56..61f71b9 100644
--- a/drivers/spi/spi.c
+++ b/drivers/spi/spi.c
@@ -553,6 +553,10 @@  static void spi_pump_messages(struct kthread_work *work)
 		    master->unprepare_transfer_hardware(master))
 			dev_err(&master->dev,
 				"failed to unprepare transfer hardware\n");
+		if (master->auto_runtime_pm) {
+			pm_runtime_mark_last_busy(master->dev.parent);
+			pm_runtime_put_autosuspend(master->dev.parent);
+		}
 		return;
 	}
 
@@ -572,11 +576,23 @@  static void spi_pump_messages(struct kthread_work *work)
 		master->busy = true;
 	spin_unlock_irqrestore(&master->queue_lock, flags);
 
+	if (!was_busy && master->auto_runtime_pm) {
+		ret = pm_runtime_get_sync(master->dev.parent);
+		if (ret < 0) {
+			dev_err(&master->dev, "Failed to power device: %d\n",
+				ret);
+			return;
+		}
+	}
+
 	if (!was_busy && master->prepare_transfer_hardware) {
 		ret = master->prepare_transfer_hardware(master);
 		if (ret) {
 			dev_err(&master->dev,
 				"failed to prepare transfer hardware\n");
+
+			if (master->auto_runtime_pm)
+				pm_runtime_put(master->dev.parent);
 			return;
 		}
 	}
diff --git a/include/linux/spi/spi.h b/include/linux/spi/spi.h
index be40c97..d73059a 100644
--- a/include/linux/spi/spi.h
+++ b/include/linux/spi/spi.h
@@ -256,6 +256,8 @@  static inline void spi_unregister_driver(struct spi_driver *sdrv)
  * @busy: message pump is busy
  * @running: message pump is running
  * @rt: whether this queue is set to run as a realtime task
+ * @auto_runtime_pm: the core should ensure a runtime PM reference is held
+ *                   while the hardware is prepared
  * @prepare_transfer_hardware: a message will soon arrive from the queue
  *	so the subsystem requests the driver to prepare the transfer hardware
  *	by issuing this call
@@ -380,11 +382,13 @@  struct spi_master {
 	bool				busy;
 	bool				running;
 	bool				rt;
+	bool				auto_runtime_pm;
 
 	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);
+
 	/* gpio chip select */
 	int			*cs_gpios;
 };