diff options
Diffstat (limited to 'drivers/mmc/host/sdhci-tegra.c')
-rw-r--r-- | drivers/mmc/host/sdhci-tegra.c | 123 |
1 files changed, 57 insertions, 66 deletions
diff --git a/drivers/mmc/host/sdhci-tegra.c b/drivers/mmc/host/sdhci-tegra.c index 609fd6391d1f..8ff35e4cbfe4 100644 --- a/drivers/mmc/host/sdhci-tegra.c +++ b/drivers/mmc/host/sdhci-tegra.c @@ -74,7 +74,9 @@ static unsigned int tegra_sdhost_std_freq; #ifdef CONFIG_ARCH_TEGRA_3x_SOC static void tegra_3x_sdhci_set_card_clock(struct sdhci_host *sdhci, unsigned int clock); static void tegra3_sdhci_post_reset_init(struct sdhci_host *sdhci); +#endif +#ifndef CONFIG_ARCH_TEGRA_2x_SOC static unsigned int tegra3_sdhost_max_clk[4] = { 208000000, 104000000, 208000000, 104000000 }; #endif @@ -227,7 +229,7 @@ static void tegra3_sdhci_post_reset_init(struct sdhci_host *sdhci) SDHCI_VENDOR_MISC_CNTRL_ENABLE_SDR50_SUPPORT; sdhci_writew(sdhci, misc_ctrl, SDHCI_VENDOR_MISC_CNTRL); } -#endif +#endif /* #ifdef CONFIG_ARCH_TEGRA_3x_SOC */ static int tegra_sdhci_set_uhs_signaling(struct sdhci_host *host, unsigned int uhs) @@ -372,14 +374,7 @@ static void tegra_sdhci_set_clk_rate(struct sdhci_host *sdhci, unsigned int clk_rate; unsigned int emc_clk; - /* - * In SDR50 mode, run the sdmmc controller at freq greater than - * 104MHz to ensure the core voltage is at 1.2V. If the core voltage - * is below 1.2V, CRC errors would occur during data transfers. - */ - if (sdhci->mmc->card && - (mmc_card_ddr_mode(sdhci->mmc->card) || - (sdhci->mmc->ios.timing == MMC_TIMING_UHS_SDR50))) { + if (sdhci->mmc->ios.timing == MMC_TIMING_UHS_DDR50) { /* * In ddr mode, tegra sdmmc controller clock frequency * should be double the card clock frequency. @@ -394,6 +389,13 @@ static void tegra_sdhci_set_clk_rate(struct sdhci_host *sdhci, } else { clk_rate = clock * 2; } + } else if (sdhci->mmc->ios.timing == MMC_TIMING_UHS_SDR50) { + /* + * In SDR50 mode, run the sdmmc controller at freq greater than + * 104MHz to ensure the core voltage is at 1.2V. If the core voltage + * is below 1.2V, CRC errors would occur during data transfers. + */ + clk_rate = clock * 2; } else { if (clock <= tegra_sdhost_min_freq) clk_rate = tegra_sdhost_min_freq; @@ -410,7 +412,6 @@ static void tegra_sdhci_set_clk_rate(struct sdhci_host *sdhci, clk_set_rate(pltfm_host->clk, clk_rate); sdhci->max_clk = clk_get_rate(pltfm_host->clk); } - #ifdef CONFIG_ARCH_TEGRA_3x_SOC static void tegra_3x_sdhci_set_card_clock(struct sdhci_host *sdhci, unsigned int clock) { @@ -496,7 +497,7 @@ set_clk: out: sdhci->clock = clock; } -#endif +#endif /* #ifdef CONFIG_ARCH_TEGRA_3x_SOC */ static void tegra_sdhci_set_clock(struct sdhci_host *sdhci, unsigned int clock) { @@ -509,7 +510,12 @@ static void tegra_sdhci_set_clock(struct sdhci_host *sdhci, unsigned int clock) if (clock) { /* bring out sd instance from io dpd mode */ - tegra_io_dpd_disable(tegra_host->dpd); + if (tegra_host->dpd) { + mutex_lock(&tegra_host->dpd->delay_lock); + cancel_delayed_work_sync(&tegra_host->dpd->delay_dpd); + tegra_io_dpd_disable(tegra_host->dpd); + mutex_unlock(&tegra_host->dpd->delay_lock); + } if (!tegra_host->clk_enabled) { clk_enable(pltfm_host->clk); @@ -530,7 +536,18 @@ static void tegra_sdhci_set_clock(struct sdhci_host *sdhci, unsigned int clock) clk_disable(pltfm_host->clk); tegra_host->clk_enabled = false; /* io dpd enable call for sd instance */ - tegra_io_dpd_enable(tegra_host->dpd); + + if (tegra_host->dpd) { + mutex_lock(&tegra_host->dpd->delay_lock); + if (tegra_host->dpd->need_delay_dpd) { + schedule_delayed_work( + &tegra_host->dpd->delay_dpd, + msecs_to_jiffies(100)); + } else { + tegra_io_dpd_enable(tegra_host->dpd); + } + mutex_unlock(&tegra_host->dpd->delay_lock); + } } } @@ -658,36 +675,15 @@ static void sdhci_tegra_set_tap_delay(struct sdhci_host *sdhci, sdhci_writel(sdhci, vendor_ctrl, SDHCI_VENDOR_CLOCK_CNTRL); } -static void sdhci_tegra_clear_set_irqs(struct sdhci_host *host, - u32 clear, u32 set) -{ - u32 ier; - - ier = sdhci_readl(host, SDHCI_INT_ENABLE); - ier &= ~clear; - ier |= set; - sdhci_writel(host, ier, SDHCI_INT_ENABLE); - sdhci_writel(host, ier, SDHCI_SIGNAL_ENABLE); -} - static int sdhci_tegra_run_frequency_tuning(struct sdhci_host *sdhci) { int err = 0; u8 ctrl; - u32 ier; u32 mask; unsigned int timeout = 10; int flags; u32 intstatus; - /* - * As per the Host Controller spec v3.00, tuning command - * generates Buffer Read Ready interrupt only, so enable that. - */ - ier = sdhci_readl(sdhci, SDHCI_INT_ENABLE); - sdhci_tegra_clear_set_irqs(sdhci, ier, SDHCI_INT_DATA_AVAIL | - SDHCI_INT_DATA_CRC); - mask = SDHCI_CMD_INHIBIT | SDHCI_DATA_INHIBIT; while (sdhci_readl(sdhci, SDHCI_PRESENT_STATE) & mask) { if (timeout == 0) { @@ -759,7 +755,6 @@ static int sdhci_tegra_run_frequency_tuning(struct sdhci_host *sdhci) } mdelay(1); out: - sdhci_tegra_clear_set_irqs(sdhci, SDHCI_INT_DATA_AVAIL, ier); return err; } @@ -773,6 +768,7 @@ static int sdhci_tegra_execute_tuning(struct sdhci_host *sdhci) unsigned int temp_pass_window = 0; unsigned int best_low_pass_tap = 0; unsigned int best_pass_window = 0; + u32 ier; /* Tuning is valid only in SDR104 and SDR50 modes */ ctrl_2 = sdhci_readw(sdhci, SDHCI_HOST_CONTROL2); @@ -785,11 +781,20 @@ static int sdhci_tegra_execute_tuning(struct sdhci_host *sdhci) if (tap_delay_status == NULL) { dev_err(mmc_dev(sdhci->mmc), "failed to allocate memory" "for storing tap_delay_status\n"); - err = -ENOMEM; - goto out; + return -ENOMEM; } /* + * Disable all interrupts signalling.Enable interrupt status + * detection for buffer read ready and data crc. We use + * polling for tuning as it involves less overhead. + */ + ier = sdhci_readl(sdhci, SDHCI_INT_ENABLE); + sdhci_writel(sdhci, 0, SDHCI_SIGNAL_ENABLE); + sdhci_writel(sdhci, SDHCI_INT_DATA_AVAIL | + SDHCI_INT_DATA_CRC, SDHCI_INT_ENABLE); + + /* * Set each tap delay value and run frequency tuning. After each * run, update the tap delay status as working or not working. */ @@ -840,7 +845,10 @@ static int sdhci_tegra_execute_tuning(struct sdhci_host *sdhci) /* Run frequency tuning */ err = sdhci_tegra_run_frequency_tuning(sdhci); -out: + /* Enable the normal interrupts signalling */ + sdhci_writel(sdhci, ier, SDHCI_INT_ENABLE); + sdhci_writel(sdhci, ier, SDHCI_SIGNAL_ENABLE); + if (tap_delay_status) kfree(tap_delay_status); @@ -865,6 +873,12 @@ static int tegra_sdhci_suspend(struct sdhci_host *sdhci, pm_message_t state) } } + if (tegra_host->dpd) { + mutex_lock(&tegra_host->dpd->delay_lock); + tegra_host->dpd->need_delay_dpd = 1; + mutex_unlock(&tegra_host->dpd->delay_lock); + } + return 0; } @@ -905,9 +919,6 @@ static struct sdhci_ops tegra_sdhci_ops = { .read_w = tegra_sdhci_readw, .write_l = tegra_sdhci_writel, .platform_8bit_width = tegra_sdhci_8bit, -#ifdef CONFIG_ARCH_TEGRA_3x_SOC - .set_card_clock = tegra_3x_sdhci_set_card_clock, -#endif .set_clock = tegra_sdhci_set_clock, .suspend = tegra_sdhci_suspend, .resume = tegra_sdhci_resume, @@ -981,7 +992,6 @@ static int __devinit sdhci_tegra_probe(struct platform_device *pdev) "failed to allocate power gpio\n"); goto err_power_req; } - tegra_gpio_enable(plat->power_gpio); gpio_direction_output(plat->power_gpio, 1); } @@ -992,7 +1002,6 @@ static int __devinit sdhci_tegra_probe(struct platform_device *pdev) "failed to allocate cd gpio\n"); goto err_cd_req; } - tegra_gpio_enable(plat->cd_gpio); gpio_direction_input(plat->cd_gpio); tegra_host->card_present = (gpio_get_value(plat->cd_gpio) == 0); @@ -1027,7 +1036,6 @@ static int __devinit sdhci_tegra_probe(struct platform_device *pdev) "failed to allocate wp gpio\n"); goto err_wp_req; } - tegra_gpio_enable(plat->wp_gpio); gpio_direction_input(plat->wp_gpio); } @@ -1133,12 +1141,6 @@ static int __devinit sdhci_tegra_probe(struct platform_device *pdev) host->mmc->caps |= MMC_CAP_BKOPS; #endif -#ifdef CONFIG_MMC_EMBEDDED_SDIO - /* Do not turn OFF embedded sdio cards as it support Wake on Wireless */ - if (plat->mmc_data.embedded_sdio) - host->mmc->pm_flags |= MMC_PM_KEEP_POWER; -#endif - tegra_sdhost_min_freq = TEGRA_SDHOST_MIN_FREQ; #ifdef CONFIG_ARCH_TEGRA_2x_SOC tegra_host->hw_ops = &tegra_2x_sdhci_ops; @@ -1160,23 +1162,17 @@ err_add_host: err_clk_put: clk_put(pltfm_host->clk); err_clk_get: - if (gpio_is_valid(plat->wp_gpio)) { - tegra_gpio_disable(plat->wp_gpio); + if (gpio_is_valid(plat->wp_gpio)) gpio_free(plat->wp_gpio); - } err_wp_req: if (gpio_is_valid(plat->cd_gpio)) free_irq(gpio_to_irq(plat->cd_gpio), host); err_cd_irq_req: - if (gpio_is_valid(plat->cd_gpio)) { - tegra_gpio_disable(plat->cd_gpio); + if (gpio_is_valid(plat->cd_gpio)) gpio_free(plat->cd_gpio); - } err_cd_req: - if (gpio_is_valid(plat->power_gpio)) { - tegra_gpio_disable(plat->power_gpio); + if (gpio_is_valid(plat->power_gpio)) gpio_free(plat->power_gpio); - } err_power_req: err_no_mem: kfree(tegra_host); @@ -1209,21 +1205,16 @@ static int __devexit sdhci_tegra_remove(struct platform_device *pdev) regulator_put(tegra_host->vdd_io_reg); } - if (gpio_is_valid(plat->wp_gpio)) { - tegra_gpio_disable(plat->wp_gpio); + if (gpio_is_valid(plat->wp_gpio)) gpio_free(plat->wp_gpio); - } if (gpio_is_valid(plat->cd_gpio)) { free_irq(gpio_to_irq(plat->cd_gpio), host); - tegra_gpio_disable(plat->cd_gpio); gpio_free(plat->cd_gpio); } - if (gpio_is_valid(plat->power_gpio)) { - tegra_gpio_disable(plat->power_gpio); + if (gpio_is_valid(plat->power_gpio)) gpio_free(plat->power_gpio); - } if (tegra_host->clk_enabled) clk_disable(pltfm_host->clk); |