195f25efeSWolfram Sang /* 295f25efeSWolfram Sang * Freescale eSDHC i.MX controller driver for the platform bus. 395f25efeSWolfram Sang * 495f25efeSWolfram Sang * derived from the OF-version. 595f25efeSWolfram Sang * 695f25efeSWolfram Sang * Copyright (c) 2010 Pengutronix e.K. 795f25efeSWolfram Sang * Author: Wolfram Sang <w.sang@pengutronix.de> 895f25efeSWolfram Sang * 995f25efeSWolfram Sang * This program is free software; you can redistribute it and/or modify 1095f25efeSWolfram Sang * it under the terms of the GNU General Public License as published by 1195f25efeSWolfram Sang * the Free Software Foundation; either version 2 of the License. 1295f25efeSWolfram Sang */ 1395f25efeSWolfram Sang 1495f25efeSWolfram Sang #include <linux/io.h> 1595f25efeSWolfram Sang #include <linux/delay.h> 1695f25efeSWolfram Sang #include <linux/err.h> 1795f25efeSWolfram Sang #include <linux/clk.h> 180c6d49ceSWolfram Sang #include <linux/gpio.h> 1966506f76SShawn Guo #include <linux/module.h> 20e149860dSRichard Zhu #include <linux/slab.h> 2195f25efeSWolfram Sang #include <linux/mmc/host.h> 2258ac8177SRichard Zhu #include <linux/mmc/mmc.h> 2358ac8177SRichard Zhu #include <linux/mmc/sdio.h> 24abfafc2dSShawn Guo #include <linux/of.h> 25abfafc2dSShawn Guo #include <linux/of_device.h> 26abfafc2dSShawn Guo #include <linux/of_gpio.h> 270c6d49ceSWolfram Sang #include <mach/esdhc.h> 2895f25efeSWolfram Sang #include "sdhci-pltfm.h" 2995f25efeSWolfram Sang #include "sdhci-esdhc.h" 3095f25efeSWolfram Sang 310d58864bSTony Lin #define SDHCI_CTRL_D3CD 0x08 3258ac8177SRichard Zhu /* VENDOR SPEC register */ 3358ac8177SRichard Zhu #define SDHCI_VENDOR_SPEC 0xC0 3458ac8177SRichard Zhu #define SDHCI_VENDOR_SPEC_SDIO_QUIRK 0x00000002 3558ac8177SRichard Zhu 3658ac8177SRichard Zhu /* 3758ac8177SRichard Zhu * The CMDTYPE of the CMD register (offset 0xE) should be set to 3858ac8177SRichard Zhu * "11" when the STOP CMD12 is issued on imx53 to abort one 3958ac8177SRichard Zhu * open ended multi-blk IO. Otherwise the TC INT wouldn't 4058ac8177SRichard Zhu * be generated. 4158ac8177SRichard Zhu * In exact block transfer, the controller doesn't complete the 4258ac8177SRichard Zhu * operations automatically as required at the end of the 4358ac8177SRichard Zhu * transfer and remains on hold if the abort command is not sent. 4458ac8177SRichard Zhu * As a result, the TC flag is not asserted and SW received timeout 4558ac8177SRichard Zhu * exeception. Bit1 of Vendor Spec registor is used to fix it. 4658ac8177SRichard Zhu */ 4758ac8177SRichard Zhu #define ESDHC_FLAG_MULTIBLK_NO_INT (1 << 1) 48e149860dSRichard Zhu 4957ed3314SShawn Guo enum imx_esdhc_type { 5057ed3314SShawn Guo IMX25_ESDHC, 5157ed3314SShawn Guo IMX35_ESDHC, 5257ed3314SShawn Guo IMX51_ESDHC, 5357ed3314SShawn Guo IMX53_ESDHC, 5457ed3314SShawn Guo }; 5557ed3314SShawn Guo 56e149860dSRichard Zhu struct pltfm_imx_data { 57e149860dSRichard Zhu int flags; 58e149860dSRichard Zhu u32 scratchpad; 5957ed3314SShawn Guo enum imx_esdhc_type devtype; 60842afc02SShawn Guo struct esdhc_platform_data boarddata; 61e149860dSRichard Zhu }; 62e149860dSRichard Zhu 6357ed3314SShawn Guo static struct platform_device_id imx_esdhc_devtype[] = { 6457ed3314SShawn Guo { 6557ed3314SShawn Guo .name = "sdhci-esdhc-imx25", 6657ed3314SShawn Guo .driver_data = IMX25_ESDHC, 6757ed3314SShawn Guo }, { 6857ed3314SShawn Guo .name = "sdhci-esdhc-imx35", 6957ed3314SShawn Guo .driver_data = IMX35_ESDHC, 7057ed3314SShawn Guo }, { 7157ed3314SShawn Guo .name = "sdhci-esdhc-imx51", 7257ed3314SShawn Guo .driver_data = IMX51_ESDHC, 7357ed3314SShawn Guo }, { 7457ed3314SShawn Guo .name = "sdhci-esdhc-imx53", 7557ed3314SShawn Guo .driver_data = IMX53_ESDHC, 7657ed3314SShawn Guo }, { 7757ed3314SShawn Guo /* sentinel */ 7857ed3314SShawn Guo } 7957ed3314SShawn Guo }; 8057ed3314SShawn Guo MODULE_DEVICE_TABLE(platform, imx_esdhc_devtype); 8157ed3314SShawn Guo 82abfafc2dSShawn Guo static const struct of_device_id imx_esdhc_dt_ids[] = { 83abfafc2dSShawn Guo { .compatible = "fsl,imx25-esdhc", .data = &imx_esdhc_devtype[IMX25_ESDHC], }, 84abfafc2dSShawn Guo { .compatible = "fsl,imx35-esdhc", .data = &imx_esdhc_devtype[IMX35_ESDHC], }, 85abfafc2dSShawn Guo { .compatible = "fsl,imx51-esdhc", .data = &imx_esdhc_devtype[IMX51_ESDHC], }, 86abfafc2dSShawn Guo { .compatible = "fsl,imx53-esdhc", .data = &imx_esdhc_devtype[IMX53_ESDHC], }, 87abfafc2dSShawn Guo { /* sentinel */ } 88abfafc2dSShawn Guo }; 89abfafc2dSShawn Guo MODULE_DEVICE_TABLE(of, imx_esdhc_dt_ids); 90abfafc2dSShawn Guo 9157ed3314SShawn Guo static inline int is_imx25_esdhc(struct pltfm_imx_data *data) 9257ed3314SShawn Guo { 9357ed3314SShawn Guo return data->devtype == IMX25_ESDHC; 9457ed3314SShawn Guo } 9557ed3314SShawn Guo 9657ed3314SShawn Guo static inline int is_imx35_esdhc(struct pltfm_imx_data *data) 9757ed3314SShawn Guo { 9857ed3314SShawn Guo return data->devtype == IMX35_ESDHC; 9957ed3314SShawn Guo } 10057ed3314SShawn Guo 10157ed3314SShawn Guo static inline int is_imx51_esdhc(struct pltfm_imx_data *data) 10257ed3314SShawn Guo { 10357ed3314SShawn Guo return data->devtype == IMX51_ESDHC; 10457ed3314SShawn Guo } 10557ed3314SShawn Guo 10657ed3314SShawn Guo static inline int is_imx53_esdhc(struct pltfm_imx_data *data) 10757ed3314SShawn Guo { 10857ed3314SShawn Guo return data->devtype == IMX53_ESDHC; 10957ed3314SShawn Guo } 11057ed3314SShawn Guo 11195f25efeSWolfram Sang static inline void esdhc_clrset_le(struct sdhci_host *host, u32 mask, u32 val, int reg) 11295f25efeSWolfram Sang { 11395f25efeSWolfram Sang void __iomem *base = host->ioaddr + (reg & ~0x3); 11495f25efeSWolfram Sang u32 shift = (reg & 0x3) * 8; 11595f25efeSWolfram Sang 11695f25efeSWolfram Sang writel(((readl(base) & ~(mask << shift)) | (val << shift)), base); 11795f25efeSWolfram Sang } 11895f25efeSWolfram Sang 1197e29c306SWolfram Sang static u32 esdhc_readl_le(struct sdhci_host *host, int reg) 1207e29c306SWolfram Sang { 121842afc02SShawn Guo struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); 122842afc02SShawn Guo struct pltfm_imx_data *imx_data = pltfm_host->priv; 123842afc02SShawn Guo struct esdhc_platform_data *boarddata = &imx_data->boarddata; 1247e29c306SWolfram Sang 125913413c3SShawn Guo /* fake CARD_PRESENT flag */ 126913413c3SShawn Guo u32 val = readl(host->ioaddr + reg); 127913413c3SShawn Guo 128913413c3SShawn Guo if (unlikely((reg == SDHCI_PRESENT_STATE) 129913413c3SShawn Guo && gpio_is_valid(boarddata->cd_gpio))) { 130913413c3SShawn Guo if (gpio_get_value(boarddata->cd_gpio)) 1317e29c306SWolfram Sang /* no card, if a valid gpio says so... */ 132803862a6SShawn Guo val &= ~SDHCI_CARD_PRESENT; 1337e29c306SWolfram Sang else 1347e29c306SWolfram Sang /* ... in all other cases assume card is present */ 1357e29c306SWolfram Sang val |= SDHCI_CARD_PRESENT; 1367e29c306SWolfram Sang } 1377e29c306SWolfram Sang 1387e29c306SWolfram Sang return val; 1397e29c306SWolfram Sang } 1407e29c306SWolfram Sang 1417e29c306SWolfram Sang static void esdhc_writel_le(struct sdhci_host *host, u32 val, int reg) 1427e29c306SWolfram Sang { 143e149860dSRichard Zhu struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); 144e149860dSRichard Zhu struct pltfm_imx_data *imx_data = pltfm_host->priv; 145842afc02SShawn Guo struct esdhc_platform_data *boarddata = &imx_data->boarddata; 1460d58864bSTony Lin u32 data; 147e149860dSRichard Zhu 1480d58864bSTony Lin if (unlikely(reg == SDHCI_INT_ENABLE || reg == SDHCI_SIGNAL_ENABLE)) { 1490d58864bSTony Lin if (boarddata->cd_type == ESDHC_CD_GPIO) 1507e29c306SWolfram Sang /* 1510d58864bSTony Lin * These interrupts won't work with a custom 1520d58864bSTony Lin * card_detect gpio (only applied to mx25/35) 1537e29c306SWolfram Sang */ 1547e29c306SWolfram Sang val &= ~(SDHCI_INT_CARD_REMOVE | SDHCI_INT_CARD_INSERT); 1557e29c306SWolfram Sang 1560d58864bSTony Lin if (val & SDHCI_INT_CARD_INT) { 1570d58864bSTony Lin /* 1580d58864bSTony Lin * Clear and then set D3CD bit to avoid missing the 1590d58864bSTony Lin * card interrupt. This is a eSDHC controller problem 1600d58864bSTony Lin * so we need to apply the following workaround: clear 1610d58864bSTony Lin * and set D3CD bit will make eSDHC re-sample the card 1620d58864bSTony Lin * interrupt. In case a card interrupt was lost, 1630d58864bSTony Lin * re-sample it by the following steps. 1640d58864bSTony Lin */ 1650d58864bSTony Lin data = readl(host->ioaddr + SDHCI_HOST_CONTROL); 1660d58864bSTony Lin data &= ~SDHCI_CTRL_D3CD; 1670d58864bSTony Lin writel(data, host->ioaddr + SDHCI_HOST_CONTROL); 1680d58864bSTony Lin data |= SDHCI_CTRL_D3CD; 1690d58864bSTony Lin writel(data, host->ioaddr + SDHCI_HOST_CONTROL); 1700d58864bSTony Lin } 1710d58864bSTony Lin } 1720d58864bSTony Lin 17358ac8177SRichard Zhu if (unlikely((imx_data->flags & ESDHC_FLAG_MULTIBLK_NO_INT) 17458ac8177SRichard Zhu && (reg == SDHCI_INT_STATUS) 17558ac8177SRichard Zhu && (val & SDHCI_INT_DATA_END))) { 17658ac8177SRichard Zhu u32 v; 17758ac8177SRichard Zhu v = readl(host->ioaddr + SDHCI_VENDOR_SPEC); 17858ac8177SRichard Zhu v &= ~SDHCI_VENDOR_SPEC_SDIO_QUIRK; 17958ac8177SRichard Zhu writel(v, host->ioaddr + SDHCI_VENDOR_SPEC); 18058ac8177SRichard Zhu } 18158ac8177SRichard Zhu 1827e29c306SWolfram Sang writel(val, host->ioaddr + reg); 1837e29c306SWolfram Sang } 1847e29c306SWolfram Sang 18595f25efeSWolfram Sang static u16 esdhc_readw_le(struct sdhci_host *host, int reg) 18695f25efeSWolfram Sang { 18795f25efeSWolfram Sang if (unlikely(reg == SDHCI_HOST_VERSION)) 18895f25efeSWolfram Sang reg ^= 2; 18995f25efeSWolfram Sang 19095f25efeSWolfram Sang return readw(host->ioaddr + reg); 19195f25efeSWolfram Sang } 19295f25efeSWolfram Sang 19395f25efeSWolfram Sang static void esdhc_writew_le(struct sdhci_host *host, u16 val, int reg) 19495f25efeSWolfram Sang { 19595f25efeSWolfram Sang struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); 196e149860dSRichard Zhu struct pltfm_imx_data *imx_data = pltfm_host->priv; 19795f25efeSWolfram Sang 19895f25efeSWolfram Sang switch (reg) { 19995f25efeSWolfram Sang case SDHCI_TRANSFER_MODE: 20095f25efeSWolfram Sang /* 20195f25efeSWolfram Sang * Postpone this write, we must do it together with a 20295f25efeSWolfram Sang * command write that is down below. 20395f25efeSWolfram Sang */ 20458ac8177SRichard Zhu if ((imx_data->flags & ESDHC_FLAG_MULTIBLK_NO_INT) 20558ac8177SRichard Zhu && (host->cmd->opcode == SD_IO_RW_EXTENDED) 20658ac8177SRichard Zhu && (host->cmd->data->blocks > 1) 20758ac8177SRichard Zhu && (host->cmd->data->flags & MMC_DATA_READ)) { 20858ac8177SRichard Zhu u32 v; 20958ac8177SRichard Zhu v = readl(host->ioaddr + SDHCI_VENDOR_SPEC); 21058ac8177SRichard Zhu v |= SDHCI_VENDOR_SPEC_SDIO_QUIRK; 21158ac8177SRichard Zhu writel(v, host->ioaddr + SDHCI_VENDOR_SPEC); 21258ac8177SRichard Zhu } 213e149860dSRichard Zhu imx_data->scratchpad = val; 21495f25efeSWolfram Sang return; 21595f25efeSWolfram Sang case SDHCI_COMMAND: 21658ac8177SRichard Zhu if ((host->cmd->opcode == MMC_STOP_TRANSMISSION) 21758ac8177SRichard Zhu && (imx_data->flags & ESDHC_FLAG_MULTIBLK_NO_INT)) 21858ac8177SRichard Zhu val |= SDHCI_CMD_ABORTCMD; 219e149860dSRichard Zhu writel(val << 16 | imx_data->scratchpad, 22095f25efeSWolfram Sang host->ioaddr + SDHCI_TRANSFER_MODE); 22195f25efeSWolfram Sang return; 22295f25efeSWolfram Sang case SDHCI_BLOCK_SIZE: 22395f25efeSWolfram Sang val &= ~SDHCI_MAKE_BLKSZ(0x7, 0); 22495f25efeSWolfram Sang break; 22595f25efeSWolfram Sang } 22695f25efeSWolfram Sang esdhc_clrset_le(host, 0xffff, val, reg); 22795f25efeSWolfram Sang } 22895f25efeSWolfram Sang 22995f25efeSWolfram Sang static void esdhc_writeb_le(struct sdhci_host *host, u8 val, int reg) 23095f25efeSWolfram Sang { 23195f25efeSWolfram Sang u32 new_val; 23295f25efeSWolfram Sang 23395f25efeSWolfram Sang switch (reg) { 23495f25efeSWolfram Sang case SDHCI_POWER_CONTROL: 23595f25efeSWolfram Sang /* 23695f25efeSWolfram Sang * FSL put some DMA bits here 23795f25efeSWolfram Sang * If your board has a regulator, code should be here 23895f25efeSWolfram Sang */ 23995f25efeSWolfram Sang return; 24095f25efeSWolfram Sang case SDHCI_HOST_CONTROL: 2410d58864bSTony Lin /* FSL messed up here, so we can just keep those three */ 2420d58864bSTony Lin new_val = val & (SDHCI_CTRL_LED | \ 2430d58864bSTony Lin SDHCI_CTRL_4BITBUS | \ 2440d58864bSTony Lin SDHCI_CTRL_D3CD); 24595f25efeSWolfram Sang /* ensure the endianess */ 24695f25efeSWolfram Sang new_val |= ESDHC_HOST_CONTROL_LE; 24795f25efeSWolfram Sang /* DMA mode bits are shifted */ 24895f25efeSWolfram Sang new_val |= (val & SDHCI_CTRL_DMA_MASK) << 5; 24995f25efeSWolfram Sang 25095f25efeSWolfram Sang esdhc_clrset_le(host, 0xffff, new_val, reg); 25195f25efeSWolfram Sang return; 25295f25efeSWolfram Sang } 25395f25efeSWolfram Sang esdhc_clrset_le(host, 0xff, val, reg); 254913413c3SShawn Guo 255913413c3SShawn Guo /* 256913413c3SShawn Guo * The esdhc has a design violation to SDHC spec which tells 257913413c3SShawn Guo * that software reset should not affect card detection circuit. 258913413c3SShawn Guo * But esdhc clears its SYSCTL register bits [0..2] during the 259913413c3SShawn Guo * software reset. This will stop those clocks that card detection 260913413c3SShawn Guo * circuit relies on. To work around it, we turn the clocks on back 261913413c3SShawn Guo * to keep card detection circuit functional. 262913413c3SShawn Guo */ 263913413c3SShawn Guo if ((reg == SDHCI_SOFTWARE_RESET) && (val & 1)) 264913413c3SShawn Guo esdhc_clrset_le(host, 0x7, 0x7, ESDHC_SYSTEM_CONTROL); 26595f25efeSWolfram Sang } 26695f25efeSWolfram Sang 26795f25efeSWolfram Sang static unsigned int esdhc_pltfm_get_max_clock(struct sdhci_host *host) 26895f25efeSWolfram Sang { 26995f25efeSWolfram Sang struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); 27095f25efeSWolfram Sang 27195f25efeSWolfram Sang return clk_get_rate(pltfm_host->clk); 27295f25efeSWolfram Sang } 27395f25efeSWolfram Sang 27495f25efeSWolfram Sang static unsigned int esdhc_pltfm_get_min_clock(struct sdhci_host *host) 27595f25efeSWolfram Sang { 27695f25efeSWolfram Sang struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); 27795f25efeSWolfram Sang 27895f25efeSWolfram Sang return clk_get_rate(pltfm_host->clk) / 256 / 16; 27995f25efeSWolfram Sang } 28095f25efeSWolfram Sang 281913413c3SShawn Guo static unsigned int esdhc_pltfm_get_ro(struct sdhci_host *host) 282913413c3SShawn Guo { 283842afc02SShawn Guo struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); 284842afc02SShawn Guo struct pltfm_imx_data *imx_data = pltfm_host->priv; 285842afc02SShawn Guo struct esdhc_platform_data *boarddata = &imx_data->boarddata; 286913413c3SShawn Guo 287913413c3SShawn Guo switch (boarddata->wp_type) { 288913413c3SShawn Guo case ESDHC_WP_GPIO: 289913413c3SShawn Guo if (gpio_is_valid(boarddata->wp_gpio)) 290913413c3SShawn Guo return gpio_get_value(boarddata->wp_gpio); 291913413c3SShawn Guo case ESDHC_WP_CONTROLLER: 292913413c3SShawn Guo return !(readl(host->ioaddr + SDHCI_PRESENT_STATE) & 293913413c3SShawn Guo SDHCI_WRITE_PROTECT); 294913413c3SShawn Guo case ESDHC_WP_NONE: 295913413c3SShawn Guo break; 296913413c3SShawn Guo } 297913413c3SShawn Guo 298913413c3SShawn Guo return -ENOSYS; 299913413c3SShawn Guo } 300913413c3SShawn Guo 3010c6d49ceSWolfram Sang static struct sdhci_ops sdhci_esdhc_ops = { 302e149860dSRichard Zhu .read_l = esdhc_readl_le, 3030c6d49ceSWolfram Sang .read_w = esdhc_readw_le, 304e149860dSRichard Zhu .write_l = esdhc_writel_le, 3050c6d49ceSWolfram Sang .write_w = esdhc_writew_le, 3060c6d49ceSWolfram Sang .write_b = esdhc_writeb_le, 3070c6d49ceSWolfram Sang .set_clock = esdhc_set_clock, 3080c6d49ceSWolfram Sang .get_max_clock = esdhc_pltfm_get_max_clock, 3090c6d49ceSWolfram Sang .get_min_clock = esdhc_pltfm_get_min_clock, 310913413c3SShawn Guo .get_ro = esdhc_pltfm_get_ro, 3110c6d49ceSWolfram Sang }; 3120c6d49ceSWolfram Sang 31385d6509dSShawn Guo static struct sdhci_pltfm_data sdhci_esdhc_imx_pdata = { 31485d6509dSShawn Guo .quirks = ESDHC_DEFAULT_QUIRKS | SDHCI_QUIRK_BROKEN_ADMA 31585d6509dSShawn Guo | SDHCI_QUIRK_BROKEN_CARD_DETECTION, 31685d6509dSShawn Guo /* ADMA has issues. Might be fixable */ 31785d6509dSShawn Guo .ops = &sdhci_esdhc_ops, 31885d6509dSShawn Guo }; 31985d6509dSShawn Guo 3207e29c306SWolfram Sang static irqreturn_t cd_irq(int irq, void *data) 3217e29c306SWolfram Sang { 3227e29c306SWolfram Sang struct sdhci_host *sdhost = (struct sdhci_host *)data; 3237e29c306SWolfram Sang 3247e29c306SWolfram Sang tasklet_schedule(&sdhost->card_tasklet); 3257e29c306SWolfram Sang return IRQ_HANDLED; 3267e29c306SWolfram Sang }; 3277e29c306SWolfram Sang 328abfafc2dSShawn Guo #ifdef CONFIG_OF 329abfafc2dSShawn Guo static int __devinit 330abfafc2dSShawn Guo sdhci_esdhc_imx_probe_dt(struct platform_device *pdev, 331abfafc2dSShawn Guo struct esdhc_platform_data *boarddata) 332abfafc2dSShawn Guo { 333abfafc2dSShawn Guo struct device_node *np = pdev->dev.of_node; 334abfafc2dSShawn Guo 335abfafc2dSShawn Guo if (!np) 336abfafc2dSShawn Guo return -ENODEV; 337abfafc2dSShawn Guo 338abfafc2dSShawn Guo if (of_get_property(np, "fsl,card-wired", NULL)) 339abfafc2dSShawn Guo boarddata->cd_type = ESDHC_CD_PERMANENT; 340abfafc2dSShawn Guo 341abfafc2dSShawn Guo if (of_get_property(np, "fsl,cd-controller", NULL)) 342abfafc2dSShawn Guo boarddata->cd_type = ESDHC_CD_CONTROLLER; 343abfafc2dSShawn Guo 344abfafc2dSShawn Guo if (of_get_property(np, "fsl,wp-controller", NULL)) 345abfafc2dSShawn Guo boarddata->wp_type = ESDHC_WP_CONTROLLER; 346abfafc2dSShawn Guo 347abfafc2dSShawn Guo boarddata->cd_gpio = of_get_named_gpio(np, "cd-gpios", 0); 348abfafc2dSShawn Guo if (gpio_is_valid(boarddata->cd_gpio)) 349abfafc2dSShawn Guo boarddata->cd_type = ESDHC_CD_GPIO; 350abfafc2dSShawn Guo 351abfafc2dSShawn Guo boarddata->wp_gpio = of_get_named_gpio(np, "wp-gpios", 0); 352abfafc2dSShawn Guo if (gpio_is_valid(boarddata->wp_gpio)) 353abfafc2dSShawn Guo boarddata->wp_type = ESDHC_WP_GPIO; 354abfafc2dSShawn Guo 355abfafc2dSShawn Guo return 0; 356abfafc2dSShawn Guo } 357abfafc2dSShawn Guo #else 358abfafc2dSShawn Guo static inline int 359abfafc2dSShawn Guo sdhci_esdhc_imx_probe_dt(struct platform_device *pdev, 360abfafc2dSShawn Guo struct esdhc_platform_data *boarddata) 361abfafc2dSShawn Guo { 362abfafc2dSShawn Guo return -ENODEV; 363abfafc2dSShawn Guo } 364abfafc2dSShawn Guo #endif 365abfafc2dSShawn Guo 36685d6509dSShawn Guo static int __devinit sdhci_esdhc_imx_probe(struct platform_device *pdev) 36795f25efeSWolfram Sang { 368abfafc2dSShawn Guo const struct of_device_id *of_id = 369abfafc2dSShawn Guo of_match_device(imx_esdhc_dt_ids, &pdev->dev); 37085d6509dSShawn Guo struct sdhci_pltfm_host *pltfm_host; 37185d6509dSShawn Guo struct sdhci_host *host; 37285d6509dSShawn Guo struct esdhc_platform_data *boarddata; 37395f25efeSWolfram Sang struct clk *clk; 3740c6d49ceSWolfram Sang int err; 375e149860dSRichard Zhu struct pltfm_imx_data *imx_data; 37695f25efeSWolfram Sang 37785d6509dSShawn Guo host = sdhci_pltfm_init(pdev, &sdhci_esdhc_imx_pdata); 37885d6509dSShawn Guo if (IS_ERR(host)) 37985d6509dSShawn Guo return PTR_ERR(host); 38085d6509dSShawn Guo 38185d6509dSShawn Guo pltfm_host = sdhci_priv(host); 38285d6509dSShawn Guo 38385d6509dSShawn Guo imx_data = kzalloc(sizeof(struct pltfm_imx_data), GFP_KERNEL); 384abfafc2dSShawn Guo if (!imx_data) { 385abfafc2dSShawn Guo err = -ENOMEM; 386abfafc2dSShawn Guo goto err_imx_data; 387abfafc2dSShawn Guo } 38857ed3314SShawn Guo 389abfafc2dSShawn Guo if (of_id) 390abfafc2dSShawn Guo pdev->id_entry = of_id->data; 39157ed3314SShawn Guo imx_data->devtype = pdev->id_entry->driver_data; 39285d6509dSShawn Guo pltfm_host->priv = imx_data; 39385d6509dSShawn Guo 39495f25efeSWolfram Sang clk = clk_get(mmc_dev(host->mmc), NULL); 39595f25efeSWolfram Sang if (IS_ERR(clk)) { 39695f25efeSWolfram Sang dev_err(mmc_dev(host->mmc), "clk err\n"); 39785d6509dSShawn Guo err = PTR_ERR(clk); 39885d6509dSShawn Guo goto err_clk_get; 39995f25efeSWolfram Sang } 40095f25efeSWolfram Sang clk_enable(clk); 40195f25efeSWolfram Sang pltfm_host->clk = clk; 40295f25efeSWolfram Sang 40357ed3314SShawn Guo if (!is_imx25_esdhc(imx_data)) 40437865fe9SEric Bénard host->quirks |= SDHCI_QUIRK_BROKEN_TIMEOUT_VAL; 40537865fe9SEric Bénard 40657ed3314SShawn Guo if (is_imx25_esdhc(imx_data) || is_imx35_esdhc(imx_data)) 4070c6d49ceSWolfram Sang /* Fix errata ENGcm07207 present on i.MX25 and i.MX35 */ 40816a790bcSEric Bénard host->quirks |= SDHCI_QUIRK_NO_MULTIBLOCK; 4090c6d49ceSWolfram Sang 41057ed3314SShawn Guo if (is_imx53_esdhc(imx_data)) 41158ac8177SRichard Zhu imx_data->flags |= ESDHC_FLAG_MULTIBLK_NO_INT; 41258ac8177SRichard Zhu 413abfafc2dSShawn Guo boarddata = &imx_data->boarddata; 414abfafc2dSShawn Guo if (sdhci_esdhc_imx_probe_dt(pdev, boarddata) < 0) { 415842afc02SShawn Guo if (!host->mmc->parent->platform_data) { 416913413c3SShawn Guo dev_err(mmc_dev(host->mmc), "no board data!\n"); 417913413c3SShawn Guo err = -EINVAL; 418913413c3SShawn Guo goto no_board_data; 419913413c3SShawn Guo } 420842afc02SShawn Guo imx_data->boarddata = *((struct esdhc_platform_data *) 421842afc02SShawn Guo host->mmc->parent->platform_data); 422abfafc2dSShawn Guo } 423913413c3SShawn Guo 424913413c3SShawn Guo /* write_protect */ 425913413c3SShawn Guo if (boarddata->wp_type == ESDHC_WP_GPIO) { 4260c6d49ceSWolfram Sang err = gpio_request_one(boarddata->wp_gpio, GPIOF_IN, "ESDHC_WP"); 4270c6d49ceSWolfram Sang if (err) { 4280c6d49ceSWolfram Sang dev_warn(mmc_dev(host->mmc), 4290c6d49ceSWolfram Sang "no write-protect pin available!\n"); 430913413c3SShawn Guo boarddata->wp_gpio = -EINVAL; 431913413c3SShawn Guo } 432913413c3SShawn Guo } else { 433913413c3SShawn Guo boarddata->wp_gpio = -EINVAL; 4340c6d49ceSWolfram Sang } 4357e29c306SWolfram Sang 436913413c3SShawn Guo /* card_detect */ 437913413c3SShawn Guo if (boarddata->cd_type != ESDHC_CD_GPIO) 438913413c3SShawn Guo boarddata->cd_gpio = -EINVAL; 439913413c3SShawn Guo 440913413c3SShawn Guo switch (boarddata->cd_type) { 441913413c3SShawn Guo case ESDHC_CD_GPIO: 4427e29c306SWolfram Sang err = gpio_request_one(boarddata->cd_gpio, GPIOF_IN, "ESDHC_CD"); 4437e29c306SWolfram Sang if (err) { 444913413c3SShawn Guo dev_err(mmc_dev(host->mmc), 4457e29c306SWolfram Sang "no card-detect pin available!\n"); 4467e29c306SWolfram Sang goto no_card_detect_pin; 4470c6d49ceSWolfram Sang } 44816a790bcSEric Bénard 4497e29c306SWolfram Sang err = request_irq(gpio_to_irq(boarddata->cd_gpio), cd_irq, 4507e29c306SWolfram Sang IRQF_TRIGGER_FALLING | IRQF_TRIGGER_RISING, 4517e29c306SWolfram Sang mmc_hostname(host->mmc), host); 4527e29c306SWolfram Sang if (err) { 453913413c3SShawn Guo dev_err(mmc_dev(host->mmc), "request irq error\n"); 4547e29c306SWolfram Sang goto no_card_detect_irq; 4557e29c306SWolfram Sang } 456913413c3SShawn Guo /* fall through */ 4577e29c306SWolfram Sang 458913413c3SShawn Guo case ESDHC_CD_CONTROLLER: 459913413c3SShawn Guo /* we have a working card_detect back */ 4607e29c306SWolfram Sang host->quirks &= ~SDHCI_QUIRK_BROKEN_CARD_DETECTION; 461913413c3SShawn Guo break; 462913413c3SShawn Guo 463913413c3SShawn Guo case ESDHC_CD_PERMANENT: 464913413c3SShawn Guo host->mmc->caps = MMC_CAP_NONREMOVABLE; 465913413c3SShawn Guo break; 466913413c3SShawn Guo 467913413c3SShawn Guo case ESDHC_CD_NONE: 468913413c3SShawn Guo break; 4697e29c306SWolfram Sang } 4707e29c306SWolfram Sang 47185d6509dSShawn Guo err = sdhci_add_host(host); 47285d6509dSShawn Guo if (err) 47385d6509dSShawn Guo goto err_add_host; 47485d6509dSShawn Guo 4757e29c306SWolfram Sang return 0; 4767e29c306SWolfram Sang 47785d6509dSShawn Guo err_add_host: 478913413c3SShawn Guo if (gpio_is_valid(boarddata->cd_gpio)) 479913413c3SShawn Guo free_irq(gpio_to_irq(boarddata->cd_gpio), host); 480913413c3SShawn Guo no_card_detect_irq: 481913413c3SShawn Guo if (gpio_is_valid(boarddata->cd_gpio)) 482913413c3SShawn Guo gpio_free(boarddata->cd_gpio); 483913413c3SShawn Guo if (gpio_is_valid(boarddata->wp_gpio)) 484913413c3SShawn Guo gpio_free(boarddata->wp_gpio); 485913413c3SShawn Guo no_card_detect_pin: 486913413c3SShawn Guo no_board_data: 48785d6509dSShawn Guo clk_disable(pltfm_host->clk); 48885d6509dSShawn Guo clk_put(pltfm_host->clk); 48985d6509dSShawn Guo err_clk_get: 490913413c3SShawn Guo kfree(imx_data); 491abfafc2dSShawn Guo err_imx_data: 49285d6509dSShawn Guo sdhci_pltfm_free(pdev); 49385d6509dSShawn Guo return err; 49495f25efeSWolfram Sang } 49595f25efeSWolfram Sang 49685d6509dSShawn Guo static int __devexit sdhci_esdhc_imx_remove(struct platform_device *pdev) 49795f25efeSWolfram Sang { 49885d6509dSShawn Guo struct sdhci_host *host = platform_get_drvdata(pdev); 49995f25efeSWolfram Sang struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); 500e149860dSRichard Zhu struct pltfm_imx_data *imx_data = pltfm_host->priv; 501842afc02SShawn Guo struct esdhc_platform_data *boarddata = &imx_data->boarddata; 50285d6509dSShawn Guo int dead = (readl(host->ioaddr + SDHCI_INT_STATUS) == 0xffffffff); 50385d6509dSShawn Guo 50485d6509dSShawn Guo sdhci_remove_host(host, dead); 5050c6d49ceSWolfram Sang 506913413c3SShawn Guo if (gpio_is_valid(boarddata->wp_gpio)) 5070c6d49ceSWolfram Sang gpio_free(boarddata->wp_gpio); 50895f25efeSWolfram Sang 509913413c3SShawn Guo if (gpio_is_valid(boarddata->cd_gpio)) { 5107e29c306SWolfram Sang free_irq(gpio_to_irq(boarddata->cd_gpio), host); 511913413c3SShawn Guo gpio_free(boarddata->cd_gpio); 5127e29c306SWolfram Sang } 5137e29c306SWolfram Sang 51495f25efeSWolfram Sang clk_disable(pltfm_host->clk); 51595f25efeSWolfram Sang clk_put(pltfm_host->clk); 516e149860dSRichard Zhu kfree(imx_data); 51785d6509dSShawn Guo 51885d6509dSShawn Guo sdhci_pltfm_free(pdev); 51985d6509dSShawn Guo 52085d6509dSShawn Guo return 0; 52195f25efeSWolfram Sang } 52295f25efeSWolfram Sang 52385d6509dSShawn Guo static struct platform_driver sdhci_esdhc_imx_driver = { 52485d6509dSShawn Guo .driver = { 52585d6509dSShawn Guo .name = "sdhci-esdhc-imx", 52685d6509dSShawn Guo .owner = THIS_MODULE, 527abfafc2dSShawn Guo .of_match_table = imx_esdhc_dt_ids, 52885d6509dSShawn Guo }, 52957ed3314SShawn Guo .id_table = imx_esdhc_devtype, 53085d6509dSShawn Guo .probe = sdhci_esdhc_imx_probe, 53185d6509dSShawn Guo .remove = __devexit_p(sdhci_esdhc_imx_remove), 53285d6509dSShawn Guo #ifdef CONFIG_PM 53385d6509dSShawn Guo .suspend = sdhci_pltfm_suspend, 53485d6509dSShawn Guo .resume = sdhci_pltfm_resume, 53585d6509dSShawn Guo #endif 53695f25efeSWolfram Sang }; 53785d6509dSShawn Guo 53885d6509dSShawn Guo static int __init sdhci_esdhc_imx_init(void) 53985d6509dSShawn Guo { 54085d6509dSShawn Guo return platform_driver_register(&sdhci_esdhc_imx_driver); 54185d6509dSShawn Guo } 54285d6509dSShawn Guo module_init(sdhci_esdhc_imx_init); 54385d6509dSShawn Guo 54485d6509dSShawn Guo static void __exit sdhci_esdhc_imx_exit(void) 54585d6509dSShawn Guo { 54685d6509dSShawn Guo platform_driver_unregister(&sdhci_esdhc_imx_driver); 54785d6509dSShawn Guo } 54885d6509dSShawn Guo module_exit(sdhci_esdhc_imx_exit); 54985d6509dSShawn Guo 55085d6509dSShawn Guo MODULE_DESCRIPTION("SDHCI driver for Freescale i.MX eSDHC"); 55185d6509dSShawn Guo MODULE_AUTHOR("Wolfram Sang <w.sang@pengutronix.de>"); 55285d6509dSShawn Guo MODULE_LICENSE("GPL v2"); 553