]> git.ipfire.org Git - thirdparty/kernel/linux.git/commitdiff
mmc: sdhci-of-dwcmshc: add common bulk optional clocks support
authorChen Wang <unicorn_wang@outlook.com>
Mon, 5 Aug 2024 09:17:21 +0000 (17:17 +0800)
committerUlf Hansson <ulf.hansson@linaro.org>
Mon, 26 Aug 2024 11:01:49 +0000 (13:01 +0200)
In addition to the required core clock and optional
bus clock, the soc will expand its own clocks, so
the bulk clock mechanism is abstracted.

Note, I call the bulk clocks as "other clocks" due
to the bus clock has been called as "optional".

Signed-off-by: Chen Wang <unicorn_wang@outlook.com>
Tested-by: Drew Fustini <drew@pdp7.com> # TH1520
Tested-by: Inochi Amaoto <inochiama@outlook.com> # Duo and Huashan Pi
Acked-by: Adrian Hunter <adrian.hunter@intel.com>
Link: https://lore.kernel.org/r/e57e8c51da81f176b49608269a884f840903e78e.1722847198.git.unicorn_wang@outlook.com
Signed-off-by: Ulf Hansson <ulf.hansson@linaro.org>
drivers/mmc/host/sdhci-of-dwcmshc.c

index e79aa4b3b6c360934d3ce3ff17037d0d0571654f..35401616fb2eff7de48bb329b6ff1d70cad751b1 100644 (file)
 #define DLL_LOCK_WO_TMOUT(x) \
        ((((x) & DWCMSHC_EMMC_DLL_LOCKED) == DWCMSHC_EMMC_DLL_LOCKED) && \
        (((x) & DWCMSHC_EMMC_DLL_TIMEOUT) == 0))
-#define RK35xx_MAX_CLKS 3
 
 /* PHY register area pointer */
 #define DWC_MSHC_PTR_PHY_R     0x300
@@ -199,23 +198,54 @@ enum dwcmshc_rk_type {
 };
 
 struct rk35xx_priv {
-       /* Rockchip specified optional clocks */
-       struct clk_bulk_data rockchip_clks[RK35xx_MAX_CLKS];
        struct reset_control *reset;
        enum dwcmshc_rk_type devtype;
        u8 txclk_tapnum;
 };
 
+#define DWCMSHC_MAX_OTHER_CLKS 3
+
 struct dwcmshc_priv {
        struct clk      *bus_clk;
        int vendor_specific_area1; /* P_VENDOR_SPECIFIC_AREA1 reg */
        int vendor_specific_area2; /* P_VENDOR_SPECIFIC_AREA2 reg */
 
+       int num_other_clks;
+       struct clk_bulk_data other_clks[DWCMSHC_MAX_OTHER_CLKS];
+
        void *priv; /* pointer to SoC private stuff */
        u16 delay_line;
        u16 flags;
 };
 
