1 /* 2 * Freescale eSDHC i.MX controller driver for the platform bus. 3 * 4 * derived from the OF-version. 5 * 6 * Copyright (c) 2010 Pengutronix e.K. 7 * Author: Wolfram Sang <w.sang@pengutronix.de> 8 * 9 * This program is free software; you can redistribute it and/or modify 10 * it under the terms of the GNU General Public License as published by 11 * the Free Software Foundation; either version 2 of the License. 12 */ 13 14 #include <linux/io.h> 15 #include <linux/delay.h> 16 #include <linux/err.h> 17 #include <linux/clk.h> 18 #include <linux/gpio.h> 19 #include <linux/slab.h> 20 #include <linux/mmc/host.h> 21 #include <linux/mmc/mmc.h> 22 #include <linux/mmc/sdio.h> 23 #include <mach/hardware.h> 24 #include <mach/esdhc.h> 25 #include "sdhci-pltfm.h" 26 #include "sdhci-esdhc.h" 27 28 /* VENDOR SPEC register */ 29 #define SDHCI_VENDOR_SPEC 0xC0 30 #define SDHCI_VENDOR_SPEC_SDIO_QUIRK 0x00000002 31 32 #define ESDHC_FLAG_GPIO_FOR_CD (1 << 0) 33 /* 34 * The CMDTYPE of the CMD register (offset 0xE) should be set to 35 * "11" when the STOP CMD12 is issued on imx53 to abort one 36 * open ended multi-blk IO. Otherwise the TC INT wouldn't 37 * be generated. 38 * In exact block transfer, the controller doesn't complete the 39 * operations automatically as required at the end of the 40 * transfer and remains on hold if the abort command is not sent. 41 * As a result, the TC flag is not asserted and SW received timeout 42 * exeception. Bit1 of Vendor Spec registor is used to fix it. 43 */ 44 #define ESDHC_FLAG_MULTIBLK_NO_INT (1 << 1) 45 46 struct pltfm_imx_data { 47 int flags; 48 u32 scratchpad; 49 }; 50 51 static inline void esdhc_clrset_le(struct sdhci_host *host, u32 mask, u32 val, int reg) 52 { 53 void __iomem *base = host->ioaddr + (reg & ~0x3); 54 u32 shift = (reg & 0x3) * 8; 55 56 writel(((readl(base) & ~(mask << shift)) | (val << shift)), base); 57 } 58 59 static u32 esdhc_readl_le(struct sdhci_host *host, int reg) 60 { 61 struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); 62 struct pltfm_imx_data *imx_data = pltfm_host->priv; 63 64 /* fake CARD_PRESENT flag on mx25/35 */ 65 u32 val = readl(host->ioaddr + reg); 66 67 if (unlikely((reg == SDHCI_PRESENT_STATE) 68 && (imx_data->flags & ESDHC_FLAG_GPIO_FOR_CD))) { 69 struct esdhc_platform_data *boarddata = 70 host->mmc->parent->platform_data; 71 72 if (boarddata && gpio_is_valid(boarddata->cd_gpio) 73 && gpio_get_value(boarddata->cd_gpio)) 74 /* no card, if a valid gpio says so... */ 75 val &= ~SDHCI_CARD_PRESENT; 76 else 77 /* ... in all other cases assume card is present */ 78 val |= SDHCI_CARD_PRESENT; 79 } 80 81 return val; 82 } 83 84 static void esdhc_writel_le(struct sdhci_host *host, u32 val, int reg) 85 { 86 struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); 87 struct pltfm_imx_data *imx_data = pltfm_host->priv; 88 89 if (unlikely((reg == SDHCI_INT_ENABLE || reg == SDHCI_SIGNAL_ENABLE) 90 && (imx_data->flags & ESDHC_FLAG_GPIO_FOR_CD))) 91 /* 92 * these interrupts won't work with a custom card_detect gpio 93 * (only applied to mx25/35) 94 */ 95 val &= ~(SDHCI_INT_CARD_REMOVE | SDHCI_INT_CARD_INSERT); 96 97 if (unlikely((imx_data->flags & ESDHC_FLAG_MULTIBLK_NO_INT) 98 && (reg == SDHCI_INT_STATUS) 99 && (val & SDHCI_INT_DATA_END))) { 100 u32 v; 101 v = readl(host->ioaddr + SDHCI_VENDOR_SPEC); 102 v &= ~SDHCI_VENDOR_SPEC_SDIO_QUIRK; 103 writel(v, host->ioaddr + SDHCI_VENDOR_SPEC); 104 } 105 106 writel(val, host->ioaddr + reg); 107 } 108 109 static u16 esdhc_readw_le(struct sdhci_host *host, int reg) 110 { 111 if (unlikely(reg == SDHCI_HOST_VERSION)) 112 reg ^= 2; 113 114 return readw(host->ioaddr + reg); 115 } 116 117 static void esdhc_writew_le(struct sdhci_host *host, u16 val, int reg) 118 { 119 struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); 120 struct pltfm_imx_data *imx_data = pltfm_host->priv; 121 122 switch (reg) { 123 case SDHCI_TRANSFER_MODE: 124 /* 125 * Postpone this write, we must do it together with a 126 * command write that is down below. 127 */ 128 if ((imx_data->flags & ESDHC_FLAG_MULTIBLK_NO_INT) 129 && (host->cmd->opcode == SD_IO_RW_EXTENDED) 130 && (host->cmd->data->blocks > 1) 131 && (host->cmd->data->flags & MMC_DATA_READ)) { 132 u32 v; 133 v = readl(host->ioaddr + SDHCI_VENDOR_SPEC); 134 v |= SDHCI_VENDOR_SPEC_SDIO_QUIRK; 135 writel(v, host->ioaddr + SDHCI_VENDOR_SPEC); 136 } 137 imx_data->scratchpad = val; 138 return; 139 case SDHCI_COMMAND: 140 if ((host->cmd->opcode == MMC_STOP_TRANSMISSION) 141 && (imx_data->flags & ESDHC_FLAG_MULTIBLK_NO_INT)) 142 val |= SDHCI_CMD_ABORTCMD; 143 writel(val << 16 | imx_data->scratchpad, 144 host->ioaddr + SDHCI_TRANSFER_MODE); 145 return; 146 case SDHCI_BLOCK_SIZE: 147 val &= ~SDHCI_MAKE_BLKSZ(0x7, 0); 148 break; 149 } 150 esdhc_clrset_le(host, 0xffff, val, reg); 151 } 152 153 static void esdhc_writeb_le(struct sdhci_host *host, u8 val, int reg) 154 { 155 u32 new_val; 156 157 switch (reg) { 158 case SDHCI_POWER_CONTROL: 159 /* 160 * FSL put some DMA bits here 161 * If your board has a regulator, code should be here 162 */ 163 return; 164 case SDHCI_HOST_CONTROL: 165 /* FSL messed up here, so we can just keep those two */ 166 new_val = val & (SDHCI_CTRL_LED | SDHCI_CTRL_4BITBUS); 167 /* ensure the endianess */ 168 new_val |= ESDHC_HOST_CONTROL_LE; 169 /* DMA mode bits are shifted */ 170 new_val |= (val & SDHCI_CTRL_DMA_MASK) << 5; 171 172 esdhc_clrset_le(host, 0xffff, new_val, reg); 173 return; 174 } 175 esdhc_clrset_le(host, 0xff, val, reg); 176 } 177 178 static unsigned int esdhc_pltfm_get_max_clock(struct sdhci_host *host) 179 { 180 struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); 181 182 return clk_get_rate(pltfm_host->clk); 183 } 184 185 static unsigned int esdhc_pltfm_get_min_clock(struct sdhci_host *host) 186 { 187 struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); 188 189 return clk_get_rate(pltfm_host->clk) / 256 / 16; 190 } 191 192 static struct sdhci_ops sdhci_esdhc_ops = { 193 .read_l = esdhc_readl_le, 194 .read_w = esdhc_readw_le, 195 .write_l = esdhc_writel_le, 196 .write_w = esdhc_writew_le, 197 .write_b = esdhc_writeb_le, 198 .set_clock = esdhc_set_clock, 199 .get_max_clock = esdhc_pltfm_get_max_clock, 200 .get_min_clock = esdhc_pltfm_get_min_clock, 201 }; 202 203 static struct sdhci_pltfm_data sdhci_esdhc_imx_pdata = { 204 .quirks = ESDHC_DEFAULT_QUIRKS | SDHCI_QUIRK_BROKEN_ADMA 205 | SDHCI_QUIRK_BROKEN_CARD_DETECTION, 206 /* ADMA has issues. Might be fixable */ 207 .ops = &sdhci_esdhc_ops, 208 }; 209 210 static unsigned int esdhc_pltfm_get_ro(struct sdhci_host *host) 211 { 212 struct esdhc_platform_data *boarddata = 213 host->mmc->parent->platform_data; 214 215 if (boarddata && gpio_is_valid(boarddata->wp_gpio)) 216 return gpio_get_value(boarddata->wp_gpio); 217 else 218 return -ENOSYS; 219 } 220 221 static irqreturn_t cd_irq(int irq, void *data) 222 { 223 struct sdhci_host *sdhost = (struct sdhci_host *)data; 224 225 tasklet_schedule(&sdhost->card_tasklet); 226 return IRQ_HANDLED; 227 }; 228 229 static int __devinit sdhci_esdhc_imx_probe(struct platform_device *pdev) 230 { 231 struct sdhci_pltfm_host *pltfm_host; 232 struct sdhci_host *host; 233 struct esdhc_platform_data *boarddata; 234 struct clk *clk; 235 int err; 236 struct pltfm_imx_data *imx_data; 237 238 host = sdhci_pltfm_init(pdev, &sdhci_esdhc_imx_pdata); 239 if (IS_ERR(host)) 240 return PTR_ERR(host); 241 242 pltfm_host = sdhci_priv(host); 243 244 imx_data = kzalloc(sizeof(struct pltfm_imx_data), GFP_KERNEL); 245 if (!imx_data) 246 return -ENOMEM; 247 pltfm_host->priv = imx_data; 248 249 clk = clk_get(mmc_dev(host->mmc), NULL); 250 if (IS_ERR(clk)) { 251 dev_err(mmc_dev(host->mmc), "clk err\n"); 252 err = PTR_ERR(clk); 253 goto err_clk_get; 254 } 255 clk_enable(clk); 256 pltfm_host->clk = clk; 257 258 if (!cpu_is_mx25()) 259 host->quirks |= SDHCI_QUIRK_BROKEN_TIMEOUT_VAL; 260 261 if (cpu_is_mx25() || cpu_is_mx35()) { 262 /* Fix errata ENGcm07207 present on i.MX25 and i.MX35 */ 263 host->quirks |= SDHCI_QUIRK_NO_MULTIBLOCK; 264 /* write_protect can't be routed to controller, use gpio */ 265 sdhci_esdhc_ops.get_ro = esdhc_pltfm_get_ro; 266 } 267 268 if (!(cpu_is_mx25() || cpu_is_mx35() || cpu_is_mx51())) 269 imx_data->flags |= ESDHC_FLAG_MULTIBLK_NO_INT; 270 271 boarddata = host->mmc->parent->platform_data; 272 if (boarddata) { 273 err = gpio_request_one(boarddata->wp_gpio, GPIOF_IN, "ESDHC_WP"); 274 if (err) { 275 dev_warn(mmc_dev(host->mmc), 276 "no write-protect pin available!\n"); 277 boarddata->wp_gpio = err; 278 } 279 280 err = gpio_request_one(boarddata->cd_gpio, GPIOF_IN, "ESDHC_CD"); 281 if (err) { 282 dev_warn(mmc_dev(host->mmc), 283 "no card-detect pin available!\n"); 284 goto no_card_detect_pin; 285 } 286 287 /* i.MX5x has issues to be researched */ 288 if (!cpu_is_mx25() && !cpu_is_mx35()) 289 goto not_supported; 290 291 err = request_irq(gpio_to_irq(boarddata->cd_gpio), cd_irq, 292 IRQF_TRIGGER_FALLING | IRQF_TRIGGER_RISING, 293 mmc_hostname(host->mmc), host); 294 if (err) { 295 dev_warn(mmc_dev(host->mmc), "request irq error\n"); 296 goto no_card_detect_irq; 297 } 298 299 imx_data->flags |= ESDHC_FLAG_GPIO_FOR_CD; 300 /* Now we have a working card_detect again */ 301 host->quirks &= ~SDHCI_QUIRK_BROKEN_CARD_DETECTION; 302 } 303 304 err = sdhci_add_host(host); 305 if (err) 306 goto err_add_host; 307 308 return 0; 309 310 no_card_detect_irq: 311 gpio_free(boarddata->cd_gpio); 312 no_card_detect_pin: 313 boarddata->cd_gpio = err; 314 not_supported: 315 kfree(imx_data); 316 err_add_host: 317 clk_disable(pltfm_host->clk); 318 clk_put(pltfm_host->clk); 319 err_clk_get: 320 sdhci_pltfm_free(pdev); 321 return err; 322 } 323 324 static int __devexit sdhci_esdhc_imx_remove(struct platform_device *pdev) 325 { 326 struct sdhci_host *host = platform_get_drvdata(pdev); 327 struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); 328 struct esdhc_platform_data *boarddata = host->mmc->parent->platform_data; 329 struct pltfm_imx_data *imx_data = pltfm_host->priv; 330 int dead = (readl(host->ioaddr + SDHCI_INT_STATUS) == 0xffffffff); 331 332 sdhci_remove_host(host, dead); 333 334 if (boarddata && gpio_is_valid(boarddata->wp_gpio)) 335 gpio_free(boarddata->wp_gpio); 336 337 if (boarddata && gpio_is_valid(boarddata->cd_gpio)) { 338 gpio_free(boarddata->cd_gpio); 339 340 if (!(host->quirks & SDHCI_QUIRK_BROKEN_CARD_DETECTION)) 341 free_irq(gpio_to_irq(boarddata->cd_gpio), host); 342 } 343 344 clk_disable(pltfm_host->clk); 345 clk_put(pltfm_host->clk); 346 kfree(imx_data); 347 348 sdhci_pltfm_free(pdev); 349 350 return 0; 351 } 352 353 static struct platform_driver sdhci_esdhc_imx_driver = { 354 .driver = { 355 .name = "sdhci-esdhc-imx", 356 .owner = THIS_MODULE, 357 }, 358 .probe = sdhci_esdhc_imx_probe, 359 .remove = __devexit_p(sdhci_esdhc_imx_remove), 360 #ifdef CONFIG_PM 361 .suspend = sdhci_pltfm_suspend, 362 .resume = sdhci_pltfm_resume, 363 #endif 364 }; 365 366 static int __init sdhci_esdhc_imx_init(void) 367 { 368 return platform_driver_register(&sdhci_esdhc_imx_driver); 369 } 370 module_init(sdhci_esdhc_imx_init); 371 372 static void __exit sdhci_esdhc_imx_exit(void) 373 { 374 platform_driver_unregister(&sdhci_esdhc_imx_driver); 375 } 376 module_exit(sdhci_esdhc_imx_exit); 377 378 MODULE_DESCRIPTION("SDHCI driver for Freescale i.MX eSDHC"); 379 MODULE_AUTHOR("Wolfram Sang <w.sang@pengutronix.de>"); 380 MODULE_LICENSE("GPL v2"); 381