Skip to content

Commit

Permalink
spi: spi-orion: add runtime PM support
Browse files Browse the repository at this point in the history
Add trivial runtime PM support.  This will only be of benefit on SoCs
where the clock to the SPI interface can be shut down.

Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
Signed-off-by: Mark Brown <broonie@linaro.org>
  • Loading branch information
Russell King authored and Mark Brown committed Jun 21, 2014
1 parent c85012a commit 5c67869
Showing 1 changed file with 50 additions and 9 deletions.
59 changes: 50 additions & 9 deletions drivers/spi/spi-orion.c
Original file line number Diff line number Diff line change
Expand Up @@ -16,13 +16,17 @@
#include <linux/io.h>
#include <linux/spi/spi.h>
#include <linux/module.h>
#include <linux/pm_runtime.h>
#include <linux/of.h>
#include <linux/clk.h>
#include <linux/sizes.h>
#include <asm/unaligned.h>

#define DRIVER_NAME "orion_spi"

/* Runtime PM autosuspend timeout: PM is fairly light on this driver */
#define SPI_AUTOSUSPEND_TIMEOUT 200

#define ORION_NUM_CHIPSELECTS 1 /* only one slave is supported*/
#define ORION_SPI_WAIT_RDY_MAX_LOOP 2000 /* in usec */

Expand Down Expand Up @@ -277,7 +281,6 @@ orion_spi_write_read(struct spi_device *spi, struct spi_transfer *xfer)
return xfer->len - count;
}


static int orion_spi_transfer_one_message(struct spi_master *master,
struct spi_message *m)
{
Expand Down Expand Up @@ -370,6 +373,7 @@ static int orion_spi_probe(struct platform_device *pdev)
master->transfer_one_message = orion_spi_transfer_one_message;
master->num_chipselect = ORION_NUM_CHIPSELECTS;
master->bits_per_word_mask = SPI_BPW_MASK(8) | SPI_BPW_MASK(16);
master->auto_runtime_pm = true;

platform_set_drvdata(pdev, master);

Expand Down Expand Up @@ -397,16 +401,26 @@ static int orion_spi_probe(struct platform_device *pdev)
goto out_rel_clk;
}

pm_runtime_set_active(&pdev->dev);
pm_runtime_use_autosuspend(&pdev->dev);
pm_runtime_set_autosuspend_delay(&pdev->dev, SPI_AUTOSUSPEND_TIMEOUT);
pm_runtime_enable(&pdev->dev);

if (orion_spi_reset(spi) < 0)
goto out_rel_clk;
goto out_rel_pm;

pm_runtime_mark_last_busy(&pdev->dev);
pm_runtime_put_autosuspend(&pdev->dev);

master->dev.of_node = pdev->dev.of_node;
status = devm_spi_register_master(&pdev->dev, master);
status = spi_register_master(master);
if (status < 0)
goto out_rel_clk;
goto out_rel_pm;

return status;

out_rel_pm:
pm_runtime_disable(&pdev->dev);
out_rel_clk:
clk_disable_unprepare(spi->clk);
out:
Expand All @@ -417,19 +431,45 @@ static int orion_spi_probe(struct platform_device *pdev)

static int orion_spi_remove(struct platform_device *pdev)
{
struct spi_master *master;
struct orion_spi *spi;

master = platform_get_drvdata(pdev);
spi = spi_master_get_devdata(master);
struct spi_master *master = platform_get_drvdata(pdev);
struct orion_spi *spi = spi_master_get_devdata(master);

pm_runtime_get_sync(&pdev->dev);
clk_disable_unprepare(spi->clk);

spi_unregister_master(master);
pm_runtime_disable(&pdev->dev);

return 0;
}

MODULE_ALIAS("platform:" DRIVER_NAME);

#ifdef CONFIG_PM_RUNTIME
static int orion_spi_runtime_suspend(struct device *dev)
{
struct spi_master *master = dev_get_drvdata(dev);
struct orion_spi *spi = spi_master_get_devdata(master);

clk_disable_unprepare(spi->clk);
return 0;
}

static int orion_spi_runtime_resume(struct device *dev)
{
struct spi_master *master = dev_get_drvdata(dev);
struct orion_spi *spi = spi_master_get_devdata(master);

return clk_prepare_enable(spi->clk);
}
#endif

static const struct dev_pm_ops orion_spi_pm_ops = {
SET_RUNTIME_PM_OPS(orion_spi_runtime_suspend,
orion_spi_runtime_resume,
NULL)
};

static const struct of_device_id orion_spi_of_match_table[] = {
{ .compatible = "marvell,orion-spi", },
{}
Expand All @@ -440,6 +480,7 @@ static struct platform_driver orion_spi_driver = {
.driver = {
.name = DRIVER_NAME,
.owner = THIS_MODULE,
.pm = &orion_spi_pm_ops,
.of_match_table = of_match_ptr(orion_spi_of_match_table),
},
.probe = orion_spi_probe,
Expand Down

0 comments on commit 5c67869

Please sign in to comment.