diff options
Diffstat (limited to 'drivers')
-rw-r--r-- | drivers/mtd/spi-nor/fsl-flexspi.c | 106 |
1 files changed, 79 insertions, 27 deletions
diff --git a/drivers/mtd/spi-nor/fsl-flexspi.c b/drivers/mtd/spi-nor/fsl-flexspi.c index d4f122bddea7..1e8f2e4c662b 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 @@ -443,7 +447,7 @@ struct fsl_flexspi { u32 memmap_phy; u32 memmap_offs; u32 memmap_len; - struct clk *clk, *clk_en; + struct clk *clk; struct device *dev; struct completion c; struct fsl_flexspi_devtype_data *devtype_data; @@ -893,13 +897,9 @@ static int fsl_flexspi_clk_prep_enable(struct fsl_flexspi *flex) { int ret; - ret = clk_prepare_enable(flex->clk_en); - if (ret) - return ret; - ret = clk_prepare_enable(flex->clk); if (ret) { - clk_disable_unprepare(flex->clk_en); + dev_err(flex->dev, "failed to enable the clock\n"); return ret; } @@ -910,7 +910,17 @@ static int fsl_flexspi_clk_prep_enable(struct fsl_flexspi *flex) static void fsl_flexspi_clk_disable_unprep(struct fsl_flexspi *flex) { clk_disable_unprepare(flex->clk); - clk_disable_unprepare(flex->clk_en); +} + +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(). */ @@ -918,6 +928,13 @@ 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); @@ -940,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; } @@ -948,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); @@ -965,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; } @@ -1104,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; @@ -1120,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); } @@ -1155,6 +1188,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"); @@ -1184,11 +1218,7 @@ static int fsl_flexspi_probe(struct platform_device *pdev) flex->memmap_phy = res->start; /* find the clocks */ - flex->clk_en = devm_clk_get(dev, "qspi_en"); - if (IS_ERR(flex->clk_en)) - return PTR_ERR(flex->clk_en); - - flex->clk = devm_clk_get(dev, "qspi"); + flex->clk = devm_clk_get(dev, "fspi"); if (IS_ERR(flex->clk)) return PTR_ERR(flex->clk); @@ -1198,7 +1228,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; @@ -1208,19 +1239,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; @@ -1304,7 +1335,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: @@ -1316,8 +1346,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; @@ -1338,6 +1366,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) @@ -1346,26 +1376,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_resume(struct platform_device *pdev) +static int fsl_flexspi_pm_resume(struct device *dev) { + return pm_runtime_force_resume(dev); +} +#endif + +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); |