GNU Linux-libre 5.10.153-gnu1
[releases.git] / drivers / mmc / host / sdhci-xenon.c
1 // SPDX-License-Identifier: GPL-2.0-only
2 /*
3  * Driver for Marvell Xenon SDHC as a platform device
4  *
5  * Copyright (C) 2016 Marvell, All Rights Reserved.
6  *
7  * Author:      Hu Ziji <huziji@marvell.com>
8  * Date:        2016-8-24
9  *
10  * Inspired by Jisheng Zhang <jszhang@marvell.com>
11  * Special thanks to Video BG4 project team.
12  */
13
14 #include <linux/delay.h>
15 #include <linux/ktime.h>
16 #include <linux/module.h>
17 #include <linux/of.h>
18 #include <linux/pm.h>
19 #include <linux/pm_runtime.h>
20
21 #include "sdhci-pltfm.h"
22 #include "sdhci-xenon.h"
23
24 static int xenon_enable_internal_clk(struct sdhci_host *host)
25 {
26         u32 reg;
27         ktime_t timeout;
28
29         reg = sdhci_readl(host, SDHCI_CLOCK_CONTROL);
30         reg |= SDHCI_CLOCK_INT_EN;
31         sdhci_writel(host, reg, SDHCI_CLOCK_CONTROL);
32         /* Wait max 20 ms */
33         timeout = ktime_add_ms(ktime_get(), 20);
34         while (1) {
35                 bool timedout = ktime_after(ktime_get(), timeout);
36
37                 reg = sdhci_readw(host, SDHCI_CLOCK_CONTROL);
38                 if (reg & SDHCI_CLOCK_INT_STABLE)
39                         break;
40                 if (timedout) {
41                         dev_err(mmc_dev(host->mmc), "Internal clock never stabilised.\n");
42                         return -ETIMEDOUT;
43                 }
44                 usleep_range(900, 1100);
45         }
46
47         return 0;
48 }
49
50 /* Set SDCLK-off-while-idle */
51 static void xenon_set_sdclk_off_idle(struct sdhci_host *host,
52                                      unsigned char sdhc_id, bool enable)
53 {
54         u32 reg;
55         u32 mask;
56
57         reg = sdhci_readl(host, XENON_SYS_OP_CTRL);
58         /* Get the bit shift basing on the SDHC index */
59         mask = (0x1 << (XENON_SDCLK_IDLEOFF_ENABLE_SHIFT + sdhc_id));
60         if (enable)
61                 reg |= mask;
62         else
63                 reg &= ~mask;
64
65         sdhci_writel(host, reg, XENON_SYS_OP_CTRL);
66 }
67
68 /* Enable/Disable the Auto Clock Gating function */
69 static void xenon_set_acg(struct sdhci_host *host, bool enable)
70 {
71         u32 reg;
72
73         reg = sdhci_readl(host, XENON_SYS_OP_CTRL);
74         if (enable)
75                 reg &= ~XENON_AUTO_CLKGATE_DISABLE_MASK;
76         else
77                 reg |= XENON_AUTO_CLKGATE_DISABLE_MASK;
78         sdhci_writel(host, reg, XENON_SYS_OP_CTRL);
79 }
80
81 /* Enable this SDHC */
82 static void xenon_enable_sdhc(struct sdhci_host *host,
83                               unsigned char sdhc_id)
84 {
85         u32 reg;
86
87         reg = sdhci_readl(host, XENON_SYS_OP_CTRL);
88         reg |= (BIT(sdhc_id) << XENON_SLOT_ENABLE_SHIFT);
89         sdhci_writel(host, reg, XENON_SYS_OP_CTRL);
90
91         host->mmc->caps |= MMC_CAP_WAIT_WHILE_BUSY;
92         /*
93          * Force to clear BUS_TEST to
94          * skip bus_test_pre and bus_test_post
95          */
96         host->mmc->caps &= ~MMC_CAP_BUS_WIDTH_TEST;
97 }
98
99 /* Disable this SDHC */
100 static void xenon_disable_sdhc(struct sdhci_host *host,
101                                unsigned char sdhc_id)
102 {
103         u32 reg;
104
105         reg = sdhci_readl(host, XENON_SYS_OP_CTRL);
106         reg &= ~(BIT(sdhc_id) << XENON_SLOT_ENABLE_SHIFT);
107         sdhci_writel(host, reg, XENON_SYS_OP_CTRL);
108 }
109
110 /* Enable Parallel Transfer Mode */
111 static void xenon_enable_sdhc_parallel_tran(struct sdhci_host *host,
112                                             unsigned char sdhc_id)
113 {
114         u32 reg;
115
116         reg = sdhci_readl(host, XENON_SYS_EXT_OP_CTRL);
117         reg |= BIT(sdhc_id);
118         sdhci_writel(host, reg, XENON_SYS_EXT_OP_CTRL);
119 }
120
121 /* Mask command conflict error */
122 static void xenon_mask_cmd_conflict_err(struct sdhci_host *host)
123 {
124         u32  reg;
125
126         reg = sdhci_readl(host, XENON_SYS_EXT_OP_CTRL);
127         reg |= XENON_MASK_CMD_CONFLICT_ERR;
128         sdhci_writel(host, reg, XENON_SYS_EXT_OP_CTRL);
129 }
130
131 static void xenon_retune_setup(struct sdhci_host *host)
132 {
133         struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
134         struct xenon_priv *priv = sdhci_pltfm_priv(pltfm_host);
135         u32 reg;
136
137         /* Disable the Re-Tuning Request functionality */
138         reg = sdhci_readl(host, XENON_SLOT_RETUNING_REQ_CTRL);
139         reg &= ~XENON_RETUNING_COMPATIBLE;
140         sdhci_writel(host, reg, XENON_SLOT_RETUNING_REQ_CTRL);
141
142         /* Disable the Re-tuning Interrupt */
143         reg = sdhci_readl(host, SDHCI_SIGNAL_ENABLE);
144         reg &= ~SDHCI_INT_RETUNE;
145         sdhci_writel(host, reg, SDHCI_SIGNAL_ENABLE);
146         reg = sdhci_readl(host, SDHCI_INT_ENABLE);
147         reg &= ~SDHCI_INT_RETUNE;
148         sdhci_writel(host, reg, SDHCI_INT_ENABLE);
149
150         /* Force to use Tuning Mode 1 */
151         host->tuning_mode = SDHCI_TUNING_MODE_1;
152         /* Set re-tuning period */
153         host->tuning_count = 1 << (priv->tuning_count - 1);
154 }
155
156 /*
157  * Operations inside struct sdhci_ops
158  */
159 /* Recover the Register Setting cleared during SOFTWARE_RESET_ALL */
160 static void xenon_reset_exit(struct sdhci_host *host,
161                              unsigned char sdhc_id, u8 mask)
162 {
163         /* Only SOFTWARE RESET ALL will clear the register setting */
164         if (!(mask & SDHCI_RESET_ALL))
165                 return;
166
167         /* Disable tuning request and auto-retuning again */
168         xenon_retune_setup(host);
169
170         /*
171          * The ACG should be turned off at the early init time, in order
172          * to solve a possible issues with the 1.8V regulator stabilization.
173          * The feature is enabled in later stage.
174          */
175         xenon_set_acg(host, false);
176
177         xenon_set_sdclk_off_idle(host, sdhc_id, false);
178
179         xenon_mask_cmd_conflict_err(host);
180 }
181
182 static void xenon_reset(struct sdhci_host *host, u8 mask)
183 {
184         struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
185         struct xenon_priv *priv = sdhci_pltfm_priv(pltfm_host);
186
187         sdhci_reset(host, mask);
188         xenon_reset_exit(host, priv->sdhc_id, mask);
189 }
190
191 /*
192  * Xenon defines different values for HS200 and HS400
193  * in Host_Control_2
194  */
195 static void xenon_set_uhs_signaling(struct sdhci_host *host,
196                                     unsigned int timing)
197 {
198         u16 ctrl_2;
199
200         ctrl_2 = sdhci_readw(host, SDHCI_HOST_CONTROL2);
201         /* Select Bus Speed Mode for host */
202         ctrl_2 &= ~SDHCI_CTRL_UHS_MASK;
203         if (timing == MMC_TIMING_MMC_HS200)
204                 ctrl_2 |= XENON_CTRL_HS200;
205         else if (timing == MMC_TIMING_UHS_SDR104)
206                 ctrl_2 |= SDHCI_CTRL_UHS_SDR104;
207         else if (timing == MMC_TIMING_UHS_SDR12)
208                 ctrl_2 |= SDHCI_CTRL_UHS_SDR12;
209         else if (timing == MMC_TIMING_UHS_SDR25)
210                 ctrl_2 |= SDHCI_CTRL_UHS_SDR25;
211         else if (timing == MMC_TIMING_UHS_SDR50)
212                 ctrl_2 |= SDHCI_CTRL_UHS_SDR50;
213         else if ((timing == MMC_TIMING_UHS_DDR50) ||
214                  (timing == MMC_TIMING_MMC_DDR52))
215                 ctrl_2 |= SDHCI_CTRL_UHS_DDR50;
216         else if (timing == MMC_TIMING_MMC_HS400)
217                 ctrl_2 |= XENON_CTRL_HS400;
218         sdhci_writew(host, ctrl_2, SDHCI_HOST_CONTROL2);
219 }
220
221 static void xenon_set_power(struct sdhci_host *host, unsigned char mode,
222                 unsigned short vdd)
223 {
224         struct mmc_host *mmc = host->mmc;
225         u8 pwr = host->pwr;
226
227         sdhci_set_power_noreg(host, mode, vdd);
228
229         if (host->pwr == pwr)
230                 return;
231
232         if (host->pwr == 0)
233                 vdd = 0;
234
235         if (!IS_ERR(mmc->supply.vmmc))
236                 mmc_regulator_set_ocr(mmc, mmc->supply.vmmc, vdd);
237 }
238
239 static void xenon_voltage_switch(struct sdhci_host *host)
240 {
241         /* Wait for 5ms after set 1.8V signal enable bit */
242         usleep_range(5000, 5500);
243 }
244
245 static const struct sdhci_ops sdhci_xenon_ops = {
246         .voltage_switch         = xenon_voltage_switch,
247         .set_clock              = sdhci_set_clock,
248         .set_power              = xenon_set_power,
249         .set_bus_width          = sdhci_set_bus_width,
250         .reset                  = xenon_reset,
251         .set_uhs_signaling      = xenon_set_uhs_signaling,
252         .get_max_clock          = sdhci_pltfm_clk_get_max_clock,
253 };
254
255 static const struct sdhci_pltfm_data sdhci_xenon_pdata = {
256         .ops = &sdhci_xenon_ops,
257         .quirks = SDHCI_QUIRK_NO_ENDATTR_IN_NOPDESC |
258                   SDHCI_QUIRK_NO_SIMULT_VDD_AND_POWER |
259                   SDHCI_QUIRK_CAP_CLOCK_BASE_BROKEN,
260 };
261
262 /*
263  * Xenon Specific Operations in mmc_host_ops
264  */
265 static void xenon_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
266 {
267         struct sdhci_host *host = mmc_priv(mmc);
268         struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
269         struct xenon_priv *priv = sdhci_pltfm_priv(pltfm_host);
270         u32 reg;
271
272         /*
273          * HS400/HS200/eMMC HS doesn't have Preset Value register.
274          * However, sdhci_set_ios will read HS400/HS200 Preset register.
275          * Disable Preset Value register for HS400/HS200.
276          * eMMC HS with preset_enabled set will trigger a bug in
277          * get_preset_value().
278          */
279         if ((ios->timing == MMC_TIMING_MMC_HS400) ||
280             (ios->timing == MMC_TIMING_MMC_HS200) ||
281             (ios->timing == MMC_TIMING_MMC_HS)) {
282                 host->preset_enabled = false;
283                 host->quirks2 |= SDHCI_QUIRK2_PRESET_VALUE_BROKEN;
284                 host->flags &= ~SDHCI_PV_ENABLED;
285
286                 reg = sdhci_readw(host, SDHCI_HOST_CONTROL2);
287                 reg &= ~SDHCI_CTRL_PRESET_VAL_ENABLE;
288                 sdhci_writew(host, reg, SDHCI_HOST_CONTROL2);
289         } else {
290                 host->quirks2 &= ~SDHCI_QUIRK2_PRESET_VALUE_BROKEN;
291         }
292
293         sdhci_set_ios(mmc, ios);
294         xenon_phy_adj(host, ios);
295
296         if (host->clock > XENON_DEFAULT_SDCLK_FREQ)
297                 xenon_set_sdclk_off_idle(host, priv->sdhc_id, true);
298 }
299
300 static int xenon_start_signal_voltage_switch(struct mmc_host *mmc,
301                                              struct mmc_ios *ios)
302 {
303         struct sdhci_host *host = mmc_priv(mmc);
304
305         /*
306          * Before SD/SDIO set signal voltage, SD bus clock should be
307          * disabled. However, sdhci_set_clock will also disable the Internal
308          * clock in mmc_set_signal_voltage().
309          * If Internal clock is disabled, the 3.3V/1.8V bit can not be updated.
310          * Thus here manually enable internal clock.
311          *
312          * After switch completes, it is unnecessary to disable internal clock,
313          * since keeping internal clock active obeys SD spec.
314          */
315         xenon_enable_internal_clk(host);
316
317         xenon_soc_pad_ctrl(host, ios->signal_voltage);
318
319         /*
320          * If Vqmmc is fixed on platform, vqmmc regulator should be unavailable.
321          * Thus SDHCI_CTRL_VDD_180 bit might not work then.
322          * Skip the standard voltage switch to avoid any issue.
323          */
324         if (PTR_ERR(mmc->supply.vqmmc) == -ENODEV)
325                 return 0;
326
327         return sdhci_start_signal_voltage_switch(mmc, ios);
328 }
329
330 /*
331  * Update card type.
332  * priv->init_card_type will be used in PHY timing adjustment.
333  */
334 static void xenon_init_card(struct mmc_host *mmc, struct mmc_card *card)
335 {
336         struct sdhci_host *host = mmc_priv(mmc);
337         struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
338         struct xenon_priv *priv = sdhci_pltfm_priv(pltfm_host);
339
340         /* Update card type*/
341         priv->init_card_type = card->type;
342 }
343
344 static int xenon_execute_tuning(struct mmc_host *mmc, u32 opcode)
345 {
346         struct sdhci_host *host = mmc_priv(mmc);
347
348         if (host->timing == MMC_TIMING_UHS_DDR50 ||
349                 host->timing == MMC_TIMING_MMC_DDR52)
350                 return 0;
351
352         /*
353          * Currently force Xenon driver back to support mode 1 only,
354          * even though Xenon might claim to support mode 2 or mode 3.
355          * It requires more time to test mode 2/mode 3 on more platforms.
356          */
357         if (host->tuning_mode != SDHCI_TUNING_MODE_1)
358                 xenon_retune_setup(host);
359
360         return sdhci_execute_tuning(mmc, opcode);
361 }
362
363 static void xenon_enable_sdio_irq(struct mmc_host *mmc, int enable)
364 {
365         struct sdhci_host *host = mmc_priv(mmc);
366         struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
367         struct xenon_priv *priv = sdhci_pltfm_priv(pltfm_host);
368         u32 reg;
369         u8 sdhc_id = priv->sdhc_id;
370
371         sdhci_enable_sdio_irq(mmc, enable);
372
373         if (enable) {
374                 /*
375                  * Set SDIO Card Inserted indication
376                  * to enable detecting SDIO async irq.
377                  */
378                 reg = sdhci_readl(host, XENON_SYS_CFG_INFO);
379                 reg |= (1 << (sdhc_id + XENON_SLOT_TYPE_SDIO_SHIFT));
380                 sdhci_writel(host, reg, XENON_SYS_CFG_INFO);
381         } else {
382                 /* Clear SDIO Card Inserted indication */
383                 reg = sdhci_readl(host, XENON_SYS_CFG_INFO);
384                 reg &= ~(1 << (sdhc_id + XENON_SLOT_TYPE_SDIO_SHIFT));
385                 sdhci_writel(host, reg, XENON_SYS_CFG_INFO);
386         }
387 }
388
389 static void xenon_replace_mmc_host_ops(struct sdhci_host *host)
390 {
391         host->mmc_host_ops.set_ios = xenon_set_ios;
392         host->mmc_host_ops.start_signal_voltage_switch =
393                         xenon_start_signal_voltage_switch;
394         host->mmc_host_ops.init_card = xenon_init_card;
395         host->mmc_host_ops.execute_tuning = xenon_execute_tuning;
396         host->mmc_host_ops.enable_sdio_irq = xenon_enable_sdio_irq;
397 }
398
399 /*
400  * Parse Xenon specific DT properties:
401  * sdhc-id: the index of current SDHC.
402  *          Refer to XENON_SYS_CFG_INFO register
403  * tun-count: the interval between re-tuning
404  */
405 static int xenon_probe_dt(struct platform_device *pdev)
406 {
407         struct device_node *np = pdev->dev.of_node;
408         struct sdhci_host *host = platform_get_drvdata(pdev);
409         struct mmc_host *mmc = host->mmc;
410         struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
411         struct xenon_priv *priv = sdhci_pltfm_priv(pltfm_host);
412         u32 sdhc_id, nr_sdhc;
413         u32 tuning_count;
414
415         /* Disable HS200 on Armada AP806 */
416         if (of_device_is_compatible(np, "marvell,armada-ap806-sdhci"))
417                 host->quirks2 |= SDHCI_QUIRK2_BROKEN_HS200;
418
419         sdhc_id = 0x0;
420         if (!of_property_read_u32(np, "marvell,xenon-sdhc-id", &sdhc_id)) {
421                 nr_sdhc = sdhci_readl(host, XENON_SYS_CFG_INFO);
422                 nr_sdhc &= XENON_NR_SUPPORTED_SLOT_MASK;
423                 if (unlikely(sdhc_id > nr_sdhc)) {
424                         dev_err(mmc_dev(mmc), "SDHC Index %d exceeds Number of SDHCs %d\n",
425                                 sdhc_id, nr_sdhc);
426                         return -EINVAL;
427                 }
428         }
429         priv->sdhc_id = sdhc_id;
430
431         tuning_count = XENON_DEF_TUNING_COUNT;
432         if (!of_property_read_u32(np, "marvell,xenon-tun-count",
433                                   &tuning_count)) {
434                 if (unlikely(tuning_count >= XENON_TMR_RETUN_NO_PRESENT)) {
435                         dev_err(mmc_dev(mmc), "Wrong Re-tuning Count. Set default value %d\n",
436                                 XENON_DEF_TUNING_COUNT);
437                         tuning_count = XENON_DEF_TUNING_COUNT;
438                 }
439         }
440         priv->tuning_count = tuning_count;
441
442         return xenon_phy_parse_dt(np, host);
443 }
444
445 static int xenon_sdhc_prepare(struct sdhci_host *host)
446 {
447         struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
448         struct xenon_priv *priv = sdhci_pltfm_priv(pltfm_host);
449         u8 sdhc_id = priv->sdhc_id;
450
451         /* Enable SDHC */
452         xenon_enable_sdhc(host, sdhc_id);
453
454         /* Enable ACG */
455         xenon_set_acg(host, true);
456
457         /* Enable Parallel Transfer Mode */
458         xenon_enable_sdhc_parallel_tran(host, sdhc_id);
459
460         /* Disable SDCLK-Off-While-Idle before card init */
461         xenon_set_sdclk_off_idle(host, sdhc_id, false);
462
463         xenon_mask_cmd_conflict_err(host);
464
465         return 0;
466 }
467
468 static void xenon_sdhc_unprepare(struct sdhci_host *host)
469 {
470         struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
471         struct xenon_priv *priv = sdhci_pltfm_priv(pltfm_host);
472         u8 sdhc_id = priv->sdhc_id;
473
474         /* disable SDHC */
475         xenon_disable_sdhc(host, sdhc_id);
476 }
477
478 static int xenon_probe(struct platform_device *pdev)
479 {
480         struct sdhci_pltfm_host *pltfm_host;
481         struct sdhci_host *host;
482         struct xenon_priv *priv;
483         int err;
484
485         host = sdhci_pltfm_init(pdev, &sdhci_xenon_pdata,
486                                 sizeof(struct xenon_priv));
487         if (IS_ERR(host))
488                 return PTR_ERR(host);
489
490         pltfm_host = sdhci_priv(host);
491         priv = sdhci_pltfm_priv(pltfm_host);
492
493         /*
494          * Link Xenon specific mmc_host_ops function,
495          * to replace standard ones in sdhci_ops.
496          */
497         xenon_replace_mmc_host_ops(host);
498
499         pltfm_host->clk = devm_clk_get(&pdev->dev, "core");
500         if (IS_ERR(pltfm_host->clk)) {
501                 err = PTR_ERR(pltfm_host->clk);
502                 dev_err(&pdev->dev, "Failed to setup input clk: %d\n", err);
503                 goto free_pltfm;
504         }
505         err = clk_prepare_enable(pltfm_host->clk);
506         if (err)
507                 goto free_pltfm;
508
509         priv->axi_clk = devm_clk_get(&pdev->dev, "axi");
510         if (IS_ERR(priv->axi_clk)) {
511                 err = PTR_ERR(priv->axi_clk);
512                 if (err == -EPROBE_DEFER)
513                         goto err_clk;
514         } else {
515                 err = clk_prepare_enable(priv->axi_clk);
516                 if (err)
517                         goto err_clk;
518         }
519
520         err = mmc_of_parse(host->mmc);
521         if (err)
522                 goto err_clk_axi;
523
524         sdhci_get_of_property(pdev);
525
526         xenon_set_acg(host, false);
527
528         /* Xenon specific dt parse */
529         err = xenon_probe_dt(pdev);
530         if (err)
531                 goto err_clk_axi;
532
533         err = xenon_sdhc_prepare(host);
534         if (err)
535                 goto err_clk_axi;
536
537         pm_runtime_get_noresume(&pdev->dev);
538         pm_runtime_set_active(&pdev->dev);
539         pm_runtime_set_autosuspend_delay(&pdev->dev, 50);
540         pm_runtime_use_autosuspend(&pdev->dev);
541         pm_runtime_enable(&pdev->dev);
542         pm_suspend_ignore_children(&pdev->dev, 1);
543
544         err = sdhci_add_host(host);
545         if (err)
546                 goto remove_sdhc;
547
548         pm_runtime_put_autosuspend(&pdev->dev);
549
550         return 0;
551
552 remove_sdhc:
553         pm_runtime_disable(&pdev->dev);
554         pm_runtime_put_noidle(&pdev->dev);
555         xenon_sdhc_unprepare(host);
556 err_clk_axi:
557         clk_disable_unprepare(priv->axi_clk);
558 err_clk:
559         clk_disable_unprepare(pltfm_host->clk);
560 free_pltfm:
561         sdhci_pltfm_free(pdev);
562         return err;
563 }
564
565 static int xenon_remove(struct platform_device *pdev)
566 {
567         struct sdhci_host *host = platform_get_drvdata(pdev);
568         struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
569         struct xenon_priv *priv = sdhci_pltfm_priv(pltfm_host);
570
571         pm_runtime_get_sync(&pdev->dev);
572         pm_runtime_disable(&pdev->dev);
573         pm_runtime_put_noidle(&pdev->dev);
574
575         sdhci_remove_host(host, 0);
576
577         xenon_sdhc_unprepare(host);
578         clk_disable_unprepare(priv->axi_clk);
579         clk_disable_unprepare(pltfm_host->clk);
580
581         sdhci_pltfm_free(pdev);
582
583         return 0;
584 }
585
586 #ifdef CONFIG_PM_SLEEP
587 static int xenon_suspend(struct device *dev)
588 {
589         struct sdhci_host *host = dev_get_drvdata(dev);
590         struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
591         struct xenon_priv *priv = sdhci_pltfm_priv(pltfm_host);
592         int ret;
593
594         ret = pm_runtime_force_suspend(dev);
595
596         priv->restore_needed = true;
597         return ret;
598 }
599 #endif
600
601 #ifdef CONFIG_PM
602 static int xenon_runtime_suspend(struct device *dev)
603 {
604         struct sdhci_host *host = dev_get_drvdata(dev);
605         struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
606         struct xenon_priv *priv = sdhci_pltfm_priv(pltfm_host);
607         int ret;
608
609         ret = sdhci_runtime_suspend_host(host);
610         if (ret)
611                 return ret;
612
613         if (host->tuning_mode != SDHCI_TUNING_MODE_3)
614                 mmc_retune_needed(host->mmc);
615
616         clk_disable_unprepare(pltfm_host->clk);
617         /*
618          * Need to update the priv->clock here, or when runtime resume
619          * back, phy don't aware the clock change and won't adjust phy
620          * which will cause cmd err
621          */
622         priv->clock = 0;
623         return 0;
624 }
625
626 static int xenon_runtime_resume(struct device *dev)
627 {
628         struct sdhci_host *host = dev_get_drvdata(dev);
629         struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
630         struct xenon_priv *priv = sdhci_pltfm_priv(pltfm_host);
631         int ret;
632
633         ret = clk_prepare_enable(pltfm_host->clk);
634         if (ret) {
635                 dev_err(dev, "can't enable mainck\n");
636                 return ret;
637         }
638
639         if (priv->restore_needed) {
640                 ret = xenon_sdhc_prepare(host);
641                 if (ret)
642                         goto out;
643                 priv->restore_needed = false;
644         }
645
646         ret = sdhci_runtime_resume_host(host, 0);
647         if (ret)
648                 goto out;
649         return 0;
650 out:
651         clk_disable_unprepare(pltfm_host->clk);
652         return ret;
653 }
654 #endif /* CONFIG_PM */
655
656 static const struct dev_pm_ops sdhci_xenon_dev_pm_ops = {
657         SET_SYSTEM_SLEEP_PM_OPS(xenon_suspend,
658                                 pm_runtime_force_resume)
659         SET_RUNTIME_PM_OPS(xenon_runtime_suspend,
660                            xenon_runtime_resume,
661                            NULL)
662 };
663
664 static const struct of_device_id sdhci_xenon_dt_ids[] = {
665         { .compatible = "marvell,armada-ap806-sdhci",},
666         { .compatible = "marvell,armada-cp110-sdhci",},
667         { .compatible = "marvell,armada-3700-sdhci",},
668         {}
669 };
670 MODULE_DEVICE_TABLE(of, sdhci_xenon_dt_ids);
671
672 static struct platform_driver sdhci_xenon_driver = {
673         .driver = {
674                 .name   = "xenon-sdhci",
675                 .probe_type = PROBE_PREFER_ASYNCHRONOUS,
676                 .of_match_table = sdhci_xenon_dt_ids,
677                 .pm = &sdhci_xenon_dev_pm_ops,
678         },
679         .probe  = xenon_probe,
680         .remove = xenon_remove,
681 };
682
683 module_platform_driver(sdhci_xenon_driver);
684
685 MODULE_DESCRIPTION("SDHCI platform driver for Marvell Xenon SDHC");
686 MODULE_AUTHOR("Hu Ziji <huziji@marvell.com>");
687 MODULE_LICENSE("GPL v2");