Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0-only
0002 /*
0003  * Copyright (C) 2010 Marvell International Ltd.
0004  *      Zhangfei Gao <zhangfei.gao@marvell.com>
0005  *      Kevin Wang <dwang4@marvell.com>
0006  *      Mingwei Wang <mwwang@marvell.com>
0007  *      Philip Rakity <prakity@marvell.com>
0008  *      Mark Brown <markb@marvell.com>
0009  */
0010 #include <linux/err.h>
0011 #include <linux/init.h>
0012 #include <linux/platform_device.h>
0013 #include <linux/clk.h>
0014 #include <linux/io.h>
0015 #include <linux/mmc/card.h>
0016 #include <linux/mmc/host.h>
0017 #include <linux/platform_data/pxa_sdhci.h>
0018 #include <linux/slab.h>
0019 #include <linux/delay.h>
0020 #include <linux/module.h>
0021 #include <linux/of.h>
0022 #include <linux/of_device.h>
0023 #include <linux/pm.h>
0024 #include <linux/pm_runtime.h>
0025 #include <linux/mbus.h>
0026 
0027 #include "sdhci.h"
0028 #include "sdhci-pltfm.h"
0029 
0030 #define PXAV3_RPM_DELAY_MS     50
0031 
0032 #define SD_CLOCK_BURST_SIZE_SETUP       0x10A
0033 #define SDCLK_SEL   0x100
0034 #define SDCLK_DELAY_SHIFT   9
0035 #define SDCLK_DELAY_MASK    0x1f
0036 
0037 #define SD_CFG_FIFO_PARAM       0x100
0038 #define SDCFG_GEN_PAD_CLK_ON    (1<<6)
0039 #define SDCFG_GEN_PAD_CLK_CNT_MASK  0xFF
0040 #define SDCFG_GEN_PAD_CLK_CNT_SHIFT 24
0041 
0042 #define SD_SPI_MODE          0x108
0043 #define SD_CE_ATA_1          0x10C
0044 
0045 #define SD_CE_ATA_2          0x10E
0046 #define SDCE_MISC_INT       (1<<2)
0047 #define SDCE_MISC_INT_EN    (1<<1)
0048 
0049 struct sdhci_pxa {
0050     struct clk *clk_core;
0051     struct clk *clk_io;
0052     u8  power_mode;
0053     void __iomem *sdio3_conf_reg;
0054 };
0055 
0056 /*
0057  * These registers are relative to the second register region, for the
0058  * MBus bridge.
0059  */
0060 #define SDHCI_WINDOW_CTRL(i)    (0x80 + ((i) << 3))
0061 #define SDHCI_WINDOW_BASE(i)    (0x84 + ((i) << 3))
0062 #define SDHCI_MAX_WIN_NUM   8
0063 
0064 /*
0065  * Fields below belong to SDIO3 Configuration Register (third register
0066  * region for the Armada 38x flavor)
0067  */
0068 
0069 #define SDIO3_CONF_CLK_INV  BIT(0)
0070 #define SDIO3_CONF_SD_FB_CLK    BIT(2)
0071 
0072 static int mv_conf_mbus_windows(struct platform_device *pdev,
0073                 const struct mbus_dram_target_info *dram)
0074 {
0075     int i;
0076     void __iomem *regs;
0077     struct resource *res;
0078 
0079     if (!dram) {
0080         dev_err(&pdev->dev, "no mbus dram info\n");
0081         return -EINVAL;
0082     }
0083 
0084     res = platform_get_resource(pdev, IORESOURCE_MEM, 1);
0085     if (!res) {
0086         dev_err(&pdev->dev, "cannot get mbus registers\n");
0087         return -EINVAL;
0088     }
0089 
0090     regs = ioremap(res->start, resource_size(res));
0091     if (!regs) {
0092         dev_err(&pdev->dev, "cannot map mbus registers\n");
0093         return -ENOMEM;
0094     }
0095 
0096     for (i = 0; i < SDHCI_MAX_WIN_NUM; i++) {
0097         writel(0, regs + SDHCI_WINDOW_CTRL(i));
0098         writel(0, regs + SDHCI_WINDOW_BASE(i));
0099     }
0100 
0101     for (i = 0; i < dram->num_cs; i++) {
0102         const struct mbus_dram_window *cs = dram->cs + i;
0103 
0104         /* Write size, attributes and target id to control register */
0105         writel(((cs->size - 1) & 0xffff0000) |
0106             (cs->mbus_attr << 8) |
0107             (dram->mbus_dram_target_id << 4) | 1,
0108             regs + SDHCI_WINDOW_CTRL(i));
0109         /* Write base address to base register */
0110         writel(cs->base, regs + SDHCI_WINDOW_BASE(i));
0111     }
0112 
0113     iounmap(regs);
0114 
0115     return 0;
0116 }
0117 
0118 static int armada_38x_quirks(struct platform_device *pdev,
0119                  struct sdhci_host *host)
0120 {
0121     struct device_node *np = pdev->dev.of_node;
0122     struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
0123     struct sdhci_pxa *pxa = sdhci_pltfm_priv(pltfm_host);
0124     struct resource *res;
0125 
0126     host->quirks &= ~SDHCI_QUIRK_CAP_CLOCK_BASE_BROKEN;
0127     host->quirks |= SDHCI_QUIRK_MISSING_CAPS;
0128 
0129     host->caps = sdhci_readl(host, SDHCI_CAPABILITIES);
0130     host->caps1 = sdhci_readl(host, SDHCI_CAPABILITIES_1);
0131 
0132     res = platform_get_resource_byname(pdev, IORESOURCE_MEM,
0133                        "conf-sdio3");
0134     if (res) {
0135         pxa->sdio3_conf_reg = devm_ioremap_resource(&pdev->dev, res);
0136         if (IS_ERR(pxa->sdio3_conf_reg))
0137             return PTR_ERR(pxa->sdio3_conf_reg);
0138     } else {
0139         /*
0140          * According to erratum 'FE-2946959' both SDR50 and DDR50
0141          * modes require specific clock adjustments in SDIO3
0142          * Configuration register, if the adjustment is not done,
0143          * remove them from the capabilities.
0144          */
0145         host->caps1 &= ~(SDHCI_SUPPORT_SDR50 | SDHCI_SUPPORT_DDR50);
0146 
0147         dev_warn(&pdev->dev, "conf-sdio3 register not found: disabling SDR50 and DDR50 modes.\nConsider updating your dtb\n");
0148     }
0149 
0150     /*
0151      * According to erratum 'ERR-7878951' Armada 38x SDHCI
0152      * controller has different capabilities than the ones shown
0153      * in its registers
0154      */
0155     if (of_property_read_bool(np, "no-1-8-v")) {
0156         host->caps &= ~SDHCI_CAN_VDD_180;
0157         host->mmc->caps &= ~MMC_CAP_1_8V_DDR;
0158     } else {
0159         host->caps &= ~SDHCI_CAN_VDD_330;
0160     }
0161     host->caps1 &= ~(SDHCI_SUPPORT_SDR104 | SDHCI_USE_SDR50_TUNING);
0162 
0163     return 0;
0164 }
0165 
0166 static void pxav3_reset(struct sdhci_host *host, u8 mask)
0167 {
0168     struct platform_device *pdev = to_platform_device(mmc_dev(host->mmc));
0169     struct sdhci_pxa_platdata *pdata = pdev->dev.platform_data;
0170 
0171     sdhci_reset(host, mask);
0172 
0173     if (mask == SDHCI_RESET_ALL) {
0174         /*
0175          * tune timing of read data/command when crc error happen
0176          * no performance impact
0177          */
0178         if (pdata && 0 != pdata->clk_delay_cycles) {
0179             u16 tmp;
0180 
0181             tmp = readw(host->ioaddr + SD_CLOCK_BURST_SIZE_SETUP);
0182             tmp |= (pdata->clk_delay_cycles & SDCLK_DELAY_MASK)
0183                 << SDCLK_DELAY_SHIFT;
0184             tmp |= SDCLK_SEL;
0185             writew(tmp, host->ioaddr + SD_CLOCK_BURST_SIZE_SETUP);
0186         }
0187     }
0188 }
0189 
0190 #define MAX_WAIT_COUNT 5
0191 static void pxav3_gen_init_74_clocks(struct sdhci_host *host, u8 power_mode)
0192 {
0193     struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
0194     struct sdhci_pxa *pxa = sdhci_pltfm_priv(pltfm_host);
0195     u16 tmp;
0196     int count;
0197 
0198     if (pxa->power_mode == MMC_POWER_UP
0199             && power_mode == MMC_POWER_ON) {
0200 
0201         dev_dbg(mmc_dev(host->mmc),
0202                 "%s: slot->power_mode = %d,"
0203                 "ios->power_mode = %d\n",
0204                 __func__,
0205                 pxa->power_mode,
0206                 power_mode);
0207 
0208         /* set we want notice of when 74 clocks are sent */
0209         tmp = readw(host->ioaddr + SD_CE_ATA_2);
0210         tmp |= SDCE_MISC_INT_EN;
0211         writew(tmp, host->ioaddr + SD_CE_ATA_2);
0212 
0213         /* start sending the 74 clocks */
0214         tmp = readw(host->ioaddr + SD_CFG_FIFO_PARAM);
0215         tmp |= SDCFG_GEN_PAD_CLK_ON;
0216         writew(tmp, host->ioaddr + SD_CFG_FIFO_PARAM);
0217 
0218         /* slowest speed is about 100KHz or 10usec per clock */
0219         udelay(740);
0220         count = 0;
0221 
0222         while (count++ < MAX_WAIT_COUNT) {
0223             if ((readw(host->ioaddr + SD_CE_ATA_2)
0224                         & SDCE_MISC_INT) == 0)
0225                 break;
0226             udelay(10);
0227         }
0228 
0229         if (count == MAX_WAIT_COUNT)
0230             dev_warn(mmc_dev(host->mmc), "74 clock interrupt not cleared\n");
0231 
0232         /* clear the interrupt bit if posted */
0233         tmp = readw(host->ioaddr + SD_CE_ATA_2);
0234         tmp |= SDCE_MISC_INT;
0235         writew(tmp, host->ioaddr + SD_CE_ATA_2);
0236     }
0237     pxa->power_mode = power_mode;
0238 }
0239 
0240 static void pxav3_set_uhs_signaling(struct sdhci_host *host, unsigned int uhs)
0241 {
0242     struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
0243     struct sdhci_pxa *pxa = sdhci_pltfm_priv(pltfm_host);
0244     u16 ctrl_2;
0245 
0246     /*
0247      * Set V18_EN -- UHS modes do not work without this.
0248      * does not change signaling voltage
0249      */
0250     ctrl_2 = sdhci_readw(host, SDHCI_HOST_CONTROL2);
0251 
0252     /* Select Bus Speed Mode for host */
0253     ctrl_2 &= ~SDHCI_CTRL_UHS_MASK;
0254     switch (uhs) {
0255     case MMC_TIMING_UHS_SDR12:
0256         ctrl_2 |= SDHCI_CTRL_UHS_SDR12;
0257         break;
0258     case MMC_TIMING_UHS_SDR25:
0259         ctrl_2 |= SDHCI_CTRL_UHS_SDR25;
0260         break;
0261     case MMC_TIMING_UHS_SDR50:
0262         ctrl_2 |= SDHCI_CTRL_UHS_SDR50 | SDHCI_CTRL_VDD_180;
0263         break;
0264     case MMC_TIMING_UHS_SDR104:
0265         ctrl_2 |= SDHCI_CTRL_UHS_SDR104 | SDHCI_CTRL_VDD_180;
0266         break;
0267     case MMC_TIMING_MMC_DDR52:
0268     case MMC_TIMING_UHS_DDR50:
0269         ctrl_2 |= SDHCI_CTRL_UHS_DDR50 | SDHCI_CTRL_VDD_180;
0270         break;
0271     }
0272 
0273     /*
0274      * Update SDIO3 Configuration register according to erratum
0275      * FE-2946959
0276      */
0277     if (pxa->sdio3_conf_reg) {
0278         u8 reg_val  = readb(pxa->sdio3_conf_reg);
0279 
0280         if (uhs == MMC_TIMING_UHS_SDR50 ||
0281             uhs == MMC_TIMING_UHS_DDR50) {
0282             reg_val &= ~SDIO3_CONF_CLK_INV;
0283             reg_val |= SDIO3_CONF_SD_FB_CLK;
0284         } else if (uhs == MMC_TIMING_MMC_HS) {
0285             reg_val &= ~SDIO3_CONF_CLK_INV;
0286             reg_val &= ~SDIO3_CONF_SD_FB_CLK;
0287         } else {
0288             reg_val |= SDIO3_CONF_CLK_INV;
0289             reg_val &= ~SDIO3_CONF_SD_FB_CLK;
0290         }
0291         writeb(reg_val, pxa->sdio3_conf_reg);
0292     }
0293 
0294     sdhci_writew(host, ctrl_2, SDHCI_HOST_CONTROL2);
0295     dev_dbg(mmc_dev(host->mmc),
0296         "%s uhs = %d, ctrl_2 = %04X\n",
0297         __func__, uhs, ctrl_2);
0298 }
0299 
0300 static void pxav3_set_power(struct sdhci_host *host, unsigned char mode,
0301                 unsigned short vdd)
0302 {
0303     struct mmc_host *mmc = host->mmc;
0304     u8 pwr = host->pwr;
0305 
0306     sdhci_set_power_noreg(host, mode, vdd);
0307 
0308     if (host->pwr == pwr)
0309         return;
0310 
0311     if (host->pwr == 0)
0312         vdd = 0;
0313 
0314     if (!IS_ERR(mmc->supply.vmmc))
0315         mmc_regulator_set_ocr(mmc, mmc->supply.vmmc, vdd);
0316 }
0317 
0318 static const struct sdhci_ops pxav3_sdhci_ops = {
0319     .set_clock = sdhci_set_clock,
0320     .set_power = pxav3_set_power,
0321     .platform_send_init_74_clocks = pxav3_gen_init_74_clocks,
0322     .get_max_clock = sdhci_pltfm_clk_get_max_clock,
0323     .set_bus_width = sdhci_set_bus_width,
0324     .reset = pxav3_reset,
0325     .set_uhs_signaling = pxav3_set_uhs_signaling,
0326 };
0327 
0328 static const struct sdhci_pltfm_data sdhci_pxav3_pdata = {
0329     .quirks = SDHCI_QUIRK_DATA_TIMEOUT_USES_SDCLK
0330         | SDHCI_QUIRK_NO_ENDATTR_IN_NOPDESC
0331         | SDHCI_QUIRK_32BIT_ADMA_SIZE
0332         | SDHCI_QUIRK_CAP_CLOCK_BASE_BROKEN,
0333     .ops = &pxav3_sdhci_ops,
0334 };
0335 
0336 #ifdef CONFIG_OF
0337 static const struct of_device_id sdhci_pxav3_of_match[] = {
0338     {
0339         .compatible = "mrvl,pxav3-mmc",
0340     },
0341     {
0342         .compatible = "marvell,armada-380-sdhci",
0343     },
0344     {},
0345 };
0346 MODULE_DEVICE_TABLE(of, sdhci_pxav3_of_match);
0347 
0348 static struct sdhci_pxa_platdata *pxav3_get_mmc_pdata(struct device *dev)
0349 {
0350     struct sdhci_pxa_platdata *pdata;
0351     struct device_node *np = dev->of_node;
0352     u32 clk_delay_cycles;
0353 
0354     pdata = devm_kzalloc(dev, sizeof(*pdata), GFP_KERNEL);
0355     if (!pdata)
0356         return NULL;
0357 
0358     if (!of_property_read_u32(np, "mrvl,clk-delay-cycles",
0359                   &clk_delay_cycles))
0360         pdata->clk_delay_cycles = clk_delay_cycles;
0361 
0362     return pdata;
0363 }
0364 #else
0365 static inline struct sdhci_pxa_platdata *pxav3_get_mmc_pdata(struct device *dev)
0366 {
0367     return NULL;
0368 }
0369 #endif
0370 
0371 static int sdhci_pxav3_probe(struct platform_device *pdev)
0372 {
0373     struct sdhci_pltfm_host *pltfm_host;
0374     struct sdhci_pxa_platdata *pdata = pdev->dev.platform_data;
0375     struct device *dev = &pdev->dev;
0376     struct device_node *np = pdev->dev.of_node;
0377     struct sdhci_host *host = NULL;
0378     struct sdhci_pxa *pxa = NULL;
0379     const struct of_device_id *match;
0380     int ret;
0381 
0382     host = sdhci_pltfm_init(pdev, &sdhci_pxav3_pdata, sizeof(*pxa));
0383     if (IS_ERR(host))
0384         return PTR_ERR(host);
0385 
0386     pltfm_host = sdhci_priv(host);
0387     pxa = sdhci_pltfm_priv(pltfm_host);
0388 
0389     pxa->clk_io = devm_clk_get(dev, "io");
0390     if (IS_ERR(pxa->clk_io))
0391         pxa->clk_io = devm_clk_get(dev, NULL);
0392     if (IS_ERR(pxa->clk_io)) {
0393         dev_err(dev, "failed to get io clock\n");
0394         ret = PTR_ERR(pxa->clk_io);
0395         goto err_clk_get;
0396     }
0397     pltfm_host->clk = pxa->clk_io;
0398     clk_prepare_enable(pxa->clk_io);
0399 
0400     pxa->clk_core = devm_clk_get(dev, "core");
0401     if (!IS_ERR(pxa->clk_core))
0402         clk_prepare_enable(pxa->clk_core);
0403 
0404     /* enable 1/8V DDR capable */
0405     host->mmc->caps |= MMC_CAP_1_8V_DDR;
0406 
0407     if (of_device_is_compatible(np, "marvell,armada-380-sdhci")) {
0408         ret = armada_38x_quirks(pdev, host);
0409         if (ret < 0)
0410             goto err_mbus_win;
0411         ret = mv_conf_mbus_windows(pdev, mv_mbus_dram_info());
0412         if (ret < 0)
0413             goto err_mbus_win;
0414     }
0415 
0416     match = of_match_device(of_match_ptr(sdhci_pxav3_of_match), &pdev->dev);
0417     if (match) {
0418         ret = mmc_of_parse(host->mmc);
0419         if (ret)
0420             goto err_of_parse;
0421         sdhci_get_of_property(pdev);
0422         pdata = pxav3_get_mmc_pdata(dev);
0423         pdev->dev.platform_data = pdata;
0424     } else if (pdata) {
0425         /* on-chip device */
0426         if (pdata->flags & PXA_FLAG_CARD_PERMANENT)
0427             host->mmc->caps |= MMC_CAP_NONREMOVABLE;
0428 
0429         /* If slot design supports 8 bit data, indicate this to MMC. */
0430         if (pdata->flags & PXA_FLAG_SD_8_BIT_CAPABLE_SLOT)
0431             host->mmc->caps |= MMC_CAP_8_BIT_DATA;
0432 
0433         if (pdata->quirks)
0434             host->quirks |= pdata->quirks;
0435         if (pdata->quirks2)
0436             host->quirks2 |= pdata->quirks2;
0437         if (pdata->host_caps)
0438             host->mmc->caps |= pdata->host_caps;
0439         if (pdata->host_caps2)
0440             host->mmc->caps2 |= pdata->host_caps2;
0441         if (pdata->pm_caps)
0442             host->mmc->pm_caps |= pdata->pm_caps;
0443     }
0444 
0445     pm_runtime_get_noresume(&pdev->dev);
0446     pm_runtime_set_active(&pdev->dev);
0447     pm_runtime_set_autosuspend_delay(&pdev->dev, PXAV3_RPM_DELAY_MS);
0448     pm_runtime_use_autosuspend(&pdev->dev);
0449     pm_runtime_enable(&pdev->dev);
0450     pm_suspend_ignore_children(&pdev->dev, 1);
0451 
0452     ret = sdhci_add_host(host);
0453     if (ret)
0454         goto err_add_host;
0455 
0456     if (host->mmc->pm_caps & MMC_PM_WAKE_SDIO_IRQ)
0457         device_init_wakeup(&pdev->dev, 1);
0458 
0459     pm_runtime_put_autosuspend(&pdev->dev);
0460 
0461     return 0;
0462 
0463 err_add_host:
0464     pm_runtime_disable(&pdev->dev);
0465     pm_runtime_put_noidle(&pdev->dev);
0466 err_of_parse:
0467 err_mbus_win:
0468     clk_disable_unprepare(pxa->clk_io);
0469     clk_disable_unprepare(pxa->clk_core);
0470 err_clk_get:
0471     sdhci_pltfm_free(pdev);
0472     return ret;
0473 }
0474 
0475 static int sdhci_pxav3_remove(struct platform_device *pdev)
0476 {
0477     struct sdhci_host *host = platform_get_drvdata(pdev);
0478     struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
0479     struct sdhci_pxa *pxa = sdhci_pltfm_priv(pltfm_host);
0480 
0481     pm_runtime_get_sync(&pdev->dev);
0482     pm_runtime_disable(&pdev->dev);
0483     pm_runtime_put_noidle(&pdev->dev);
0484 
0485     sdhci_remove_host(host, 1);
0486 
0487     clk_disable_unprepare(pxa->clk_io);
0488     clk_disable_unprepare(pxa->clk_core);
0489 
0490     sdhci_pltfm_free(pdev);
0491 
0492     return 0;
0493 }
0494 
0495 #ifdef CONFIG_PM_SLEEP
0496 static int sdhci_pxav3_suspend(struct device *dev)
0497 {
0498     int ret;
0499     struct sdhci_host *host = dev_get_drvdata(dev);
0500 
0501     pm_runtime_get_sync(dev);
0502     if (host->tuning_mode != SDHCI_TUNING_MODE_3)
0503         mmc_retune_needed(host->mmc);
0504     ret = sdhci_suspend_host(host);
0505     pm_runtime_mark_last_busy(dev);
0506     pm_runtime_put_autosuspend(dev);
0507 
0508     return ret;
0509 }
0510 
0511 static int sdhci_pxav3_resume(struct device *dev)
0512 {
0513     int ret;
0514     struct sdhci_host *host = dev_get_drvdata(dev);
0515 
0516     pm_runtime_get_sync(dev);
0517     ret = sdhci_resume_host(host);
0518     pm_runtime_mark_last_busy(dev);
0519     pm_runtime_put_autosuspend(dev);
0520 
0521     return ret;
0522 }
0523 #endif
0524 
0525 #ifdef CONFIG_PM
0526 static int sdhci_pxav3_runtime_suspend(struct device *dev)
0527 {
0528     struct sdhci_host *host = dev_get_drvdata(dev);
0529     struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
0530     struct sdhci_pxa *pxa = sdhci_pltfm_priv(pltfm_host);
0531     int ret;
0532 
0533     ret = sdhci_runtime_suspend_host(host);
0534     if (ret)
0535         return ret;
0536 
0537     if (host->tuning_mode != SDHCI_TUNING_MODE_3)
0538         mmc_retune_needed(host->mmc);
0539 
0540     clk_disable_unprepare(pxa->clk_io);
0541     if (!IS_ERR(pxa->clk_core))
0542         clk_disable_unprepare(pxa->clk_core);
0543 
0544     return 0;
0545 }
0546 
0547 static int sdhci_pxav3_runtime_resume(struct device *dev)
0548 {
0549     struct sdhci_host *host = dev_get_drvdata(dev);
0550     struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
0551     struct sdhci_pxa *pxa = sdhci_pltfm_priv(pltfm_host);
0552 
0553     clk_prepare_enable(pxa->clk_io);
0554     if (!IS_ERR(pxa->clk_core))
0555         clk_prepare_enable(pxa->clk_core);
0556 
0557     return sdhci_runtime_resume_host(host, 0);
0558 }
0559 #endif
0560 
0561 static const struct dev_pm_ops sdhci_pxav3_pmops = {
0562     SET_SYSTEM_SLEEP_PM_OPS(sdhci_pxav3_suspend, sdhci_pxav3_resume)
0563     SET_RUNTIME_PM_OPS(sdhci_pxav3_runtime_suspend,
0564         sdhci_pxav3_runtime_resume, NULL)
0565 };
0566 
0567 static struct platform_driver sdhci_pxav3_driver = {
0568     .driver     = {
0569         .name   = "sdhci-pxav3",
0570         .probe_type = PROBE_PREFER_ASYNCHRONOUS,
0571         .of_match_table = of_match_ptr(sdhci_pxav3_of_match),
0572         .pm = &sdhci_pxav3_pmops,
0573     },
0574     .probe      = sdhci_pxav3_probe,
0575     .remove     = sdhci_pxav3_remove,
0576 };
0577 
0578 module_platform_driver(sdhci_pxav3_driver);
0579 
0580 MODULE_DESCRIPTION("SDHCI driver for pxav3");
0581 MODULE_AUTHOR("Marvell International Ltd.");
0582 MODULE_LICENSE("GPL v2");
0583