OpenWrt – Rev 4

Subversion Repositories:
Rev:
From 3c6b94d7091f0793445f2faf777e584af643e9da Mon Sep 17 00:00:00 2001
From: Chaotian Jing <chaotian.jing@mediatek.com>
Date: Mon, 16 Oct 2017 09:46:36 +0800
Subject: [PATCH 157/224] mmc: mediatek: add support of source_cg clock

source clock need an independent cg to control, when doing clk mode
switch, need gate source clock to avoid hw issue(multi-bit sync hw hang)

Signed-off-by: Chaotian Jing <chaotian.jing@mediatek.com>
Tested-by: Sean Wang <sean.wang@mediatek.com>
Signed-off-by: Ulf Hansson <ulf.hansson@linaro.org>
---
 drivers/mmc/host/mtk-sd.c | 23 ++++++++++++++++++++++-
 1 file changed, 22 insertions(+), 1 deletion(-)

--- a/drivers/mmc/host/mtk-sd.c
+++ b/drivers/mmc/host/mtk-sd.c
@@ -372,6 +372,7 @@ struct msdc_host {
 
        struct clk *src_clk;    /* msdc source clock */
        struct clk *h_clk;      /* msdc h_clk */
+       struct clk *src_clk_cg; /* msdc source clock control gate */
        u32 mclk;               /* mmc subsystem clock frequency */
        u32 src_clk_freq;       /* source clock frequency */
        u32 sclk;               /* SD/MS bus clock frequency */
@@ -616,6 +617,7 @@ static void msdc_set_timeout(struct msdc
 
 static void msdc_gate_clock(struct msdc_host *host)
 {
+       clk_disable_unprepare(host->src_clk_cg);
        clk_disable_unprepare(host->src_clk);
        clk_disable_unprepare(host->h_clk);
 }
@@ -624,6 +626,7 @@ static void msdc_ungate_clock(struct msd
 {
        clk_prepare_enable(host->h_clk);
        clk_prepare_enable(host->src_clk);
+       clk_prepare_enable(host->src_clk_cg);
        while (!(readl(host->base + MSDC_CFG) & MSDC_CFG_CKSTB))
                cpu_relax();
 }
@@ -692,6 +695,15 @@ static void msdc_set_mclk(struct msdc_ho
                        sclk = (host->src_clk_freq >> 2) / div;
                }
        }
+       sdr_clr_bits(host->base + MSDC_CFG, MSDC_CFG_CKPDN);
+       /*
+        * As src_clk/HCLK use the same bit to gate/ungate,
+        * So if want to only gate src_clk, need gate its parent(mux).
+        */
+       if (host->src_clk_cg)
+               clk_disable_unprepare(host->src_clk_cg);
+       else
+               clk_disable_unprepare(clk_get_parent(host->src_clk));
        if (host->dev_comp->clk_div_bits == 8)
                sdr_set_field(host->base + MSDC_CFG,
                              MSDC_CFG_CKMOD | MSDC_CFG_CKDIV,
@@ -700,10 +712,14 @@ static void msdc_set_mclk(struct msdc_ho
                sdr_set_field(host->base + MSDC_CFG,
                              MSDC_CFG_CKMOD_EXTRA | MSDC_CFG_CKDIV_EXTRA,
                              (mode << 12) | div);
+       if (host->src_clk_cg)
+               clk_prepare_enable(host->src_clk_cg);
+       else
+               clk_prepare_enable(clk_get_parent(host->src_clk));
 
-       sdr_set_bits(host->base + MSDC_CFG, MSDC_CFG_CKPDN);
        while (!(readl(host->base + MSDC_CFG) & MSDC_CFG_CKSTB))
                cpu_relax();
+       sdr_set_bits(host->base + MSDC_CFG, MSDC_CFG_CKPDN);
        host->sclk = sclk;
        host->mclk = hz;
        host->timing = timing;
@@ -1822,6 +1838,11 @@ static int msdc_drv_probe(struct platfor
                goto host_free;
        }
 
+       /*source clock control gate is optional clock*/
+       host->src_clk_cg = devm_clk_get(&pdev->dev, "source_cg");
+       if (IS_ERR(host->src_clk_cg))
+               host->src_clk_cg = NULL;
+
        host->irq = platform_get_irq(pdev, 0);
        if (host->irq < 0) {
                ret = -EINVAL;