+static int dwcmshc_get_enable_other_clks(struct device *dev,
+                                        struct dwcmshc_priv *priv,
+                                        int num_clks,
+                                        const char * const clk_ids[])
+{
+       int err;
+
+       if (num_clks > DWCMSHC_MAX_OTHER_CLKS)
+               return -EINVAL;
+
+       for (int i = 0; i < num_clks; i++)
+               priv->other_clks[i].id = clk_ids[i];
+
+       err = devm_clk_bulk_get_optional(dev, num_clks, priv->other_clks);
+       if (err) {
+               dev_err(dev, "failed to get clocks %d\n", err);
+               return err;
+       }
+
+       err = clk_bulk_prepare_enable(num_clks, priv->other_clks);
+       if (err)
+               dev_err(dev, "failed to enable clocks %d\n", err);
+
+       priv->num_other_clks = num_clks;
+
+       return err;
+}
+
 /*
  * If DMA addr spans 128MB boundary, we split the DMA transfer into two
  * so that each DMA transfer doesn't exceed the boundary.
@@ -1036,8 +1066,9 @@ dsbl_cqe_caps:
 
 static int dwcmshc_rk35xx_init(struct sdhci_host *host, struct dwcmshc_priv *dwc_priv)
 {
-       int err;
+       static const char * const clk_ids[] = {"axi", "block", "timer"};
        struct rk35xx_priv *priv = dwc_priv->priv;
+       int err;
 
        priv->reset = devm_reset_control_array_get_optional_exclusive(mmc_dev(host->mmc));
        if (IS_ERR(priv->reset)) {
@@ -1046,21 +1077,10 @@ static int dwcmshc_rk35xx_init(struct sdhci_host *host, struct dwcmshc_priv *dwc
                return err;
        }
 
-       priv->rockchip_clks[0].id = "axi";
-       priv->rockchip_clks[1].id = "block";
-       priv->rockchip_clks[2].id = "timer";
-       err = devm_clk_bulk_get_optional(mmc_dev(host->mmc), RK35xx_MAX_CLKS,
-                                        priv->rockchip_clks);
-       if (err) {
-               dev_err(mmc_dev(host->mmc), "failed to get clocks %d\n", err);
-               return err;
-       }
-
-       err = clk_bulk_prepare_enable(RK35xx_MAX_CLKS, priv->rockchip_clks);
-       if (err) {
-               dev_err(mmc_dev(host->mmc), "failed to enable clocks %d\n", err);
+       err = dwcmshc_get_enable_other_clks(mmc_dev(host->mmc), dwc_priv,
+                                           ARRAY_SIZE(clk_ids), clk_ids);
+       if (err)
                return err;
-       }
 
        if (of_property_read_u8(mmc_dev(host->mmc)->of_node, "rockchip,txclk-tapnum",
                                &priv->txclk_tapnum))
@@ -1280,9 +1300,7 @@ err_rpm:
 err_clk:
        clk_disable_unprepare(pltfm_host->clk);
        clk_disable_unprepare(priv->bus_clk);
-       if (rk_priv)
-               clk_bulk_disable_unprepare(RK35xx_MAX_CLKS,
-                                          rk_priv->rockchip_clks);
+       clk_bulk_disable_unprepare(priv->num_other_clks, priv->other_clks);
 free_pltfm:
        sdhci_pltfm_free(pdev);
        return err;
@@ -1304,7 +1322,6 @@ static void dwcmshc_remove(struct platform_device *pdev)
        struct sdhci_host *host = platform_get_drvdata(pdev);
        struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
        struct dwcmshc_priv *priv = sdhci_pltfm_priv(pltfm_host);
-       struct rk35xx_priv *rk_priv = priv->priv;
 
        pm_runtime_get_sync(&pdev->dev);
        pm_runtime_disable(&pdev->dev);
@@ -1316,9 +1333,7 @@ static void dwcmshc_remove(struct platform_device *pdev)
 
        clk_disable_unprepare(pltfm_host->clk);
        clk_disable_unprepare(priv->bus_clk);
-       if (rk_priv)
-               clk_bulk_disable_unprepare(RK35xx_MAX_CLKS,
-                                          rk_priv->rockchip_clks);
+       clk_bulk_disable_unprepare(priv->num_other_clks, priv->other_clks);
        sdhci_pltfm_free(pdev);
 }
 
@@ -1328,7 +1343,6 @@ static int dwcmshc_suspend(struct device *dev)
        struct sdhci_host *host = dev_get_drvdata(dev);
        struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
        struct dwcmshc_priv *priv = sdhci_pltfm_priv(pltfm_host);
-       struct rk35xx_priv *rk_priv = priv->priv;
        int ret;
 
        pm_runtime_resume(dev);
@@ -1347,9 +1361,7 @@ static int dwcmshc_suspend(struct device *dev)
        if (!IS_ERR(priv->bus_clk))
                clk_disable_unprepare(priv->bus_clk);
 
-       if (rk_priv)
-               clk_bulk_disable_unprepare(RK35xx_MAX_CLKS,
-                                          rk_priv->rockchip_clks);
+       clk_bulk_disable_unprepare(priv->num_other_clks, priv->other_clks);
 
        return ret;
 }
@@ -1359,7 +1371,6 @@ static int dwcmshc_resume(struct device *dev)
        struct sdhci_host *host = dev_get_drvdata(dev);
        struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
        struct dwcmshc_priv *priv = sdhci_pltfm_priv(pltfm_host);
-       struct rk35xx_priv *rk_priv = priv->priv;
        int ret;
 
        ret = clk_prepare_enable(pltfm_host->clk);
@@ -1372,29 +1383,24 @@ static int dwcmshc_resume(struct device *dev)
                        goto disable_clk;
        }
 
-       if (rk_priv) {
-               ret = clk_bulk_prepare_enable(RK35xx_MAX_CLKS,
-                                             rk_priv->rockchip_clks);
-               if (ret)
-                       goto disable_bus_clk;
-       }
+       ret = clk_bulk_prepare_enable(priv->num_other_clks, priv->other_clks);
+       if (ret)
+               goto disable_bus_clk;
 
        ret = sdhci_resume_host(host);
        if (ret)
-               goto disable_rockchip_clks;
+               goto disable_other_clks;
 
        if (host->mmc->caps2 & MMC_CAP2_CQE) {
                ret = cqhci_resume(host->mmc);
                if (ret)
-                       goto disable_rockchip_clks;
+                       goto disable_other_clks;
        }
 
        return 0;
 
-disable_rockchip_clks:
-       if (rk_priv)
-               clk_bulk_disable_unprepare(RK35xx_MAX_CLKS,
-                                          rk_priv->rockchip_clks);
+disable_other_clks:
+       clk_bulk_disable_unprepare(priv->num_other_clks, priv->other_clks);
 disable_bus_clk:
        if (!IS_ERR(priv->bus_clk))
                clk_disable_unprepare(priv->bus_clk);