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(+)
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; };
From: Mark Brown broonie@linaro.org
Signed-off-by: Mark Brown broonie@linaro.org --- drivers/spi/spi-bcm63xx.c | 21 +-------------------- 1 file changed, 1 insertion(+), 20 deletions(-)
diff --git a/drivers/spi/spi-bcm63xx.c b/drivers/spi/spi-bcm63xx.c index 9fd7a39..4ac028d 100644 --- a/drivers/spi/spi-bcm63xx.c +++ b/drivers/spi/spi-bcm63xx.c @@ -231,24 +231,6 @@ static int bcm63xx_txrx_bufs(struct spi_device *spi, struct spi_transfer *first, return 0; }
-static int bcm63xx_spi_prepare_transfer(struct spi_master *master) -{ - struct bcm63xx_spi *bs = spi_master_get_devdata(master); - - pm_runtime_get_sync(&bs->pdev->dev); - - return 0; -} - -static int bcm63xx_spi_unprepare_transfer(struct spi_master *master) -{ - struct bcm63xx_spi *bs = spi_master_get_devdata(master); - - pm_runtime_put(&bs->pdev->dev); - - return 0; -} - static int bcm63xx_spi_transfer_one(struct spi_master *master, struct spi_message *m) { @@ -412,11 +394,10 @@ static int bcm63xx_spi_probe(struct platform_device *pdev)
master->bus_num = pdata->bus_num; master->num_chipselect = pdata->num_chipselect; - master->prepare_transfer_hardware = bcm63xx_spi_prepare_transfer; - master->unprepare_transfer_hardware = bcm63xx_spi_unprepare_transfer; master->transfer_one_message = bcm63xx_spi_transfer_one; master->mode_bits = MODEBITS; master->bits_per_word_mask = SPI_BPW_MASK(8); + master->auto_runtime_pm = true; bs->msg_type_shift = pdata->msg_type_shift; bs->msg_ctl_width = pdata->msg_ctl_width; bs->tx_io = (u8 *)(bs->regs + bcm63xx_spireg(SPI_MSG_DATA));
From: Mark Brown broonie@linaro.org
Signed-off-by: Mark Brown broonie@linaro.org --- drivers/spi/spi-coldfire-qspi.c | 21 +-------------------- 1 file changed, 1 insertion(+), 20 deletions(-)
diff --git a/drivers/spi/spi-coldfire-qspi.c b/drivers/spi/spi-coldfire-qspi.c index 0631b9d..e4265ea 100644 --- a/drivers/spi/spi-coldfire-qspi.c +++ b/drivers/spi/spi-coldfire-qspi.c @@ -354,24 +354,6 @@ static int mcfqspi_transfer_one_message(struct spi_master *master,
}
-static int mcfqspi_prepare_transfer_hw(struct spi_master *master) -{ - struct mcfqspi *mcfqspi = spi_master_get_devdata(master); - - pm_runtime_get_sync(mcfqspi->dev); - - return 0; -} - -static int mcfqspi_unprepare_transfer_hw(struct spi_master *master) -{ - struct mcfqspi *mcfqspi = spi_master_get_devdata(master); - - pm_runtime_put_sync(mcfqspi->dev); - - return 0; -} - static int mcfqspi_setup(struct spi_device *spi) { if (spi->chip_select >= spi->master->num_chipselect) { @@ -473,8 +455,7 @@ static int mcfqspi_probe(struct platform_device *pdev) master->bits_per_word_mask = SPI_BPW_RANGE_MASK(8, 16); master->setup = mcfqspi_setup; master->transfer_one_message = mcfqspi_transfer_one_message; - master->prepare_transfer_hardware = mcfqspi_prepare_transfer_hw; - master->unprepare_transfer_hardware = mcfqspi_unprepare_transfer_hw; + master->auto_runtime_pm = true;
platform_set_drvdata(pdev, master);
From: Mark Brown broonie@linaro.org
Signed-off-by: Mark Brown broonie@linaro.org --- drivers/spi/spi-omap2-mcspi.c | 20 +------------------- 1 file changed, 1 insertion(+), 19 deletions(-)
diff --git a/drivers/spi/spi-omap2-mcspi.c b/drivers/spi/spi-omap2-mcspi.c index 5994039..973c1cb 100644 --- a/drivers/spi/spi-omap2-mcspi.c +++ b/drivers/spi/spi-omap2-mcspi.c @@ -335,23 +335,6 @@ static void omap2_mcspi_restore_ctx(struct omap2_mcspi *mcspi) __raw_writel(cs->chconf0, cs->base + OMAP2_MCSPI_CHCONF0); }
-static int omap2_prepare_transfer(struct spi_master *master) -{ - struct omap2_mcspi *mcspi = spi_master_get_devdata(master); - - pm_runtime_get_sync(mcspi->dev); - return 0; -} - -static int omap2_unprepare_transfer(struct spi_master *master) -{ - struct omap2_mcspi *mcspi = spi_master_get_devdata(master); - - pm_runtime_mark_last_busy(mcspi->dev); - pm_runtime_put_autosuspend(mcspi->dev); - return 0; -} - static int mcspi_wait_for_reg_bit(void __iomem *reg, unsigned long bit) { unsigned long timeout; @@ -1318,8 +1301,7 @@ static int omap2_mcspi_probe(struct platform_device *pdev) master->mode_bits = SPI_CPOL | SPI_CPHA | SPI_CS_HIGH; master->bits_per_word_mask = SPI_BPW_RANGE_MASK(4, 32); master->setup = omap2_mcspi_setup; - master->prepare_transfer_hardware = omap2_prepare_transfer; - master->unprepare_transfer_hardware = omap2_unprepare_transfer; + master->auto_runtime_pm = true; master->transfer_one_message = omap2_mcspi_transfer_one_message; master->cleanup = omap2_mcspi_cleanup; master->dev.of_node = node;
Hi,
On Sun, Jul 28, 2013 at 03:43:19PM +0100, Mark Brown wrote:
From: Mark Brown broonie@linaro.org
Signed-off-by: Mark Brown broonie@linaro.org
Reviewed-by: Felipe Balbi balbi@ti.com
From: Mark Brown broonie@linaro.org
Signed-off-by: Mark Brown broonie@linaro.org --- drivers/spi/spi-pl022.c | 21 +-------------------- 1 file changed, 1 insertion(+), 20 deletions(-)
diff --git a/drivers/spi/spi-pl022.c b/drivers/spi/spi-pl022.c index abef061..07e6db6 100644 --- a/drivers/spi/spi-pl022.c +++ b/drivers/spi/spi-pl022.c @@ -1555,18 +1555,6 @@ static int pl022_transfer_one_message(struct spi_master *master, return 0; }
-static int pl022_prepare_transfer_hardware(struct spi_master *master) -{ - struct pl022 *pl022 = spi_master_get_devdata(master); - - /* - * Just make sure we have all we need to run the transfer by syncing - * with the runtime PM framework. - */ - pm_runtime_get_sync(&pl022->adev->dev); - return 0; -} - static int pl022_unprepare_transfer_hardware(struct spi_master *master) { struct pl022 *pl022 = spi_master_get_devdata(master); @@ -1575,13 +1563,6 @@ static int pl022_unprepare_transfer_hardware(struct spi_master *master) writew((readw(SSP_CR1(pl022->virtbase)) & (~SSP_CR1_MASK_SSE)), SSP_CR1(pl022->virtbase));
- if (pl022->master_info->autosuspend_delay > 0) { - pm_runtime_mark_last_busy(&pl022->adev->dev); - pm_runtime_put_autosuspend(&pl022->adev->dev); - } else { - pm_runtime_put(&pl022->adev->dev); - } - return 0; }
@@ -2139,7 +2120,7 @@ static int pl022_probe(struct amba_device *adev, const struct amba_id *id) master->num_chipselect = num_cs; master->cleanup = pl022_cleanup; master->setup = pl022_setup; - master->prepare_transfer_hardware = pl022_prepare_transfer_hardware; + master->auto_runtime_pm = true; master->transfer_one_message = pl022_transfer_one_message; master->unprepare_transfer_hardware = pl022_unprepare_transfer_hardware; master->rt = platform_info->rt;
On Sun, Jul 28, 2013 at 4:43 PM, Mark Brown broonie@kernel.org wrote:
From: Mark Brown broonie@linaro.org
Signed-off-by: Mark Brown broonie@linaro.org
Reviewed-by: Linus Walleij linus.walleij@linaro.org
Someone moaned about oneline commit messages in the last LWN...
Yours, Linus Walleij
On Sun, Jul 28, 2013 at 10:52:38PM +0200, Linus Walleij wrote:
Someone moaned about oneline commit messages in the last LWN...
I saw that (and even followed up). To be honest for this sort of patch I'm not that concerned about it - it's fairly clear what's going on and why it might be a good idea.
From: Mark Brown broonie@linaro.org
Signed-off-by: Mark Brown broonie@linaro.org --- drivers/spi/spi-pxa2xx.c | 12 +----------- 1 file changed, 1 insertion(+), 11 deletions(-)
diff --git a/drivers/spi/spi-pxa2xx.c b/drivers/spi/spi-pxa2xx.c index e0fd6f6..2eb06ee 100644 --- a/drivers/spi/spi-pxa2xx.c +++ b/drivers/spi/spi-pxa2xx.c @@ -811,14 +811,6 @@ static int pxa2xx_spi_transfer_one_message(struct spi_master *master, return 0; }
-static int pxa2xx_spi_prepare_transfer(struct spi_master *master) -{ - struct driver_data *drv_data = spi_master_get_devdata(master); - - pm_runtime_get_sync(&drv_data->pdev->dev); - return 0; -} - static int pxa2xx_spi_unprepare_transfer(struct spi_master *master) { struct driver_data *drv_data = spi_master_get_devdata(master); @@ -827,8 +819,6 @@ static int pxa2xx_spi_unprepare_transfer(struct spi_master *master) write_SSCR0(read_SSCR0(drv_data->ioaddr) & ~SSCR0_SSE, drv_data->ioaddr);
- pm_runtime_mark_last_busy(&drv_data->pdev->dev); - pm_runtime_put_autosuspend(&drv_data->pdev->dev); return 0; }
@@ -1141,8 +1131,8 @@ static int pxa2xx_spi_probe(struct platform_device *pdev) master->cleanup = cleanup; master->setup = setup; master->transfer_one_message = pxa2xx_spi_transfer_one_message; - master->prepare_transfer_hardware = pxa2xx_spi_prepare_transfer; master->unprepare_transfer_hardware = pxa2xx_spi_unprepare_transfer; + master->auto_runtime_pm = true;
drv_data->ssp_type = ssp->type; drv_data->null_dma_buf = (u32 *)PTR_ALIGN(&drv_data[1], DMA_ALIGNMENT);
From: Mark Brown broonie@linaro.org
Signed-off-by: Mark Brown broonie@linaro.org --- drivers/spi/spi-sh-hspi.c | 18 +----------------- 1 file changed, 1 insertion(+), 17 deletions(-)
diff --git a/drivers/spi/spi-sh-hspi.c b/drivers/spi/spi-sh-hspi.c index daf2bf2..0b68cb5 100644 --- a/drivers/spi/spi-sh-hspi.c +++ b/drivers/spi/spi-sh-hspi.c @@ -99,21 +99,6 @@ static int hspi_status_check_timeout(struct hspi_priv *hspi, u32 mask, u32 val) /* * spi master function */ -static int hspi_prepare_transfer(struct spi_master *master) -{ - struct hspi_priv *hspi = spi_master_get_devdata(master); - - pm_runtime_get_sync(hspi->dev); - return 0; -} - -static int hspi_unprepare_transfer(struct spi_master *master) -{ - struct hspi_priv *hspi = spi_master_get_devdata(master); - - pm_runtime_put_sync(hspi->dev); - return 0; -}
#define hspi_hw_cs_enable(hspi) hspi_hw_cs_ctrl(hspi, 0) #define hspi_hw_cs_disable(hspi) hspi_hw_cs_ctrl(hspi, 1) @@ -316,9 +301,8 @@ static int hspi_probe(struct platform_device *pdev) master->setup = hspi_setup; master->cleanup = hspi_cleanup; master->mode_bits = SPI_CPOL | SPI_CPHA; - master->prepare_transfer_hardware = hspi_prepare_transfer; + master->auto_runtime_pm = true; master->transfer_one_message = hspi_transfer_one_message; - master->unprepare_transfer_hardware = hspi_unprepare_transfer; ret = spi_register_master(master); if (ret < 0) { dev_err(&pdev->dev, "spi_register_master error.\n");
From: Mark Brown broonie@linaro.org
Signed-off-by: Mark Brown broonie@linaro.org --- drivers/spi/spi-s3c64xx.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-)
diff --git a/drivers/spi/spi-s3c64xx.c b/drivers/spi/spi-s3c64xx.c index c9d0b12..62f32c4 100644 --- a/drivers/spi/spi-s3c64xx.c +++ b/drivers/spi/spi-s3c64xx.c @@ -356,8 +356,6 @@ static int s3c64xx_spi_prepare_transfer(struct spi_master *spi) while (!is_polling(sdd) && !acquire_dma(sdd)) usleep_range(10000, 11000);
- pm_runtime_get_sync(&sdd->pdev->dev); - return 0; }
@@ -372,7 +370,6 @@ static int s3c64xx_spi_unprepare_transfer(struct spi_master *spi) sdd->ops->release((enum dma_ch)sdd->tx_dma.ch, &s3c64xx_spi_dma_client); } - pm_runtime_put(&sdd->pdev->dev);
return 0; } @@ -1375,6 +1372,7 @@ static int s3c64xx_spi_probe(struct platform_device *pdev) SPI_BPW_MASK(8); /* the spi->mode bits understood by this driver: */ master->mode_bits = SPI_CPOL | SPI_CPHA | SPI_CS_HIGH; + master->auto_runtime_pm = true;
sdd->regs = devm_ioremap_resource(&pdev->dev, mem_res); if (IS_ERR(sdd->regs)) {
From: Mark Brown broonie@linaro.org
Signed-off-by: Mark Brown broonie@linaro.org --- drivers/spi/spi-tegra114.c | 26 +------------------------- 1 file changed, 1 insertion(+), 25 deletions(-)
diff --git a/drivers/spi/spi-tegra114.c b/drivers/spi/spi-tegra114.c index e7d48a1..2e208dc 100644 --- a/drivers/spi/spi-tegra114.c +++ b/drivers/spi/spi-tegra114.c @@ -803,20 +803,6 @@ static int tegra_spi_setup(struct spi_device *spi) return 0; }
-static int tegra_spi_prepare_transfer(struct spi_master *spi) -{ - struct tegra_spi_data *tspi = spi_master_get_devdata(spi); - int ret; - - ret = pm_runtime_get_sync(tspi->dev); - if (ret < 0) { - dev_err(tspi->dev, "runtime PM get failed: %d\n", ret); - return ret; - } - - return ret; -} - static int tegra_spi_transfer_one_message(struct spi_master *master, struct spi_message *msg) { @@ -870,15 +856,6 @@ exit: return ret; }
-static int tegra_spi_unprepare_transfer(struct spi_master *spi) -{ - struct tegra_spi_data *tspi = spi_master_get_devdata(spi); - - pm_runtime_put(tspi->dev); - - return 0; -} - static irqreturn_t handle_cpu_based_xfer(struct tegra_spi_data *tspi) { struct spi_transfer *t = tspi->curr_xfer; @@ -1064,11 +1041,10 @@ static int tegra_spi_probe(struct platform_device *pdev) /* the spi->mode bits understood by this driver: */ master->mode_bits = SPI_CPOL | SPI_CPHA | SPI_CS_HIGH; master->setup = tegra_spi_setup; - master->prepare_transfer_hardware = tegra_spi_prepare_transfer; master->transfer_one_message = tegra_spi_transfer_one_message; - master->unprepare_transfer_hardware = tegra_spi_unprepare_transfer; master->num_chipselect = MAX_CHIP_SELECT; master->bus_num = -1; + master->auto_runtime_pm = true;
tspi->master = master; tspi->dev = &pdev->dev;
From: Mark Brown broonie@linaro.org
Signed-off-by: Mark Brown broonie@linaro.org --- drivers/spi/spi-tegra20-sflash.c | 26 +------------------------- 1 file changed, 1 insertion(+), 25 deletions(-)
diff --git a/drivers/spi/spi-tegra20-sflash.c b/drivers/spi/spi-tegra20-sflash.c index f871c4e..1d814dc 100644 --- a/drivers/spi/spi-tegra20-sflash.c +++ b/drivers/spi/spi-tegra20-sflash.c @@ -325,20 +325,6 @@ static int tegra_sflash_setup(struct spi_device *spi) return 0; }
-static int tegra_sflash_prepare_transfer(struct spi_master *spi) -{ - struct tegra_sflash_data *tsd = spi_master_get_devdata(spi); - int ret; - - ret = pm_runtime_get_sync(tsd->dev); - if (ret < 0) { - dev_err(tsd->dev, "runtime PM get failed: %d\n", ret); - return ret; - } - - return ret; -} - static int tegra_sflash_transfer_one_message(struct spi_master *master, struct spi_message *msg) { @@ -391,15 +377,6 @@ exit: return ret; }
-static int tegra_sflash_unprepare_transfer(struct spi_master *spi) -{ - struct tegra_sflash_data *tsd = spi_master_get_devdata(spi); - - pm_runtime_put(tsd->dev); - - return 0; -} - static irqreturn_t handle_cpu_based_xfer(struct tegra_sflash_data *tsd) { struct spi_transfer *t = tsd->curr_xfer; @@ -492,9 +469,8 @@ static int tegra_sflash_probe(struct platform_device *pdev) /* the spi->mode bits understood by this driver: */ master->mode_bits = SPI_CPOL | SPI_CPHA; master->setup = tegra_sflash_setup; - master->prepare_transfer_hardware = tegra_sflash_prepare_transfer; master->transfer_one_message = tegra_sflash_transfer_one_message; - master->unprepare_transfer_hardware = tegra_sflash_unprepare_transfer; + master->auto_runtime_pm = true; master->num_chipselect = MAX_CHIP_SELECT; master->bus_num = -1;
From: Mark Brown broonie@linaro.org
Signed-off-by: Mark Brown broonie@linaro.org --- drivers/spi/spi-tegra20-slink.c | 26 +------------------------- 1 file changed, 1 insertion(+), 25 deletions(-)
diff --git a/drivers/spi/spi-tegra20-slink.c b/drivers/spi/spi-tegra20-slink.c index b2fb115..c703536 100644 --- a/drivers/spi/spi-tegra20-slink.c +++ b/drivers/spi/spi-tegra20-slink.c @@ -824,20 +824,6 @@ static int tegra_slink_setup(struct spi_device *spi) return 0; }
-static int tegra_slink_prepare_transfer(struct spi_master *spi) -{ - struct tegra_slink_data *tspi = spi_master_get_devdata(spi); - int ret; - - ret = pm_runtime_get_sync(tspi->dev); - if (ret < 0) { - dev_err(tspi->dev, "runtime PM get failed: %d\n", ret); - return ret; - } - - return ret; -} - static int tegra_slink_transfer_one_message(struct spi_master *master, struct spi_message *msg) { @@ -892,15 +878,6 @@ exit: return ret; }
-static int tegra_slink_unprepare_transfer(struct spi_master *spi) -{ - struct tegra_slink_data *tspi = spi_master_get_devdata(spi); - - pm_runtime_put(tspi->dev); - - return 0; -} - static irqreturn_t handle_cpu_based_xfer(struct tegra_slink_data *tspi) { struct spi_transfer *t = tspi->curr_xfer; @@ -1101,9 +1078,8 @@ static int tegra_slink_probe(struct platform_device *pdev) /* the spi->mode bits understood by this driver: */ master->mode_bits = SPI_CPOL | SPI_CPHA | SPI_CS_HIGH; master->setup = tegra_slink_setup; - master->prepare_transfer_hardware = tegra_slink_prepare_transfer; master->transfer_one_message = tegra_slink_transfer_one_message; - master->unprepare_transfer_hardware = tegra_slink_unprepare_transfer; + master->auto_runtime_pm = true; master->num_chipselect = MAX_CHIP_SELECT; master->bus_num = -1;
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
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.
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
linaro-kernel@lists.linaro.org