| --- a/drivers/mmc/host/mtk-sd.c |
| +++ b/drivers/mmc/host/mtk-sd.c |
| @@ -33,6 +33,7 @@ |
| #include <linux/mmc/slot-gpio.h> |
| |
| #define MAX_BD_NUM 1024 |
| +#define MSDC_NR_CLOCKS 3 |
| |
| /*--------------------------------------------------------------------------*/ |
| /* Common Definition */ |
| @@ -419,6 +420,8 @@ struct msdc_host { |
| struct clk *h_clk; /* msdc h_clk */ |
| struct clk *bus_clk; /* bus clock which used to access register */ |
| struct clk *src_clk_cg; /* msdc source clock control gate */ |
| + struct clk *sys_clk_cg; /* msdc subsys clock control gate */ |
| + struct clk_bulk_data bulk_clks[MSDC_NR_CLOCKS]; |
| u32 mclk; /* mmc subsystem clock frequency */ |
| u32 src_clk_freq; /* source clock frequency */ |
| unsigned char timing; |
| @@ -745,6 +748,7 @@ static void msdc_set_timeout(struct msdc |
| |
| static void msdc_gate_clock(struct msdc_host *host) |
| { |
| + clk_bulk_disable_unprepare(MSDC_NR_CLOCKS, host->bulk_clks); |
| clk_disable_unprepare(host->src_clk_cg); |
| clk_disable_unprepare(host->src_clk); |
| clk_disable_unprepare(host->bus_clk); |
| @@ -753,10 +757,18 @@ static void msdc_gate_clock(struct msdc_ |
| |
| static void msdc_ungate_clock(struct msdc_host *host) |
| { |
| + int ret; |
| + |
| clk_prepare_enable(host->h_clk); |
| clk_prepare_enable(host->bus_clk); |
| clk_prepare_enable(host->src_clk); |
| clk_prepare_enable(host->src_clk_cg); |
| + ret = clk_bulk_prepare_enable(MSDC_NR_CLOCKS, host->bulk_clks); |
| + if (ret) { |
| + dev_err(host->dev, "Cannot enable pclk/axi/ahb clock gates\n"); |
| + return; |
| + } |
| + |
| while (!(readl(host->base + MSDC_CFG) & MSDC_CFG_CKSTB)) |
| cpu_relax(); |
| } |
| @@ -2195,6 +2207,50 @@ static void msdc_of_property_parse(struc |
| host->hs400_cmd_resp_sel_rising = false; |
| } |
| |
| +static int msdc_of_clock_parse(struct platform_device *pdev, |
| + struct msdc_host *host) |
| +{ |
| + int ret; |
| + |
| + host->src_clk = devm_clk_get(&pdev->dev, "source"); |
| + if (IS_ERR(host->src_clk)) |
| + return PTR_ERR(host->src_clk); |
| + |
| + host->h_clk = devm_clk_get(&pdev->dev, "hclk"); |
| + if (IS_ERR(host->h_clk)) |
| + return PTR_ERR(host->h_clk); |
| + |
| + host->bus_clk = devm_clk_get_optional(&pdev->dev, "bus_clk"); |
| + if (IS_ERR(host->bus_clk)) |
| + host->bus_clk = NULL; |
| + |
| + |
| + /*source clock control gate is optional clock*/ |
| + host->src_clk_cg = devm_clk_get_optional(&pdev->dev, "source_cg"); |
| + if (IS_ERR(host->src_clk_cg)) |
| + host->src_clk_cg = NULL; |
| + |
| + host->sys_clk_cg = devm_clk_get_optional(&pdev->dev, "sys_cg"); |
| + if (IS_ERR(host->sys_clk_cg)) |
| + host->sys_clk_cg = NULL; |
| + |
| + /* If present, always enable for this clock gate */ |
| + clk_prepare_enable(host->sys_clk_cg); |
| + |
| + host->bulk_clks[0].id = "pclk_cg"; |
| + host->bulk_clks[1].id = "axi_cg"; |
| + host->bulk_clks[2].id = "ahb_cg"; |
| + |
| + ret = devm_clk_bulk_get_optional(&pdev->dev, MSDC_NR_CLOCKS, |
| + host->bulk_clks); |
| + if (ret) { |
| + dev_err(&pdev->dev, "Cannot get pclk/axi/ahb clock gates\n"); |
| + return ret; |
| + } |
| + |
| + return 0; |
| +} |
| + |
| static int msdc_drv_probe(struct platform_device *pdev) |
| { |
| struct mmc_host *mmc; |
| @@ -2235,25 +2291,9 @@ static int msdc_drv_probe(struct platfor |
| if (ret) |
| goto host_free; |
| |
| - host->src_clk = devm_clk_get(&pdev->dev, "source"); |
| - if (IS_ERR(host->src_clk)) { |
| - ret = PTR_ERR(host->src_clk); |
| - goto host_free; |
| - } |
| - |
| - host->h_clk = devm_clk_get(&pdev->dev, "hclk"); |
| - if (IS_ERR(host->h_clk)) { |
| - ret = PTR_ERR(host->h_clk); |
| + ret = msdc_of_clock_parse(pdev, host); |
| + if (ret) |
| goto host_free; |
| - } |
| - |
| - host->bus_clk = devm_clk_get(&pdev->dev, "bus_clk"); |
| - if (IS_ERR(host->bus_clk)) |
| - host->bus_clk = NULL; |
| - /*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->reset = devm_reset_control_get_optional_exclusive(&pdev->dev, |
| "hrst"); |