summaryrefslogtreecommitdiff
path: root/drivers/mmc
diff options
context:
space:
mode:
authorPavan Kunapuli <pkunapuli@nvidia.com>2011-02-07 00:10:30 -0800
committerDan Willemsen <dwillemsen@nvidia.com>2011-04-26 15:51:33 -0700
commitaa5fab21680aa755e6f6afb7956031a9b644b9a2 (patch)
treee1f621f66e13f0d70be9ef3ad38f18334d4b2363 /drivers/mmc
parentf365de1fe89b6b33caf6ab81c86b1f2843010e14 (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.c55
-rw-r--r--drivers/mmc/host/sdhci.c21
-rw-r--r--drivers/mmc/host/sdhci.h1
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);