diff options
author | Han Xu <han.xu@nxp.com> | 2017-11-10 15:33:24 -0600 |
---|---|---|
committer | Jason Liu <jason.hui.liu@nxp.com> | 2019-02-12 10:33:12 +0800 |
commit | afe2b51521d46a86d8c3ca164fab055a220a0fb2 (patch) | |
tree | 0ad86b8eea5e5a767f967c3bd7ce5f1525bd14dd /drivers/mtd | |
parent | cc5229aeab660149cdcb217dec09d6c3a6723459 (diff) |
MLK-16799: mtd: flexspi: support runtime pm for flexspi
enabled runtime pm for flexspi, also removed the redundant clock.
Tested with the latest SCFW and ATF.
BuildInfo:
- SCFW 15d20cde, IMX-MKIMAGE ff9860c5, ATF
- U-Boot 2017.03-00003-gd09f5db
Signed-off-by: Han Xu <han.xu@nxp.com>
(cherry picked from commit 138fd5bb66dde0c1d391d5cff3ed5ef40ed3a212)
Diffstat (limited to 'drivers/mtd')
-rw-r--r-- | drivers/mtd/spi-nor/fsl-flexspi.c | 92 |
1 files changed, 77 insertions, 15 deletions
diff --git a/drivers/mtd/spi-nor/fsl-flexspi.c b/drivers/mtd/spi-nor/fsl-flexspi.c index ffff6f2b38ad..68d03fd36d76 100644 --- a/drivers/mtd/spi-nor/fsl-flexspi.c +++ b/drivers/mtd/spi-nor/fsl-flexspi.c @@ -30,6 +30,10 @@ #include <linux/pm_qos.h> #include <linux/pci.h> #include <soc/imx8/sc/sci.h> +#include <linux/pm_runtime.h> + +/* runtime pm timeout */ +#define FSL_FLEXSPI_RPM_TIMEOUT 50 /* 50ms */ /* The registers */ #define FLEXSPI_MCR0 0x00 @@ -895,6 +899,7 @@ static int fsl_flexspi_clk_prep_enable(struct fsl_flexspi *flex) ret = clk_prepare_enable(flex->clk); if (ret) { + dev_err(flex->dev, "failed to enable the clock\n"); return ret; } @@ -907,11 +912,29 @@ static void fsl_flexspi_clk_disable_unprep(struct fsl_flexspi *flex) clk_disable_unprepare(flex->clk); } +static int fsl_flexspi_init_rpm(struct fsl_flexspi *flex) +{ + struct device *dev = flex->dev; + + pm_runtime_enable(dev); + pm_runtime_set_autosuspend_delay(dev, FSL_FLEXSPI_RPM_TIMEOUT); + pm_runtime_use_autosuspend(dev); + + return 0; +} + /* We use this function to do some basic init for spi_nor_scan(). */ static int fsl_flexspi_nor_setup(struct fsl_flexspi *flex) { void __iomem *base = flex->iobase; u32 reg; + int ret; + + ret = pm_runtime_get_sync(flex->dev); + if (ret < 0) { + dev_err(flex->dev, "Failed to enable clock %d\n", __LINE__); + return ret; + } /* Reset the module */ writel(FLEXSPI_MCR0_SWRST_MASK, base + FLEXSPI_MCR0); @@ -934,6 +957,10 @@ static int fsl_flexspi_nor_setup(struct fsl_flexspi *flex) /* enable the interrupt */ writel(FLEXSPI_INTEN_IPCMDDONE_MASK, flex->iobase + FLEXSPI_INTEN); + + pm_runtime_mark_last_busy(flex->dev); + pm_runtime_put_autosuspend(flex->dev); + return 0; } @@ -942,6 +969,12 @@ static int fsl_flexspi_nor_setup_last(struct fsl_flexspi *flex) unsigned long rate = flex->clk_rate; int ret; + ret = pm_runtime_get_sync(flex->dev); + if (ret < 0) { + dev_err(flex->dev, "Failed to enable clock %d\n", __LINE__); + return ret; + } + /* disable and unprepare clock to avoid glitch pass to controller */ fsl_flexspi_clk_disable_unprep(flex); @@ -959,6 +992,9 @@ static int fsl_flexspi_nor_setup_last(struct fsl_flexspi *flex) /* Init for AHB read */ fsl_flexspi_init_ahb_read(flex); + pm_runtime_mark_last_busy(flex->dev); + pm_runtime_put_autosuspend(flex->dev); + return 0; } @@ -1098,9 +1134,11 @@ static int fsl_flexspi_prep(struct spi_nor *nor, enum spi_nor_ops ops) mutex_lock(&flex->lock); - ret = fsl_flexspi_clk_prep_enable(flex); - if (ret) + ret = pm_runtime_get_sync(flex->dev); + if (ret < 0) { + dev_err(flex->dev, "Failed to enable clock %d\n", __LINE__); goto err_mutex; + } fsl_flexspi_set_base_addr(flex, nor); return 0; @@ -1114,7 +1152,8 @@ static void fsl_flexspi_unprep(struct spi_nor *nor, enum spi_nor_ops ops) { struct fsl_flexspi *flex = nor->priv; - fsl_flexspi_clk_disable_unprep(flex); + pm_runtime_mark_last_busy(flex->dev); + pm_runtime_put_autosuspend(flex->dev); mutex_unlock(&flex->lock); } @@ -1152,6 +1191,7 @@ static int fsl_flexspi_probe(struct platform_device *pdev) flex->dev = dev; flex->devtype_data = (struct fsl_flexspi_devtype_data *)of_id->data; platform_set_drvdata(pdev, flex); + dev_set_drvdata(dev, flex); /* find the resources */ res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "FlexSPI"); @@ -1191,7 +1231,8 @@ static int fsl_flexspi_probe(struct platform_device *pdev) if (ret) flex->ddr_smp = 0; - ret = fsl_flexspi_clk_prep_enable(flex); + /* enable the clock */ + ret = fsl_flexspi_init_rpm(flex); if (ret) { dev_err(dev, "can not enable the clock\n"); goto clk_failed; @@ -1201,19 +1242,19 @@ static int fsl_flexspi_probe(struct platform_device *pdev) ret = platform_get_irq(pdev, 0); if (ret < 0) { dev_err(dev, "failed to get the irq: %d\n", ret); - goto irq_failed; + goto clk_failed; } ret = devm_request_irq(dev, ret, fsl_flexspi_irq_handler, 0, pdev->name, flex); if (ret) { dev_err(dev, "failed to request irq: %d\n", ret); - goto irq_failed; + goto clk_failed; } ret = fsl_flexspi_nor_setup(flex); if (ret) - goto irq_failed; + goto clk_failed; if (of_get_property(np, "fsl,qspi-has-second-chip", NULL)) flex->has_second_chip = true; @@ -1298,7 +1339,6 @@ static int fsl_flexspi_probe(struct platform_device *pdev) if (ret) goto last_init_failed; - fsl_flexspi_clk_disable_unprep(flex); return 0; last_init_failed: @@ -1310,8 +1350,6 @@ last_init_failed: } mutex_failed: mutex_destroy(&flex->lock); -irq_failed: - fsl_flexspi_clk_disable_unprep(flex); clk_failed: dev_err(dev, "Freescale FlexSPI probe failed\n"); return ret; @@ -1332,6 +1370,8 @@ static int fsl_flexspi_remove(struct platform_device *pdev) /* disable the hardware */ writel(FLEXSPI_MCR0_MDIS_MASK, flex->iobase + FLEXSPI_MCR0); + pm_runtime_disable(flex->dev); + mutex_destroy(&flex->lock); if (flex->ahb_addr) @@ -1340,26 +1380,48 @@ static int fsl_flexspi_remove(struct platform_device *pdev) return 0; } -static int fsl_flexspi_suspend(struct platform_device *pdev, pm_message_t state) +#ifdef CONFIG_PM_SLEEP +static int fsl_flexspi_pm_suspend(struct device *dev) { - return 0; + return pm_runtime_force_suspend(dev); +} + +static int fsl_flexspi_pm_resume(struct device *dev) +{ + return pm_runtime_force_resume(dev); } +#endif -static int fsl_flexspi_resume(struct platform_device *pdev) +int fsl_flexspi_runtime_suspend(struct device *dev) { + struct fsl_flexspi *flex = dev_get_drvdata(dev); + + fsl_flexspi_clk_disable_unprep(flex); + return 0; } +int fsl_flexspi_runtime_resume(struct device *dev) +{ + struct fsl_flexspi *flex = dev_get_drvdata(dev); + + return fsl_flexspi_clk_prep_enable(flex); +} + +static const struct dev_pm_ops fsl_flexspi_pm_ops = { + SET_RUNTIME_PM_OPS(fsl_flexspi_runtime_suspend, fsl_flexspi_runtime_resume, NULL) + SET_SYSTEM_SLEEP_PM_OPS(fsl_flexspi_pm_suspend, fsl_flexspi_pm_resume) +}; + static struct platform_driver fsl_flexspi_driver = { .driver = { .name = "fsl-flexspi", .bus = &platform_bus_type, + .pm = &fsl_flexspi_pm_ops, .of_match_table = fsl_flexspi_dt_ids, }, .probe = fsl_flexspi_probe, .remove = fsl_flexspi_remove, - .suspend = fsl_flexspi_suspend, - .resume = fsl_flexspi_resume, }; module_platform_driver(fsl_flexspi_driver); |