summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--arch/arm/mach-tegra/board-cardhu-pinmux.c6
-rw-r--r--arch/arm/mach-tegra/board-cardhu-sdhci.c61
-rw-r--r--arch/arm/mach-tegra/include/mach/sdhci.h2
-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
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);