arm64: dts: qcom: sm8550: add TRNG node
[linux-modified.git] / drivers / mmc / host / dw_mmc-exynos.c
1 // SPDX-License-Identifier: GPL-2.0-or-later
2 /*
3  * Exynos Specific Extensions for Synopsys DW Multimedia Card Interface driver
4  *
5  * Copyright (C) 2012, Samsung Electronics Co., Ltd.
6  */
7
8 #include <linux/module.h>
9 #include <linux/platform_device.h>
10 #include <linux/clk.h>
11 #include <linux/mmc/host.h>
12 #include <linux/mmc/mmc.h>
13 #include <linux/of.h>
14 #include <linux/of_gpio.h>
15 #include <linux/pm_runtime.h>
16 #include <linux/slab.h>
17
18 #include "dw_mmc.h"
19 #include "dw_mmc-pltfm.h"
20 #include "dw_mmc-exynos.h"
21
22 /* Variations in Exynos specific dw-mshc controller */
23 enum dw_mci_exynos_type {
24         DW_MCI_TYPE_EXYNOS4210,
25         DW_MCI_TYPE_EXYNOS4412,
26         DW_MCI_TYPE_EXYNOS5250,
27         DW_MCI_TYPE_EXYNOS5420,
28         DW_MCI_TYPE_EXYNOS5420_SMU,
29         DW_MCI_TYPE_EXYNOS7,
30         DW_MCI_TYPE_EXYNOS7_SMU,
31         DW_MCI_TYPE_ARTPEC8,
32 };
33
34 /* Exynos implementation specific driver private data */
35 struct dw_mci_exynos_priv_data {
36         enum dw_mci_exynos_type         ctrl_type;
37         u8                              ciu_div;
38         u32                             sdr_timing;
39         u32                             ddr_timing;
40         u32                             hs400_timing;
41         u32                             tuned_sample;
42         u32                             cur_speed;
43         u32                             dqs_delay;
44         u32                             saved_dqs_en;
45         u32                             saved_strobe_ctrl;
46 };
47
48 static struct dw_mci_exynos_compatible {
49         char                            *compatible;
50         enum dw_mci_exynos_type         ctrl_type;
51 } exynos_compat[] = {
52         {
53                 .compatible     = "samsung,exynos4210-dw-mshc",
54                 .ctrl_type      = DW_MCI_TYPE_EXYNOS4210,
55         }, {
56                 .compatible     = "samsung,exynos4412-dw-mshc",
57                 .ctrl_type      = DW_MCI_TYPE_EXYNOS4412,
58         }, {
59                 .compatible     = "samsung,exynos5250-dw-mshc",
60                 .ctrl_type      = DW_MCI_TYPE_EXYNOS5250,
61         }, {
62                 .compatible     = "samsung,exynos5420-dw-mshc",
63                 .ctrl_type      = DW_MCI_TYPE_EXYNOS5420,
64         }, {
65                 .compatible     = "samsung,exynos5420-dw-mshc-smu",
66                 .ctrl_type      = DW_MCI_TYPE_EXYNOS5420_SMU,
67         }, {
68                 .compatible     = "samsung,exynos7-dw-mshc",
69                 .ctrl_type      = DW_MCI_TYPE_EXYNOS7,
70         }, {
71                 .compatible     = "samsung,exynos7-dw-mshc-smu",
72                 .ctrl_type      = DW_MCI_TYPE_EXYNOS7_SMU,
73         }, {
74                 .compatible     = "axis,artpec8-dw-mshc",
75                 .ctrl_type      = DW_MCI_TYPE_ARTPEC8,
76         },
77 };
78
79 static inline u8 dw_mci_exynos_get_ciu_div(struct dw_mci *host)
80 {
81         struct dw_mci_exynos_priv_data *priv = host->priv;
82
83         if (priv->ctrl_type == DW_MCI_TYPE_EXYNOS4412)
84                 return EXYNOS4412_FIXED_CIU_CLK_DIV;
85         else if (priv->ctrl_type == DW_MCI_TYPE_EXYNOS4210)
86                 return EXYNOS4210_FIXED_CIU_CLK_DIV;
87         else if (priv->ctrl_type == DW_MCI_TYPE_EXYNOS7 ||
88                         priv->ctrl_type == DW_MCI_TYPE_EXYNOS7_SMU ||
89                         priv->ctrl_type == DW_MCI_TYPE_ARTPEC8)
90                 return SDMMC_CLKSEL_GET_DIV(mci_readl(host, CLKSEL64)) + 1;
91         else
92                 return SDMMC_CLKSEL_GET_DIV(mci_readl(host, CLKSEL)) + 1;
93 }
94
95 static void dw_mci_exynos_config_smu(struct dw_mci *host)
96 {
97         struct dw_mci_exynos_priv_data *priv = host->priv;
98
99         /*
100          * If Exynos is provided the Security management,
101          * set for non-ecryption mode at this time.
102          */
103         if (priv->ctrl_type == DW_MCI_TYPE_EXYNOS5420_SMU ||
104                 priv->ctrl_type == DW_MCI_TYPE_EXYNOS7_SMU) {
105                 mci_writel(host, MPSBEGIN0, 0);
106                 mci_writel(host, MPSEND0, SDMMC_ENDING_SEC_NR_MAX);
107                 mci_writel(host, MPSCTRL0, SDMMC_MPSCTRL_SECURE_WRITE_BIT |
108                            SDMMC_MPSCTRL_NON_SECURE_READ_BIT |
109                            SDMMC_MPSCTRL_VALID |
110                            SDMMC_MPSCTRL_NON_SECURE_WRITE_BIT);
111         }
112 }
113
114 static int dw_mci_exynos_priv_init(struct dw_mci *host)
115 {
116         struct dw_mci_exynos_priv_data *priv = host->priv;
117
118         dw_mci_exynos_config_smu(host);
119
120         if (priv->ctrl_type >= DW_MCI_TYPE_EXYNOS5420) {
121                 priv->saved_strobe_ctrl = mci_readl(host, HS400_DLINE_CTRL);
122                 priv->saved_dqs_en = mci_readl(host, HS400_DQS_EN);
123                 priv->saved_dqs_en |= AXI_NON_BLOCKING_WR;
124                 mci_writel(host, HS400_DQS_EN, priv->saved_dqs_en);
125                 if (!priv->dqs_delay)
126                         priv->dqs_delay =
127                                 DQS_CTRL_GET_RD_DELAY(priv->saved_strobe_ctrl);
128         }
129
130         if (priv->ctrl_type == DW_MCI_TYPE_ARTPEC8) {
131                 /* Quirk needed for the ARTPEC-8 SoC */
132                 host->quirks |= DW_MMC_QUIRK_EXTENDED_TMOUT;
133         }
134
135         host->bus_hz /= (priv->ciu_div + 1);
136
137         return 0;
138 }
139
140 static void dw_mci_exynos_set_clksel_timing(struct dw_mci *host, u32 timing)
141 {
142         struct dw_mci_exynos_priv_data *priv = host->priv;
143         u32 clksel;
144
145         if (priv->ctrl_type == DW_MCI_TYPE_EXYNOS7 ||
146                 priv->ctrl_type == DW_MCI_TYPE_EXYNOS7_SMU ||
147                 priv->ctrl_type == DW_MCI_TYPE_ARTPEC8)
148                 clksel = mci_readl(host, CLKSEL64);
149         else
150                 clksel = mci_readl(host, CLKSEL);
151
152         clksel = (clksel & ~SDMMC_CLKSEL_TIMING_MASK) | timing;
153
154         if (priv->ctrl_type == DW_MCI_TYPE_EXYNOS7 ||
155                 priv->ctrl_type == DW_MCI_TYPE_EXYNOS7_SMU ||
156                 priv->ctrl_type == DW_MCI_TYPE_ARTPEC8)
157                 mci_writel(host, CLKSEL64, clksel);
158         else
159                 mci_writel(host, CLKSEL, clksel);
160
161         /*
162          * Exynos4412 and Exynos5250 extends the use of CMD register with the
163          * use of bit 29 (which is reserved on standard MSHC controllers) for
164          * optionally bypassing the HOLD register for command and data. The
165          * HOLD register should be bypassed in case there is no phase shift
166          * applied on CMD/DATA that is sent to the card.
167          */
168         if (!SDMMC_CLKSEL_GET_DRV_WD3(clksel) && host->slot)
169                 set_bit(DW_MMC_CARD_NO_USE_HOLD, &host->slot->flags);
170 }
171
172 #ifdef CONFIG_PM
173 static int dw_mci_exynos_runtime_resume(struct device *dev)
174 {
175         struct dw_mci *host = dev_get_drvdata(dev);
176         int ret;
177
178         ret = dw_mci_runtime_resume(dev);
179         if (ret)
180                 return ret;
181
182         dw_mci_exynos_config_smu(host);
183
184         return ret;
185 }
186 #endif /* CONFIG_PM */
187
188 #ifdef CONFIG_PM_SLEEP
189 /**
190  * dw_mci_exynos_suspend_noirq - Exynos-specific suspend code
191  * @dev: Device to suspend (this device)
192  *
193  * This ensures that device will be in runtime active state in
194  * dw_mci_exynos_resume_noirq after calling pm_runtime_force_resume()
195  */
196 static int dw_mci_exynos_suspend_noirq(struct device *dev)
197 {
198         pm_runtime_get_noresume(dev);
199         return pm_runtime_force_suspend(dev);
200 }
201
202 /**
203  * dw_mci_exynos_resume_noirq - Exynos-specific resume code
204  * @dev: Device to resume (this device)
205  *
206  * On exynos5420 there is a silicon errata that will sometimes leave the
207  * WAKEUP_INT bit in the CLKSEL register asserted.  This bit is 1 to indicate
208  * that it fired and we can clear it by writing a 1 back.  Clear it to prevent
209  * interrupts from going off constantly.
210  *
211  * We run this code on all exynos variants because it doesn't hurt.
212  */
213 static int dw_mci_exynos_resume_noirq(struct device *dev)
214 {
215         struct dw_mci *host = dev_get_drvdata(dev);
216         struct dw_mci_exynos_priv_data *priv = host->priv;
217         u32 clksel;
218         int ret;
219
220         ret = pm_runtime_force_resume(dev);
221         if (ret)
222                 return ret;
223
224         if (priv->ctrl_type == DW_MCI_TYPE_EXYNOS7 ||
225                 priv->ctrl_type == DW_MCI_TYPE_EXYNOS7_SMU ||
226                 priv->ctrl_type == DW_MCI_TYPE_ARTPEC8)
227                 clksel = mci_readl(host, CLKSEL64);
228         else
229                 clksel = mci_readl(host, CLKSEL);
230
231         if (clksel & SDMMC_CLKSEL_WAKEUP_INT) {
232                 if (priv->ctrl_type == DW_MCI_TYPE_EXYNOS7 ||
233                         priv->ctrl_type == DW_MCI_TYPE_EXYNOS7_SMU ||
234                         priv->ctrl_type == DW_MCI_TYPE_ARTPEC8)
235                         mci_writel(host, CLKSEL64, clksel);
236                 else
237                         mci_writel(host, CLKSEL, clksel);
238         }
239
240         pm_runtime_put(dev);
241
242         return 0;
243 }
244 #endif /* CONFIG_PM_SLEEP */
245
246 static void dw_mci_exynos_config_hs400(struct dw_mci *host, u32 timing)
247 {
248         struct dw_mci_exynos_priv_data *priv = host->priv;
249         u32 dqs, strobe;
250
251         /*
252          * Not supported to configure register
253          * related to HS400
254          */
255         if ((priv->ctrl_type < DW_MCI_TYPE_EXYNOS5420) ||
256                 (priv->ctrl_type == DW_MCI_TYPE_ARTPEC8)) {
257                 if (timing == MMC_TIMING_MMC_HS400)
258                         dev_warn(host->dev,
259                                  "cannot configure HS400, unsupported chipset\n");
260                 return;
261         }
262
263         dqs = priv->saved_dqs_en;
264         strobe = priv->saved_strobe_ctrl;
265
266         if (timing == MMC_TIMING_MMC_HS400) {
267                 dqs |= DATA_STROBE_EN;
268                 strobe = DQS_CTRL_RD_DELAY(strobe, priv->dqs_delay);
269         } else if (timing == MMC_TIMING_UHS_SDR104) {
270                 dqs &= 0xffffff00;
271         } else {
272                 dqs &= ~DATA_STROBE_EN;
273         }
274
275         mci_writel(host, HS400_DQS_EN, dqs);
276         mci_writel(host, HS400_DLINE_CTRL, strobe);
277 }
278
279 static void dw_mci_exynos_adjust_clock(struct dw_mci *host, unsigned int wanted)
280 {
281         struct dw_mci_exynos_priv_data *priv = host->priv;
282         unsigned long actual;
283         u8 div;
284         int ret;
285         /*
286          * Don't care if wanted clock is zero or
287          * ciu clock is unavailable
288          */
289         if (!wanted || IS_ERR(host->ciu_clk))
290                 return;
291
292         /* Guaranteed minimum frequency for cclkin */
293         if (wanted < EXYNOS_CCLKIN_MIN)
294                 wanted = EXYNOS_CCLKIN_MIN;
295
296         if (wanted == priv->cur_speed)
297                 return;
298
299         div = dw_mci_exynos_get_ciu_div(host);
300         ret = clk_set_rate(host->ciu_clk, wanted * div);
301         if (ret)
302                 dev_warn(host->dev,
303                         "failed to set clk-rate %u error: %d\n",
304                         wanted * div, ret);
305         actual = clk_get_rate(host->ciu_clk);
306         host->bus_hz = actual / div;
307         priv->cur_speed = wanted;
308         host->current_speed = 0;
309 }
310
311 static void dw_mci_exynos_set_ios(struct dw_mci *host, struct mmc_ios *ios)
312 {
313         struct dw_mci_exynos_priv_data *priv = host->priv;
314         unsigned int wanted = ios->clock;
315         u32 timing = ios->timing, clksel;
316
317         switch (timing) {
318         case MMC_TIMING_MMC_HS400:
319                 /* Update tuned sample timing */
320                 clksel = SDMMC_CLKSEL_UP_SAMPLE(
321                                 priv->hs400_timing, priv->tuned_sample);
322                 wanted <<= 1;
323                 break;
324         case MMC_TIMING_MMC_DDR52:
325                 clksel = priv->ddr_timing;
326                 /* Should be double rate for DDR mode */
327                 if (ios->bus_width == MMC_BUS_WIDTH_8)
328                         wanted <<= 1;
329                 break;
330         case MMC_TIMING_UHS_SDR104:
331         case MMC_TIMING_UHS_SDR50:
332                 clksel = (priv->sdr_timing & 0xfff8ffff) |
333                         (priv->ciu_div << 16);
334                 break;
335         case MMC_TIMING_UHS_DDR50:
336                 clksel = (priv->ddr_timing & 0xfff8ffff) |
337                         (priv->ciu_div << 16);
338                 break;
339         default:
340                 clksel = priv->sdr_timing;
341         }
342
343         /* Set clock timing for the requested speed mode*/
344         dw_mci_exynos_set_clksel_timing(host, clksel);
345
346         /* Configure setting for HS400 */
347         dw_mci_exynos_config_hs400(host, timing);
348
349         /* Configure clock rate */
350         dw_mci_exynos_adjust_clock(host, wanted);
351 }
352
353 static int dw_mci_exynos_parse_dt(struct dw_mci *host)
354 {
355         struct dw_mci_exynos_priv_data *priv;
356         struct device_node *np = host->dev->of_node;
357         u32 timing[2];
358         u32 div = 0;
359         int idx;
360         int ret;
361
362         priv = devm_kzalloc(host->dev, sizeof(*priv), GFP_KERNEL);
363         if (!priv)
364                 return -ENOMEM;
365
366         for (idx = 0; idx < ARRAY_SIZE(exynos_compat); idx++) {
367                 if (of_device_is_compatible(np, exynos_compat[idx].compatible))
368                         priv->ctrl_type = exynos_compat[idx].ctrl_type;
369         }
370
371         if (priv->ctrl_type == DW_MCI_TYPE_EXYNOS4412)
372                 priv->ciu_div = EXYNOS4412_FIXED_CIU_CLK_DIV - 1;
373         else if (priv->ctrl_type == DW_MCI_TYPE_EXYNOS4210)
374                 priv->ciu_div = EXYNOS4210_FIXED_CIU_CLK_DIV - 1;
375         else {
376                 of_property_read_u32(np, "samsung,dw-mshc-ciu-div", &div);
377                 priv->ciu_div = div;
378         }
379
380         ret = of_property_read_u32_array(np,
381                         "samsung,dw-mshc-sdr-timing", timing, 2);
382         if (ret)
383                 return ret;
384
385         priv->sdr_timing = SDMMC_CLKSEL_TIMING(timing[0], timing[1], div);
386
387         ret = of_property_read_u32_array(np,
388                         "samsung,dw-mshc-ddr-timing", timing, 2);
389         if (ret)
390                 return ret;
391
392         priv->ddr_timing = SDMMC_CLKSEL_TIMING(timing[0], timing[1], div);
393
394         ret = of_property_read_u32_array(np,
395                         "samsung,dw-mshc-hs400-timing", timing, 2);
396         if (!ret && of_property_read_u32(np,
397                                 "samsung,read-strobe-delay", &priv->dqs_delay))
398                 dev_dbg(host->dev,
399                         "read-strobe-delay is not found, assuming usage of default value\n");
400
401         priv->hs400_timing = SDMMC_CLKSEL_TIMING(timing[0], timing[1],
402                                                 HS400_FIXED_CIU_CLK_DIV);
403         host->priv = priv;
404         return 0;
405 }
406
407 static inline u8 dw_mci_exynos_get_clksmpl(struct dw_mci *host)
408 {
409         struct dw_mci_exynos_priv_data *priv = host->priv;
410
411         if (priv->ctrl_type == DW_MCI_TYPE_EXYNOS7 ||
412                 priv->ctrl_type == DW_MCI_TYPE_EXYNOS7_SMU ||
413                 priv->ctrl_type == DW_MCI_TYPE_ARTPEC8)
414                 return SDMMC_CLKSEL_CCLK_SAMPLE(mci_readl(host, CLKSEL64));
415         else
416                 return SDMMC_CLKSEL_CCLK_SAMPLE(mci_readl(host, CLKSEL));
417 }
418
419 static inline void dw_mci_exynos_set_clksmpl(struct dw_mci *host, u8 sample)
420 {
421         u32 clksel;
422         struct dw_mci_exynos_priv_data *priv = host->priv;
423
424         if (priv->ctrl_type == DW_MCI_TYPE_EXYNOS7 ||
425                 priv->ctrl_type == DW_MCI_TYPE_EXYNOS7_SMU ||
426                 priv->ctrl_type == DW_MCI_TYPE_ARTPEC8)
427                 clksel = mci_readl(host, CLKSEL64);
428         else
429                 clksel = mci_readl(host, CLKSEL);
430         clksel = SDMMC_CLKSEL_UP_SAMPLE(clksel, sample);
431         if (priv->ctrl_type == DW_MCI_TYPE_EXYNOS7 ||
432                 priv->ctrl_type == DW_MCI_TYPE_EXYNOS7_SMU ||
433                 priv->ctrl_type == DW_MCI_TYPE_ARTPEC8)
434                 mci_writel(host, CLKSEL64, clksel);
435         else
436                 mci_writel(host, CLKSEL, clksel);
437 }
438
439 static inline u8 dw_mci_exynos_move_next_clksmpl(struct dw_mci *host)
440 {
441         struct dw_mci_exynos_priv_data *priv = host->priv;
442         u32 clksel;
443         u8 sample;
444
445         if (priv->ctrl_type == DW_MCI_TYPE_EXYNOS7 ||
446                 priv->ctrl_type == DW_MCI_TYPE_EXYNOS7_SMU ||
447                 priv->ctrl_type == DW_MCI_TYPE_ARTPEC8)
448                 clksel = mci_readl(host, CLKSEL64);
449         else
450                 clksel = mci_readl(host, CLKSEL);
451
452         sample = (clksel + 1) & 0x7;
453         clksel = SDMMC_CLKSEL_UP_SAMPLE(clksel, sample);
454
455         if (priv->ctrl_type == DW_MCI_TYPE_EXYNOS7 ||
456                 priv->ctrl_type == DW_MCI_TYPE_EXYNOS7_SMU ||
457                 priv->ctrl_type == DW_MCI_TYPE_ARTPEC8)
458                 mci_writel(host, CLKSEL64, clksel);
459         else
460                 mci_writel(host, CLKSEL, clksel);
461
462         return sample;
463 }
464
465 static s8 dw_mci_exynos_get_best_clksmpl(u8 candidates)
466 {
467         const u8 iter = 8;
468         u8 __c;
469         s8 i, loc = -1;
470
471         for (i = 0; i < iter; i++) {
472                 __c = ror8(candidates, i);
473                 if ((__c & 0xc7) == 0xc7) {
474                         loc = i;
475                         goto out;
476                 }
477         }
478
479         for (i = 0; i < iter; i++) {
480                 __c = ror8(candidates, i);
481                 if ((__c & 0x83) == 0x83) {
482                         loc = i;
483                         goto out;
484                 }
485         }
486
487         /*
488          * If there is no cadiates value, then it needs to return -EIO.
489          * If there are candidates values and don't find bset clk sample value,
490          * then use a first candidates clock sample value.
491          */
492         for (i = 0; i < iter; i++) {
493                 __c = ror8(candidates, i);
494                 if ((__c & 0x1) == 0x1) {
495                         loc = i;
496                         goto out;
497                 }
498         }
499 out:
500         return loc;
501 }
502
503 static int dw_mci_exynos_execute_tuning(struct dw_mci_slot *slot, u32 opcode)
504 {
505         struct dw_mci *host = slot->host;
506         struct dw_mci_exynos_priv_data *priv = host->priv;
507         struct mmc_host *mmc = slot->mmc;
508         u8 start_smpl, smpl, candidates = 0;
509         s8 found;
510         int ret = 0;
511
512         start_smpl = dw_mci_exynos_get_clksmpl(host);
513
514         do {
515                 mci_writel(host, TMOUT, ~0);
516                 smpl = dw_mci_exynos_move_next_clksmpl(host);
517
518                 if (!mmc_send_tuning(mmc, opcode, NULL))
519                         candidates |= (1 << smpl);
520
521         } while (start_smpl != smpl);
522
523         found = dw_mci_exynos_get_best_clksmpl(candidates);
524         if (found >= 0) {
525                 dw_mci_exynos_set_clksmpl(host, found);
526                 priv->tuned_sample = found;
527         } else {
528                 ret = -EIO;
529                 dev_warn(&mmc->class_dev,
530                         "There is no candidates value about clksmpl!\n");
531         }
532
533         return ret;
534 }
535
536 static int dw_mci_exynos_prepare_hs400_tuning(struct dw_mci *host,
537                                         struct mmc_ios *ios)
538 {
539         struct dw_mci_exynos_priv_data *priv = host->priv;
540
541         dw_mci_exynos_set_clksel_timing(host, priv->hs400_timing);
542         dw_mci_exynos_adjust_clock(host, (ios->clock) << 1);
543
544         return 0;
545 }
546
547 static void dw_mci_exynos_set_data_timeout(struct dw_mci *host,
548                                            unsigned int timeout_ns)
549 {
550         u32 clk_div, tmout;
551         u64 tmp;
552         unsigned int tmp2;
553
554         clk_div = (mci_readl(host, CLKDIV) & 0xFF) * 2;
555         if (clk_div == 0)
556                 clk_div = 1;
557
558         tmp = DIV_ROUND_UP_ULL((u64)timeout_ns * host->bus_hz, NSEC_PER_SEC);
559         tmp = DIV_ROUND_UP_ULL(tmp, clk_div);
560
561         /* TMOUT[7:0] (RESPONSE_TIMEOUT) */
562         tmout = 0xFF; /* Set maximum */
563
564         /*
565          * Extended HW timer (max = 0x6FFFFF2):
566          * ((TMOUT[10:8] - 1) * 0xFFFFFF + TMOUT[31:11] * 8)
567          */
568         if (!tmp || tmp > 0x6FFFFF2)
569                 tmout |= (0xFFFFFF << 8);
570         else {
571                 /* TMOUT[10:8] */
572                 tmp2 = (((unsigned int)tmp / 0xFFFFFF) + 1) & 0x7;
573                 tmout |= tmp2 << 8;
574
575                 /* TMOUT[31:11] */
576                 tmp = tmp - ((tmp2 - 1) * 0xFFFFFF);
577                 tmout |= (tmp & 0xFFFFF8) << 8;
578         }
579
580         mci_writel(host, TMOUT, tmout);
581         dev_dbg(host->dev, "timeout_ns: %u => TMOUT[31:8]: %#08x",
582                 timeout_ns, tmout >> 8);
583 }
584
585 static u32 dw_mci_exynos_get_drto_clks(struct dw_mci *host)
586 {
587         u32 drto_clks;
588
589         drto_clks = mci_readl(host, TMOUT) >> 8;
590
591         return (((drto_clks & 0x7) - 1) * 0xFFFFFF) + ((drto_clks & 0xFFFFF8));
592 }
593
594 /* Common capabilities of Exynos4/Exynos5 SoC */
595 static unsigned long exynos_dwmmc_caps[4] = {
596         MMC_CAP_1_8V_DDR | MMC_CAP_8_BIT_DATA,
597         0,
598         0,
599         0,
600 };
601
602 static const struct dw_mci_drv_data exynos_drv_data = {
603         .caps                   = exynos_dwmmc_caps,
604         .num_caps               = ARRAY_SIZE(exynos_dwmmc_caps),
605         .common_caps            = MMC_CAP_CMD23,
606         .init                   = dw_mci_exynos_priv_init,
607         .set_ios                = dw_mci_exynos_set_ios,
608         .parse_dt               = dw_mci_exynos_parse_dt,
609         .execute_tuning         = dw_mci_exynos_execute_tuning,
610         .prepare_hs400_tuning   = dw_mci_exynos_prepare_hs400_tuning,
611 };
612
613 static const struct dw_mci_drv_data artpec_drv_data = {
614         .common_caps            = MMC_CAP_CMD23,
615         .init                   = dw_mci_exynos_priv_init,
616         .set_ios                = dw_mci_exynos_set_ios,
617         .parse_dt               = dw_mci_exynos_parse_dt,
618         .execute_tuning         = dw_mci_exynos_execute_tuning,
619         .set_data_timeout               = dw_mci_exynos_set_data_timeout,
620         .get_drto_clks          = dw_mci_exynos_get_drto_clks,
621 };
622
623 static const struct of_device_id dw_mci_exynos_match[] = {
624         { .compatible = "samsung,exynos4412-dw-mshc",
625                         .data = &exynos_drv_data, },
626         { .compatible = "samsung,exynos5250-dw-mshc",
627                         .data = &exynos_drv_data, },
628         { .compatible = "samsung,exynos5420-dw-mshc",
629                         .data = &exynos_drv_data, },
630         { .compatible = "samsung,exynos5420-dw-mshc-smu",
631                         .data = &exynos_drv_data, },
632         { .compatible = "samsung,exynos7-dw-mshc",
633                         .data = &exynos_drv_data, },
634         { .compatible = "samsung,exynos7-dw-mshc-smu",
635                         .data = &exynos_drv_data, },
636         { .compatible = "axis,artpec8-dw-mshc",
637                         .data = &artpec_drv_data, },
638         {},
639 };
640 MODULE_DEVICE_TABLE(of, dw_mci_exynos_match);
641
642 static int dw_mci_exynos_probe(struct platform_device *pdev)
643 {
644         const struct dw_mci_drv_data *drv_data;
645         const struct of_device_id *match;
646         int ret;
647
648         match = of_match_node(dw_mci_exynos_match, pdev->dev.of_node);
649         drv_data = match->data;
650
651         pm_runtime_get_noresume(&pdev->dev);
652         pm_runtime_set_active(&pdev->dev);
653         pm_runtime_enable(&pdev->dev);
654
655         ret = dw_mci_pltfm_register(pdev, drv_data);
656         if (ret) {
657                 pm_runtime_disable(&pdev->dev);
658                 pm_runtime_set_suspended(&pdev->dev);
659                 pm_runtime_put_noidle(&pdev->dev);
660
661                 return ret;
662         }
663
664         return 0;
665 }
666
667 static void dw_mci_exynos_remove(struct platform_device *pdev)
668 {
669         pm_runtime_disable(&pdev->dev);
670         pm_runtime_set_suspended(&pdev->dev);
671         pm_runtime_put_noidle(&pdev->dev);
672
673         dw_mci_pltfm_remove(pdev);
674 }
675
676 static const struct dev_pm_ops dw_mci_exynos_pmops = {
677         SET_NOIRQ_SYSTEM_SLEEP_PM_OPS(dw_mci_exynos_suspend_noirq,
678                                       dw_mci_exynos_resume_noirq)
679         SET_RUNTIME_PM_OPS(dw_mci_runtime_suspend,
680                            dw_mci_exynos_runtime_resume,
681                            NULL)
682 };
683
684 static struct platform_driver dw_mci_exynos_pltfm_driver = {
685         .probe          = dw_mci_exynos_probe,
686         .remove_new     = dw_mci_exynos_remove,
687         .driver         = {
688                 .name           = "dwmmc_exynos",
689                 .probe_type     = PROBE_PREFER_ASYNCHRONOUS,
690                 .of_match_table = dw_mci_exynos_match,
691                 .pm             = &dw_mci_exynos_pmops,
692         },
693 };
694
695 module_platform_driver(dw_mci_exynos_pltfm_driver);
696
697 MODULE_DESCRIPTION("Samsung Specific DW-MSHC Driver Extension");
698 MODULE_AUTHOR("Thomas Abraham <thomas.ab@samsung.com");
699 MODULE_LICENSE("GPL v2");
700 MODULE_ALIAS("platform:dwmmc_exynos");