developer | 30389d9 | 2022-05-10 09:35:17 +0800 | [diff] [blame] | 1 | --- a/drivers/mmc/host/mtk-sd.c |
| 2 | +++ b/drivers/mmc/host/mtk-sd.c |
| 3 | @@ -33,6 +33,7 @@ |
| 4 | #include <linux/mmc/slot-gpio.h> |
| 5 | |
| 6 | #define MAX_BD_NUM 1024 |
| 7 | +#define MSDC_NR_CLOCKS 3 |
| 8 | |
| 9 | /*--------------------------------------------------------------------------*/ |
| 10 | /* Common Definition */ |
| 11 | @@ -419,6 +420,8 @@ struct msdc_host { |
| 12 | struct clk *h_clk; /* msdc h_clk */ |
| 13 | struct clk *bus_clk; /* bus clock which used to access register */ |
| 14 | struct clk *src_clk_cg; /* msdc source clock control gate */ |
| 15 | + struct clk *sys_clk_cg; /* msdc subsys clock control gate */ |
| 16 | + struct clk_bulk_data bulk_clks[MSDC_NR_CLOCKS]; |
| 17 | u32 mclk; /* mmc subsystem clock frequency */ |
| 18 | u32 src_clk_freq; /* source clock frequency */ |
| 19 | unsigned char timing; |
| 20 | @@ -745,6 +748,7 @@ static void msdc_set_timeout(struct msdc |
| 21 | |
| 22 | static void msdc_gate_clock(struct msdc_host *host) |
| 23 | { |
| 24 | + clk_bulk_disable_unprepare(MSDC_NR_CLOCKS, host->bulk_clks); |
| 25 | clk_disable_unprepare(host->src_clk_cg); |
| 26 | clk_disable_unprepare(host->src_clk); |
| 27 | clk_disable_unprepare(host->bus_clk); |
| 28 | @@ -753,10 +757,18 @@ static void msdc_gate_clock(struct msdc_ |
| 29 | |
| 30 | static void msdc_ungate_clock(struct msdc_host *host) |
| 31 | { |
| 32 | + int ret; |
| 33 | + |
| 34 | clk_prepare_enable(host->h_clk); |
| 35 | clk_prepare_enable(host->bus_clk); |
| 36 | clk_prepare_enable(host->src_clk); |
| 37 | clk_prepare_enable(host->src_clk_cg); |
| 38 | + ret = clk_bulk_prepare_enable(MSDC_NR_CLOCKS, host->bulk_clks); |
| 39 | + if (ret) { |
| 40 | + dev_err(host->dev, "Cannot enable pclk/axi/ahb clock gates\n"); |
| 41 | + return; |
| 42 | + } |
| 43 | + |
| 44 | while (!(readl(host->base + MSDC_CFG) & MSDC_CFG_CKSTB)) |
| 45 | cpu_relax(); |
| 46 | } |
| 47 | @@ -2195,6 +2207,50 @@ static void msdc_of_property_parse(struc |
| 48 | host->hs400_cmd_resp_sel_rising = false; |
| 49 | } |
| 50 | |
| 51 | +static int msdc_of_clock_parse(struct platform_device *pdev, |
| 52 | + struct msdc_host *host) |
| 53 | +{ |
| 54 | + int ret; |
| 55 | + |
| 56 | + host->src_clk = devm_clk_get(&pdev->dev, "source"); |
| 57 | + if (IS_ERR(host->src_clk)) |
| 58 | + return PTR_ERR(host->src_clk); |
| 59 | + |
| 60 | + host->h_clk = devm_clk_get(&pdev->dev, "hclk"); |
| 61 | + if (IS_ERR(host->h_clk)) |
| 62 | + return PTR_ERR(host->h_clk); |
| 63 | + |
| 64 | + host->bus_clk = devm_clk_get_optional(&pdev->dev, "bus_clk"); |
| 65 | + if (IS_ERR(host->bus_clk)) |
| 66 | + host->bus_clk = NULL; |
| 67 | + |
| 68 | + |
| 69 | + /*source clock control gate is optional clock*/ |
| 70 | + host->src_clk_cg = devm_clk_get_optional(&pdev->dev, "source_cg"); |
| 71 | + if (IS_ERR(host->src_clk_cg)) |
| 72 | + host->src_clk_cg = NULL; |
| 73 | + |
| 74 | + host->sys_clk_cg = devm_clk_get_optional(&pdev->dev, "sys_cg"); |
| 75 | + if (IS_ERR(host->sys_clk_cg)) |
| 76 | + host->sys_clk_cg = NULL; |
| 77 | + |
| 78 | + /* If present, always enable for this clock gate */ |
| 79 | + clk_prepare_enable(host->sys_clk_cg); |
| 80 | + |
| 81 | + host->bulk_clks[0].id = "pclk_cg"; |
| 82 | + host->bulk_clks[1].id = "axi_cg"; |
| 83 | + host->bulk_clks[2].id = "ahb_cg"; |
| 84 | + |
| 85 | + ret = devm_clk_bulk_get_optional(&pdev->dev, MSDC_NR_CLOCKS, |
| 86 | + host->bulk_clks); |
| 87 | + if (ret) { |
| 88 | + dev_err(&pdev->dev, "Cannot get pclk/axi/ahb clock gates\n"); |
| 89 | + return ret; |
| 90 | + } |
| 91 | + |
| 92 | + return 0; |
| 93 | +} |
| 94 | + |
| 95 | static int msdc_drv_probe(struct platform_device *pdev) |
| 96 | { |
| 97 | struct mmc_host *mmc; |
| 98 | @@ -2235,25 +2291,9 @@ static int msdc_drv_probe(struct platfor |
| 99 | if (ret) |
| 100 | goto host_free; |
| 101 | |
| 102 | - host->src_clk = devm_clk_get(&pdev->dev, "source"); |
| 103 | - if (IS_ERR(host->src_clk)) { |
| 104 | - ret = PTR_ERR(host->src_clk); |
| 105 | - goto host_free; |
| 106 | - } |
| 107 | - |
| 108 | - host->h_clk = devm_clk_get(&pdev->dev, "hclk"); |
| 109 | - if (IS_ERR(host->h_clk)) { |
| 110 | - ret = PTR_ERR(host->h_clk); |
| 111 | + ret = msdc_of_clock_parse(pdev, host); |
| 112 | + if (ret) |
| 113 | goto host_free; |
| 114 | - } |
| 115 | - |
| 116 | - host->bus_clk = devm_clk_get(&pdev->dev, "bus_clk"); |
| 117 | - if (IS_ERR(host->bus_clk)) |
| 118 | - host->bus_clk = NULL; |
| 119 | - /*source clock control gate is optional clock*/ |
| 120 | - host->src_clk_cg = devm_clk_get(&pdev->dev, "source_cg"); |
| 121 | - if (IS_ERR(host->src_clk_cg)) |
| 122 | - host->src_clk_cg = NULL; |
| 123 | |
| 124 | host->reset = devm_reset_control_get_optional_exclusive(&pdev->dev, |
| 125 | "hrst"); |