Commit | Line | Data |
---|---|---|
6b1baefe | 1 | // SPDX-License-Identifier: GPL-2.0-only |
7d326930 KVA |
2 | /** |
3 | * SDHCI Controller driver for TI's OMAP SoCs | |
4 | * | |
5 | * Copyright (C) 2017 Texas Instruments | |
6 | * Author: Kishon Vijay Abraham I <kishon@ti.com> | |
7d326930 KVA |
7 | */ |
8 | ||
9 | #include <linux/delay.h> | |
5da5e494 | 10 | #include <linux/mmc/mmc.h> |
7d326930 KVA |
11 | #include <linux/mmc/slot-gpio.h> |
12 | #include <linux/module.h> | |
13 | #include <linux/of.h> | |
14 | #include <linux/of_device.h> | |
a1e97bd2 | 15 | #include <linux/of_irq.h> |
7d326930 KVA |
16 | #include <linux/platform_device.h> |
17 | #include <linux/pm_runtime.h> | |
a1e97bd2 | 18 | #include <linux/pm_wakeirq.h> |
7d326930 | 19 | #include <linux/regulator/consumer.h> |
8d20b2ea | 20 | #include <linux/pinctrl/consumer.h> |
212f4f8a | 21 | #include <linux/sys_soc.h> |
961de0a8 | 22 | #include <linux/thermal.h> |
7d326930 KVA |
23 | |
24 | #include "sdhci-pltfm.h" | |
25 | ||
42b380b6 TL |
26 | /* |
27 | * Note that the register offsets used here are from omap_regs | |
28 | * base which is 0x100 for omap4 and later, and 0 for omap3 and | |
29 | * earlier. | |
30 | */ | |
31 | #define SDHCI_OMAP_SYSCONFIG 0x10 | |
53f9460e | 32 | |
42b380b6 | 33 | #define SDHCI_OMAP_CON 0x2c |
7d326930 KVA |
34 | #define CON_DW8 BIT(5) |
35 | #define CON_DMA_MASTER BIT(20) | |
27ceb7e0 | 36 | #define CON_DDR BIT(19) |
20ea26a1 KVA |
37 | #define CON_CLKEXTFREE BIT(16) |
38 | #define CON_PADEN BIT(15) | |
efde12b2 | 39 | #define CON_CTPL BIT(11) |
7d326930 KVA |
40 | #define CON_INIT BIT(1) |
41 | #define CON_OD BIT(0) | |
42 | ||
42b380b6 | 43 | #define SDHCI_OMAP_DLL 0x34 |
9fc2cd76 KVA |
44 | #define DLL_SWT BIT(20) |
45 | #define DLL_FORCE_SR_C_SHIFT 13 | |
46 | #define DLL_FORCE_SR_C_MASK (0x7f << DLL_FORCE_SR_C_SHIFT) | |
47 | #define DLL_FORCE_VALUE BIT(12) | |
48 | #define DLL_CALIB BIT(1) | |
49 | ||
42b380b6 | 50 | #define SDHCI_OMAP_CMD 0x10c |
7d326930 | 51 | |
42b380b6 | 52 | #define SDHCI_OMAP_PSTATE 0x124 |
20ea26a1 KVA |
53 | #define PSTATE_DLEV_DAT0 BIT(20) |
54 | #define PSTATE_DATI BIT(1) | |
55 | ||
42b380b6 | 56 | #define SDHCI_OMAP_HCTL 0x128 |
7d326930 KVA |
57 | #define HCTL_SDBP BIT(8) |
58 | #define HCTL_SDVS_SHIFT 9 | |
59 | #define HCTL_SDVS_MASK (0x7 << HCTL_SDVS_SHIFT) | |
60 | #define HCTL_SDVS_33 (0x7 << HCTL_SDVS_SHIFT) | |
61 | #define HCTL_SDVS_30 (0x6 << HCTL_SDVS_SHIFT) | |
62 | #define HCTL_SDVS_18 (0x5 << HCTL_SDVS_SHIFT) | |
63 | ||
42b380b6 | 64 | #define SDHCI_OMAP_SYSCTL 0x12c |
7d326930 KVA |
65 | #define SYSCTL_CEN BIT(2) |
66 | #define SYSCTL_CLKD_SHIFT 6 | |
67 | #define SYSCTL_CLKD_MASK 0x3ff | |
68 | ||
42b380b6 | 69 | #define SDHCI_OMAP_STAT 0x130 |
7d326930 | 70 | |
42b380b6 | 71 | #define SDHCI_OMAP_IE 0x134 |
7d326930 KVA |
72 | #define INT_CC_EN BIT(0) |
73 | ||
42b380b6 | 74 | #define SDHCI_OMAP_ISE 0x138 |
d806e334 | 75 | |
42b380b6 | 76 | #define SDHCI_OMAP_AC12 0x13c |
7d326930 | 77 | #define AC12_V1V8_SIGEN BIT(19) |
9fc2cd76 | 78 | #define AC12_SCLK_SEL BIT(23) |
7d326930 | 79 | |
42b380b6 | 80 | #define SDHCI_OMAP_CAPA 0x140 |
7d326930 KVA |
81 | #define CAPA_VS33 BIT(24) |
82 | #define CAPA_VS30 BIT(25) | |
83 | #define CAPA_VS18 BIT(26) | |
84 | ||
42b380b6 | 85 | #define SDHCI_OMAP_CAPA2 0x144 |
9fc2cd76 KVA |
86 | #define CAPA2_TSDR50 BIT(13) |
87 | ||
7d326930 KVA |
88 | #define SDHCI_OMAP_TIMEOUT 1 /* 1 msec */ |
89 | ||
90 | #define SYSCTL_CLKD_MAX 0x3FF | |
91 | ||
92 | #define IOV_1V8 1800000 /* 180000 uV */ | |
93 | #define IOV_3V0 3000000 /* 300000 uV */ | |
94 | #define IOV_3V3 3300000 /* 330000 uV */ | |
95 | ||
9fc2cd76 KVA |
96 | #define MAX_PHASE_DELAY 0x7C |
97 | ||
8d20b2ea KVA |
98 | /* sdhci-omap controller flags */ |
99 | #define SDHCI_OMAP_REQUIRE_IODELAY BIT(0) | |
9e84a2e6 | 100 | #define SDHCI_OMAP_SPECIAL_RESET BIT(1) |
8d20b2ea | 101 | |
7d326930 | 102 | struct sdhci_omap_data { |
42b380b6 TL |
103 | int omap_offset; /* Offset for omap regs from base */ |
104 | u32 offset; /* Offset for SDHCI regs from base */ | |
8d20b2ea | 105 | u8 flags; |
7d326930 KVA |
106 | }; |
107 | ||
108 | struct sdhci_omap_host { | |
212f4f8a | 109 | char *version; |
7d326930 KVA |
110 | void __iomem *base; |
111 | struct device *dev; | |
112 | struct regulator *pbias; | |
113 | bool pbias_enabled; | |
114 | struct sdhci_host *host; | |
115 | u8 bus_mode; | |
116 | u8 power_mode; | |
8d20b2ea KVA |
117 | u8 timing; |
118 | u8 flags; | |
119 | ||
120 | struct pinctrl *pinctrl; | |
121 | struct pinctrl_state **pinctrl_state; | |
a1e97bd2 | 122 | int wakeirq; |
5b0d6210 | 123 | bool is_tuning; |
42b380b6 TL |
124 | |
125 | /* Offset for omap specific registers from base */ | |
126 | int omap_offset; | |
127 | ||
ee0f3092 FA |
128 | /* Omap specific context save */ |
129 | u32 con; | |
130 | u32 hctl; | |
131 | u32 sysctl; | |
132 | u32 capa; | |
d806e334 TL |
133 | u32 ie; |
134 | u32 ise; | |
7d326930 KVA |
135 | }; |
136 | ||
8d20b2ea KVA |
137 | static void sdhci_omap_start_clock(struct sdhci_omap_host *omap_host); |
138 | static void sdhci_omap_stop_clock(struct sdhci_omap_host *omap_host); | |
139 | ||
7d326930 KVA |
140 | static inline u32 sdhci_omap_readl(struct sdhci_omap_host *host, |
141 | unsigned int offset) | |
142 | { | |
42b380b6 | 143 | return readl(host->base + host->omap_offset + offset); |
7d326930 KVA |
144 | } |
145 | ||
146 | static inline void sdhci_omap_writel(struct sdhci_omap_host *host, | |
147 | unsigned int offset, u32 data) | |
148 | { | |
42b380b6 | 149 | writel(data, host->base + host->omap_offset + offset); |
7d326930 KVA |
150 | } |
151 | ||
152 | static int sdhci_omap_set_pbias(struct sdhci_omap_host *omap_host, | |
153 | bool power_on, unsigned int iov) | |
154 | { | |
155 | int ret; | |
156 | struct device *dev = omap_host->dev; | |
157 | ||
158 | if (IS_ERR(omap_host->pbias)) | |
159 | return 0; | |
160 | ||
161 | if (power_on) { | |
162 | ret = regulator_set_voltage(omap_host->pbias, iov, iov); | |
163 | if (ret) { | |
164 | dev_err(dev, "pbias set voltage failed\n"); | |
165 | return ret; | |
166 | } | |
167 | ||
168 | if (omap_host->pbias_enabled) | |
169 | return 0; | |
170 | ||
171 | ret = regulator_enable(omap_host->pbias); | |
172 | if (ret) { | |
173 | dev_err(dev, "pbias reg enable fail\n"); | |
174 | return ret; | |
175 | } | |
176 | ||
177 | omap_host->pbias_enabled = true; | |
178 | } else { | |
179 | if (!omap_host->pbias_enabled) | |
180 | return 0; | |
181 | ||
182 | ret = regulator_disable(omap_host->pbias); | |
183 | if (ret) { | |
184 | dev_err(dev, "pbias reg disable fail\n"); | |
185 | return ret; | |
186 | } | |
187 | omap_host->pbias_enabled = false; | |
188 | } | |
189 | ||
190 | return 0; | |
191 | } | |
192 | ||
193 | static int sdhci_omap_enable_iov(struct sdhci_omap_host *omap_host, | |
de5ccd2a | 194 | unsigned int iov_pbias) |
7d326930 KVA |
195 | { |
196 | int ret; | |
197 | struct sdhci_host *host = omap_host->host; | |
198 | struct mmc_host *mmc = host->mmc; | |
199 | ||
200 | ret = sdhci_omap_set_pbias(omap_host, false, 0); | |
201 | if (ret) | |
202 | return ret; | |
203 | ||
204 | if (!IS_ERR(mmc->supply.vqmmc)) { | |
de5ccd2a TL |
205 | /* Pick the right voltage to allow 3.0V for 3.3V nominal PBIAS */ |
206 | ret = mmc_regulator_set_vqmmc(mmc, &mmc->ios); | |
207 | if (ret < 0) { | |
7d326930 KVA |
208 | dev_err(mmc_dev(mmc), "vqmmc set voltage failed\n"); |
209 | return ret; | |
210 | } | |
211 | } | |
212 | ||
de5ccd2a | 213 | ret = sdhci_omap_set_pbias(omap_host, true, iov_pbias); |
7d326930 KVA |
214 | if (ret) |
215 | return ret; | |
216 | ||
217 | return 0; | |
218 | } | |
219 | ||
220 | static void sdhci_omap_conf_bus_power(struct sdhci_omap_host *omap_host, | |
221 | unsigned char signal_voltage) | |
222 | { | |
de5ccd2a | 223 | u32 reg, capa; |
7d326930 KVA |
224 | ktime_t timeout; |
225 | ||
226 | reg = sdhci_omap_readl(omap_host, SDHCI_OMAP_HCTL); | |
227 | reg &= ~HCTL_SDVS_MASK; | |
228 | ||
de5ccd2a TL |
229 | switch (signal_voltage) { |
230 | case MMC_SIGNAL_VOLTAGE_330: | |
231 | capa = sdhci_omap_readl(omap_host, SDHCI_OMAP_CAPA); | |
232 | if (capa & CAPA_VS33) | |
233 | reg |= HCTL_SDVS_33; | |
234 | else if (capa & CAPA_VS30) | |
235 | reg |= HCTL_SDVS_30; | |
236 | else | |
237 | dev_warn(omap_host->dev, "misconfigured CAPA: %08x\n", | |
238 | capa); | |
239 | break; | |
240 | case MMC_SIGNAL_VOLTAGE_180: | |
241 | default: | |
7d326930 | 242 | reg |= HCTL_SDVS_18; |
de5ccd2a TL |
243 | break; |
244 | } | |
7d326930 KVA |
245 | |
246 | sdhci_omap_writel(omap_host, SDHCI_OMAP_HCTL, reg); | |
247 | ||
248 | reg |= HCTL_SDBP; | |
249 | sdhci_omap_writel(omap_host, SDHCI_OMAP_HCTL, reg); | |
250 | ||
251 | /* wait 1ms */ | |
252 | timeout = ktime_add_ms(ktime_get(), SDHCI_OMAP_TIMEOUT); | |
9f0ea0bd AH |
253 | while (1) { |
254 | bool timedout = ktime_after(ktime_get(), timeout); | |
255 | ||
256 | if (sdhci_omap_readl(omap_host, SDHCI_OMAP_HCTL) & HCTL_SDBP) | |
257 | break; | |
258 | if (WARN_ON(timedout)) | |
7d326930 KVA |
259 | return; |
260 | usleep_range(5, 10); | |
261 | } | |
262 | } | |
263 | ||
efde12b2 KVA |
264 | static void sdhci_omap_enable_sdio_irq(struct mmc_host *mmc, int enable) |
265 | { | |
266 | struct sdhci_host *host = mmc_priv(mmc); | |
267 | struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); | |
268 | struct sdhci_omap_host *omap_host = sdhci_pltfm_priv(pltfm_host); | |
269 | u32 reg; | |
270 | ||
271 | reg = sdhci_omap_readl(omap_host, SDHCI_OMAP_CON); | |
272 | if (enable) | |
273 | reg |= (CON_CTPL | CON_CLKEXTFREE); | |
274 | else | |
275 | reg &= ~(CON_CTPL | CON_CLKEXTFREE); | |
276 | sdhci_omap_writel(omap_host, SDHCI_OMAP_CON, reg); | |
277 | ||
278 | sdhci_enable_sdio_irq(mmc, enable); | |
279 | } | |
280 | ||
9fc2cd76 KVA |
281 | static inline void sdhci_omap_set_dll(struct sdhci_omap_host *omap_host, |
282 | int count) | |
283 | { | |
284 | int i; | |
285 | u32 reg; | |
286 | ||
287 | reg = sdhci_omap_readl(omap_host, SDHCI_OMAP_DLL); | |
288 | reg |= DLL_FORCE_VALUE; | |
289 | reg &= ~DLL_FORCE_SR_C_MASK; | |
290 | reg |= (count << DLL_FORCE_SR_C_SHIFT); | |
291 | sdhci_omap_writel(omap_host, SDHCI_OMAP_DLL, reg); | |
292 | ||
293 | reg |= DLL_CALIB; | |
294 | sdhci_omap_writel(omap_host, SDHCI_OMAP_DLL, reg); | |
295 | for (i = 0; i < 1000; i++) { | |
296 | reg = sdhci_omap_readl(omap_host, SDHCI_OMAP_DLL); | |
297 | if (reg & DLL_CALIB) | |
298 | break; | |
299 | } | |
300 | reg &= ~DLL_CALIB; | |
301 | sdhci_omap_writel(omap_host, SDHCI_OMAP_DLL, reg); | |
302 | } | |
303 | ||
304 | static void sdhci_omap_disable_tuning(struct sdhci_omap_host *omap_host) | |
305 | { | |
306 | u32 reg; | |
307 | ||
308 | reg = sdhci_omap_readl(omap_host, SDHCI_OMAP_AC12); | |
309 | reg &= ~AC12_SCLK_SEL; | |
310 | sdhci_omap_writel(omap_host, SDHCI_OMAP_AC12, reg); | |
311 | ||
312 | reg = sdhci_omap_readl(omap_host, SDHCI_OMAP_DLL); | |
313 | reg &= ~(DLL_FORCE_VALUE | DLL_SWT); | |
314 | sdhci_omap_writel(omap_host, SDHCI_OMAP_DLL, reg); | |
315 | } | |
316 | ||
317 | static int sdhci_omap_execute_tuning(struct mmc_host *mmc, u32 opcode) | |
318 | { | |
319 | struct sdhci_host *host = mmc_priv(mmc); | |
320 | struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); | |
321 | struct sdhci_omap_host *omap_host = sdhci_pltfm_priv(pltfm_host); | |
961de0a8 | 322 | struct thermal_zone_device *thermal_dev; |
9fc2cd76 KVA |
323 | struct device *dev = omap_host->dev; |
324 | struct mmc_ios *ios = &mmc->ios; | |
325 | u32 start_window = 0, max_window = 0; | |
961de0a8 | 326 | bool single_point_failure = false; |
db2039fc | 327 | bool dcrc_was_enabled = false; |
9fc2cd76 KVA |
328 | u8 cur_match, prev_match = 0; |
329 | u32 length = 0, max_len = 0; | |
330 | u32 phase_delay = 0; | |
961de0a8 | 331 | int temperature; |
9fc2cd76 KVA |
332 | int ret = 0; |
333 | u32 reg; | |
961de0a8 | 334 | int i; |
9fc2cd76 | 335 | |
9fc2cd76 KVA |
336 | /* clock tuning is not needed for upto 52MHz */ |
337 | if (ios->clock <= 52000000) | |
338 | return 0; | |
339 | ||
340 | reg = sdhci_omap_readl(omap_host, SDHCI_OMAP_CAPA2); | |
341 | if (ios->timing == MMC_TIMING_UHS_SDR50 && !(reg & CAPA2_TSDR50)) | |
342 | return 0; | |
343 | ||
961de0a8 FA |
344 | thermal_dev = thermal_zone_get_zone_by_name("cpu_thermal"); |
345 | if (IS_ERR(thermal_dev)) { | |
346 | dev_err(dev, "Unable to get thermal zone for tuning\n"); | |
347 | return PTR_ERR(thermal_dev); | |
348 | } | |
349 | ||
350 | ret = thermal_zone_get_temp(thermal_dev, &temperature); | |
351 | if (ret) | |
352 | return ret; | |
353 | ||
9fc2cd76 KVA |
354 | reg = sdhci_omap_readl(omap_host, SDHCI_OMAP_DLL); |
355 | reg |= DLL_SWT; | |
356 | sdhci_omap_writel(omap_host, SDHCI_OMAP_DLL, reg); | |
357 | ||
7d33c358 KVA |
358 | /* |
359 | * OMAP5/DRA74X/DRA72x Errata i802: | |
360 | * DCRC error interrupts (MMCHS_STAT[21] DCRC=0x1) can occur | |
361 | * during the tuning procedure. So disable it during the | |
362 | * tuning procedure. | |
363 | */ | |
db2039fc FA |
364 | if (host->ier & SDHCI_INT_DATA_CRC) { |
365 | host->ier &= ~SDHCI_INT_DATA_CRC; | |
366 | dcrc_was_enabled = true; | |
367 | } | |
7d33c358 | 368 | |
5b0d6210 FA |
369 | omap_host->is_tuning = true; |
370 | ||
961de0a8 FA |
371 | /* |
372 | * Stage 1: Search for a maximum pass window ignoring any | |
373 | * any single point failures. If the tuning value ends up | |
374 | * near it, move away from it in stage 2 below | |
375 | */ | |
9fc2cd76 KVA |
376 | while (phase_delay <= MAX_PHASE_DELAY) { |
377 | sdhci_omap_set_dll(omap_host, phase_delay); | |
378 | ||
379 | cur_match = !mmc_send_tuning(mmc, opcode, NULL); | |
380 | if (cur_match) { | |
381 | if (prev_match) { | |
382 | length++; | |
961de0a8 FA |
383 | } else if (single_point_failure) { |
384 | /* ignore single point failure */ | |
385 | length++; | |
9fc2cd76 KVA |
386 | } else { |
387 | start_window = phase_delay; | |
388 | length = 1; | |
389 | } | |
961de0a8 FA |
390 | } else { |
391 | single_point_failure = prev_match; | |
9fc2cd76 KVA |
392 | } |
393 | ||
394 | if (length > max_len) { | |
395 | max_window = start_window; | |
396 | max_len = length; | |
397 | } | |
398 | ||
399 | prev_match = cur_match; | |
400 | phase_delay += 4; | |
401 | } | |
402 | ||
403 | if (!max_len) { | |
404 | dev_err(dev, "Unable to find match\n"); | |
405 | ret = -EIO; | |
406 | goto tuning_error; | |
407 | } | |
408 | ||
961de0a8 FA |
409 | /* |
410 | * Assign tuning value as a ratio of maximum pass window based | |
411 | * on temperature | |
412 | */ | |
413 | if (temperature < -20000) | |
feb40824 | 414 | phase_delay = min(max_window + 4 * (max_len - 1) - 24, |
961de0a8 FA |
415 | max_window + |
416 | DIV_ROUND_UP(13 * max_len, 16) * 4); | |
417 | else if (temperature < 20000) | |
418 | phase_delay = max_window + DIV_ROUND_UP(9 * max_len, 16) * 4; | |
419 | else if (temperature < 40000) | |
420 | phase_delay = max_window + DIV_ROUND_UP(8 * max_len, 16) * 4; | |
421 | else if (temperature < 70000) | |
422 | phase_delay = max_window + DIV_ROUND_UP(7 * max_len, 16) * 4; | |
423 | else if (temperature < 90000) | |
424 | phase_delay = max_window + DIV_ROUND_UP(5 * max_len, 16) * 4; | |
425 | else if (temperature < 120000) | |
426 | phase_delay = max_window + DIV_ROUND_UP(4 * max_len, 16) * 4; | |
427 | else | |
428 | phase_delay = max_window + DIV_ROUND_UP(3 * max_len, 16) * 4; | |
429 | ||
430 | /* | |
431 | * Stage 2: Search for a single point failure near the chosen tuning | |
432 | * value in two steps. First in the +3 to +10 range and then in the | |
433 | * +2 to -10 range. If found, move away from it in the appropriate | |
434 | * direction by the appropriate amount depending on the temperature. | |
435 | */ | |
436 | for (i = 3; i <= 10; i++) { | |
437 | sdhci_omap_set_dll(omap_host, phase_delay + i); | |
438 | ||
439 | if (mmc_send_tuning(mmc, opcode, NULL)) { | |
440 | if (temperature < 10000) | |
441 | phase_delay += i + 6; | |
442 | else if (temperature < 20000) | |
443 | phase_delay += i - 12; | |
444 | else if (temperature < 70000) | |
445 | phase_delay += i - 8; | |
446 | else | |
447 | phase_delay += i - 6; | |
448 | ||
449 | goto single_failure_found; | |
450 | } | |
451 | } | |
452 | ||
453 | for (i = 2; i >= -10; i--) { | |
454 | sdhci_omap_set_dll(omap_host, phase_delay + i); | |
455 | ||
456 | if (mmc_send_tuning(mmc, opcode, NULL)) { | |
457 | if (temperature < 10000) | |
458 | phase_delay += i + 12; | |
459 | else if (temperature < 20000) | |
460 | phase_delay += i + 8; | |
461 | else if (temperature < 70000) | |
462 | phase_delay += i + 8; | |
463 | else if (temperature < 90000) | |
464 | phase_delay += i + 10; | |
465 | else | |
466 | phase_delay += i + 12; | |
467 | ||
468 | goto single_failure_found; | |
469 | } | |
470 | } | |
471 | ||
472 | single_failure_found: | |
9fc2cd76 KVA |
473 | reg = sdhci_omap_readl(omap_host, SDHCI_OMAP_AC12); |
474 | if (!(reg & AC12_SCLK_SEL)) { | |
475 | ret = -EIO; | |
476 | goto tuning_error; | |
477 | } | |
478 | ||
9fc2cd76 KVA |
479 | sdhci_omap_set_dll(omap_host, phase_delay); |
480 | ||
5b0d6210 FA |
481 | omap_host->is_tuning = false; |
482 | ||
9fc2cd76 KVA |
483 | goto ret; |
484 | ||
485 | tuning_error: | |
5b0d6210 | 486 | omap_host->is_tuning = false; |
9fc2cd76 KVA |
487 | dev_err(dev, "Tuning failed\n"); |
488 | sdhci_omap_disable_tuning(omap_host); | |
489 | ||
490 | ret: | |
491 | sdhci_reset(host, SDHCI_RESET_CMD | SDHCI_RESET_DATA); | |
db2039fc FA |
492 | /* Reenable forbidden interrupt */ |
493 | if (dcrc_was_enabled) | |
494 | host->ier |= SDHCI_INT_DATA_CRC; | |
7d33c358 KVA |
495 | sdhci_writel(host, host->ier, SDHCI_INT_ENABLE); |
496 | sdhci_writel(host, host->ier, SDHCI_SIGNAL_ENABLE); | |
9fc2cd76 KVA |
497 | return ret; |
498 | } | |
499 | ||
20ea26a1 KVA |
500 | static int sdhci_omap_card_busy(struct mmc_host *mmc) |
501 | { | |
502 | u32 reg, ac12; | |
503 | int ret = false; | |
504 | struct sdhci_host *host = mmc_priv(mmc); | |
505 | struct sdhci_pltfm_host *pltfm_host; | |
506 | struct sdhci_omap_host *omap_host; | |
507 | u32 ier = host->ier; | |
508 | ||
509 | pltfm_host = sdhci_priv(host); | |
510 | omap_host = sdhci_pltfm_priv(pltfm_host); | |
511 | ||
512 | reg = sdhci_omap_readl(omap_host, SDHCI_OMAP_CON); | |
513 | ac12 = sdhci_omap_readl(omap_host, SDHCI_OMAP_AC12); | |
514 | reg &= ~CON_CLKEXTFREE; | |
515 | if (ac12 & AC12_V1V8_SIGEN) | |
516 | reg |= CON_CLKEXTFREE; | |
517 | reg |= CON_PADEN; | |
518 | sdhci_omap_writel(omap_host, SDHCI_OMAP_CON, reg); | |
519 | ||
520 | disable_irq(host->irq); | |
521 | ier |= SDHCI_INT_CARD_INT; | |
522 | sdhci_writel(host, ier, SDHCI_INT_ENABLE); | |
523 | sdhci_writel(host, ier, SDHCI_SIGNAL_ENABLE); | |
524 | ||
525 | /* | |
526 | * Delay is required for PSTATE to correctly reflect | |
527 | * DLEV/CLEV values after PADEN is set. | |
528 | */ | |
529 | usleep_range(50, 100); | |
530 | reg = sdhci_omap_readl(omap_host, SDHCI_OMAP_PSTATE); | |
531 | if ((reg & PSTATE_DATI) || !(reg & PSTATE_DLEV_DAT0)) | |
532 | ret = true; | |
533 | ||
534 | reg = sdhci_omap_readl(omap_host, SDHCI_OMAP_CON); | |
535 | reg &= ~(CON_CLKEXTFREE | CON_PADEN); | |
536 | sdhci_omap_writel(omap_host, SDHCI_OMAP_CON, reg); | |
537 | ||
538 | sdhci_writel(host, host->ier, SDHCI_INT_ENABLE); | |
539 | sdhci_writel(host, host->ier, SDHCI_SIGNAL_ENABLE); | |
540 | enable_irq(host->irq); | |
541 | ||
542 | return ret; | |
543 | } | |
544 | ||
7d326930 KVA |
545 | static int sdhci_omap_start_signal_voltage_switch(struct mmc_host *mmc, |
546 | struct mmc_ios *ios) | |
547 | { | |
548 | u32 reg; | |
549 | int ret; | |
550 | unsigned int iov; | |
551 | struct sdhci_host *host = mmc_priv(mmc); | |
552 | struct sdhci_pltfm_host *pltfm_host; | |
553 | struct sdhci_omap_host *omap_host; | |
554 | struct device *dev; | |
555 | ||
556 | pltfm_host = sdhci_priv(host); | |
557 | omap_host = sdhci_pltfm_priv(pltfm_host); | |
558 | dev = omap_host->dev; | |
559 | ||
560 | if (ios->signal_voltage == MMC_SIGNAL_VOLTAGE_330) { | |
561 | reg = sdhci_omap_readl(omap_host, SDHCI_OMAP_CAPA); | |
de5ccd2a | 562 | if (!(reg & (CAPA_VS30 | CAPA_VS33))) |
7d326930 KVA |
563 | return -EOPNOTSUPP; |
564 | ||
de5ccd2a TL |
565 | if (reg & CAPA_VS30) |
566 | iov = IOV_3V0; | |
567 | else | |
568 | iov = IOV_3V3; | |
569 | ||
7d326930 KVA |
570 | sdhci_omap_conf_bus_power(omap_host, ios->signal_voltage); |
571 | ||
572 | reg = sdhci_omap_readl(omap_host, SDHCI_OMAP_AC12); | |
573 | reg &= ~AC12_V1V8_SIGEN; | |
574 | sdhci_omap_writel(omap_host, SDHCI_OMAP_AC12, reg); | |
575 | ||
7d326930 KVA |
576 | } else if (ios->signal_voltage == MMC_SIGNAL_VOLTAGE_180) { |
577 | reg = sdhci_omap_readl(omap_host, SDHCI_OMAP_CAPA); | |
578 | if (!(reg & CAPA_VS18)) | |
579 | return -EOPNOTSUPP; | |
580 | ||
de5ccd2a TL |
581 | iov = IOV_1V8; |
582 | ||
7d326930 KVA |
583 | sdhci_omap_conf_bus_power(omap_host, ios->signal_voltage); |
584 | ||
585 | reg = sdhci_omap_readl(omap_host, SDHCI_OMAP_AC12); | |
586 | reg |= AC12_V1V8_SIGEN; | |
587 | sdhci_omap_writel(omap_host, SDHCI_OMAP_AC12, reg); | |
7d326930 KVA |
588 | } else { |
589 | return -EOPNOTSUPP; | |
590 | } | |
591 | ||
592 | ret = sdhci_omap_enable_iov(omap_host, iov); | |
593 | if (ret) { | |
594 | dev_err(dev, "failed to switch IO voltage to %dmV\n", iov); | |
595 | return ret; | |
596 | } | |
597 | ||
598 | dev_dbg(dev, "IO voltage switched to %dmV\n", iov); | |
599 | return 0; | |
600 | } | |
601 | ||
8d20b2ea KVA |
602 | static void sdhci_omap_set_timing(struct sdhci_omap_host *omap_host, u8 timing) |
603 | { | |
604 | int ret; | |
605 | struct pinctrl_state *pinctrl_state; | |
606 | struct device *dev = omap_host->dev; | |
607 | ||
608 | if (!(omap_host->flags & SDHCI_OMAP_REQUIRE_IODELAY)) | |
609 | return; | |
610 | ||
611 | if (omap_host->timing == timing) | |
612 | return; | |
613 | ||
614 | sdhci_omap_stop_clock(omap_host); | |
615 | ||
616 | pinctrl_state = omap_host->pinctrl_state[timing]; | |
617 | ret = pinctrl_select_state(omap_host->pinctrl, pinctrl_state); | |
618 | if (ret) { | |
619 | dev_err(dev, "failed to select pinctrl state\n"); | |
620 | return; | |
621 | } | |
622 | ||
623 | sdhci_omap_start_clock(omap_host); | |
624 | omap_host->timing = timing; | |
625 | } | |
626 | ||
300df508 KVA |
627 | static void sdhci_omap_set_power_mode(struct sdhci_omap_host *omap_host, |
628 | u8 power_mode) | |
629 | { | |
9fc2cd76 KVA |
630 | if (omap_host->bus_mode == MMC_POWER_OFF) |
631 | sdhci_omap_disable_tuning(omap_host); | |
300df508 KVA |
632 | omap_host->power_mode = power_mode; |
633 | } | |
634 | ||
7d326930 KVA |
635 | static void sdhci_omap_set_bus_mode(struct sdhci_omap_host *omap_host, |
636 | unsigned int mode) | |
637 | { | |
638 | u32 reg; | |
639 | ||
640 | if (omap_host->bus_mode == mode) | |
641 | return; | |
642 | ||
643 | reg = sdhci_omap_readl(omap_host, SDHCI_OMAP_CON); | |
644 | if (mode == MMC_BUSMODE_OPENDRAIN) | |
645 | reg |= CON_OD; | |
646 | else | |
647 | reg &= ~CON_OD; | |
648 | sdhci_omap_writel(omap_host, SDHCI_OMAP_CON, reg); | |
649 | ||
650 | omap_host->bus_mode = mode; | |
651 | } | |
652 | ||
ddde0e7d | 653 | static void sdhci_omap_set_ios(struct mmc_host *mmc, struct mmc_ios *ios) |
7d326930 KVA |
654 | { |
655 | struct sdhci_host *host = mmc_priv(mmc); | |
656 | struct sdhci_pltfm_host *pltfm_host; | |
657 | struct sdhci_omap_host *omap_host; | |
658 | ||
659 | pltfm_host = sdhci_priv(host); | |
660 | omap_host = sdhci_pltfm_priv(pltfm_host); | |
661 | ||
662 | sdhci_omap_set_bus_mode(omap_host, ios->bus_mode); | |
8d20b2ea | 663 | sdhci_omap_set_timing(omap_host, ios->timing); |
7d326930 | 664 | sdhci_set_ios(mmc, ios); |
300df508 | 665 | sdhci_omap_set_power_mode(omap_host, ios->power_mode); |
7d326930 KVA |
666 | } |
667 | ||
668 | static u16 sdhci_omap_calc_divisor(struct sdhci_pltfm_host *host, | |
669 | unsigned int clock) | |
670 | { | |
671 | u16 dsor; | |
672 | ||
673 | dsor = DIV_ROUND_UP(clk_get_rate(host->clk), clock); | |
674 | if (dsor > SYSCTL_CLKD_MAX) | |
675 | dsor = SYSCTL_CLKD_MAX; | |
676 | ||
677 | return dsor; | |
678 | } | |
679 | ||
680 | static void sdhci_omap_start_clock(struct sdhci_omap_host *omap_host) | |
681 | { | |
682 | u32 reg; | |
683 | ||
684 | reg = sdhci_omap_readl(omap_host, SDHCI_OMAP_SYSCTL); | |
685 | reg |= SYSCTL_CEN; | |
686 | sdhci_omap_writel(omap_host, SDHCI_OMAP_SYSCTL, reg); | |
687 | } | |
688 | ||
689 | static void sdhci_omap_stop_clock(struct sdhci_omap_host *omap_host) | |
690 | { | |
691 | u32 reg; | |
692 | ||
693 | reg = sdhci_omap_readl(omap_host, SDHCI_OMAP_SYSCTL); | |
694 | reg &= ~SYSCTL_CEN; | |
695 | sdhci_omap_writel(omap_host, SDHCI_OMAP_SYSCTL, reg); | |
696 | } | |
697 | ||
698 | static void sdhci_omap_set_clock(struct sdhci_host *host, unsigned int clock) | |
699 | { | |
700 | struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); | |
701 | struct sdhci_omap_host *omap_host = sdhci_pltfm_priv(pltfm_host); | |
702 | unsigned long clkdiv; | |
703 | ||
704 | sdhci_omap_stop_clock(omap_host); | |
705 | ||
706 | if (!clock) | |
707 | return; | |
708 | ||
709 | clkdiv = sdhci_omap_calc_divisor(pltfm_host, clock); | |
710 | clkdiv = (clkdiv & SYSCTL_CLKD_MASK) << SYSCTL_CLKD_SHIFT; | |
711 | sdhci_enable_clk(host, clkdiv); | |
712 | ||
713 | sdhci_omap_start_clock(omap_host); | |
714 | } | |
715 | ||
ddde0e7d | 716 | static void sdhci_omap_set_power(struct sdhci_host *host, unsigned char mode, |
7d326930 KVA |
717 | unsigned short vdd) |
718 | { | |
719 | struct mmc_host *mmc = host->mmc; | |
720 | ||
8e0e7bd3 TL |
721 | if (!IS_ERR(mmc->supply.vmmc)) |
722 | mmc_regulator_set_ocr(mmc, mmc->supply.vmmc, vdd); | |
7d326930 KVA |
723 | } |
724 | ||
c66e21fd TL |
725 | /* |
726 | * MMCHS_HL_HWINFO has the MADMA_EN bit set if the controller instance | |
727 | * is connected to L3 interconnect and is bus master capable. Note that | |
728 | * the MMCHS_HL_HWINFO register is in the module registers before the | |
729 | * omap registers and sdhci registers. The offset can vary for omap | |
730 | * registers depending on the SoC. Do not use sdhci_omap_readl() here. | |
731 | */ | |
732 | static bool sdhci_omap_has_adma(struct sdhci_omap_host *omap_host, int offset) | |
733 | { | |
734 | /* MMCHS_HL_HWINFO register is only available on omap4 and later */ | |
735 | if (offset < 0x200) | |
736 | return false; | |
737 | ||
738 | return readl(omap_host->base + 4) & 1; | |
739 | } | |
740 | ||
7d326930 KVA |
741 | static int sdhci_omap_enable_dma(struct sdhci_host *host) |
742 | { | |
743 | u32 reg; | |
744 | struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); | |
745 | struct sdhci_omap_host *omap_host = sdhci_pltfm_priv(pltfm_host); | |
746 | ||
747 | reg = sdhci_omap_readl(omap_host, SDHCI_OMAP_CON); | |
195fadb7 CZ |
748 | reg &= ~CON_DMA_MASTER; |
749 | /* Switch to DMA slave mode when using external DMA */ | |
750 | if (!host->use_external_dma) | |
751 | reg |= CON_DMA_MASTER; | |
752 | ||
7d326930 KVA |
753 | sdhci_omap_writel(omap_host, SDHCI_OMAP_CON, reg); |
754 | ||
755 | return 0; | |
756 | } | |
757 | ||
ddde0e7d | 758 | static unsigned int sdhci_omap_get_min_clock(struct sdhci_host *host) |
7d326930 KVA |
759 | { |
760 | struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); | |
761 | ||
762 | return clk_get_rate(pltfm_host->clk) / SYSCTL_CLKD_MAX; | |
763 | } | |
764 | ||
765 | static void sdhci_omap_set_bus_width(struct sdhci_host *host, int width) | |
766 | { | |
767 | struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); | |
768 | struct sdhci_omap_host *omap_host = sdhci_pltfm_priv(pltfm_host); | |
769 | u32 reg; | |
770 | ||
771 | reg = sdhci_omap_readl(omap_host, SDHCI_OMAP_CON); | |
772 | if (width == MMC_BUS_WIDTH_8) | |
773 | reg |= CON_DW8; | |
774 | else | |
775 | reg &= ~CON_DW8; | |
776 | sdhci_omap_writel(omap_host, SDHCI_OMAP_CON, reg); | |
777 | ||
778 | sdhci_set_bus_width(host, width); | |
779 | } | |
780 | ||
781 | static void sdhci_omap_init_74_clocks(struct sdhci_host *host, u8 power_mode) | |
782 | { | |
783 | u32 reg; | |
784 | ktime_t timeout; | |
785 | struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); | |
786 | struct sdhci_omap_host *omap_host = sdhci_pltfm_priv(pltfm_host); | |
787 | ||
788 | if (omap_host->power_mode == power_mode) | |
789 | return; | |
790 | ||
791 | if (power_mode != MMC_POWER_ON) | |
792 | return; | |
793 | ||
794 | disable_irq(host->irq); | |
795 | ||
796 | reg = sdhci_omap_readl(omap_host, SDHCI_OMAP_CON); | |
797 | reg |= CON_INIT; | |
798 | sdhci_omap_writel(omap_host, SDHCI_OMAP_CON, reg); | |
799 | sdhci_omap_writel(omap_host, SDHCI_OMAP_CMD, 0x0); | |
800 | ||
801 | /* wait 1ms */ | |
802 | timeout = ktime_add_ms(ktime_get(), SDHCI_OMAP_TIMEOUT); | |
9f0ea0bd AH |
803 | while (1) { |
804 | bool timedout = ktime_after(ktime_get(), timeout); | |
805 | ||
806 | if (sdhci_omap_readl(omap_host, SDHCI_OMAP_STAT) & INT_CC_EN) | |
807 | break; | |
808 | if (WARN_ON(timedout)) | |
7d326930 KVA |
809 | return; |
810 | usleep_range(5, 10); | |
811 | } | |
812 | ||
813 | reg = sdhci_omap_readl(omap_host, SDHCI_OMAP_CON); | |
814 | reg &= ~CON_INIT; | |
815 | sdhci_omap_writel(omap_host, SDHCI_OMAP_CON, reg); | |
816 | sdhci_omap_writel(omap_host, SDHCI_OMAP_STAT, INT_CC_EN); | |
817 | ||
818 | enable_irq(host->irq); | |
7d326930 KVA |
819 | } |
820 | ||
27ceb7e0 KVA |
821 | static void sdhci_omap_set_uhs_signaling(struct sdhci_host *host, |
822 | unsigned int timing) | |
823 | { | |
824 | u32 reg; | |
825 | struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); | |
826 | struct sdhci_omap_host *omap_host = sdhci_pltfm_priv(pltfm_host); | |
827 | ||
828 | sdhci_omap_stop_clock(omap_host); | |
829 | ||
830 | reg = sdhci_omap_readl(omap_host, SDHCI_OMAP_CON); | |
831 | if (timing == MMC_TIMING_UHS_DDR50 || timing == MMC_TIMING_MMC_DDR52) | |
832 | reg |= CON_DDR; | |
833 | else | |
834 | reg &= ~CON_DDR; | |
835 | sdhci_omap_writel(omap_host, SDHCI_OMAP_CON, reg); | |
836 | ||
837 | sdhci_set_uhs_signaling(host, timing); | |
838 | sdhci_omap_start_clock(omap_host); | |
839 | } | |
840 | ||
9e84a2e6 | 841 | #define MMC_TIMEOUT_US 20000 /* 20000 micro Sec */ |
2198eeff | 842 | static void sdhci_omap_reset(struct sdhci_host *host, u8 mask) |
5b0d6210 FA |
843 | { |
844 | struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); | |
845 | struct sdhci_omap_host *omap_host = sdhci_pltfm_priv(pltfm_host); | |
9e84a2e6 FA |
846 | unsigned long limit = MMC_TIMEOUT_US; |
847 | unsigned long i = 0; | |
53f9460e TL |
848 | u32 sysc; |
849 | ||
850 | /* Save target module sysconfig configured by SoC PM layer */ | |
851 | if (mask & SDHCI_RESET_ALL) | |
852 | sysc = sdhci_omap_readl(omap_host, SDHCI_OMAP_SYSCONFIG); | |
5b0d6210 FA |
853 | |
854 | /* Don't reset data lines during tuning operation */ | |
855 | if (omap_host->is_tuning) | |
856 | mask &= ~SDHCI_RESET_DATA; | |
857 | ||
9e84a2e6 FA |
858 | if (omap_host->flags & SDHCI_OMAP_SPECIAL_RESET) { |
859 | sdhci_writeb(host, mask, SDHCI_SOFTWARE_RESET); | |
860 | while ((!(sdhci_readb(host, SDHCI_SOFTWARE_RESET) & mask)) && | |
861 | (i++ < limit)) | |
862 | udelay(1); | |
863 | i = 0; | |
864 | while ((sdhci_readb(host, SDHCI_SOFTWARE_RESET) & mask) && | |
865 | (i++ < limit)) | |
866 | udelay(1); | |
867 | ||
868 | if (sdhci_readb(host, SDHCI_SOFTWARE_RESET) & mask) | |
869 | dev_err(mmc_dev(host->mmc), | |
870 | "Timeout waiting on controller reset in %s\n", | |
871 | __func__); | |
53f9460e TL |
872 | |
873 | goto restore_sysc; | |
9e84a2e6 FA |
874 | } |
875 | ||
5b0d6210 | 876 | sdhci_reset(host, mask); |
53f9460e TL |
877 | |
878 | restore_sysc: | |
879 | if (mask & SDHCI_RESET_ALL) | |
880 | sdhci_omap_writel(omap_host, SDHCI_OMAP_SYSCONFIG, sysc); | |
5b0d6210 FA |
881 | } |
882 | ||
5c41ea6d FA |
883 | #define CMD_ERR_MASK (SDHCI_INT_CRC | SDHCI_INT_END_BIT | SDHCI_INT_INDEX |\ |
884 | SDHCI_INT_TIMEOUT) | |
885 | #define CMD_MASK (CMD_ERR_MASK | SDHCI_INT_RESPONSE) | |
886 | ||
887 | static u32 sdhci_omap_irq(struct sdhci_host *host, u32 intmask) | |
888 | { | |
889 | struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); | |
890 | struct sdhci_omap_host *omap_host = sdhci_pltfm_priv(pltfm_host); | |
891 | ||
892 | if (omap_host->is_tuning && host->cmd && !host->data_early && | |
893 | (intmask & CMD_ERR_MASK)) { | |
894 | ||
895 | /* | |
896 | * Since we are not resetting data lines during tuning | |
897 | * operation, data error or data complete interrupts | |
898 | * might still arrive. Mark this request as a failure | |
899 | * but still wait for the data interrupt | |
900 | */ | |
901 | if (intmask & SDHCI_INT_TIMEOUT) | |
902 | host->cmd->error = -ETIMEDOUT; | |
903 | else | |
904 | host->cmd->error = -EILSEQ; | |
905 | ||
906 | host->cmd = NULL; | |
907 | ||
908 | /* | |
909 | * Sometimes command error interrupts and command complete | |
910 | * interrupt will arrive together. Clear all command related | |
911 | * interrupts here. | |
912 | */ | |
913 | sdhci_writel(host, intmask & CMD_MASK, SDHCI_INT_STATUS); | |
914 | intmask &= ~CMD_MASK; | |
915 | } | |
916 | ||
917 | return intmask; | |
918 | } | |
919 | ||
5da5e494 FA |
920 | static void sdhci_omap_set_timeout(struct sdhci_host *host, |
921 | struct mmc_command *cmd) | |
922 | { | |
923 | if (cmd->opcode == MMC_ERASE) | |
924 | sdhci_set_data_timeout_irq(host, false); | |
925 | ||
926 | __sdhci_set_timeout(host, cmd); | |
927 | } | |
928 | ||
7d326930 KVA |
929 | static struct sdhci_ops sdhci_omap_ops = { |
930 | .set_clock = sdhci_omap_set_clock, | |
931 | .set_power = sdhci_omap_set_power, | |
932 | .enable_dma = sdhci_omap_enable_dma, | |
933 | .get_max_clock = sdhci_pltfm_clk_get_max_clock, | |
934 | .get_min_clock = sdhci_omap_get_min_clock, | |
935 | .set_bus_width = sdhci_omap_set_bus_width, | |
936 | .platform_send_init_74_clocks = sdhci_omap_init_74_clocks, | |
5b0d6210 | 937 | .reset = sdhci_omap_reset, |
27ceb7e0 | 938 | .set_uhs_signaling = sdhci_omap_set_uhs_signaling, |
5c41ea6d | 939 | .irq = sdhci_omap_irq, |
5da5e494 | 940 | .set_timeout = sdhci_omap_set_timeout, |
7d326930 KVA |
941 | }; |
942 | ||
de5ccd2a TL |
943 | static unsigned int sdhci_omap_regulator_get_caps(struct device *dev, |
944 | const char *name) | |
7d326930 | 945 | { |
de5ccd2a TL |
946 | struct regulator *reg; |
947 | unsigned int caps = 0; | |
948 | ||
949 | reg = regulator_get(dev, name); | |
950 | if (IS_ERR(reg)) | |
951 | return ~0U; | |
952 | ||
953 | if (regulator_is_supported_voltage(reg, 1700000, 1950000)) | |
954 | caps |= SDHCI_CAN_VDD_180; | |
955 | if (regulator_is_supported_voltage(reg, 2700000, 3150000)) | |
956 | caps |= SDHCI_CAN_VDD_300; | |
957 | if (regulator_is_supported_voltage(reg, 3150000, 3600000)) | |
958 | caps |= SDHCI_CAN_VDD_330; | |
959 | ||
960 | regulator_put(reg); | |
961 | ||
962 | return caps; | |
963 | } | |
964 | ||
965 | static int sdhci_omap_set_capabilities(struct sdhci_host *host) | |
966 | { | |
967 | struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); | |
968 | struct sdhci_omap_host *omap_host = sdhci_pltfm_priv(pltfm_host); | |
7d326930 | 969 | struct device *dev = omap_host->dev; |
de5ccd2a TL |
970 | const u32 mask = SDHCI_CAN_VDD_180 | SDHCI_CAN_VDD_300 | SDHCI_CAN_VDD_330; |
971 | unsigned int pbias, vqmmc, caps = 0; | |
972 | u32 reg; | |
7d326930 | 973 | |
de5ccd2a TL |
974 | pbias = sdhci_omap_regulator_get_caps(dev, "pbias"); |
975 | vqmmc = sdhci_omap_regulator_get_caps(dev, "vqmmc"); | |
976 | caps = pbias & vqmmc; | |
977 | ||
978 | if (pbias != ~0U && vqmmc == ~0U) | |
979 | dev_warn(dev, "vqmmc regulator missing for pbias\n"); | |
980 | else if (caps == ~0U) | |
981 | return 0; | |
982 | ||
983 | /* | |
984 | * Quirk handling to allow 3.0V vqmmc with a valid 3.3V PBIAS. This is | |
985 | * needed for 3.0V ldo9_reg on omap5 at least. | |
986 | */ | |
987 | if (pbias != ~0U && (pbias & SDHCI_CAN_VDD_330) && | |
988 | (vqmmc & SDHCI_CAN_VDD_300)) | |
989 | caps |= SDHCI_CAN_VDD_330; | |
7d326930 KVA |
990 | |
991 | /* voltage capabilities might be set by boot loader, clear it */ | |
992 | reg = sdhci_omap_readl(omap_host, SDHCI_OMAP_CAPA); | |
993 | reg &= ~(CAPA_VS18 | CAPA_VS30 | CAPA_VS33); | |
994 | ||
de5ccd2a | 995 | if (caps & SDHCI_CAN_VDD_180) |
7d326930 KVA |
996 | reg |= CAPA_VS18; |
997 | ||
de5ccd2a TL |
998 | if (caps & SDHCI_CAN_VDD_300) |
999 | reg |= CAPA_VS30; | |
1000 | ||
1001 | if (caps & SDHCI_CAN_VDD_330) | |
1002 | reg |= CAPA_VS33; | |
1003 | ||
7d326930 KVA |
1004 | sdhci_omap_writel(omap_host, SDHCI_OMAP_CAPA, reg); |
1005 | ||
de5ccd2a TL |
1006 | host->caps &= ~mask; |
1007 | host->caps |= caps; | |
7d326930 | 1008 | |
de5ccd2a | 1009 | return 0; |
7d326930 KVA |
1010 | } |
1011 | ||
1012 | static const struct sdhci_pltfm_data sdhci_omap_pdata = { | |
1013 | .quirks = SDHCI_QUIRK_BROKEN_CARD_DETECTION | | |
1014 | SDHCI_QUIRK_DATA_TIMEOUT_USES_SDCLK | | |
1015 | SDHCI_QUIRK_CAP_CLOCK_BASE_BROKEN | | |
1016 | SDHCI_QUIRK_NO_HISPD_BIT | | |
1017 | SDHCI_QUIRK_BROKEN_ADMA_ZEROLEN_DESC, | |
e0b2dbcf KVA |
1018 | .quirks2 = SDHCI_QUIRK2_ACMD23_BROKEN | |
1019 | SDHCI_QUIRK2_PRESET_VALUE_BROKEN | | |
25f80d86 KVA |
1020 | SDHCI_QUIRK2_RSP_136_HAS_CRC | |
1021 | SDHCI_QUIRK2_DISABLE_HW_TIMEOUT, | |
7d326930 KVA |
1022 | .ops = &sdhci_omap_ops, |
1023 | }; | |
1024 | ||
42b380b6 TL |
1025 | static const struct sdhci_omap_data omap2430_data = { |
1026 | .omap_offset = 0, | |
1027 | .offset = 0x100, | |
1028 | }; | |
1029 | ||
1030 | static const struct sdhci_omap_data omap3_data = { | |
1031 | .omap_offset = 0, | |
1032 | .offset = 0x100, | |
1033 | }; | |
1034 | ||
de5ccd2a | 1035 | static const struct sdhci_omap_data omap4_data = { |
42b380b6 | 1036 | .omap_offset = 0x100, |
de5ccd2a TL |
1037 | .offset = 0x200, |
1038 | .flags = SDHCI_OMAP_SPECIAL_RESET, | |
1039 | }; | |
1040 | ||
1041 | static const struct sdhci_omap_data omap5_data = { | |
42b380b6 | 1042 | .omap_offset = 0x100, |
de5ccd2a TL |
1043 | .offset = 0x200, |
1044 | .flags = SDHCI_OMAP_SPECIAL_RESET, | |
1045 | }; | |
1046 | ||
6d75df75 | 1047 | static const struct sdhci_omap_data k2g_data = { |
42b380b6 | 1048 | .omap_offset = 0x100, |
6d75df75 KVA |
1049 | .offset = 0x200, |
1050 | }; | |
1051 | ||
d6fe4928 | 1052 | static const struct sdhci_omap_data am335_data = { |
42b380b6 | 1053 | .omap_offset = 0x100, |
d6fe4928 | 1054 | .offset = 0x200, |
9e84a2e6 | 1055 | .flags = SDHCI_OMAP_SPECIAL_RESET, |
d6fe4928 FA |
1056 | }; |
1057 | ||
1058 | static const struct sdhci_omap_data am437_data = { | |
42b380b6 | 1059 | .omap_offset = 0x100, |
d6fe4928 | 1060 | .offset = 0x200, |
9e84a2e6 | 1061 | .flags = SDHCI_OMAP_SPECIAL_RESET, |
d6fe4928 FA |
1062 | }; |
1063 | ||
7d326930 | 1064 | static const struct sdhci_omap_data dra7_data = { |
42b380b6 | 1065 | .omap_offset = 0x100, |
7d326930 | 1066 | .offset = 0x200, |
8d20b2ea | 1067 | .flags = SDHCI_OMAP_REQUIRE_IODELAY, |
7d326930 KVA |
1068 | }; |
1069 | ||
1070 | static const struct of_device_id omap_sdhci_match[] = { | |
42b380b6 TL |
1071 | { .compatible = "ti,omap2430-sdhci", .data = &omap2430_data }, |
1072 | { .compatible = "ti,omap3-sdhci", .data = &omap3_data }, | |
de5ccd2a TL |
1073 | { .compatible = "ti,omap4-sdhci", .data = &omap4_data }, |
1074 | { .compatible = "ti,omap5-sdhci", .data = &omap5_data }, | |
7d326930 | 1075 | { .compatible = "ti,dra7-sdhci", .data = &dra7_data }, |
6d75df75 | 1076 | { .compatible = "ti,k2g-sdhci", .data = &k2g_data }, |
d6fe4928 FA |
1077 | { .compatible = "ti,am335-sdhci", .data = &am335_data }, |
1078 | { .compatible = "ti,am437-sdhci", .data = &am437_data }, | |
7d326930 KVA |
1079 | {}, |
1080 | }; | |
1081 | MODULE_DEVICE_TABLE(of, omap_sdhci_match); | |
1082 | ||
8d20b2ea KVA |
1083 | static struct pinctrl_state |
1084 | *sdhci_omap_iodelay_pinctrl_state(struct sdhci_omap_host *omap_host, char *mode, | |
1085 | u32 *caps, u32 capmask) | |
1086 | { | |
1087 | struct device *dev = omap_host->dev; | |
212f4f8a | 1088 | char *version = omap_host->version; |
8d20b2ea | 1089 | struct pinctrl_state *pinctrl_state = ERR_PTR(-ENODEV); |
212f4f8a | 1090 | char str[20]; |
8d20b2ea KVA |
1091 | |
1092 | if (!(*caps & capmask)) | |
1093 | goto ret; | |
1094 | ||
212f4f8a KVA |
1095 | if (version) { |
1096 | snprintf(str, 20, "%s-%s", mode, version); | |
1097 | pinctrl_state = pinctrl_lookup_state(omap_host->pinctrl, str); | |
1098 | } | |
1099 | ||
1100 | if (IS_ERR(pinctrl_state)) | |
1101 | pinctrl_state = pinctrl_lookup_state(omap_host->pinctrl, mode); | |
1102 | ||
8d20b2ea KVA |
1103 | if (IS_ERR(pinctrl_state)) { |
1104 | dev_err(dev, "no pinctrl state for %s mode", mode); | |
1105 | *caps &= ~capmask; | |
1106 | } | |
1107 | ||
1108 | ret: | |
1109 | return pinctrl_state; | |
1110 | } | |
1111 | ||
1112 | static int sdhci_omap_config_iodelay_pinctrl_state(struct sdhci_omap_host | |
1113 | *omap_host) | |
1114 | { | |
1115 | struct device *dev = omap_host->dev; | |
1116 | struct sdhci_host *host = omap_host->host; | |
1117 | struct mmc_host *mmc = host->mmc; | |
1118 | u32 *caps = &mmc->caps; | |
1119 | u32 *caps2 = &mmc->caps2; | |
1120 | struct pinctrl_state *state; | |
1121 | struct pinctrl_state **pinctrl_state; | |
1122 | ||
1123 | if (!(omap_host->flags & SDHCI_OMAP_REQUIRE_IODELAY)) | |
1124 | return 0; | |
1125 | ||
a86854d0 KC |
1126 | pinctrl_state = devm_kcalloc(dev, |
1127 | MMC_TIMING_MMC_HS200 + 1, | |
1128 | sizeof(*pinctrl_state), | |
1129 | GFP_KERNEL); | |
8d20b2ea KVA |
1130 | if (!pinctrl_state) |
1131 | return -ENOMEM; | |
1132 | ||
1133 | omap_host->pinctrl = devm_pinctrl_get(omap_host->dev); | |
1134 | if (IS_ERR(omap_host->pinctrl)) { | |
1135 | dev_err(dev, "Cannot get pinctrl\n"); | |
1136 | return PTR_ERR(omap_host->pinctrl); | |
1137 | } | |
1138 | ||
1139 | state = pinctrl_lookup_state(omap_host->pinctrl, "default"); | |
1140 | if (IS_ERR(state)) { | |
1141 | dev_err(dev, "no pinctrl state for default mode\n"); | |
1142 | return PTR_ERR(state); | |
1143 | } | |
1144 | pinctrl_state[MMC_TIMING_LEGACY] = state; | |
1145 | ||
1146 | state = sdhci_omap_iodelay_pinctrl_state(omap_host, "sdr104", caps, | |
1147 | MMC_CAP_UHS_SDR104); | |
1148 | if (!IS_ERR(state)) | |
1149 | pinctrl_state[MMC_TIMING_UHS_SDR104] = state; | |
1150 | ||
1151 | state = sdhci_omap_iodelay_pinctrl_state(omap_host, "ddr50", caps, | |
1152 | MMC_CAP_UHS_DDR50); | |
1153 | if (!IS_ERR(state)) | |
1154 | pinctrl_state[MMC_TIMING_UHS_DDR50] = state; | |
1155 | ||
1156 | state = sdhci_omap_iodelay_pinctrl_state(omap_host, "sdr50", caps, | |
1157 | MMC_CAP_UHS_SDR50); | |
1158 | if (!IS_ERR(state)) | |
1159 | pinctrl_state[MMC_TIMING_UHS_SDR50] = state; | |
1160 | ||
1161 | state = sdhci_omap_iodelay_pinctrl_state(omap_host, "sdr25", caps, | |
1162 | MMC_CAP_UHS_SDR25); | |
1163 | if (!IS_ERR(state)) | |
1164 | pinctrl_state[MMC_TIMING_UHS_SDR25] = state; | |
1165 | ||
1166 | state = sdhci_omap_iodelay_pinctrl_state(omap_host, "sdr12", caps, | |
1167 | MMC_CAP_UHS_SDR12); | |
1168 | if (!IS_ERR(state)) | |
1169 | pinctrl_state[MMC_TIMING_UHS_SDR12] = state; | |
1170 | ||
1171 | state = sdhci_omap_iodelay_pinctrl_state(omap_host, "ddr_1_8v", caps, | |
1172 | MMC_CAP_1_8V_DDR); | |
3f402878 | 1173 | if (!IS_ERR(state)) { |
8d20b2ea | 1174 | pinctrl_state[MMC_TIMING_MMC_DDR52] = state; |
3f402878 KVA |
1175 | } else { |
1176 | state = sdhci_omap_iodelay_pinctrl_state(omap_host, "ddr_3_3v", | |
1177 | caps, | |
1178 | MMC_CAP_3_3V_DDR); | |
1179 | if (!IS_ERR(state)) | |
1180 | pinctrl_state[MMC_TIMING_MMC_DDR52] = state; | |
1181 | } | |
8d20b2ea KVA |
1182 | |
1183 | state = sdhci_omap_iodelay_pinctrl_state(omap_host, "hs", caps, | |
1184 | MMC_CAP_SD_HIGHSPEED); | |
1185 | if (!IS_ERR(state)) | |
1186 | pinctrl_state[MMC_TIMING_SD_HS] = state; | |
1187 | ||
1188 | state = sdhci_omap_iodelay_pinctrl_state(omap_host, "hs", caps, | |
1189 | MMC_CAP_MMC_HIGHSPEED); | |
1190 | if (!IS_ERR(state)) | |
1191 | pinctrl_state[MMC_TIMING_MMC_HS] = state; | |
1192 | ||
1193 | state = sdhci_omap_iodelay_pinctrl_state(omap_host, "hs200_1_8v", caps2, | |
1194 | MMC_CAP2_HS200_1_8V_SDR); | |
1195 | if (!IS_ERR(state)) | |
1196 | pinctrl_state[MMC_TIMING_MMC_HS200] = state; | |
1197 | ||
1198 | omap_host->pinctrl_state = pinctrl_state; | |
1199 | ||
1200 | return 0; | |
1201 | } | |
1202 | ||
212f4f8a KVA |
1203 | static const struct soc_device_attribute sdhci_omap_soc_devices[] = { |
1204 | { | |
1205 | .machine = "DRA7[45]*", | |
1206 | .revision = "ES1.[01]", | |
1207 | }, | |
1208 | { | |
1209 | /* sentinel */ | |
1210 | } | |
1211 | }; | |
1212 | ||
7d326930 KVA |
1213 | static int sdhci_omap_probe(struct platform_device *pdev) |
1214 | { | |
1215 | int ret; | |
1216 | u32 offset; | |
1217 | struct device *dev = &pdev->dev; | |
1218 | struct sdhci_host *host; | |
1219 | struct sdhci_pltfm_host *pltfm_host; | |
1220 | struct sdhci_omap_host *omap_host; | |
1221 | struct mmc_host *mmc; | |
897ae3fe | 1222 | const struct sdhci_omap_data *data; |
212f4f8a | 1223 | const struct soc_device_attribute *soc; |
195fadb7 | 1224 | struct resource *regs; |
7d326930 | 1225 | |
897ae3fe | 1226 | data = of_device_get_match_data(&pdev->dev); |
7d326930 KVA |
1227 | if (!data) { |
1228 | dev_err(dev, "no sdhci omap data\n"); | |
1229 | return -EINVAL; | |
1230 | } | |
1231 | offset = data->offset; | |
1232 | ||
195fadb7 CZ |
1233 | regs = platform_get_resource(pdev, IORESOURCE_MEM, 0); |
1234 | if (!regs) | |
1235 | return -ENXIO; | |
1236 | ||
7d326930 KVA |
1237 | host = sdhci_pltfm_init(pdev, &sdhci_omap_pdata, |
1238 | sizeof(*omap_host)); | |
1239 | if (IS_ERR(host)) { | |
1240 | dev_err(dev, "Failed sdhci_pltfm_init\n"); | |
1241 | return PTR_ERR(host); | |
1242 | } | |
1243 | ||
1244 | pltfm_host = sdhci_priv(host); | |
1245 | omap_host = sdhci_pltfm_priv(pltfm_host); | |
1246 | omap_host->host = host; | |
1247 | omap_host->base = host->ioaddr; | |
1248 | omap_host->dev = dev; | |
300df508 | 1249 | omap_host->power_mode = MMC_POWER_UNDEFINED; |
8d20b2ea KVA |
1250 | omap_host->timing = MMC_TIMING_LEGACY; |
1251 | omap_host->flags = data->flags; | |
42b380b6 | 1252 | omap_host->omap_offset = data->omap_offset; |
f433e8aa | 1253 | omap_host->con = -EINVAL; /* Prevent invalid restore on first resume */ |
7d326930 | 1254 | host->ioaddr += offset; |
195fadb7 | 1255 | host->mapbase = regs->start + offset; |
7d326930 KVA |
1256 | |
1257 | mmc = host->mmc; | |
1d3a2220 | 1258 | sdhci_get_of_property(pdev); |
7d326930 KVA |
1259 | ret = mmc_of_parse(mmc); |
1260 | if (ret) | |
1261 | goto err_pltfm_free; | |
1262 | ||
212f4f8a KVA |
1263 | soc = soc_device_match(sdhci_omap_soc_devices); |
1264 | if (soc) { | |
1265 | omap_host->version = "rev11"; | |
1266 | if (!strcmp(dev_name(dev), "4809c000.mmc")) | |
1267 | mmc->f_max = 96000000; | |
1268 | if (!strcmp(dev_name(dev), "480b4000.mmc")) | |
1269 | mmc->f_max = 48000000; | |
1270 | if (!strcmp(dev_name(dev), "480ad000.mmc")) | |
1271 | mmc->f_max = 48000000; | |
1272 | } | |
1273 | ||
031d2ccc KVA |
1274 | if (!mmc_can_gpio_ro(mmc)) |
1275 | mmc->caps2 |= MMC_CAP2_NO_WRITE_PROTECT; | |
1276 | ||
7d326930 KVA |
1277 | pltfm_host->clk = devm_clk_get(dev, "fck"); |
1278 | if (IS_ERR(pltfm_host->clk)) { | |
1279 | ret = PTR_ERR(pltfm_host->clk); | |
1280 | goto err_pltfm_free; | |
1281 | } | |
1282 | ||
1283 | ret = clk_set_rate(pltfm_host->clk, mmc->f_max); | |
1284 | if (ret) { | |
1285 | dev_err(dev, "failed to set clock to %d\n", mmc->f_max); | |
1286 | goto err_pltfm_free; | |
1287 | } | |
1288 | ||
1289 | omap_host->pbias = devm_regulator_get_optional(dev, "pbias"); | |
1290 | if (IS_ERR(omap_host->pbias)) { | |
1291 | ret = PTR_ERR(omap_host->pbias); | |
1292 | if (ret != -ENODEV) | |
1293 | goto err_pltfm_free; | |
1294 | dev_dbg(dev, "unable to get pbias regulator %d\n", ret); | |
1295 | } | |
1296 | omap_host->pbias_enabled = false; | |
1297 | ||
1298 | /* | |
1299 | * omap_device_pm_domain has callbacks to enable the main | |
1300 | * functional clock, interface clock and also configure the | |
1301 | * SYSCONFIG register of omap devices. The callback will be invoked | |
1302 | * as part of pm_runtime_get_sync. | |
1303 | */ | |
f433e8aa TL |
1304 | pm_runtime_use_autosuspend(dev); |
1305 | pm_runtime_set_autosuspend_delay(dev, 50); | |
7d326930 | 1306 | pm_runtime_enable(dev); |
809ae4e1 TT |
1307 | ret = pm_runtime_resume_and_get(dev); |
1308 | if (ret) { | |
7d326930 | 1309 | dev_err(dev, "pm_runtime_get_sync failed\n"); |
7d326930 KVA |
1310 | goto err_rpm_disable; |
1311 | } | |
1312 | ||
de5ccd2a | 1313 | ret = sdhci_omap_set_capabilities(host); |
7d326930 KVA |
1314 | if (ret) { |
1315 | dev_err(dev, "failed to set system capabilities\n"); | |
f433e8aa | 1316 | goto err_rpm_put; |
7d326930 KVA |
1317 | } |
1318 | ||
7d326930 KVA |
1319 | host->mmc_host_ops.start_signal_voltage_switch = |
1320 | sdhci_omap_start_signal_voltage_switch; | |
1321 | host->mmc_host_ops.set_ios = sdhci_omap_set_ios; | |
20ea26a1 | 1322 | host->mmc_host_ops.card_busy = sdhci_omap_card_busy; |
9fc2cd76 | 1323 | host->mmc_host_ops.execute_tuning = sdhci_omap_execute_tuning; |
efde12b2 | 1324 | host->mmc_host_ops.enable_sdio_irq = sdhci_omap_enable_sdio_irq; |
7d326930 | 1325 | |
c66e21fd TL |
1326 | /* |
1327 | * Switch to external DMA only if there is the "dmas" property and | |
1328 | * ADMA is not available on the controller instance. | |
1329 | */ | |
1330 | if (device_property_present(dev, "dmas") && | |
1331 | !sdhci_omap_has_adma(omap_host, offset)) | |
195fadb7 CZ |
1332 | sdhci_switch_external_dma(host, true); |
1333 | ||
3781d288 TL |
1334 | if (device_property_read_bool(dev, "ti,non-removable")) { |
1335 | dev_warn_once(dev, "using old ti,non-removable property\n"); | |
1336 | mmc->caps |= MMC_CAP_NONREMOVABLE; | |
1337 | } | |
1338 | ||
055e0483 UH |
1339 | /* R1B responses is required to properly manage HW busy detection. */ |
1340 | mmc->caps |= MMC_CAP_NEED_RSP_BUSY; | |
1341 | ||
3edf588e TL |
1342 | /* Allow card power off and runtime PM for eMMC/SD card devices */ |
1343 | mmc->caps |= MMC_CAP_POWER_OFF_CARD | MMC_CAP_AGGRESSIVE_PM; | |
1344 | ||
0ec4ee3c | 1345 | ret = sdhci_setup_host(host); |
7d326930 | 1346 | if (ret) |
f433e8aa | 1347 | goto err_rpm_put; |
7d326930 | 1348 | |
0ec4ee3c KVA |
1349 | ret = sdhci_omap_config_iodelay_pinctrl_state(omap_host); |
1350 | if (ret) | |
1351 | goto err_cleanup_host; | |
1352 | ||
1353 | ret = __sdhci_add_host(host); | |
1354 | if (ret) | |
1355 | goto err_cleanup_host; | |
1356 | ||
a1e97bd2 TL |
1357 | /* |
1358 | * SDIO devices can use the dat1 pin as a wake-up interrupt. Some | |
1359 | * devices like wl1xxx, use an out-of-band GPIO interrupt instead. | |
1360 | */ | |
1361 | omap_host->wakeirq = of_irq_get_byname(dev->of_node, "wakeup"); | |
1362 | if (omap_host->wakeirq == -EPROBE_DEFER) { | |
1363 | ret = -EPROBE_DEFER; | |
1364 | goto err_cleanup_host; | |
1365 | } | |
1366 | if (omap_host->wakeirq > 0) { | |
1367 | device_init_wakeup(dev, true); | |
1368 | ret = dev_pm_set_dedicated_wake_irq(dev, omap_host->wakeirq); | |
1369 | if (ret) { | |
1370 | device_init_wakeup(dev, false); | |
1371 | goto err_cleanup_host; | |
1372 | } | |
1373 | host->mmc->pm_caps |= MMC_PM_KEEP_POWER | MMC_PM_WAKE_SDIO_IRQ; | |
1374 | } | |
1375 | ||
f433e8aa TL |
1376 | pm_runtime_mark_last_busy(dev); |
1377 | pm_runtime_put_autosuspend(dev); | |
1378 | ||
7d326930 KVA |
1379 | return 0; |
1380 | ||
0ec4ee3c KVA |
1381 | err_cleanup_host: |
1382 | sdhci_cleanup_host(host); | |
1383 | ||
f433e8aa TL |
1384 | err_rpm_put: |
1385 | pm_runtime_mark_last_busy(dev); | |
1386 | pm_runtime_put_autosuspend(dev); | |
7d326930 | 1387 | err_rpm_disable: |
f433e8aa | 1388 | pm_runtime_dont_use_autosuspend(dev); |
7d326930 KVA |
1389 | pm_runtime_disable(dev); |
1390 | ||
1391 | err_pltfm_free: | |
1392 | sdhci_pltfm_free(pdev); | |
1393 | return ret; | |
1394 | } | |
1395 | ||
1396 | static int sdhci_omap_remove(struct platform_device *pdev) | |
1397 | { | |
1398 | struct device *dev = &pdev->dev; | |
1399 | struct sdhci_host *host = platform_get_drvdata(pdev); | |
1400 | ||
f433e8aa | 1401 | pm_runtime_get_sync(dev); |
7d326930 | 1402 | sdhci_remove_host(host, true); |
a1e97bd2 TL |
1403 | device_init_wakeup(dev, false); |
1404 | dev_pm_clear_wake_irq(dev); | |
f433e8aa | 1405 | pm_runtime_dont_use_autosuspend(dev); |
7d326930 | 1406 | pm_runtime_put_sync(dev); |
f433e8aa TL |
1407 | /* Ensure device gets disabled despite userspace sysfs config */ |
1408 | pm_runtime_force_suspend(dev); | |
7d326930 KVA |
1409 | sdhci_pltfm_free(pdev); |
1410 | ||
1411 | return 0; | |
1412 | } | |
f85a15c5 TL |
1413 | |
1414 | #ifdef CONFIG_PM | |
1415 | static void __maybe_unused sdhci_omap_context_save(struct sdhci_omap_host *omap_host) | |
ee0f3092 FA |
1416 | { |
1417 | omap_host->con = sdhci_omap_readl(omap_host, SDHCI_OMAP_CON); | |
1418 | omap_host->hctl = sdhci_omap_readl(omap_host, SDHCI_OMAP_HCTL); | |
d806e334 | 1419 | omap_host->sysctl = sdhci_omap_readl(omap_host, SDHCI_OMAP_SYSCTL); |
ee0f3092 | 1420 | omap_host->capa = sdhci_omap_readl(omap_host, SDHCI_OMAP_CAPA); |
d806e334 TL |
1421 | omap_host->ie = sdhci_omap_readl(omap_host, SDHCI_OMAP_IE); |
1422 | omap_host->ise = sdhci_omap_readl(omap_host, SDHCI_OMAP_ISE); | |
ee0f3092 FA |
1423 | } |
1424 | ||
d806e334 | 1425 | /* Order matters here, HCTL must be restored in two phases */ |
f85a15c5 | 1426 | static void __maybe_unused sdhci_omap_context_restore(struct sdhci_omap_host *omap_host) |
ee0f3092 | 1427 | { |
ee0f3092 FA |
1428 | sdhci_omap_writel(omap_host, SDHCI_OMAP_HCTL, omap_host->hctl); |
1429 | sdhci_omap_writel(omap_host, SDHCI_OMAP_CAPA, omap_host->capa); | |
d806e334 TL |
1430 | sdhci_omap_writel(omap_host, SDHCI_OMAP_HCTL, omap_host->hctl); |
1431 | ||
1432 | sdhci_omap_writel(omap_host, SDHCI_OMAP_SYSCTL, omap_host->sysctl); | |
1433 | sdhci_omap_writel(omap_host, SDHCI_OMAP_CON, omap_host->con); | |
1434 | sdhci_omap_writel(omap_host, SDHCI_OMAP_IE, omap_host->ie); | |
1435 | sdhci_omap_writel(omap_host, SDHCI_OMAP_ISE, omap_host->ise); | |
ee0f3092 FA |
1436 | } |
1437 | ||
f433e8aa | 1438 | static int __maybe_unused sdhci_omap_runtime_suspend(struct device *dev) |
ee0f3092 FA |
1439 | { |
1440 | struct sdhci_host *host = dev_get_drvdata(dev); | |
1441 | struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); | |
1442 | struct sdhci_omap_host *omap_host = sdhci_pltfm_priv(pltfm_host); | |
1443 | ||
f433e8aa | 1444 | sdhci_runtime_suspend_host(host); |
ee0f3092 FA |
1445 | |
1446 | sdhci_omap_context_save(omap_host); | |
1447 | ||
1448 | pinctrl_pm_select_idle_state(dev); | |
1449 | ||
ee0f3092 FA |
1450 | return 0; |
1451 | } | |
1452 | ||
f433e8aa | 1453 | static int __maybe_unused sdhci_omap_runtime_resume(struct device *dev) |
ee0f3092 FA |
1454 | { |
1455 | struct sdhci_host *host = dev_get_drvdata(dev); | |
1456 | struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); | |
1457 | struct sdhci_omap_host *omap_host = sdhci_pltfm_priv(pltfm_host); | |
1458 | ||
ee0f3092 FA |
1459 | pinctrl_pm_select_default_state(dev); |
1460 | ||
f433e8aa TL |
1461 | if (omap_host->con != -EINVAL) |
1462 | sdhci_omap_context_restore(omap_host); | |
ee0f3092 | 1463 | |
f433e8aa | 1464 | sdhci_runtime_resume_host(host, 0); |
ee0f3092 FA |
1465 | |
1466 | return 0; | |
1467 | } | |
1468 | #endif | |
f433e8aa TL |
1469 | |
1470 | static const struct dev_pm_ops sdhci_omap_dev_pm_ops = { | |
1471 | SET_RUNTIME_PM_OPS(sdhci_omap_runtime_suspend, | |
1472 | sdhci_omap_runtime_resume, NULL) | |
1473 | SET_SYSTEM_SLEEP_PM_OPS(pm_runtime_force_suspend, | |
1474 | pm_runtime_force_resume) | |
1475 | }; | |
7d326930 KVA |
1476 | |
1477 | static struct platform_driver sdhci_omap_driver = { | |
1478 | .probe = sdhci_omap_probe, | |
1479 | .remove = sdhci_omap_remove, | |
1480 | .driver = { | |
1481 | .name = "sdhci-omap", | |
a1a48919 | 1482 | .probe_type = PROBE_PREFER_ASYNCHRONOUS, |
ee0f3092 | 1483 | .pm = &sdhci_omap_dev_pm_ops, |
7d326930 KVA |
1484 | .of_match_table = omap_sdhci_match, |
1485 | }, | |
1486 | }; | |
1487 | ||
1488 | module_platform_driver(sdhci_omap_driver); | |
1489 | ||
1490 | MODULE_DESCRIPTION("SDHCI driver for OMAP SoCs"); | |
1491 | MODULE_AUTHOR("Texas Instruments Inc."); | |
1492 | MODULE_LICENSE("GPL v2"); | |
1493 | MODULE_ALIAS("platform:sdhci_omap"); |