diff --git a/drivers/mtd/spi-nor/fsl-quadspi.c b/drivers/mtd/spi-nor/fsl-quadspi.c index a5db7ad8fc202a13d46ef2206b4853f4fd00ecf7..8a69b2caa7923025df95c3012fa1c97e93a729ad 100644 --- a/drivers/mtd/spi-nor/fsl-quadspi.c +++ b/drivers/mtd/spi-nor/fsl-quadspi.c @@ -655,6 +655,32 @@ static void fsl_qspi_init_abh_read(struct fsl_qspi *q) q->iobase + QUADSPI_BFGENCR); } +/* This function was used to prepare and enable QSPI clock */ +static int fsl_qspi_clk_prep_enable(struct fsl_qspi *q) +{ + int ret; + + ret = clk_prepare_enable(q->clk_en); + if (ret) + return ret; + + ret = clk_prepare_enable(q->clk); + if (ret) { + clk_disable_unprepare(q->clk_en); + return ret; + } + + return 0; +} + +/* This function was used to disable and unprepare QSPI clock */ +static void fsl_qspi_clk_disable_unprep(struct fsl_qspi *q) +{ + clk_disable_unprepare(q->clk); + clk_disable_unprepare(q->clk_en); + +} + /* We use this function to do some basic init for spi_nor_scan(). */ static int fsl_qspi_nor_setup(struct fsl_qspi *q) { @@ -662,11 +688,18 @@ static int fsl_qspi_nor_setup(struct fsl_qspi *q) u32 reg; int ret; - /* the default frequency, we will change it in the future.*/ + /* disable and unprepare clock to avoid glitch pass to controller */ + fsl_qspi_clk_disable_unprep(q); + + /* the default frequency, we will change it in the future. */ ret = clk_set_rate(q->clk, 66000000); if (ret) return ret; + ret = fsl_qspi_clk_prep_enable(q); + if (ret) + return ret; + /* Init the LUT table. */ fsl_qspi_init_lut(q); @@ -698,10 +731,17 @@ static int fsl_qspi_nor_setup_last(struct fsl_qspi *q) if (needs_4x_clock(q)) rate *= 4; + /* disable and unprepare clock to avoid glitch pass to controller */ + fsl_qspi_clk_disable_unprep(q); + ret = clk_set_rate(q->clk, rate); if (ret) return ret; + ret = fsl_qspi_clk_prep_enable(q); + if (ret) + return ret; + /* Init the LUT table again. */ fsl_qspi_init_lut(q); @@ -844,22 +884,16 @@ static int fsl_qspi_prep(struct spi_nor *nor, enum spi_nor_ops ops) int ret; mutex_lock(&q->lock); - ret = clk_enable(q->clk_en); - if (ret) - goto err_mutex; - ret = clk_enable(q->clk); + ret = fsl_qspi_clk_prep_enable(q); if (ret) - goto err_clk; + goto err_mutex; fsl_qspi_set_base_addr(q, nor); return 0; -err_clk: - clk_disable(q->clk_en); err_mutex: mutex_unlock(&q->lock); - return ret; } @@ -867,8 +901,7 @@ static void fsl_qspi_unprep(struct spi_nor *nor, enum spi_nor_ops ops) { struct fsl_qspi *q = nor->priv; - clk_disable(q->clk); - clk_disable(q->clk_en); + fsl_qspi_clk_disable_unprep(q); mutex_unlock(&q->lock); } @@ -918,15 +951,9 @@ static int fsl_qspi_probe(struct platform_device *pdev) if (IS_ERR(q->clk)) return PTR_ERR(q->clk); - ret = clk_prepare_enable(q->clk_en); + ret = fsl_qspi_clk_prep_enable(q); if (ret) { - dev_err(dev, "cannot enable the qspi_en clock: %d\n", ret); - return ret; - } - - ret = clk_prepare_enable(q->clk); - if (ret) { - dev_err(dev, "cannot enable the qspi clock: %d\n", ret); + dev_err(dev, "can not enable the clock\n"); goto clk_failed; } @@ -1032,8 +1059,7 @@ static int fsl_qspi_probe(struct platform_device *pdev) if (ret) goto last_init_failed; - clk_disable(q->clk); - clk_disable(q->clk_en); + fsl_qspi_clk_disable_unprep(q); return 0; last_init_failed: @@ -1046,9 +1072,9 @@ static int fsl_qspi_probe(struct platform_device *pdev) mutex_failed: mutex_destroy(&q->lock); irq_failed: - clk_disable_unprepare(q->clk); + fsl_qspi_clk_disable_unprep(q); clk_failed: - clk_disable_unprepare(q->clk_en); + dev_err(dev, "Freescale QuadSPI probe failed\n"); return ret; } @@ -1069,8 +1095,6 @@ static int fsl_qspi_remove(struct platform_device *pdev) writel(0x0, q->iobase + QUADSPI_RSER); mutex_destroy(&q->lock); - clk_unprepare(q->clk); - clk_unprepare(q->clk_en); if (q->ahb_addr) iounmap(q->ahb_addr); @@ -1085,12 +1109,19 @@ static int fsl_qspi_suspend(struct platform_device *pdev, pm_message_t state) static int fsl_qspi_resume(struct platform_device *pdev) { + int ret; struct fsl_qspi *q = platform_get_drvdata(pdev); + ret = fsl_qspi_clk_prep_enable(q); + if (ret) + return ret; + fsl_qspi_nor_setup(q); fsl_qspi_set_map_addr(q); fsl_qspi_nor_setup_last(q); + fsl_qspi_clk_disable_unprep(q); + return 0; }