linux/drivers/mmc/host/sdhci-xenon.c
<<
>>
Prefs
   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
  24static 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 */
  51static 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 */
  69static 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 */
  82static 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 */
 100static 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 */
 111static 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 */
 122static 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
 131static 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 */
 160static 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
 177static 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 */
 190static 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
 216static 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
 234static 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
 250static 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
 260static 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 */
 270static 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
 305static 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 */
 339static 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
 349static 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
 368static 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
 394static 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 */
 410static 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
 450static 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
 473static 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
 483static 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
 557remove_sdhc:
 558        pm_runtime_disable(&pdev->dev);
 559        pm_runtime_put_noidle(&pdev->dev);
 560        xenon_sdhc_unprepare(host);
 561err_clk_axi:
 562        clk_disable_unprepare(priv->axi_clk);
 563err_clk:
 564        clk_disable_unprepare(pltfm_host->clk);
 565free_pltfm:
 566        sdhci_pltfm_free(pdev);
 567        return err;
 568}
 569
 570static 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
 592static 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
 607static 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
 631static 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;
 655out:
 656        clk_disable_unprepare(pltfm_host->clk);
 657        return ret;
 658}
 659#endif /* CONFIG_PM */
 660
 661static 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
 669static 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};
 675MODULE_DEVICE_TABLE(of, sdhci_xenon_dt_ids);
 676
 677static 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
 687module_platform_driver(sdhci_xenon_driver);
 688
 689MODULE_DESCRIPTION("SDHCI platform driver for Marvell Xenon SDHC");
 690MODULE_AUTHOR("Hu Ziji <huziji@marvell.com>");
 691MODULE_LICENSE("GPL v2");
 692