mediatek: add support for the new MT7623 Arm SoC
[openwrt/openwrt.git] / target / linux / mediatek / patches / 0036-mmc-mediatek-Add-PM-support-for-MMC-driver.patch
1 From 4ca0e8a959569852b520b607d39ce6ceeeb0f518 Mon Sep 17 00:00:00 2001
2 From: Chaotian Jing <chaotian.jing@mediatek.com>
3 Date: Mon, 15 Jun 2015 19:20:49 +0800
4 Subject: [PATCH 36/76] mmc: mediatek: Add PM support for MMC driver
5
6 Add PM support for Mediatek MMC driver
7 Save/restore registers when PM
8
9 Signed-off-by: Chaotian Jing <chaotian.jing@mediatek.com>
10 ---
11 drivers/mmc/host/mtk-sd.c | 89 +++++++++++++++++++++++++++++++++++++++++++--
12 1 file changed, 86 insertions(+), 3 deletions(-)
13
14 diff --git a/drivers/mmc/host/mtk-sd.c b/drivers/mmc/host/mtk-sd.c
15 index 952be2e..7c20f28 100644
16 --- a/drivers/mmc/host/mtk-sd.c
17 +++ b/drivers/mmc/host/mtk-sd.c
18 @@ -22,6 +22,8 @@
19 #include <linux/of_gpio.h>
20 #include <linux/pinctrl/consumer.h>
21 #include <linux/platform_device.h>
22 +#include <linux/pm.h>
23 +#include <linux/pm_runtime.h>
24 #include <linux/regulator/consumer.h>
25 #include <linux/spinlock.h>
26
27 @@ -212,6 +214,7 @@
28 #define MSDC_ASYNC_FLAG (0x1 << 1)
29 #define MSDC_MMAP_FLAG (0x1 << 2)
30
31 +#define MTK_MMC_AUTOSUSPEND_DELAY 50
32 #define CMD_TIMEOUT (HZ/10 * 5) /* 100ms x5 */
33 #define DAT_TIMEOUT (HZ * 5) /* 1000ms x5 */
34
35 @@ -254,6 +257,15 @@ struct msdc_dma {
36 dma_addr_t bd_addr; /* the physical address of bd array */
37 };
38
39 +struct msdc_save_para {
40 + u32 msdc_cfg;
41 + u32 iocon;
42 + u32 sdc_cfg;
43 + u32 pad_tune;
44 + u32 patch_bit0;
45 + u32 patch_bit1;
46 +};
47 +
48 struct msdc_host {
49 struct device *dev;
50 struct mmc_host *mmc; /* mmc structure */
51 @@ -286,6 +298,7 @@ struct msdc_host {
52 u32 sclk; /* SD/MS bus clock frequency */
53 bool ddr;
54 bool vqmmc_enabled;
55 + struct msdc_save_para save_para; /* used when gate HCLK */
56 };
57
58 static void sdr_set_bits(void __iomem *reg, u32 bs)
59 @@ -677,6 +690,9 @@ static void msdc_request_done(struct msdc_host *host, struct mmc_request *mrq)
60 if (mrq->data)
61 msdc_unprepare_data(host, mrq);
62 mmc_request_done(host->mmc, mrq);
63 +
64 + pm_runtime_mark_last_busy(host->dev);
65 + pm_runtime_put_autosuspend(host->dev);
66 }
67
68 /* returns true if command is fully handled; returns false otherwise */
69 @@ -831,6 +847,8 @@ static void msdc_ops_request(struct mmc_host *mmc, struct mmc_request *mrq)
70 WARN_ON(host->mrq);
71 host->mrq = mrq;
72
73 + pm_runtime_get_sync(host->dev);
74 +
75 if (mrq->data)
76 msdc_prepare_data(host, mrq);
77
78 @@ -1145,6 +1163,8 @@ static void msdc_ops_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
79 int ret;
80 u32 ddr = 0;
81
82 + pm_runtime_get_sync(host->dev);
83 +
84 if (ios->timing == MMC_TIMING_UHS_DDR50 ||
85 ios->timing == MMC_TIMING_MMC_DDR52)
86 ddr = 1;
87 @@ -1159,7 +1179,7 @@ static void msdc_ops_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
88 ios->vdd);
89 if (ret) {
90 dev_err(host->dev, "Failed to set vmmc power!\n");
91 - return;
92 + goto end;
93 }
94 }
95 break;
96 @@ -1187,6 +1207,10 @@ static void msdc_ops_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
97
98 if (host->mclk != ios->clock || host->ddr != ddr)
99 msdc_set_mclk(host, ddr, ios->clock);
100 +
101 +end:
102 + pm_runtime_mark_last_busy(host->dev);
103 + pm_runtime_put_autosuspend(host->dev);
104 }
105
106 static struct mmc_host_ops mt_msdc_ops = {
107 @@ -1310,12 +1334,18 @@ static int msdc_drv_probe(struct platform_device *pdev)
108 if (ret)
109 goto release;
110
111 + pm_runtime_set_active(host->dev);
112 + pm_runtime_set_autosuspend_delay(host->dev, MTK_MMC_AUTOSUSPEND_DELAY);
113 + pm_runtime_use_autosuspend(host->dev);
114 + pm_runtime_enable(host->dev);
115 ret = mmc_add_host(mmc);
116 +
117 if (ret)
118 - goto release;
119 + goto end;
120
121 return 0;
122 -
123 +end:
124 + pm_runtime_disable(host->dev);
125 release:
126 platform_set_drvdata(pdev, NULL);
127 msdc_deinit_hw(host);
128 @@ -1343,11 +1373,15 @@ static int msdc_drv_remove(struct platform_device *pdev)
129 mmc = platform_get_drvdata(pdev);
130 host = mmc_priv(mmc);
131
132 + pm_runtime_get_sync(host->dev);
133 +
134 platform_set_drvdata(pdev, NULL);
135 mmc_remove_host(host->mmc);
136 msdc_deinit_hw(host);
137 msdc_gate_clock(host);
138
139 + pm_runtime_disable(host->dev);
140 + pm_runtime_put_noidle(host->dev);
141 dma_free_coherent(&pdev->dev,
142 sizeof(struct mt_gpdma_desc),
143 host->dma.gpd, host->dma.gpd_addr);
144 @@ -1359,6 +1393,54 @@ static int msdc_drv_remove(struct platform_device *pdev)
145 return 0;
146 }
147
148 +#ifdef CONFIG_PM
149 +static void msdc_save_reg(struct msdc_host *host)
150 +{
151 + host->save_para.msdc_cfg = readl(host->base + MSDC_CFG);
152 + host->save_para.iocon = readl(host->base + MSDC_IOCON);
153 + host->save_para.sdc_cfg = readl(host->base + SDC_CFG);
154 + host->save_para.pad_tune = readl(host->base + MSDC_PAD_TUNE);
155 + host->save_para.patch_bit0 = readl(host->base + MSDC_PATCH_BIT);
156 + host->save_para.patch_bit1 = readl(host->base + MSDC_PATCH_BIT1);
157 +}
158 +
159 +static void msdc_restore_reg(struct msdc_host *host)
160 +{
161 + writel(host->save_para.msdc_cfg, host->base + MSDC_CFG);
162 + writel(host->save_para.iocon, host->base + MSDC_IOCON);
163 + writel(host->save_para.sdc_cfg, host->base + SDC_CFG);
164 + writel(host->save_para.pad_tune, host->base + MSDC_PAD_TUNE);
165 + writel(host->save_para.patch_bit0, host->base + MSDC_PATCH_BIT);
166 + writel(host->save_para.patch_bit1, host->base + MSDC_PATCH_BIT1);
167 +}
168 +
169 +static int msdc_runtime_suspend(struct device *dev)
170 +{
171 + struct mmc_host *mmc = dev_get_drvdata(dev);
172 + struct msdc_host *host = mmc_priv(mmc);
173 +
174 + msdc_save_reg(host);
175 + msdc_gate_clock(host);
176 + return 0;
177 +}
178 +
179 +static int msdc_runtime_resume(struct device *dev)
180 +{
181 + struct mmc_host *mmc = dev_get_drvdata(dev);
182 + struct msdc_host *host = mmc_priv(mmc);
183 +
184 + msdc_ungate_clock(host);
185 + msdc_restore_reg(host);
186 + return 0;
187 +}
188 +#endif
189 +
190 +static const struct dev_pm_ops msdc_dev_pm_ops = {
191 + SET_SYSTEM_SLEEP_PM_OPS(pm_runtime_force_suspend,
192 + pm_runtime_force_resume)
193 + SET_RUNTIME_PM_OPS(msdc_runtime_suspend, msdc_runtime_resume, NULL)
194 +};
195 +
196 static const struct of_device_id msdc_of_ids[] = {
197 { .compatible = "mediatek,mt8135-mmc", },
198 {}
199 @@ -1370,6 +1452,7 @@ static struct platform_driver mt_msdc_driver = {
200 .driver = {
201 .name = "mtk-msdc",
202 .of_match_table = msdc_of_ids,
203 + .pm = &msdc_dev_pm_ops,
204 },
205 };
206
207 --
208 1.7.10.4
209