diff options
-rw-r--r-- | arch/arm/mach-tegra/board-cardhu-pinmux.c | 6 | ||||
-rw-r--r-- | arch/arm/mach-tegra/board-cardhu-sdhci.c | 61 | ||||
-rw-r--r-- | arch/arm/mach-tegra/include/mach/sdhci.h | 2 | ||||
-rw-r--r-- | drivers/mmc/host/sdhci-tegra.c | 55 | ||||
-rw-r--r-- | drivers/mmc/host/sdhci.c | 21 | ||||
-rw-r--r-- | drivers/mmc/host/sdhci.h | 1 |
6 files changed, 112 insertions, 34 deletions
diff --git a/arch/arm/mach-tegra/board-cardhu-pinmux.c b/arch/arm/mach-tegra/board-cardhu-pinmux.c index 9c8c77ff8c13..9963d91282df 100644 --- a/arch/arm/mach-tegra/board-cardhu-pinmux.c +++ b/arch/arm/mach-tegra/board-cardhu-pinmux.c @@ -375,10 +375,10 @@ static __initdata struct tegra_pingroup_config cardhu_pinmux[] = { DEFAULT_PINMUX(HDMI_INT, RSVD0, NORMAL, TRISTATE, INPUT), /* Gpios */ - /* SDMMC1 WP gpio */ - DEFAULT_PINMUX(VI_D11, RSVD1, NORMAL, NORMAL, INPUT), /* SDMMC1 CD gpio */ - DEFAULT_PINMUX(GMI_IORDY, RSVD1, NORMAL, NORMAL, INPUT), + DEFAULT_PINMUX(GMI_IORDY, RSVD1, PULL_UP, NORMAL, INPUT), + /* SDMMC1 WP gpio */ + DEFAULT_PINMUX(VI_D11, RSVD1, PULL_UP, NORMAL, INPUT), /* Touch panel GPIO */ /* Touch IRQ */ diff --git a/arch/arm/mach-tegra/board-cardhu-sdhci.c b/arch/arm/mach-tegra/board-cardhu-sdhci.c index d52ee9e39fca..340f95299e12 100644 --- a/arch/arm/mach-tegra/board-cardhu-sdhci.c +++ b/arch/arm/mach-tegra/board-cardhu-sdhci.c @@ -34,6 +34,8 @@ #define CARDHU_WLAN_PWR TEGRA_GPIO_PD4 #define CARDHU_WLAN_RST TEGRA_GPIO_PD3 +#define CARDHU_SD_CD TEGRA_GPIO_PI5 +#define CARDHU_SD_WP TEGRA_GPIO_PT3 static void (*wifi_status_cb)(int card_present, void *dev_id); static void *wifi_status_cb_devid; @@ -183,15 +185,19 @@ static int cardhu_sd_cd_gpio_init(void) { unsigned int rc = 0; - rc = gpio_request(TEGRA_GPIO_PI5, "card_detect"); - if (rc) + rc = gpio_request(CARDHU_SD_CD, "card_detect"); + if (rc) { + pr_err("Card detect gpio request failed:%d\n", rc); return rc; + } - tegra_gpio_enable(TEGRA_GPIO_PI5); + tegra_gpio_enable(CARDHU_SD_CD); - rc = gpio_direction_input(TEGRA_GPIO_PI5); - if (rc) + rc = gpio_direction_input(CARDHU_SD_CD); + if (rc) { + pr_err("Unable to configure direction for card detect gpio:%d\n", rc); return rc; + } return 0; } @@ -200,15 +206,19 @@ static int cardhu_sd_wp_gpio_init(void) { unsigned int rc = 0; - rc = gpio_request(TEGRA_GPIO_PT3, "write_protect"); - if (rc) + rc = gpio_request(CARDHU_SD_WP, "write_protect"); + if (rc) { + pr_err("Write protect gpio request failed:%d\n", rc); return rc; + } - tegra_gpio_enable(TEGRA_GPIO_PT3); + tegra_gpio_enable(CARDHU_SD_WP); - rc = gpio_direction_input(TEGRA_GPIO_PT3); - if (rc) + rc = gpio_direction_input(CARDHU_SD_WP); + if (rc) { + pr_err("Unable to configure direction for write protect gpio:%d\n", rc); return rc; + } return 0; } @@ -253,15 +263,24 @@ static int cardhu_wifi_reset(int on) static int __init cardhu_wifi_init(void) { + int rc; - gpio_request(CARDHU_WLAN_PWR, "wlan_power"); - gpio_request(CARDHU_WLAN_RST, "wlan_rst"); + rc = gpio_request(CARDHU_WLAN_PWR, "wlan_power"); + if (rc) + pr_err("WLAN_PWR gpio request failed:%d\n", rc); + rc = gpio_request(CARDHU_WLAN_RST, "wlan_rst"); + if (rc) + pr_err("WLAN_RST gpio request failed:%d\n", rc); tegra_gpio_enable(CARDHU_WLAN_PWR); tegra_gpio_enable(CARDHU_WLAN_RST); - gpio_direction_output(CARDHU_WLAN_PWR, 0); + rc = gpio_direction_output(CARDHU_WLAN_PWR, 0); + if (rc) + pr_err("WLAN_PWR gpio direction configuration failed:%d\n", rc); gpio_direction_output(CARDHU_WLAN_RST, 0); + if (rc) + pr_err("WLAN_RST gpio direction configuration failed:%d\n", rc); platform_device_register(&cardhu_wifi_device); return 0; @@ -273,16 +292,18 @@ int __init cardhu_sdhci_init(void) platform_device_register(&tegra_sdhci_device3); platform_device_register(&tegra_sdhci_device2); -#if 0 /* Fix ME: The gpios have to enabled for hot plug support */ rc = cardhu_sd_cd_gpio_init(); - if (!rc) - tegra_sdhci_platform_data0.cd_gpio = TEGRA_GPIO_PI5; - + if (!rc) { + tegra_sdhci_platform_data0.cd_gpio = CARDHU_SD_CD; + tegra_sdhci_platform_data0.cd_gpio_polarity = 0; + } rc = cardhu_sd_wp_gpio_init(); - if (!rc) - tegra_sdhci_platform_data0.cd_gpio = TEGRA_GPIO_PT3; -#endif + if (!rc) { + tegra_sdhci_platform_data0.wp_gpio = CARDHU_SD_WP; + tegra_sdhci_platform_data0.wp_gpio_polarity = 1; + } + platform_device_register(&tegra_sdhci_device0); cardhu_wifi_init(); diff --git a/arch/arm/mach-tegra/include/mach/sdhci.h b/arch/arm/mach-tegra/include/mach/sdhci.h index 63a874558483..8a63d5c3f609 100644 --- a/arch/arm/mach-tegra/include/mach/sdhci.h +++ b/arch/arm/mach-tegra/include/mach/sdhci.h @@ -24,7 +24,9 @@ struct tegra_sdhci_platform_data { const char *clk_id; int force_hs; int cd_gpio; + int cd_gpio_polarity; int wp_gpio; + int wp_gpio_polarity; int power_gpio; unsigned int tap_delay; bool is_voltage_switch_supported; diff --git a/drivers/mmc/host/sdhci-tegra.c b/drivers/mmc/host/sdhci-tegra.c index 90d8d023e0eb..a2a0617f7484 100644 --- a/drivers/mmc/host/sdhci-tegra.c +++ b/drivers/mmc/host/sdhci-tegra.c @@ -62,19 +62,35 @@ struct tegra_sdhci_host { int clk_enabled; bool card_always_on; u32 sdhci_ints; + int cd_gpio; + int cd_gpio_polarity; + int wp_gpio; + int wp_gpio_polarity; unsigned int tap_delay; unsigned int max_clk; struct regulator *vsd; + unsigned int card_present; }; static irqreturn_t carddetect_irq(int irq, void *data) { struct sdhci_host *sdhost = (struct sdhci_host *)data; + struct tegra_sdhci_host *host = sdhci_priv(sdhost); + + host->card_present = + (gpio_get_value(host->cd_gpio) == host->cd_gpio_polarity); tasklet_schedule(&sdhost->card_tasklet); return IRQ_HANDLED; }; +static int tegra_sdhci_card_detect(struct sdhci_host *sdhci) +{ + struct tegra_sdhci_host *host = sdhci_priv(sdhci); + + return host->card_present; +} + static void tegra_sdhci_status_notify_cb(int card_present, void *dev_id) { struct sdhci_host *sdhci = (struct sdhci_host *)dev_id; @@ -191,10 +207,19 @@ static void tegra_sdhci_set_signalling_voltage(struct sdhci_host *sdhci, } } +static int tegra_sdhci_get_ro(struct sdhci_host *sdhci) +{ + struct tegra_sdhci_host *host = sdhci_priv(sdhci); + + BUG_ON(host->wp_gpio == -1); + return (gpio_get_value(host->wp_gpio) == host->wp_gpio_polarity); +} + static struct sdhci_ops tegra_sdhci_ops = { .enable_dma = tegra_sdhci_enable_dma, .set_clock = tegra_sdhci_set_clock, .configure_capabilities = tegra_sdhci_configure_capabilities, + .get_cd = tegra_sdhci_card_detect, }; static int __devinit tegra_sdhci_probe(struct platform_device *pdev) @@ -236,6 +261,10 @@ static int __devinit tegra_sdhci_probe(struct platform_device *pdev) host->card_always_on = (plat->power_gpio == -1) ? 1 : 0; host->max_clk = plat->max_clk; host->tap_delay = plat->tap_delay; + host->cd_gpio = plat->cd_gpio; + host->cd_gpio_polarity = plat->cd_gpio_polarity; + host->wp_gpio = plat->wp_gpio; + host->wp_gpio_polarity = plat->wp_gpio_polarity; host->clk = clk_get(&pdev->dev, plat->clk_id); if (IS_ERR(host->clk)) { @@ -314,6 +343,9 @@ static int __devinit tegra_sdhci_probe(struct platform_device *pdev) SDHCI_QUIRK_8_BIT_DATA | SDHCI_QUIRK_BROKEN_ADMA_ZEROLEN_DESC | SDHCI_QUIRK_RUNTIME_DISABLE; +#ifdef CONFIG_ARCH_TEGRA_3x_SOC + sdhci->quirks |= SDHCI_QUIRK_BROKEN_CARD_DETECTION; +#endif if (plat->force_hs != 0) sdhci->quirks |= SDHCI_QUIRK_FORCE_HIGH_SPEED_MODE; @@ -325,25 +357,36 @@ static int __devinit tegra_sdhci_probe(struct platform_device *pdev) plat->num_funcs); #endif - - rc = sdhci_add_host(sdhci); - if (rc) - goto err_clk_disable; - platform_set_drvdata(pdev, host); + /* + * If the card detect gpio is not present, treat the card as + * non-removable. + */ + if (plat->cd_gpio == -1) + host->card_present = 1; + if (plat->cd_gpio != -1) { rc = request_irq(gpio_to_irq(plat->cd_gpio), carddetect_irq, IRQF_TRIGGER_FALLING | IRQF_TRIGGER_RISING, mmc_hostname(sdhci->mmc), sdhci); - if (rc) goto err_remove_host; + + host->card_present = + (gpio_get_value(plat->cd_gpio) == host->cd_gpio_polarity); } else if (plat->register_status_notify) { plat->register_status_notify( tegra_sdhci_status_notify_cb, sdhci); } + if (plat->wp_gpio != -1) + tegra_sdhci_ops.get_ro = tegra_sdhci_get_ro; + + rc = sdhci_add_host(sdhci); + if (rc) + goto err_clk_disable; + if (plat->board_probe) plat->board_probe(pdev->id, sdhci->mmc); diff --git a/drivers/mmc/host/sdhci.c b/drivers/mmc/host/sdhci.c index 153866bc8e0e..d01ca11291d0 100644 --- a/drivers/mmc/host/sdhci.c +++ b/drivers/mmc/host/sdhci.c @@ -1141,10 +1141,14 @@ static void sdhci_request(struct mmc_host *mmc, struct mmc_request *mrq) host->mrq = mrq; - /* If polling, assume that the card is always present. */ - if (host->quirks & SDHCI_QUIRK_BROKEN_CARD_DETECTION) - present = true; - else + if (host->quirks & SDHCI_QUIRK_BROKEN_CARD_DETECTION) { + if (host->ops->get_cd) + present = host->ops->get_cd(host); + else { + /* If polling, assume that card is always present. */ + present = true; + } + } else present = sdhci_readl(host, SDHCI_PRESENT_STATE) & SDHCI_CARD_PRESENT; @@ -1416,10 +1420,17 @@ static const struct mmc_host_ops sdhci_ops = { void sdhci_card_detect_callback(struct sdhci_host *host) { unsigned long flags; + int present; spin_lock_irqsave(&host->lock, flags); - if (!(sdhci_readl(host, SDHCI_PRESENT_STATE) & SDHCI_CARD_PRESENT)) { + if ((host->quirks & SDHCI_QUIRK_BROKEN_CARD_DETECTION) && host->ops->get_cd) + present = host->ops->get_cd(host); + else + present = (sdhci_readl(host, SDHCI_PRESENT_STATE) & + SDHCI_CARD_PRESENT); + + if (!present) { if (host->mrq) { printk(KERN_ERR "%s: Card removed during transfer!\n", mmc_hostname(host->mmc)); diff --git a/drivers/mmc/host/sdhci.h b/drivers/mmc/host/sdhci.h index 9dfa40cf393c..2626f21a6514 100644 --- a/drivers/mmc/host/sdhci.h +++ b/drivers/mmc/host/sdhci.h @@ -358,6 +358,7 @@ struct sdhci_ops { unsigned int signalling_voltage); int (*enable_dma)(struct sdhci_host *host); + int (*get_cd)(struct sdhci_host *host); int (*get_ro)(struct sdhci_host *host); unsigned int (*get_max_clock)(struct sdhci_host *host); unsigned int (*get_min_clock)(struct sdhci_host *host); |