spi: cadence-quadspi: Add clock configuration for StarFive JH7110 QSPI
authorWilliam Qiu <william.qiu@starfivetech.com>
Fri, 4 Aug 2023 02:02:53 +0000 (10:02 +0800)
committerMark Brown <broonie@kernel.org>
Fri, 4 Aug 2023 12:29:50 +0000 (13:29 +0100)
Add JH7110's clock initialization code to the driver.

Signed-off-by: William Qiu <william.qiu@starfivetech.com>
Reviewed-by: Hal Feng <hal.feng@starfivetech.com>
Link: https://lore.kernel.org/r/20230804020254.291239-3-william.qiu@starfivetech.com
Signed-off-by: Mark Brown <broonie@kernel.org>
drivers/spi/spi-cadence-quadspi.c

index e1a8cf0..6064b8e 100644 (file)
 
 #define CQSPI_OP_WIDTH(part) ((part).nbytes ? ilog2((part).buswidth) : 0)
 
+enum {
+       CLK_QSPI_APB = 0,
+       CLK_QSPI_AHB,
+       CLK_QSPI_NUM,
+};
+
 struct cqspi_st;
 
 struct cqspi_flash_pdata {
@@ -63,6 +69,7 @@ struct cqspi_st {
        struct platform_device  *pdev;
        struct spi_master       *master;
        struct clk              *clk;
+       struct clk              *clks[CLK_QSPI_NUM];
        unsigned int            sclk;
 
        void __iomem            *iobase;
@@ -91,6 +98,8 @@ struct cqspi_st {
        bool                    wr_completion;
        bool                    slow_sram;
        bool                    apb_ahb_hazard;
+
+       bool                    is_jh7110; /* Flag for StarFive JH7110 SoC */
 };
 
 struct cqspi_driver_platdata {
@@ -99,6 +108,8 @@ struct cqspi_driver_platdata {
        int (*indirect_read_dma)(struct cqspi_flash_pdata *f_pdata,
                                 u_char *rxbuf, loff_t from_addr, size_t n_rx);
        u32 (*get_dma_status)(struct cqspi_st *cqspi);
+       int (*jh7110_clk_init)(struct platform_device *pdev,
+                              struct cqspi_st *cqspi);
 };
 
 /* Operation timeout value */
@@ -1629,6 +1640,51 @@ static int cqspi_setup_flash(struct cqspi_st *cqspi)
        return 0;
 }
 
+static int cqspi_jh7110_clk_init(struct platform_device *pdev, struct cqspi_st *cqspi)
+{
+       static struct clk_bulk_data qspiclk[] = {
+               { .id = "apb" },
+               { .id = "ahb" },
+       };
+
+       int ret = 0;
+
+       ret = devm_clk_bulk_get(&pdev->dev, ARRAY_SIZE(qspiclk), qspiclk);
+       if (ret) {
+               dev_err(&pdev->dev, "%s: failed to get qspi clocks\n", __func__);
+               return ret;
+       }
+
+       cqspi->clks[CLK_QSPI_APB] = qspiclk[0].clk;
+       cqspi->clks[CLK_QSPI_AHB] = qspiclk[1].clk;
+
+       ret = clk_prepare_enable(cqspi->clks[CLK_QSPI_APB]);
+       if (ret) {
+               dev_err(&pdev->dev, "%s: failed to enable CLK_QSPI_APB\n", __func__);
+               return ret;
+       }
+
+       ret = clk_prepare_enable(cqspi->clks[CLK_QSPI_AHB]);
+       if (ret) {
+               dev_err(&pdev->dev, "%s: failed to enable CLK_QSPI_AHB\n", __func__);
+               goto disable_apb_clk;
+       }
+
+       cqspi->is_jh7110 = true;
+
+       return 0;
+
+disable_apb_clk:
+       clk_disable_unprepare(cqspi->clks[CLK_QSPI_APB]);
+
+       return ret;
+}
+
+static void cqspi_jh7110_disable_clk(struct platform_device *pdev, struct cqspi_st *cqspi)
+{
+       clk_disable_unprepare(cqspi->clks[CLK_QSPI_AHB]);
+       clk_disable_unprepare(cqspi->clks[CLK_QSPI_APB]);
+}
 static int cqspi_probe(struct platform_device *pdev)
 {
        const struct cqspi_driver_platdata *ddata;
@@ -1654,6 +1710,7 @@ static int cqspi_probe(struct platform_device *pdev)
 
        cqspi->pdev = pdev;
        cqspi->master = master;
+       cqspi->is_jh7110 = false;
        platform_set_drvdata(pdev, cqspi);
 
        /* Obtain configuration from OF. */
@@ -1765,6 +1822,12 @@ static int cqspi_probe(struct platform_device *pdev)
                if (ddata->quirks & CQSPI_NEEDS_APB_AHB_HAZARD_WAR)
                        cqspi->apb_ahb_hazard = true;
 
+               if (ddata->jh7110_clk_init) {
+                       ret = cqspi_jh7110_clk_init(pdev, cqspi);
+                       if (ret)
+                               goto probe_clk_failed;
+               }
+
                if (of_device_is_compatible(pdev->dev.of_node,
                                            "xlnx,versal-ospi-1.0")) {
                        ret = dma_set_mask(&pdev->dev, DMA_BIT_MASK(64));
@@ -1829,6 +1892,9 @@ static void cqspi_remove(struct platform_device *pdev)
 
        clk_disable_unprepare(cqspi->clk);
 
+       if (cqspi->is_jh7110)
+               cqspi_jh7110_disable_clk(pdev, cqspi);
+
        pm_runtime_put_sync(&pdev->dev);
        pm_runtime_disable(&pdev->dev);
 }
@@ -1896,6 +1962,7 @@ static const struct cqspi_driver_platdata versal_ospi = {
 
 static const struct cqspi_driver_platdata jh7110_qspi = {
        .quirks = CQSPI_DISABLE_DAC_MODE,
+       .jh7110_clk_init = cqspi_jh7110_clk_init,
 };
 
 static const struct cqspi_driver_platdata pensando_cdns_qspi = {