summaryrefslogtreecommitdiff
path: root/drivers
diff options
context:
space:
mode:
authorHan Xu <han.xu@nxp.com>2017-11-10 15:33:24 -0600
committerHan Xu <han.xu@nxp.com>2017-11-10 20:28:52 -0600
commitc0046aeca6ea89669f9a57b1fbf2a98bd42751bb (patch)
tree06496764a400f42721a47e7657210954dd940465 /drivers
parentc21c017ab4e908680834f09aa936858993ce311a (diff)
MLK-16799-2: 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 697db25256bf4a09115ca082f9ecf3ef67232ae3)
Diffstat (limited to 'drivers')
-rw-r--r--drivers/mtd/spi-nor/fsl-flexspi.c106
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);