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> 19e149860dSRichard Zhu #include <linux/slab.h> 2095f25efeSWolfram Sang #include <linux/mmc/host.h> 2158ac8177SRichard Zhu #include <linux/mmc/mmc.h> 2258ac8177SRichard Zhu #include <linux/mmc/sdio.h> 23abfafc2dSShawn Guo #include <linux/of.h> 24abfafc2dSShawn Guo #include <linux/of_device.h> 25abfafc2dSShawn Guo #include <linux/of_gpio.h> 260c6d49ceSWolfram Sang #include <mach/esdhc.h> 2795f25efeSWolfram Sang #include "sdhci-pltfm.h" 2895f25efeSWolfram Sang #include "sdhci-esdhc.h" 2995f25efeSWolfram Sang 300d58864bSTony Lin #define SDHCI_CTRL_D3CD 0x08 3158ac8177SRichard Zhu /* VENDOR SPEC register */ 3258ac8177SRichard Zhu #define SDHCI_VENDOR_SPEC 0xC0 3358ac8177SRichard Zhu #define SDHCI_VENDOR_SPEC_SDIO_QUIRK 0x00000002 3458ac8177SRichard Zhu 3558ac8177SRichard Zhu /* 3658ac8177SRichard Zhu * The CMDTYPE of the CMD register (offset 0xE) should be set to 3758ac8177SRichard Zhu * "11" when the STOP CMD12 is issued on imx53 to abort one 3858ac8177SRichard Zhu * open ended multi-blk IO. Otherwise the TC INT wouldn't 3958ac8177SRichard Zhu * be generated. 4058ac8177SRichard Zhu * In exact block transfer, the controller doesn't complete the 4158ac8177SRichard Zhu * operations automatically as required at the end of the 4258ac8177SRichard Zhu * transfer and remains on hold if the abort command is not sent. 4358ac8177SRichard Zhu * As a result, the TC flag is not asserted and SW received timeout 4458ac8177SRichard Zhu * exeception. Bit1 of Vendor Spec registor is used to fix it. 4558ac8177SRichard Zhu */ 4658ac8177SRichard Zhu #define ESDHC_FLAG_MULTIBLK_NO_INT (1 << 1) 47e149860dSRichard Zhu 4857ed3314SShawn Guo enum imx_esdhc_type { 4957ed3314SShawn Guo IMX25_ESDHC, 5057ed3314SShawn Guo IMX35_ESDHC, 5157ed3314SShawn Guo IMX51_ESDHC, 5257ed3314SShawn Guo IMX53_ESDHC, 5357ed3314SShawn Guo }; 5457ed3314SShawn Guo 55e149860dSRichard Zhu struct pltfm_imx_data { 56e149860dSRichard Zhu int flags; 57e149860dSRichard Zhu u32 scratchpad; 5857ed3314SShawn Guo enum imx_esdhc_type devtype; 59842afc02SShawn Guo struct esdhc_platform_data boarddata; 60e149860dSRichard Zhu }; 61e149860dSRichard Zhu 6257ed3314SShawn Guo static struct platform_device_id imx_esdhc_devtype[] = { 6357ed3314SShawn Guo { 6457ed3314SShawn Guo .name = "sdhci-esdhc-imx25", 6557ed3314SShawn Guo .driver_data = IMX25_ESDHC, 6657ed3314SShawn Guo }, { 6757ed3314SShawn Guo .name = "sdhci-esdhc-imx35", 6857ed3314SShawn Guo .driver_data = IMX35_ESDHC, 6957ed3314SShawn Guo }, { 7057ed3314SShawn Guo .name = "sdhci-esdhc-imx51", 7157ed3314SShawn Guo .driver_data = IMX51_ESDHC, 7257ed3314SShawn Guo }, { 7357ed3314SShawn Guo .name = "sdhci-esdhc-imx53", 7457ed3314SShawn Guo .driver_data = IMX53_ESDHC, 7557ed3314SShawn Guo }, { 7657ed3314SShawn Guo /* sentinel */ 7757ed3314SShawn Guo } 7857ed3314SShawn Guo }; 7957ed3314SShawn Guo MODULE_DEVICE_TABLE(platform, imx_esdhc_devtype); 8057ed3314SShawn Guo 81abfafc2dSShawn Guo static const struct of_device_id imx_esdhc_dt_ids[] = { 82abfafc2dSShawn Guo { .compatible = "fsl,imx25-esdhc", .data = &imx_esdhc_devtype[IMX25_ESDHC], }, 83abfafc2dSShawn Guo { .compatible = "fsl,imx35-esdhc", .data = &imx_esdhc_devtype[IMX35_ESDHC], }, 84abfafc2dSShawn Guo { .compatible = "fsl,imx51-esdhc", .data = &imx_esdhc_devtype[IMX51_ESDHC], }, 85abfafc2dSShawn Guo { .compatible = "fsl,imx53-esdhc", .data = &imx_esdhc_devtype[IMX53_ESDHC], }, 86abfafc2dSShawn Guo { /* sentinel */ } 87abfafc2dSShawn Guo }; 88abfafc2dSShawn Guo MODULE_DEVICE_TABLE(of, imx_esdhc_dt_ids); 89abfafc2dSShawn Guo 9057ed3314SShawn Guo static inline int is_imx25_esdhc(struct pltfm_imx_data *data) 9157ed3314SShawn Guo { 9257ed3314SShawn Guo return data->devtype == IMX25_ESDHC; 9357ed3314SShawn Guo } 9457ed3314SShawn Guo 9557ed3314SShawn Guo static inline int is_imx35_esdhc(struct pltfm_imx_data *data) 9657ed3314SShawn Guo { 9757ed3314SShawn Guo return data->devtype == IMX35_ESDHC; 9857ed3314SShawn Guo } 9957ed3314SShawn Guo 10057ed3314SShawn Guo static inline int is_imx51_esdhc(struct pltfm_imx_data *data) 10157ed3314SShawn Guo { 10257ed3314SShawn Guo return data->devtype == IMX51_ESDHC; 10357ed3314SShawn Guo } 10457ed3314SShawn Guo 10557ed3314SShawn Guo static inline int is_imx53_esdhc(struct pltfm_imx_data *data) 10657ed3314SShawn Guo { 10757ed3314SShawn Guo return data->devtype == IMX53_ESDHC; 10857ed3314SShawn Guo } 10957ed3314SShawn Guo 11095f25efeSWolfram Sang static inline void esdhc_clrset_le(struct sdhci_host *host, u32 mask, u32 val, int reg) 11195f25efeSWolfram Sang { 11295f25efeSWolfram Sang void __iomem *base = host->ioaddr + (reg & ~0x3); 11395f25efeSWolfram Sang u32 shift = (reg & 0x3) * 8; 11495f25efeSWolfram Sang 11595f25efeSWolfram Sang writel(((readl(base) & ~(mask << shift)) | (val << shift)), base); 11695f25efeSWolfram Sang } 11795f25efeSWolfram Sang 1187e29c306SWolfram Sang static u32 esdhc_readl_le(struct sdhci_host *host, int reg) 1197e29c306SWolfram Sang { 120842afc02SShawn Guo struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); 121842afc02SShawn Guo struct pltfm_imx_data *imx_data = pltfm_host->priv; 122842afc02SShawn Guo struct esdhc_platform_data *boarddata = &imx_data->boarddata; 1237e29c306SWolfram Sang 124913413c3SShawn Guo /* fake CARD_PRESENT flag */ 125913413c3SShawn Guo u32 val = readl(host->ioaddr + reg); 126913413c3SShawn Guo 127913413c3SShawn Guo if (unlikely((reg == SDHCI_PRESENT_STATE) 128913413c3SShawn Guo && gpio_is_valid(boarddata->cd_gpio))) { 129913413c3SShawn Guo if (gpio_get_value(boarddata->cd_gpio)) 1307e29c306SWolfram Sang /* no card, if a valid gpio says so... */ 131803862a6SShawn Guo val &= ~SDHCI_CARD_PRESENT; 1327e29c306SWolfram Sang else 1337e29c306SWolfram Sang /* ... in all other cases assume card is present */ 1347e29c306SWolfram Sang val |= SDHCI_CARD_PRESENT; 1357e29c306SWolfram Sang } 1367e29c306SWolfram Sang 1377e29c306SWolfram Sang return val; 1387e29c306SWolfram Sang } 1397e29c306SWolfram Sang 1407e29c306SWolfram Sang static void esdhc_writel_le(struct sdhci_host *host, u32 val, int reg) 1417e29c306SWolfram Sang { 142e149860dSRichard Zhu struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); 143e149860dSRichard Zhu struct pltfm_imx_data *imx_data = pltfm_host->priv; 144842afc02SShawn Guo struct esdhc_platform_data *boarddata = &imx_data->boarddata; 1450d58864bSTony Lin u32 data; 146e149860dSRichard Zhu 1470d58864bSTony Lin if (unlikely(reg == SDHCI_INT_ENABLE || reg == SDHCI_SIGNAL_ENABLE)) { 1480d58864bSTony Lin if (boarddata->cd_type == ESDHC_CD_GPIO) 1497e29c306SWolfram Sang /* 1500d58864bSTony Lin * These interrupts won't work with a custom 1510d58864bSTony Lin * card_detect gpio (only applied to mx25/35) 1527e29c306SWolfram Sang */ 1537e29c306SWolfram Sang val &= ~(SDHCI_INT_CARD_REMOVE | SDHCI_INT_CARD_INSERT); 1547e29c306SWolfram Sang 1550d58864bSTony Lin if (val & SDHCI_INT_CARD_INT) { 1560d58864bSTony Lin /* 1570d58864bSTony Lin * Clear and then set D3CD bit to avoid missing the 1580d58864bSTony Lin * card interrupt. This is a eSDHC controller problem 1590d58864bSTony Lin * so we need to apply the following workaround: clear 1600d58864bSTony Lin * and set D3CD bit will make eSDHC re-sample the card 1610d58864bSTony Lin * interrupt. In case a card interrupt was lost, 1620d58864bSTony Lin * re-sample it by the following steps. 1630d58864bSTony Lin */ 1640d58864bSTony Lin data = readl(host->ioaddr + SDHCI_HOST_CONTROL); 1650d58864bSTony Lin data &= ~SDHCI_CTRL_D3CD; 1660d58864bSTony Lin writel(data, host->ioaddr + SDHCI_HOST_CONTROL); 1670d58864bSTony Lin data |= SDHCI_CTRL_D3CD; 1680d58864bSTony Lin writel(data, host->ioaddr + SDHCI_HOST_CONTROL); 1690d58864bSTony Lin } 1700d58864bSTony Lin } 1710d58864bSTony Lin 17258ac8177SRichard Zhu if (unlikely((imx_data->flags & ESDHC_FLAG_MULTIBLK_NO_INT) 17358ac8177SRichard Zhu && (reg == SDHCI_INT_STATUS) 17458ac8177SRichard Zhu && (val & SDHCI_INT_DATA_END))) { 17558ac8177SRichard Zhu u32 v; 17658ac8177SRichard Zhu v = readl(host->ioaddr + SDHCI_VENDOR_SPEC); 17758ac8177SRichard Zhu v &= ~SDHCI_VENDOR_SPEC_SDIO_QUIRK; 17858ac8177SRichard Zhu writel(v, host->ioaddr + SDHCI_VENDOR_SPEC); 17958ac8177SRichard Zhu } 18058ac8177SRichard Zhu 1817e29c306SWolfram Sang writel(val, host->ioaddr + reg); 1827e29c306SWolfram Sang } 1837e29c306SWolfram Sang 18495f25efeSWolfram Sang static u16 esdhc_readw_le(struct sdhci_host *host, int reg) 18595f25efeSWolfram Sang { 18695f25efeSWolfram Sang if (unlikely(reg == SDHCI_HOST_VERSION)) 18795f25efeSWolfram Sang reg ^= 2; 18895f25efeSWolfram Sang 18995f25efeSWolfram Sang return readw(host->ioaddr + reg); 19095f25efeSWolfram Sang } 19195f25efeSWolfram Sang 19295f25efeSWolfram Sang static void esdhc_writew_le(struct sdhci_host *host, u16 val, int reg) 19395f25efeSWolfram Sang { 19495f25efeSWolfram Sang struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); 195e149860dSRichard Zhu struct pltfm_imx_data *imx_data = pltfm_host->priv; 19695f25efeSWolfram Sang 19795f25efeSWolfram Sang switch (reg) { 19895f25efeSWolfram Sang case SDHCI_TRANSFER_MODE: 19995f25efeSWolfram Sang /* 20095f25efeSWolfram Sang * Postpone this write, we must do it together with a 20195f25efeSWolfram Sang * command write that is down below. 20295f25efeSWolfram Sang */ 20358ac8177SRichard Zhu if ((imx_data->flags & ESDHC_FLAG_MULTIBLK_NO_INT) 20458ac8177SRichard Zhu && (host->cmd->opcode == SD_IO_RW_EXTENDED) 20558ac8177SRichard Zhu && (host->cmd->data->blocks > 1) 20658ac8177SRichard Zhu && (host->cmd->data->flags & MMC_DATA_READ)) { 20758ac8177SRichard Zhu u32 v; 20858ac8177SRichard Zhu v = readl(host->ioaddr + SDHCI_VENDOR_SPEC); 20958ac8177SRichard Zhu v |= SDHCI_VENDOR_SPEC_SDIO_QUIRK; 21058ac8177SRichard Zhu writel(v, host->ioaddr + SDHCI_VENDOR_SPEC); 21158ac8177SRichard Zhu } 212e149860dSRichard Zhu imx_data->scratchpad = val; 21395f25efeSWolfram Sang return; 21495f25efeSWolfram Sang case SDHCI_COMMAND: 21558ac8177SRichard Zhu if ((host->cmd->opcode == MMC_STOP_TRANSMISSION) 21658ac8177SRichard Zhu && (imx_data->flags & ESDHC_FLAG_MULTIBLK_NO_INT)) 21758ac8177SRichard Zhu val |= SDHCI_CMD_ABORTCMD; 218e149860dSRichard Zhu writel(val << 16 | imx_data->scratchpad, 21995f25efeSWolfram Sang host->ioaddr + SDHCI_TRANSFER_MODE); 22095f25efeSWolfram Sang return; 22195f25efeSWolfram Sang case SDHCI_BLOCK_SIZE: 22295f25efeSWolfram Sang val &= ~SDHCI_MAKE_BLKSZ(0x7, 0); 22395f25efeSWolfram Sang break; 22495f25efeSWolfram Sang } 22595f25efeSWolfram Sang esdhc_clrset_le(host, 0xffff, val, reg); 22695f25efeSWolfram Sang } 22795f25efeSWolfram Sang 22895f25efeSWolfram Sang static void esdhc_writeb_le(struct sdhci_host *host, u8 val, int reg) 22995f25efeSWolfram Sang { 23095f25efeSWolfram Sang u32 new_val; 23195f25efeSWolfram Sang 23295f25efeSWolfram Sang switch (reg) { 23395f25efeSWolfram Sang case SDHCI_POWER_CONTROL: 23495f25efeSWolfram Sang /* 23595f25efeSWolfram Sang * FSL put some DMA bits here 23695f25efeSWolfram Sang * If your board has a regulator, code should be here 23795f25efeSWolfram Sang */ 23895f25efeSWolfram Sang return; 23995f25efeSWolfram Sang case SDHCI_HOST_CONTROL: 2400d58864bSTony Lin /* FSL messed up here, so we can just keep those three */ 2410d58864bSTony Lin new_val = val & (SDHCI_CTRL_LED | \ 2420d58864bSTony Lin SDHCI_CTRL_4BITBUS | \ 2430d58864bSTony Lin SDHCI_CTRL_D3CD); 24495f25efeSWolfram Sang /* ensure the endianess */ 24595f25efeSWolfram Sang new_val |= ESDHC_HOST_CONTROL_LE; 24695f25efeSWolfram Sang /* DMA mode bits are shifted */ 24795f25efeSWolfram Sang new_val |= (val & SDHCI_CTRL_DMA_MASK) << 5; 24895f25efeSWolfram Sang 24995f25efeSWolfram Sang esdhc_clrset_le(host, 0xffff, new_val, reg); 25095f25efeSWolfram Sang return; 25195f25efeSWolfram Sang } 25295f25efeSWolfram Sang esdhc_clrset_le(host, 0xff, val, reg); 253913413c3SShawn Guo 254913413c3SShawn Guo /* 255913413c3SShawn Guo * The esdhc has a design violation to SDHC spec which tells 256913413c3SShawn Guo * that software reset should not affect card detection circuit. 257913413c3SShawn Guo * But esdhc clears its SYSCTL register bits [0..2] during the 258913413c3SShawn Guo * software reset. This will stop those clocks that card detection 259913413c3SShawn Guo * circuit relies on. To work around it, we turn the clocks on back 260913413c3SShawn Guo * to keep card detection circuit functional. 261913413c3SShawn Guo */ 262913413c3SShawn Guo if ((reg == SDHCI_SOFTWARE_RESET) && (val & 1)) 263913413c3SShawn Guo esdhc_clrset_le(host, 0x7, 0x7, ESDHC_SYSTEM_CONTROL); 26495f25efeSWolfram Sang } 26595f25efeSWolfram Sang 26695f25efeSWolfram Sang static unsigned int esdhc_pltfm_get_max_clock(struct sdhci_host *host) 26795f25efeSWolfram Sang { 26895f25efeSWolfram Sang struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); 26995f25efeSWolfram Sang 27095f25efeSWolfram Sang return clk_get_rate(pltfm_host->clk); 27195f25efeSWolfram Sang } 27295f25efeSWolfram Sang 27395f25efeSWolfram Sang static unsigned int esdhc_pltfm_get_min_clock(struct sdhci_host *host) 27495f25efeSWolfram Sang { 27595f25efeSWolfram Sang struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); 27695f25efeSWolfram Sang 27795f25efeSWolfram Sang return clk_get_rate(pltfm_host->clk) / 256 / 16; 27895f25efeSWolfram Sang } 27995f25efeSWolfram Sang 280913413c3SShawn Guo static unsigned int esdhc_pltfm_get_ro(struct sdhci_host *host) 281913413c3SShawn Guo { 282842afc02SShawn Guo struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); 283842afc02SShawn Guo struct pltfm_imx_data *imx_data = pltfm_host->priv; 284842afc02SShawn Guo struct esdhc_platform_data *boarddata = &imx_data->boarddata; 285913413c3SShawn Guo 286913413c3SShawn Guo switch (boarddata->wp_type) { 287913413c3SShawn Guo case ESDHC_WP_GPIO: 288913413c3SShawn Guo if (gpio_is_valid(boarddata->wp_gpio)) 289913413c3SShawn Guo return gpio_get_value(boarddata->wp_gpio); 290913413c3SShawn Guo case ESDHC_WP_CONTROLLER: 291913413c3SShawn Guo return !(readl(host->ioaddr + SDHCI_PRESENT_STATE) & 292913413c3SShawn Guo SDHCI_WRITE_PROTECT); 293913413c3SShawn Guo case ESDHC_WP_NONE: 294913413c3SShawn Guo break; 295913413c3SShawn Guo } 296913413c3SShawn Guo 297913413c3SShawn Guo return -ENOSYS; 298913413c3SShawn Guo } 299913413c3SShawn Guo 3000c6d49ceSWolfram Sang static struct sdhci_ops sdhci_esdhc_ops = { 301e149860dSRichard Zhu .read_l = esdhc_readl_le, 3020c6d49ceSWolfram Sang .read_w = esdhc_readw_le, 303e149860dSRichard Zhu .write_l = esdhc_writel_le, 3040c6d49ceSWolfram Sang .write_w = esdhc_writew_le, 3050c6d49ceSWolfram Sang .write_b = esdhc_writeb_le, 3060c6d49ceSWolfram Sang .set_clock = esdhc_set_clock, 3070c6d49ceSWolfram Sang .get_max_clock = esdhc_pltfm_get_max_clock, 3080c6d49ceSWolfram Sang .get_min_clock = esdhc_pltfm_get_min_clock, 309913413c3SShawn Guo .get_ro = esdhc_pltfm_get_ro, 3100c6d49ceSWolfram Sang }; 3110c6d49ceSWolfram Sang 31285d6509dSShawn Guo static struct sdhci_pltfm_data sdhci_esdhc_imx_pdata = { 31385d6509dSShawn Guo .quirks = ESDHC_DEFAULT_QUIRKS | SDHCI_QUIRK_BROKEN_ADMA 31485d6509dSShawn Guo | SDHCI_QUIRK_BROKEN_CARD_DETECTION, 31585d6509dSShawn Guo /* ADMA has issues. Might be fixable */ 31685d6509dSShawn Guo .ops = &sdhci_esdhc_ops, 31785d6509dSShawn Guo }; 31885d6509dSShawn Guo 3197e29c306SWolfram Sang static irqreturn_t cd_irq(int irq, void *data) 3207e29c306SWolfram Sang { 3217e29c306SWolfram Sang struct sdhci_host *sdhost = (struct sdhci_host *)data; 3227e29c306SWolfram Sang 3237e29c306SWolfram Sang tasklet_schedule(&sdhost->card_tasklet); 3247e29c306SWolfram Sang return IRQ_HANDLED; 3257e29c306SWolfram Sang }; 3267e29c306SWolfram Sang 327abfafc2dSShawn Guo #ifdef CONFIG_OF 328abfafc2dSShawn Guo static int __devinit 329abfafc2dSShawn Guo sdhci_esdhc_imx_probe_dt(struct platform_device *pdev, 330abfafc2dSShawn Guo struct esdhc_platform_data *boarddata) 331abfafc2dSShawn Guo { 332abfafc2dSShawn Guo struct device_node *np = pdev->dev.of_node; 333abfafc2dSShawn Guo 334abfafc2dSShawn Guo if (!np) 335abfafc2dSShawn Guo return -ENODEV; 336abfafc2dSShawn Guo 337abfafc2dSShawn Guo if (of_get_property(np, "fsl,card-wired", NULL)) 338abfafc2dSShawn Guo boarddata->cd_type = ESDHC_CD_PERMANENT; 339abfafc2dSShawn Guo 340abfafc2dSShawn Guo if (of_get_property(np, "fsl,cd-controller", NULL)) 341abfafc2dSShawn Guo boarddata->cd_type = ESDHC_CD_CONTROLLER; 342abfafc2dSShawn Guo 343abfafc2dSShawn Guo if (of_get_property(np, "fsl,wp-controller", NULL)) 344abfafc2dSShawn Guo boarddata->wp_type = ESDHC_WP_CONTROLLER; 345abfafc2dSShawn Guo 346abfafc2dSShawn Guo boarddata->cd_gpio = of_get_named_gpio(np, "cd-gpios", 0); 347abfafc2dSShawn Guo if (gpio_is_valid(boarddata->cd_gpio)) 348abfafc2dSShawn Guo boarddata->cd_type = ESDHC_CD_GPIO; 349abfafc2dSShawn Guo 350abfafc2dSShawn Guo boarddata->wp_gpio = of_get_named_gpio(np, "wp-gpios", 0); 351abfafc2dSShawn Guo if (gpio_is_valid(boarddata->wp_gpio)) 352abfafc2dSShawn Guo boarddata->wp_type = ESDHC_WP_GPIO; 353abfafc2dSShawn Guo 354abfafc2dSShawn Guo return 0; 355abfafc2dSShawn Guo } 356abfafc2dSShawn Guo #else 357abfafc2dSShawn Guo static inline int 358abfafc2dSShawn Guo sdhci_esdhc_imx_probe_dt(struct platform_device *pdev, 359abfafc2dSShawn Guo struct esdhc_platform_data *boarddata) 360abfafc2dSShawn Guo { 361abfafc2dSShawn Guo return -ENODEV; 362abfafc2dSShawn Guo } 363abfafc2dSShawn Guo #endif 364abfafc2dSShawn Guo 36585d6509dSShawn Guo static int __devinit sdhci_esdhc_imx_probe(struct platform_device *pdev) 36695f25efeSWolfram Sang { 367abfafc2dSShawn Guo const struct of_device_id *of_id = 368abfafc2dSShawn Guo of_match_device(imx_esdhc_dt_ids, &pdev->dev); 36985d6509dSShawn Guo struct sdhci_pltfm_host *pltfm_host; 37085d6509dSShawn Guo struct sdhci_host *host; 37185d6509dSShawn Guo struct esdhc_platform_data *boarddata; 37295f25efeSWolfram Sang struct clk *clk; 3730c6d49ceSWolfram Sang int err; 374e149860dSRichard Zhu struct pltfm_imx_data *imx_data; 37595f25efeSWolfram Sang 37685d6509dSShawn Guo host = sdhci_pltfm_init(pdev, &sdhci_esdhc_imx_pdata); 37785d6509dSShawn Guo if (IS_ERR(host)) 37885d6509dSShawn Guo return PTR_ERR(host); 37985d6509dSShawn Guo 38085d6509dSShawn Guo pltfm_host = sdhci_priv(host); 38185d6509dSShawn Guo 38285d6509dSShawn Guo imx_data = kzalloc(sizeof(struct pltfm_imx_data), GFP_KERNEL); 383abfafc2dSShawn Guo if (!imx_data) { 384abfafc2dSShawn Guo err = -ENOMEM; 385abfafc2dSShawn Guo goto err_imx_data; 386abfafc2dSShawn Guo } 38757ed3314SShawn Guo 388abfafc2dSShawn Guo if (of_id) 389abfafc2dSShawn Guo pdev->id_entry = of_id->data; 39057ed3314SShawn Guo imx_data->devtype = pdev->id_entry->driver_data; 39185d6509dSShawn Guo pltfm_host->priv = imx_data; 39285d6509dSShawn Guo 39395f25efeSWolfram Sang clk = clk_get(mmc_dev(host->mmc), NULL); 39495f25efeSWolfram Sang if (IS_ERR(clk)) { 39595f25efeSWolfram Sang dev_err(mmc_dev(host->mmc), "clk err\n"); 39685d6509dSShawn Guo err = PTR_ERR(clk); 39785d6509dSShawn Guo goto err_clk_get; 39895f25efeSWolfram Sang } 39995f25efeSWolfram Sang clk_enable(clk); 40095f25efeSWolfram Sang pltfm_host->clk = clk; 40195f25efeSWolfram Sang 40257ed3314SShawn Guo if (!is_imx25_esdhc(imx_data)) 40337865fe9SEric Bénard host->quirks |= SDHCI_QUIRK_BROKEN_TIMEOUT_VAL; 40437865fe9SEric Bénard 40557ed3314SShawn Guo if (is_imx25_esdhc(imx_data) || is_imx35_esdhc(imx_data)) 4060c6d49ceSWolfram Sang /* Fix errata ENGcm07207 present on i.MX25 and i.MX35 */ 40716a790bcSEric Bénard host->quirks |= SDHCI_QUIRK_NO_MULTIBLOCK; 4080c6d49ceSWolfram Sang 40957ed3314SShawn Guo if (is_imx53_esdhc(imx_data)) 41058ac8177SRichard Zhu imx_data->flags |= ESDHC_FLAG_MULTIBLK_NO_INT; 41158ac8177SRichard Zhu 412abfafc2dSShawn Guo boarddata = &imx_data->boarddata; 413abfafc2dSShawn Guo if (sdhci_esdhc_imx_probe_dt(pdev, boarddata) < 0) { 414842afc02SShawn Guo if (!host->mmc->parent->platform_data) { 415913413c3SShawn Guo dev_err(mmc_dev(host->mmc), "no board data!\n"); 416913413c3SShawn Guo err = -EINVAL; 417913413c3SShawn Guo goto no_board_data; 418913413c3SShawn Guo } 419842afc02SShawn Guo imx_data->boarddata = *((struct esdhc_platform_data *) 420842afc02SShawn Guo host->mmc->parent->platform_data); 421abfafc2dSShawn Guo } 422913413c3SShawn Guo 423913413c3SShawn Guo /* write_protect */ 424913413c3SShawn Guo if (boarddata->wp_type == ESDHC_WP_GPIO) { 4250c6d49ceSWolfram Sang err = gpio_request_one(boarddata->wp_gpio, GPIOF_IN, "ESDHC_WP"); 4260c6d49ceSWolfram Sang if (err) { 4270c6d49ceSWolfram Sang dev_warn(mmc_dev(host->mmc), 4280c6d49ceSWolfram Sang "no write-protect pin available!\n"); 429913413c3SShawn Guo boarddata->wp_gpio = -EINVAL; 430913413c3SShawn Guo } 431913413c3SShawn Guo } else { 432913413c3SShawn Guo boarddata->wp_gpio = -EINVAL; 4330c6d49ceSWolfram Sang } 4347e29c306SWolfram Sang 435913413c3SShawn Guo /* card_detect */ 436913413c3SShawn Guo if (boarddata->cd_type != ESDHC_CD_GPIO) 437913413c3SShawn Guo boarddata->cd_gpio = -EINVAL; 438913413c3SShawn Guo 439913413c3SShawn Guo switch (boarddata->cd_type) { 440913413c3SShawn Guo case ESDHC_CD_GPIO: 4417e29c306SWolfram Sang err = gpio_request_one(boarddata->cd_gpio, GPIOF_IN, "ESDHC_CD"); 4427e29c306SWolfram Sang if (err) { 443913413c3SShawn Guo dev_err(mmc_dev(host->mmc), 4447e29c306SWolfram Sang "no card-detect pin available!\n"); 4457e29c306SWolfram Sang goto no_card_detect_pin; 4460c6d49ceSWolfram Sang } 44716a790bcSEric Bénard 4487e29c306SWolfram Sang err = request_irq(gpio_to_irq(boarddata->cd_gpio), cd_irq, 4497e29c306SWolfram Sang IRQF_TRIGGER_FALLING | IRQF_TRIGGER_RISING, 4507e29c306SWolfram Sang mmc_hostname(host->mmc), host); 4517e29c306SWolfram Sang if (err) { 452913413c3SShawn Guo dev_err(mmc_dev(host->mmc), "request irq error\n"); 4537e29c306SWolfram Sang goto no_card_detect_irq; 4547e29c306SWolfram Sang } 455913413c3SShawn Guo /* fall through */ 4567e29c306SWolfram Sang 457913413c3SShawn Guo case ESDHC_CD_CONTROLLER: 458913413c3SShawn Guo /* we have a working card_detect back */ 4597e29c306SWolfram Sang host->quirks &= ~SDHCI_QUIRK_BROKEN_CARD_DETECTION; 460913413c3SShawn Guo break; 461913413c3SShawn Guo 462913413c3SShawn Guo case ESDHC_CD_PERMANENT: 463913413c3SShawn Guo host->mmc->caps = MMC_CAP_NONREMOVABLE; 464913413c3SShawn Guo break; 465913413c3SShawn Guo 466913413c3SShawn Guo case ESDHC_CD_NONE: 467913413c3SShawn Guo break; 4687e29c306SWolfram Sang } 4697e29c306SWolfram Sang 47085d6509dSShawn Guo err = sdhci_add_host(host); 47185d6509dSShawn Guo if (err) 47285d6509dSShawn Guo goto err_add_host; 47385d6509dSShawn Guo 4747e29c306SWolfram Sang return 0; 4757e29c306SWolfram Sang 47685d6509dSShawn Guo err_add_host: 477913413c3SShawn Guo if (gpio_is_valid(boarddata->cd_gpio)) 478913413c3SShawn Guo free_irq(gpio_to_irq(boarddata->cd_gpio), host); 479913413c3SShawn Guo no_card_detect_irq: 480913413c3SShawn Guo if (gpio_is_valid(boarddata->cd_gpio)) 481913413c3SShawn Guo gpio_free(boarddata->cd_gpio); 482913413c3SShawn Guo if (gpio_is_valid(boarddata->wp_gpio)) 483913413c3SShawn Guo gpio_free(boarddata->wp_gpio); 484913413c3SShawn Guo no_card_detect_pin: 485913413c3SShawn Guo no_board_data: 48685d6509dSShawn Guo clk_disable(pltfm_host->clk); 48785d6509dSShawn Guo clk_put(pltfm_host->clk); 48885d6509dSShawn Guo err_clk_get: 489913413c3SShawn Guo kfree(imx_data); 490abfafc2dSShawn Guo err_imx_data: 49185d6509dSShawn Guo sdhci_pltfm_free(pdev); 49285d6509dSShawn Guo return err; 49395f25efeSWolfram Sang } 49495f25efeSWolfram Sang 49585d6509dSShawn Guo static int __devexit sdhci_esdhc_imx_remove(struct platform_device *pdev) 49695f25efeSWolfram Sang { 49785d6509dSShawn Guo struct sdhci_host *host = platform_get_drvdata(pdev); 49895f25efeSWolfram Sang struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); 499e149860dSRichard Zhu struct pltfm_imx_data *imx_data = pltfm_host->priv; 500842afc02SShawn Guo struct esdhc_platform_data *boarddata = &imx_data->boarddata; 50185d6509dSShawn Guo int dead = (readl(host->ioaddr + SDHCI_INT_STATUS) == 0xffffffff); 50285d6509dSShawn Guo 50385d6509dSShawn Guo sdhci_remove_host(host, dead); 5040c6d49ceSWolfram Sang 505913413c3SShawn Guo if (gpio_is_valid(boarddata->wp_gpio)) 5060c6d49ceSWolfram Sang gpio_free(boarddata->wp_gpio); 50795f25efeSWolfram Sang 508913413c3SShawn Guo if (gpio_is_valid(boarddata->cd_gpio)) { 5097e29c306SWolfram Sang free_irq(gpio_to_irq(boarddata->cd_gpio), host); 510913413c3SShawn Guo gpio_free(boarddata->cd_gpio); 5117e29c306SWolfram Sang } 5127e29c306SWolfram Sang 51395f25efeSWolfram Sang clk_disable(pltfm_host->clk); 51495f25efeSWolfram Sang clk_put(pltfm_host->clk); 515e149860dSRichard Zhu kfree(imx_data); 51685d6509dSShawn Guo 51785d6509dSShawn Guo sdhci_pltfm_free(pdev); 51885d6509dSShawn Guo 51985d6509dSShawn Guo return 0; 52095f25efeSWolfram Sang } 52195f25efeSWolfram Sang 52285d6509dSShawn Guo static struct platform_driver sdhci_esdhc_imx_driver = { 52385d6509dSShawn Guo .driver = { 52485d6509dSShawn Guo .name = "sdhci-esdhc-imx", 52585d6509dSShawn Guo .owner = THIS_MODULE, 526abfafc2dSShawn Guo .of_match_table = imx_esdhc_dt_ids, 52785d6509dSShawn Guo }, 52857ed3314SShawn Guo .id_table = imx_esdhc_devtype, 52985d6509dSShawn Guo .probe = sdhci_esdhc_imx_probe, 53085d6509dSShawn Guo .remove = __devexit_p(sdhci_esdhc_imx_remove), 53185d6509dSShawn Guo #ifdef CONFIG_PM 53285d6509dSShawn Guo .suspend = sdhci_pltfm_suspend, 53385d6509dSShawn Guo .resume = sdhci_pltfm_resume, 53485d6509dSShawn Guo #endif 53595f25efeSWolfram Sang }; 53685d6509dSShawn Guo 53785d6509dSShawn Guo static int __init sdhci_esdhc_imx_init(void) 53885d6509dSShawn Guo { 53985d6509dSShawn Guo return platform_driver_register(&sdhci_esdhc_imx_driver); 54085d6509dSShawn Guo } 54185d6509dSShawn Guo module_init(sdhci_esdhc_imx_init); 54285d6509dSShawn Guo 54385d6509dSShawn Guo static void __exit sdhci_esdhc_imx_exit(void) 54485d6509dSShawn Guo { 54585d6509dSShawn Guo platform_driver_unregister(&sdhci_esdhc_imx_driver); 54685d6509dSShawn Guo } 54785d6509dSShawn Guo module_exit(sdhci_esdhc_imx_exit); 54885d6509dSShawn Guo 54985d6509dSShawn Guo MODULE_DESCRIPTION("SDHCI driver for Freescale i.MX eSDHC"); 55085d6509dSShawn Guo MODULE_AUTHOR("Wolfram Sang <w.sang@pengutronix.de>"); 55185d6509dSShawn Guo MODULE_LICENSE("GPL v2"); 552