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