diff options
author | Pavan Kunapuli <pkunapuli@nvidia.com> | 2011-02-07 00:10:30 -0800 |
---|---|---|
committer | Dan Willemsen <dwillemsen@nvidia.com> | 2011-04-26 15:51:33 -0700 |
commit | aa5fab21680aa755e6f6afb7956031a9b644b9a2 (patch) | |
tree | e1f621f66e13f0d70be9ef3ad38f18334d4b2363 /drivers/mmc | |
parent | f365de1fe89b6b33caf6ab81c86b1f2843010e14 (diff) |
sdhci-tegra:Enable Hotplugin and wp support for sd card.
Enabling hot plugin/plugout support for sd card using
a gpio.
Enabling write protect detection support for sd card
using a gpio.
Enabling SDHCI_QUIRK_BROKEN_CARD_DETECTION quirk for
sdmmc on T30.
Bug 784133
Bug 786261
Original-Change-Id: Ie9a49472f4b2337a7e2b0eb52c2cb346b021f768
Reviewed-on: http://git-master/r/18438
Tested-by: Pavan Kunapuli <pkunapuli@nvidia.com>
Reviewed-by: Venkata Nageswara Penumarty <vpenumarty@nvidia.com>
Reviewed-by: Laxman Dewangan <ldewangan@nvidia.com>
Reviewed-by: Scott Williams <scwilliams@nvidia.com>
Change-Id: I5b41730281aa360b2ec29fd94c7644d008e8be28
Diffstat (limited to 'drivers/mmc')
-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 |
3 files changed, 66 insertions, 11 deletions
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); |