From 2e70c9f0621b65a563ba6961310ad7de9c6b4052 Mon Sep 17 00:00:00 2001 From: Justin Waters Date: Tue, 18 May 2010 10:10:26 -0400 Subject: Add support for SDIO Wireless chip on the CCWMX51JS --- arch/arm/mach-mx51/mx51_ccwmx51js_gpio.c | 37 ++++++++++ arch/arm/plat-mxc/include/mach/mmc.h | 1 + drivers/mmc/core/core.c | 2 + drivers/mmc/core/sdio_ops.c | 119 ++++++++++++++++++------------- drivers/mmc/core/sdio_ops.h | 1 + drivers/mmc/host/mx_sdhci.c | 23 +++++- 6 files changed, 133 insertions(+), 50 deletions(-) diff --git a/arch/arm/mach-mx51/mx51_ccwmx51js_gpio.c b/arch/arm/mach-mx51/mx51_ccwmx51js_gpio.c index 293c9aa9545f..5d6d5def4566 100644 --- a/arch/arm/mach-mx51/mx51_ccwmx51js_gpio.c +++ b/arch/arm/mach-mx51/mx51_ccwmx51js_gpio.c @@ -332,6 +332,43 @@ static struct mxc_iomux_pin_cfg __initdata mxc_iomux_pins[] = { MX51_PIN_GPIO1_0, IOMUX_CONFIG_GPIO | IOMUX_CONFIG_SION, (PAD_CTL_HYS_ENABLE | PAD_CTL_100K_PU), }, + /* SDHC2*/ +#if defined(CONFIG_MMC_IMX_ESDHCI) || defined(CONFIG_MMC_IMX_ESDHCI_MODULE) + { + MX51_PIN_SD2_CMD, IOMUX_CONFIG_ALT0 | IOMUX_CONFIG_SION, + (PAD_CTL_PUE_KEEPER | PAD_CTL_PKE_ENABLE | PAD_CTL_DRV_HIGH | + PAD_CTL_47K_PU | PAD_CTL_SRE_FAST), + }, + { + MX51_PIN_SD2_CLK, IOMUX_CONFIG_ALT0, + (PAD_CTL_PUE_KEEPER | PAD_CTL_PKE_ENABLE | PAD_CTL_DRV_HIGH | + PAD_CTL_47K_PU | PAD_CTL_SRE_FAST), + }, + { + MX51_PIN_SD2_DATA0, IOMUX_CONFIG_ALT0, + (PAD_CTL_PUE_KEEPER | PAD_CTL_PKE_ENABLE | PAD_CTL_DRV_HIGH | + PAD_CTL_47K_PU | PAD_CTL_SRE_FAST), + }, + { + MX51_PIN_SD2_DATA1, IOMUX_CONFIG_ALT0, + (PAD_CTL_PUE_KEEPER | PAD_CTL_PKE_ENABLE | PAD_CTL_DRV_HIGH | + PAD_CTL_47K_PU | PAD_CTL_SRE_FAST), + }, + { + MX51_PIN_SD2_DATA2, IOMUX_CONFIG_ALT0, + (PAD_CTL_PUE_KEEPER | PAD_CTL_PKE_ENABLE | PAD_CTL_DRV_HIGH | + PAD_CTL_47K_PU | PAD_CTL_SRE_FAST), + }, + { + MX51_PIN_SD2_DATA3, IOMUX_CONFIG_ALT0, + (PAD_CTL_PUE_KEEPER | PAD_CTL_PKE_ENABLE | PAD_CTL_DRV_HIGH | + PAD_CTL_47K_PU | PAD_CTL_SRE_FAST), + }, + { + MX51_PIN_GPIO1_1, IOMUX_CONFIG_GPIO, + (PAD_CTL_HYS_ENABLE | PAD_CTL_100K_PU), + }, +#endif /* SDHC3 */ { MX51_PIN_NANDF_RDY_INT, IOMUX_CONFIG_ALT5 | IOMUX_CONFIG_SION, diff --git a/arch/arm/plat-mxc/include/mach/mmc.h b/arch/arm/plat-mxc/include/mach/mmc.h index 80cc61c175ea..d563c157bad7 100644 --- a/arch/arm/plat-mxc/include/mach/mmc.h +++ b/arch/arm/plat-mxc/include/mach/mmc.h @@ -43,6 +43,7 @@ struct mxc_mmc_platform_data { unsigned int reserved:16; unsigned int card_fixed:1; unsigned int card_inserted_state:1; + unsigned int quirks; /* Device quirks */ // u32 (*translate_vdd)(struct device *, unsigned int); unsigned int (*status) (struct device *); int (*wp_status) (struct device *); diff --git a/drivers/mmc/core/core.c b/drivers/mmc/core/core.c index d84c880fac84..50b208253440 100644 --- a/drivers/mmc/core/core.c +++ b/drivers/mmc/core/core.c @@ -890,6 +890,8 @@ void mmc_rescan(struct work_struct *work) mmc_claim_host(host); mmc_power_up(host); + sdio_go_idle(host); + mmc_go_idle(host); mmc_send_if_cond(host, host->ocr_avail); diff --git a/drivers/mmc/core/sdio_ops.c b/drivers/mmc/core/sdio_ops.c index 4eb7825fd1a7..208beeb23ed6 100644 --- a/drivers/mmc/core/sdio_ops.c +++ b/drivers/mmc/core/sdio_ops.c @@ -67,54 +67,6 @@ int mmc_send_io_op_cond(struct mmc_host *host, u32 ocr, u32 *rocr) return err; } -int mmc_io_rw_direct(struct mmc_card *card, int write, unsigned fn, - unsigned addr, u8 in, u8* out) -{ - struct mmc_command cmd; - int err; - - BUG_ON(!card); - BUG_ON(fn > 7); - - /* sanity check */ - if (addr & ~0x1FFFF) - return -EINVAL; - - memset(&cmd, 0, sizeof(struct mmc_command)); - - cmd.opcode = SD_IO_RW_DIRECT; - cmd.arg = write ? 0x80000000 : 0x00000000; - cmd.arg |= fn << 28; - cmd.arg |= (write && out) ? 0x08000000 : 0x00000000; - cmd.arg |= addr << 9; - cmd.arg |= in; - cmd.flags = MMC_RSP_SPI_R5 | MMC_RSP_R5 | MMC_CMD_AC; - - err = mmc_wait_for_cmd(card->host, &cmd, 0); - if (err) - return err; - - if (mmc_host_is_spi(card->host)) { - /* host driver already reported errors */ - } else { - if (cmd.resp[0] & R5_ERROR) - return -EIO; - if (cmd.resp[0] & R5_FUNCTION_NUMBER) - return -EINVAL; - if (cmd.resp[0] & R5_OUT_OF_RANGE) - return -ERANGE; - } - - if (out) { - if (mmc_host_is_spi(card->host)) - *out = (cmd.resp[0] >> 8) & 0xFF; - else - *out = cmd.resp[0] & 0xFF; - } - - return 0; -} - int mmc_io_rw_extended(struct mmc_card *card, int write, unsigned fn, unsigned addr, int incr_addr, u8 *buf, unsigned blocks, unsigned blksz) { @@ -182,3 +134,74 @@ int mmc_io_rw_extended(struct mmc_card *card, int write, unsigned fn, return 0; } +static int mmc_io_rw_direct_host(struct mmc_host *host, int write, unsigned fn, + unsigned addr, u8 in, u8 *out) +{ + struct mmc_command cmd; + int err; + + BUG_ON(!host); + BUG_ON(fn > 7); + + /* sanity check */ + if (addr & ~0x1FFFF) + return -EINVAL; + + memset(&cmd, 0, sizeof(struct mmc_command)); + + cmd.opcode = SD_IO_RW_DIRECT; + cmd.arg = write ? 0x80000000 : 0x00000000; + cmd.arg |= fn << 28; + cmd.arg |= (write && out) ? 0x08000000 : 0x00000000; + cmd.arg |= addr << 9; + cmd.arg |= in; + cmd.flags = MMC_RSP_SPI_R5 | MMC_RSP_R5 | MMC_CMD_AC; + + err = mmc_wait_for_cmd(host, &cmd, 0); + if (err) + return err; + + if (mmc_host_is_spi(host)) { + /* host driver already reported errors */ + } else { + if (cmd.resp[0] & R5_ERROR) + return -EIO; + if (cmd.resp[0] & R5_FUNCTION_NUMBER) + return -EINVAL; + if (cmd.resp[0] & R5_OUT_OF_RANGE) + return -ERANGE; + } + + if (out) { + if (mmc_host_is_spi(host)) + *out = (cmd.resp[0] >> 8) & 0xFF; + else + *out = cmd.resp[0] & 0xFF; + } + + return 0; +} + +int mmc_io_rw_direct(struct mmc_card *card, int write, unsigned fn, + unsigned addr, u8 in, u8 *out) +{ + BUG_ON(!card); + return mmc_io_rw_direct_host(card->host, write, fn, addr, in, out); +} + +int sdio_go_idle(struct mmc_host *host) +{ + int ret; + u8 abort; + + /* SDIO Simplified Specification V2.0, 4.4 Reset for SDIO */ + + ret = mmc_io_rw_direct_host(host, 0, 0, SDIO_CCCR_ABORT, 0, &abort); + if (ret) + abort = 0x08; + else + abort |= 0x08; + + ret = mmc_io_rw_direct_host(host, 1, 0, SDIO_CCCR_ABORT, abort, NULL); + return ret; +} diff --git a/drivers/mmc/core/sdio_ops.h b/drivers/mmc/core/sdio_ops.h index e2e74b0d17d8..9b546c71eb5e 100644 --- a/drivers/mmc/core/sdio_ops.h +++ b/drivers/mmc/core/sdio_ops.h @@ -17,6 +17,7 @@ int mmc_io_rw_direct(struct mmc_card *card, int write, unsigned fn, unsigned addr, u8 in, u8* out); int mmc_io_rw_extended(struct mmc_card *card, int write, unsigned fn, unsigned addr, int incr_addr, u8 *buf, unsigned blocks, unsigned blksz); +int sdio_go_idle(struct mmc_host *host); #endif diff --git a/drivers/mmc/host/mx_sdhci.c b/drivers/mmc/host/mx_sdhci.c index 4e686d80d071..682a6771169c 100644 --- a/drivers/mmc/host/mx_sdhci.c +++ b/drivers/mmc/host/mx_sdhci.c @@ -1184,6 +1184,16 @@ static void sdhci_tasklet_finish(unsigned long param) spin_unlock_irqrestore(&host->lock, flags); /* Stop the clock when the req is done */ + if (machine_is_mx51_ccwmx51js()) { + /** + * On the ConnectCore Wi-i.MX51 this, disabling there clock + * causes that we lose interrupts on the wireless SDIO cards + * For that reason, we dont disable the clock on this platform + */ + mmc_request_done(host->mmc, mrq); + return; + } + flags = SDHCI_DATA_ACTIVE | SDHCI_DOING_WRITE | SDHCI_DOING_READ; if (machine_is_mx35_3ds()) { /* Do not disable the eSDHC clk on MX35 3DS board, @@ -1203,7 +1213,6 @@ static void sdhci_tasklet_finish(unsigned long param) mmc_request_done(host->mmc, mrq); } - } static void sdhci_timeout_timer(unsigned long data) @@ -1784,13 +1793,13 @@ static int __devinit sdhci_probe_slot(struct platform_device set_irq_type(host->detect_irq, IRQF_TRIGGER_RISING); } while (ret != host->plat_data->status(host->mmc->parent)); + no_detect_irq: ret = host->plat_data->status(host->mmc->parent); if (ret) host->flags &= ~SDHCI_CD_PRESENT; else host->flags |= SDHCI_CD_PRESENT; - no_detect_irq: DBG("slot %d at 0x%x, irq %d \n", slot, host->res->start, host->irq); if (!request_mem_region(host->res->start, host->res->end - @@ -2064,6 +2073,7 @@ static int sdhci_probe(struct platform_device *pdev) int ret = 0, i; u8 slots = 1; struct sdhci_chip *chip; + struct mxc_mmc_platform_data *mmc_plat = pdev->dev.platform_data; printk(KERN_INFO DRIVER_NAME ": MXC SDHCI Controller Driver. \n"); BUG_ON(pdev == NULL); @@ -2085,6 +2095,15 @@ static int sdhci_probe(struct platform_device *pdev) chip->pdev = pdev; chip->quirks = mxc_quirks; + /** + * FIXME + * PPH This should be revisited and implemented a bit different. + * We pass quirks per device through the platform_data variable to allow + * different settings on each interface (DMA vs PIO, etc. + */ + if (mmc_plat->quirks != 0) + chip->quirks = mmc_plat->quirks; + if (debug_quirks) chip->quirks = debug_quirks; -- cgit v1.2.3