root/drivers/mmc/host/sdhci-xenon.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. xenon_enable_internal_clk
  2. xenon_set_sdclk_off_idle
  3. xenon_set_acg
  4. xenon_enable_sdhc
  5. xenon_disable_sdhc
  6. xenon_enable_sdhc_parallel_tran
  7. xenon_mask_cmd_conflict_err
  8. xenon_retune_setup
  9. xenon_reset_exit
  10. xenon_reset
  11. xenon_set_uhs_signaling
  12. xenon_set_power
  13. xenon_voltage_switch
  14. xenon_set_ios
  15. xenon_start_signal_voltage_switch
  16. xenon_init_card
  17. xenon_execute_tuning
  18. xenon_enable_sdio_irq
  19. xenon_replace_mmc_host_ops
  20. xenon_probe_dt
  21. xenon_sdhc_prepare
  22. xenon_sdhc_unprepare
  23. xenon_probe
  24. xenon_remove
  25. xenon_suspend
  26. xenon_runtime_suspend
  27. xenon_runtime_resume

   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         xenon_set_acg(host, true);
 171 
 172         xenon_set_sdclk_off_idle(host, sdhc_id, false);
 173 
 174         xenon_mask_cmd_conflict_err(host);
 175 }
 176 
 177 static void xenon_reset(struct sdhci_host *host, u8 mask)
 178 {
 179         struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
 180         struct xenon_priv *priv = sdhci_pltfm_priv(pltfm_host);
 181 
 182         sdhci_reset(host, mask);
 183         xenon_reset_exit(host, priv->sdhc_id, mask);
 184 }
 185 
 186 /*
 187  * Xenon defines different values for HS200 and HS400
 188  * in Host_Control_2
 189  */
 190 static void xenon_set_uhs_signaling(struct sdhci_host *host,
 191                                     unsigned int timing)
 192 {
 193         u16 ctrl_2;
 194 
 195         ctrl_2 = sdhci_readw(host, SDHCI_HOST_CONTROL2);
 196         /* Select Bus Speed Mode for host */
 197         ctrl_2 &= ~SDHCI_CTRL_UHS_MASK;
 198         if (timing == MMC_TIMING_MMC_HS200)
 199                 ctrl_2 |= XENON_CTRL_HS200;
 200         else if (timing == MMC_TIMING_UHS_SDR104)
 201                 ctrl_2 |= SDHCI_CTRL_UHS_SDR104;
 202         else if (timing == MMC_TIMING_UHS_SDR12)
 203                 ctrl_2 |= SDHCI_CTRL_UHS_SDR12;
 204         else if (timing == MMC_TIMING_UHS_SDR25)
 205                 ctrl_2 |= SDHCI_CTRL_UHS_SDR25;
 206         else if (timing == MMC_TIMING_UHS_SDR50)
 207                 ctrl_2 |= SDHCI_CTRL_UHS_SDR50;
 208         else if ((timing == MMC_TIMING_UHS_DDR50) ||
 209                  (timing == MMC_TIMING_MMC_DDR52))
 210                 ctrl_2 |= SDHCI_CTRL_UHS_DDR50;
 211         else if (timing == MMC_TIMING_MMC_HS400)
 212                 ctrl_2 |= XENON_CTRL_HS400;
 213         sdhci_writew(host, ctrl_2, SDHCI_HOST_CONTROL2);
 214 }
 215 
 216 static void xenon_set_power(struct sdhci_host *host, unsigned char mode,
 217                 unsigned short vdd)
 218 {
 219         struct mmc_host *mmc = host->mmc;
 220         u8 pwr = host->pwr;
 221 
 222         sdhci_set_power_noreg(host, mode, vdd);
 223 
 224         if (host->pwr == pwr)
 225                 return;
 226 
 227         if (host->pwr == 0)
 228                 vdd = 0;
 229 
 230         if (!IS_ERR(mmc->supply.vmmc))
 231                 mmc_regulator_set_ocr(mmc, mmc->supply.vmmc, vdd);
 232 }
 233 
 234 static void xenon_voltage_switch(struct sdhci_host *host)
 235 {
 236         /* Wait for 5ms after set 1.8V signal enable bit */
 237         usleep_range(5000, 5500);
 238 
 239         /*
 240          * For some reason the controller's Host Control2 register reports
 241          * the bit representing 1.8V signaling as 0 when read after it was
 242          * written as 1. Subsequent read reports 1.
 243          *
 244          * Since this may cause some issues, do an empty read of the Host
 245          * Control2 register here to circumvent this.
 246          */
 247         sdhci_readw(host, SDHCI_HOST_CONTROL2);
 248 }
 249 
 250 static const struct sdhci_ops sdhci_xenon_ops = {
 251         .voltage_switch         = xenon_voltage_switch,
 252         .set_clock              = sdhci_set_clock,
 253         .set_power              = xenon_set_power,
 254         .set_bus_width          = sdhci_set_bus_width,
 255         .reset                  = xenon_reset,
 256         .set_uhs_signaling      = xenon_set_uhs_signaling,
 257         .get_max_clock          = sdhci_pltfm_clk_get_max_clock,
 258 };
 259 
 260 static const struct sdhci_pltfm_data sdhci_xenon_pdata = {
 261         .ops = &sdhci_xenon_ops,
 262         .quirks = SDHCI_QUIRK_NO_ENDATTR_IN_NOPDESC |
 263                   SDHCI_QUIRK_NO_SIMULT_VDD_AND_POWER |
 264                   SDHCI_QUIRK_CAP_CLOCK_BASE_BROKEN,
 265 };
 266 
 267 /*
 268  * Xenon Specific Operations in mmc_host_ops
 269  */
 270 static void xenon_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
 271 {
 272         struct sdhci_host *host = mmc_priv(mmc);
 273         struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
 274         struct xenon_priv *priv = sdhci_pltfm_priv(pltfm_host);
 275         u32 reg;
 276 
 277         /*
 278          * HS400/HS200/eMMC HS doesn't have Preset Value register.
 279          * However, sdhci_set_ios will read HS400/HS200 Preset register.
 280          * Disable Preset Value register for HS400/HS200.
 281          * eMMC HS with preset_enabled set will trigger a bug in
 282          * get_preset_value().
 283          */
 284         if ((ios->timing == MMC_TIMING_MMC_HS400) ||
 285             (ios->timing == MMC_TIMING_MMC_HS200) ||
 286             (ios->timing == MMC_TIMING_MMC_HS)) {
 287                 host->preset_enabled = false;
 288                 host->quirks2 |= SDHCI_QUIRK2_PRESET_VALUE_BROKEN;
 289                 host->flags &= ~SDHCI_PV_ENABLED;
 290 
 291                 reg = sdhci_readw(host, SDHCI_HOST_CONTROL2);
 292                 reg &= ~SDHCI_CTRL_PRESET_VAL_ENABLE;
 293                 sdhci_writew(host, reg, SDHCI_HOST_CONTROL2);
 294         } else {
 295                 host->quirks2 &= ~SDHCI_QUIRK2_PRESET_VALUE_BROKEN;
 296         }
 297 
 298         sdhci_set_ios(mmc, ios);
 299         xenon_phy_adj(host, ios);
 300 
 301         if (host->clock > XENON_DEFAULT_SDCLK_FREQ)
 302                 xenon_set_sdclk_off_idle(host, priv->sdhc_id, true);
 303 }
 304 
 305 static int xenon_start_signal_voltage_switch(struct mmc_host *mmc,
 306                                              struct mmc_ios *ios)
 307 {
 308         struct sdhci_host *host = mmc_priv(mmc);
 309 
 310         /*
 311          * Before SD/SDIO set signal voltage, SD bus clock should be
 312          * disabled. However, sdhci_set_clock will also disable the Internal
 313          * clock in mmc_set_signal_voltage().
 314          * If Internal clock is disabled, the 3.3V/1.8V bit can not be updated.
 315          * Thus here manually enable internal clock.
 316          *
 317          * After switch completes, it is unnecessary to disable internal clock,
 318          * since keeping internal clock active obeys SD spec.
 319          */
 320         xenon_enable_internal_clk(host);
 321 
 322         xenon_soc_pad_ctrl(host, ios->signal_voltage);
 323 
 324         /*
 325          * If Vqmmc is fixed on platform, vqmmc regulator should be unavailable.
 326          * Thus SDHCI_CTRL_VDD_180 bit might not work then.
 327          * Skip the standard voltage switch to avoid any issue.
 328          */
 329         if (PTR_ERR(mmc->supply.vqmmc) == -ENODEV)
 330                 return 0;
 331 
 332         return sdhci_start_signal_voltage_switch(mmc, ios);
 333 }
 334 
 335 /*
 336  * Update card type.
 337  * priv->init_card_type will be used in PHY timing adjustment.
 338  */
 339 static void xenon_init_card(struct mmc_host *mmc, struct mmc_card *card)
 340 {
 341         struct sdhci_host *host = mmc_priv(mmc);
 342         struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
 343         struct xenon_priv *priv = sdhci_pltfm_priv(pltfm_host);
 344 
 345         /* Update card type*/
 346         priv->init_card_type = card->type;
 347 }
 348 
 349 static int xenon_execute_tuning(struct mmc_host *mmc, u32 opcode)
 350 {
 351         struct sdhci_host *host = mmc_priv(mmc);
 352 
 353         if (host->timing == MMC_TIMING_UHS_DDR50 ||
 354                 host->timing == MMC_TIMING_MMC_DDR52)
 355                 return 0;
 356 
 357         /*
 358          * Currently force Xenon driver back to support mode 1 only,
 359          * even though Xenon might claim to support mode 2 or mode 3.
 360          * It requires more time to test mode 2/mode 3 on more platforms.
 361          */
 362         if (host->tuning_mode != SDHCI_TUNING_MODE_1)
 363                 xenon_retune_setup(host);
 364 
 365         return sdhci_execute_tuning(mmc, opcode);
 366 }
 367 
 368 static void xenon_enable_sdio_irq(struct mmc_host *mmc, int enable)
 369 {
 370         struct sdhci_host *host = mmc_priv(mmc);
 371         struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
 372         struct xenon_priv *priv = sdhci_pltfm_priv(pltfm_host);
 373         u32 reg;
 374         u8 sdhc_id = priv->sdhc_id;
 375 
 376         sdhci_enable_sdio_irq(mmc, enable);
 377 
 378         if (enable) {
 379                 /*
 380                  * Set SDIO Card Inserted indication
 381                  * to enable detecting SDIO async irq.
 382                  */
 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         } else {
 387                 /* Clear SDIO Card Inserted indication */
 388                 reg = sdhci_readl(host, XENON_SYS_CFG_INFO);
 389                 reg &= ~(1 << (sdhc_id + XENON_SLOT_TYPE_SDIO_SHIFT));
 390                 sdhci_writel(host, reg, XENON_SYS_CFG_INFO);
 391         }
 392 }
 393 
 394 static void xenon_replace_mmc_host_ops(struct sdhci_host *host)
 395 {
 396         host->mmc_host_ops.set_ios = xenon_set_ios;
 397         host->mmc_host_ops.start_signal_voltage_switch =
 398                         xenon_start_signal_voltage_switch;
 399         host->mmc_host_ops.init_card = xenon_init_card;
 400         host->mmc_host_ops.execute_tuning = xenon_execute_tuning;
 401         host->mmc_host_ops.enable_sdio_irq = xenon_enable_sdio_irq;
 402 }
 403 
 404 /*
 405  * Parse Xenon specific DT properties:
 406  * sdhc-id: the index of current SDHC.
 407  *          Refer to XENON_SYS_CFG_INFO register
 408  * tun-count: the interval between re-tuning
 409  */
 410 static int xenon_probe_dt(struct platform_device *pdev)
 411 {
 412         struct device_node *np = pdev->dev.of_node;
 413         struct sdhci_host *host = platform_get_drvdata(pdev);
 414         struct mmc_host *mmc = host->mmc;
 415         struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
 416         struct xenon_priv *priv = sdhci_pltfm_priv(pltfm_host);
 417         u32 sdhc_id, nr_sdhc;
 418         u32 tuning_count;
 419 
 420         /* Disable HS200 on Armada AP806 */
 421         if (of_device_is_compatible(np, "marvell,armada-ap806-sdhci"))
 422                 host->quirks2 |= SDHCI_QUIRK2_BROKEN_HS200;
 423 
 424         sdhc_id = 0x0;
 425         if (!of_property_read_u32(np, "marvell,xenon-sdhc-id", &sdhc_id)) {
 426                 nr_sdhc = sdhci_readl(host, XENON_SYS_CFG_INFO);
 427                 nr_sdhc &= XENON_NR_SUPPORTED_SLOT_MASK;
 428                 if (unlikely(sdhc_id > nr_sdhc)) {
 429                         dev_err(mmc_dev(mmc), "SDHC Index %d exceeds Number of SDHCs %d\n",
 430                                 sdhc_id, nr_sdhc);
 431                         return -EINVAL;
 432                 }
 433         }
 434         priv->sdhc_id = sdhc_id;
 435 
 436         tuning_count = XENON_DEF_TUNING_COUNT;
 437         if (!of_property_read_u32(np, "marvell,xenon-tun-count",
 438                                   &tuning_count)) {
 439                 if (unlikely(tuning_count >= XENON_TMR_RETUN_NO_PRESENT)) {
 440                         dev_err(mmc_dev(mmc), "Wrong Re-tuning Count. Set default value %d\n",
 441                                 XENON_DEF_TUNING_COUNT);
 442                         tuning_count = XENON_DEF_TUNING_COUNT;
 443                 }
 444         }
 445         priv->tuning_count = tuning_count;
 446 
 447         return xenon_phy_parse_dt(np, host);
 448 }
 449 
 450 static int xenon_sdhc_prepare(struct sdhci_host *host)
 451 {
 452         struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
 453         struct xenon_priv *priv = sdhci_pltfm_priv(pltfm_host);
 454         u8 sdhc_id = priv->sdhc_id;
 455 
 456         /* Enable SDHC */
 457         xenon_enable_sdhc(host, sdhc_id);
 458 
 459         /* Enable ACG */
 460         xenon_set_acg(host, true);
 461 
 462         /* Enable Parallel Transfer Mode */
 463         xenon_enable_sdhc_parallel_tran(host, sdhc_id);
 464 
 465         /* Disable SDCLK-Off-While-Idle before card init */
 466         xenon_set_sdclk_off_idle(host, sdhc_id, false);
 467 
 468         xenon_mask_cmd_conflict_err(host);
 469 
 470         return 0;
 471 }
 472 
 473 static void xenon_sdhc_unprepare(struct sdhci_host *host)
 474 {
 475         struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
 476         struct xenon_priv *priv = sdhci_pltfm_priv(pltfm_host);
 477         u8 sdhc_id = priv->sdhc_id;
 478 
 479         /* disable SDHC */
 480         xenon_disable_sdhc(host, sdhc_id);
 481 }
 482 
 483 static int xenon_probe(struct platform_device *pdev)
 484 {
 485         struct sdhci_pltfm_host *pltfm_host;
 486         struct sdhci_host *host;
 487         struct xenon_priv *priv;
 488         int err;
 489 
 490         host = sdhci_pltfm_init(pdev, &sdhci_xenon_pdata,
 491                                 sizeof(struct xenon_priv));
 492         if (IS_ERR(host))
 493                 return PTR_ERR(host);
 494 
 495         pltfm_host = sdhci_priv(host);
 496         priv = sdhci_pltfm_priv(pltfm_host);
 497 
 498         /*
 499          * Link Xenon specific mmc_host_ops function,
 500          * to replace standard ones in sdhci_ops.
 501          */
 502         xenon_replace_mmc_host_ops(host);
 503 
 504         pltfm_host->clk = devm_clk_get(&pdev->dev, "core");
 505         if (IS_ERR(pltfm_host->clk)) {
 506                 err = PTR_ERR(pltfm_host->clk);
 507                 dev_err(&pdev->dev, "Failed to setup input clk: %d\n", err);
 508                 goto free_pltfm;
 509         }
 510         err = clk_prepare_enable(pltfm_host->clk);
 511         if (err)
 512                 goto free_pltfm;
 513 
 514         priv->axi_clk = devm_clk_get(&pdev->dev, "axi");
 515         if (IS_ERR(priv->axi_clk)) {
 516                 err = PTR_ERR(priv->axi_clk);
 517                 if (err == -EPROBE_DEFER)
 518                         goto err_clk;
 519         } else {
 520                 err = clk_prepare_enable(priv->axi_clk);
 521                 if (err)
 522                         goto err_clk;
 523         }
 524 
 525         err = mmc_of_parse(host->mmc);
 526         if (err)
 527                 goto err_clk_axi;
 528 
 529         sdhci_get_of_property(pdev);
 530 
 531         xenon_set_acg(host, false);
 532 
 533         /* Xenon specific dt parse */
 534         err = xenon_probe_dt(pdev);
 535         if (err)
 536                 goto err_clk_axi;
 537 
 538         err = xenon_sdhc_prepare(host);
 539         if (err)
 540                 goto err_clk_axi;
 541 
 542         pm_runtime_get_noresume(&pdev->dev);
 543         pm_runtime_set_active(&pdev->dev);
 544         pm_runtime_set_autosuspend_delay(&pdev->dev, 50);
 545         pm_runtime_use_autosuspend(&pdev->dev);
 546         pm_runtime_enable(&pdev->dev);
 547         pm_suspend_ignore_children(&pdev->dev, 1);
 548 
 549         err = sdhci_add_host(host);
 550         if (err)
 551                 goto remove_sdhc;
 552 
 553         pm_runtime_put_autosuspend(&pdev->dev);
 554 
 555         return 0;
 556 
 557 remove_sdhc:
 558         pm_runtime_disable(&pdev->dev);
 559         pm_runtime_put_noidle(&pdev->dev);
 560         xenon_sdhc_unprepare(host);
 561 err_clk_axi:
 562         clk_disable_unprepare(priv->axi_clk);
 563 err_clk:
 564         clk_disable_unprepare(pltfm_host->clk);
 565 free_pltfm:
 566         sdhci_pltfm_free(pdev);
 567         return err;
 568 }
 569 
 570 static int xenon_remove(struct platform_device *pdev)
 571 {
 572         struct sdhci_host *host = platform_get_drvdata(pdev);
 573         struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
 574         struct xenon_priv *priv = sdhci_pltfm_priv(pltfm_host);
 575 
 576         pm_runtime_get_sync(&pdev->dev);
 577         pm_runtime_disable(&pdev->dev);
 578         pm_runtime_put_noidle(&pdev->dev);
 579 
 580         sdhci_remove_host(host, 0);
 581 
 582         xenon_sdhc_unprepare(host);
 583         clk_disable_unprepare(priv->axi_clk);
 584         clk_disable_unprepare(pltfm_host->clk);
 585 
 586         sdhci_pltfm_free(pdev);
 587 
 588         return 0;
 589 }
 590 
 591 #ifdef CONFIG_PM_SLEEP
 592 static int xenon_suspend(struct device *dev)
 593 {
 594         struct sdhci_host *host = dev_get_drvdata(dev);
 595         struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
 596         struct xenon_priv *priv = sdhci_pltfm_priv(pltfm_host);
 597         int ret;
 598 
 599         ret = pm_runtime_force_suspend(dev);
 600 
 601         priv->restore_needed = true;
 602         return ret;
 603 }
 604 #endif
 605 
 606 #ifdef CONFIG_PM
 607 static int xenon_runtime_suspend(struct device *dev)
 608 {
 609         struct sdhci_host *host = dev_get_drvdata(dev);
 610         struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
 611         struct xenon_priv *priv = sdhci_pltfm_priv(pltfm_host);
 612         int ret;
 613 
 614         ret = sdhci_runtime_suspend_host(host);
 615         if (ret)
 616                 return ret;
 617 
 618         if (host->tuning_mode != SDHCI_TUNING_MODE_3)
 619                 mmc_retune_needed(host->mmc);
 620 
 621         clk_disable_unprepare(pltfm_host->clk);
 622         /*
 623          * Need to update the priv->clock here, or when runtime resume
 624          * back, phy don't aware the clock change and won't adjust phy
 625          * which will cause cmd err
 626          */
 627         priv->clock = 0;
 628         return 0;
 629 }
 630 
 631 static int xenon_runtime_resume(struct device *dev)
 632 {
 633         struct sdhci_host *host = dev_get_drvdata(dev);
 634         struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
 635         struct xenon_priv *priv = sdhci_pltfm_priv(pltfm_host);
 636         int ret;
 637 
 638         ret = clk_prepare_enable(pltfm_host->clk);
 639         if (ret) {
 640                 dev_err(dev, "can't enable mainck\n");
 641                 return ret;
 642         }
 643 
 644         if (priv->restore_needed) {
 645                 ret = xenon_sdhc_prepare(host);
 646                 if (ret)
 647                         goto out;
 648                 priv->restore_needed = false;
 649         }
 650 
 651         ret = sdhci_runtime_resume_host(host, 0);
 652         if (ret)
 653                 goto out;
 654         return 0;
 655 out:
 656         clk_disable_unprepare(pltfm_host->clk);
 657         return ret;
 658 }
 659 #endif /* CONFIG_PM */
 660 
 661 static const struct dev_pm_ops sdhci_xenon_dev_pm_ops = {
 662         SET_SYSTEM_SLEEP_PM_OPS(xenon_suspend,
 663                                 pm_runtime_force_resume)
 664         SET_RUNTIME_PM_OPS(xenon_runtime_suspend,
 665                            xenon_runtime_resume,
 666                            NULL)
 667 };
 668 
 669 static const struct of_device_id sdhci_xenon_dt_ids[] = {
 670         { .compatible = "marvell,armada-ap806-sdhci",},
 671         { .compatible = "marvell,armada-cp110-sdhci",},
 672         { .compatible = "marvell,armada-3700-sdhci",},
 673         {}
 674 };
 675 MODULE_DEVICE_TABLE(of, sdhci_xenon_dt_ids);
 676 
 677 static struct platform_driver sdhci_xenon_driver = {
 678         .driver = {
 679                 .name   = "xenon-sdhci",
 680                 .of_match_table = sdhci_xenon_dt_ids,
 681                 .pm = &sdhci_xenon_dev_pm_ops,
 682         },
 683         .probe  = xenon_probe,
 684         .remove = xenon_remove,
 685 };
 686 
 687 module_platform_driver(sdhci_xenon_driver);
 688 
 689 MODULE_DESCRIPTION("SDHCI platform driver for Marvell Xenon SDHC");
 690 MODULE_AUTHOR("Hu Ziji <huziji@marvell.com>");
 691 MODULE_LICENSE("GPL v2");

/* [<][>][^][v][top][bottom][index][help] */