diff options
Diffstat (limited to 'drivers/mmc/host/sdhci-tegra.c')
-rw-r--r-- | drivers/mmc/host/sdhci-tegra.c | 72 |
1 files changed, 64 insertions, 8 deletions
diff --git a/drivers/mmc/host/sdhci-tegra.c b/drivers/mmc/host/sdhci-tegra.c index 39a8dd088fb1..a0b5e4394514 100644 --- a/drivers/mmc/host/sdhci-tegra.c +++ b/drivers/mmc/host/sdhci-tegra.c @@ -74,13 +74,17 @@ struct tegra_sdhci_hw_ops{ void (*sdhost_init)(struct sdhci_host *sdhci); }; +#ifdef CONFIG_ARCH_TEGRA_2x_SOC static struct tegra_sdhci_hw_ops tegra_2x_sdhci_ops = { }; +#endif +#ifdef CONFIG_ARCH_TEGRA_3x_SOC static struct tegra_sdhci_hw_ops tegra_3x_sdhci_ops = { .set_card_clock = tegra_3x_sdhci_set_card_clock, .sdhost_init = tegra3_sdhci_post_reset_init, }; +#endif struct tegra_sdhci_host { bool clk_enabled; @@ -97,6 +101,8 @@ struct tegra_sdhci_host { /* max clk supported by the platform */ unsigned int max_clk_limit; struct tegra_io_dpd *dpd; + bool card_present; + bool is_rail_enabled; }; static u32 tegra_sdhci_readl(struct sdhci_host *host, int reg) @@ -274,6 +280,32 @@ static void sdhci_status_notify_cb(int card_present, void *dev_id) static irqreturn_t carddetect_irq(int irq, void *data) { struct sdhci_host *sdhost = (struct sdhci_host *)data; + struct sdhci_pltfm_host *pltfm_host = sdhci_priv(sdhost); + struct tegra_sdhci_host *tegra_host = pltfm_host->priv; + struct platform_device *pdev = to_platform_device(mmc_dev(sdhost->mmc)); + struct tegra_sdhci_platform_data *plat; + + plat = pdev->dev.platform_data; + + tegra_host->card_present = (gpio_get_value(plat->cd_gpio) == 0); + + if (tegra_host->card_present) { + if (!tegra_host->is_rail_enabled) { + if (tegra_host->vdd_slot_reg) + regulator_enable(tegra_host->vdd_slot_reg); + if (tegra_host->vdd_io_reg) + regulator_enable(tegra_host->vdd_io_reg); + tegra_host->is_rail_enabled = 1; + } + } else { + if (tegra_host->is_rail_enabled) { + if (tegra_host->vdd_io_reg) + regulator_disable(tegra_host->vdd_io_reg); + if (tegra_host->vdd_slot_reg) + regulator_disable(tegra_host->vdd_slot_reg); + tegra_host->is_rail_enabled = 0; + } + } tasklet_schedule(&sdhost->card_tasklet); return IRQ_HANDLED; @@ -528,6 +560,16 @@ static int tegra_sdhci_suspend(struct sdhci_host *sdhci, pm_message_t state) regulator_disable(tegra_host->vdd_slot_reg); if (tegra_host->vdd_io_reg) regulator_disable(tegra_host->vdd_io_reg); + if (tegra_host->card_present) { + if (tegra_host->is_rail_enabled) { + if (tegra_host->vdd_io_reg) + regulator_disable(tegra_host->vdd_io_reg); + if (tegra_host->vdd_slot_reg) + regulator_disable(tegra_host->vdd_slot_reg); + tegra_host->is_rail_enabled = 0; + } + } + return 0; } @@ -538,10 +580,17 @@ static int tegra_sdhci_resume(struct sdhci_host *sdhci) unsigned long timeout; /* Enable the power rails if any */ - if (tegra_host->vdd_io_reg) - regulator_enable(tegra_host->vdd_io_reg); - if (tegra_host->vdd_slot_reg) - regulator_enable(tegra_host->vdd_slot_reg); + if (tegra_host->card_present) { + if (!tegra_host->is_rail_enabled) { + if (tegra_host->vdd_slot_reg) + regulator_enable(tegra_host->vdd_slot_reg); + if (tegra_host->vdd_io_reg) { + regulator_enable(tegra_host->vdd_io_reg); + tegra_sdhci_signal_voltage_switch(sdhci, MMC_SIGNAL_VOLTAGE_330); + } + tegra_host->is_rail_enabled = 1; + } + } /* Setting the min identification clock of freq 400KHz */ tegra_sdhci_set_clock(sdhci, 400000); @@ -660,7 +709,10 @@ static int __devinit sdhci_tegra_probe(struct platform_device *pdev) tegra_gpio_enable(plat->cd_gpio); gpio_direction_input(plat->cd_gpio); - rc = request_irq(gpio_to_irq(plat->cd_gpio), carddetect_irq, + tegra_host->card_present = (gpio_get_value(plat->cd_gpio) == 0); + + rc = request_threaded_irq(gpio_to_irq(plat->cd_gpio), NULL, + carddetect_irq, IRQF_TRIGGER_FALLING | IRQF_TRIGGER_RISING, mmc_hostname(host->mmc), host); @@ -718,8 +770,6 @@ static int __devinit sdhci_tegra_probe(struct platform_device *pdev) if (rc) { dev_err(mmc_dev(host->mmc), "%s regulator_set_voltage failed: %d", "vddio_sdmmc", rc); - } else { - regulator_enable(tegra_host->vdd_io_reg); } } @@ -729,7 +779,13 @@ static int __devinit sdhci_tegra_probe(struct platform_device *pdev) "vddio_sd_slot", PTR_ERR(tegra_host->vdd_slot_reg)); tegra_host->vdd_slot_reg = NULL; } else { - regulator_enable(tegra_host->vdd_slot_reg); + if (tegra_host->card_present) { + if (tegra_host->vdd_slot_reg) + regulator_enable(tegra_host->vdd_slot_reg); + if (tegra_host->vdd_io_reg) + regulator_enable(tegra_host->vdd_io_reg); + tegra_host->is_rail_enabled = 1; + } } } |