Skip to content

Commit

Permalink
mmc: mediatek: add support of source_cg clock
Browse files Browse the repository at this point in the history
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 <[email protected]>
Tested-by: Sean Wang <[email protected]>
Signed-off-by: Ulf Hansson <[email protected]>
  • Loading branch information
ChaotianJing authored and storulf committed Nov 2, 2017
1 parent d9dcbfc commit 3c1a884
Showing 1 changed file with 22 additions and 1 deletion.
23 changes: 22 additions & 1 deletion drivers/mmc/host/mtk-sd.c
Original file line number Diff line number Diff line change
Expand Up @@ -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 */
Expand Down Expand Up @@ -616,6 +617,7 @@ static void msdc_set_timeout(struct msdc_host *host, u32 ns, u32 clks)

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);
}
Expand All @@ -624,6 +626,7 @@ static void msdc_ungate_clock(struct msdc_host *host)
{
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();
}
Expand Down Expand Up @@ -692,6 +695,15 @@ static void msdc_set_mclk(struct msdc_host *host, unsigned char timing, u32 hz)
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,
Expand All @@ -700,10 +712,14 @@ static void msdc_set_mclk(struct msdc_host *host, unsigned char timing, u32 hz)
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;
Expand Down Expand Up @@ -1822,6 +1838,11 @@ static int msdc_drv_probe(struct platform_device *pdev)
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;
Expand Down

0 comments on commit 3c1a884

Please sign in to comment.