From 76f3ae125f3ca777cc831d475d17184641d5bc46 Mon Sep 17 00:00:00 2001 From: Rhyland Klein Date: Wed, 20 Feb 2013 13:35:16 -0500 Subject: mmc: sdhci-tegra: cleanup ifdefs The structs wrapped with the SOC ifdefs are small enough where having them always there shouldn't be a big overhead. Removing the ifdefs also makes the code a little cleaner. Signed-off-by: Rhyland Klein Acked-by: Stephen Warren Signed-off-by: Chris Ball diff --git a/drivers/mmc/host/sdhci-tegra.c b/drivers/mmc/host/sdhci-tegra.c index 08b06e9..7300971 100644 --- a/drivers/mmc/host/sdhci-tegra.c +++ b/drivers/mmc/host/sdhci-tegra.c @@ -173,7 +173,6 @@ static struct sdhci_ops tegra_sdhci_ops = { .platform_reset_exit = tegra_sdhci_reset_exit, }; -#ifdef CONFIG_ARCH_TEGRA_2x_SOC static struct sdhci_pltfm_data sdhci_tegra20_pdata = { .quirks = SDHCI_QUIRK_BROKEN_TIMEOUT_VAL | SDHCI_QUIRK_SINGLE_POWER_WRITE | @@ -187,9 +186,7 @@ static struct sdhci_tegra_soc_data soc_data_tegra20 = { .nvquirks = NVQUIRK_FORCE_SDHCI_SPEC_200 | NVQUIRK_ENABLE_BLOCK_GAP_DET, }; -#endif -#ifdef CONFIG_ARCH_TEGRA_3x_SOC static struct sdhci_pltfm_data sdhci_tegra30_pdata = { .quirks = SDHCI_QUIRK_BROKEN_TIMEOUT_VAL | SDHCI_QUIRK_DATA_TIMEOUT_USES_SDCLK | @@ -203,15 +200,10 @@ static struct sdhci_tegra_soc_data soc_data_tegra30 = { .pdata = &sdhci_tegra30_pdata, .nvquirks = NVQUIRK_ENABLE_SDHCI_SPEC_300, }; -#endif static const struct of_device_id sdhci_tegra_dt_match[] = { -#ifdef CONFIG_ARCH_TEGRA_3x_SOC { .compatible = "nvidia,tegra30-sdhci", .data = &soc_data_tegra30 }, -#endif -#ifdef CONFIG_ARCH_TEGRA_2x_SOC { .compatible = "nvidia,tegra20-sdhci", .data = &soc_data_tegra20 }, -#endif {} }; MODULE_DEVICE_TABLE(of, sdhci_dt_ids); -- cgit v0.10.2 From 5ebf2552493228ec875ea45f6ba8a816cca3744a Mon Sep 17 00:00:00 2001 From: Rhyland Klein Date: Wed, 20 Feb 2013 13:35:17 -0500 Subject: mmc: sdhci-tegra: add basic support for Tegra114 The mmc controller on Tegra114 platforms is basically compatible with the settings used for Tegra30. However there is a difference where we don't need the extra ENABLE_SDHCI_SPEC_300 quirk as Tegra114 hardware advertises v3.0 support already. Signed-off-by: Rhyland Klein Acked-by: Stephen Warren Signed-off-by: Chris Ball diff --git a/drivers/mmc/host/sdhci-tegra.c b/drivers/mmc/host/sdhci-tegra.c index 7300971..ff99b63 100644 --- a/drivers/mmc/host/sdhci-tegra.c +++ b/drivers/mmc/host/sdhci-tegra.c @@ -201,7 +201,21 @@ static struct sdhci_tegra_soc_data soc_data_tegra30 = { .nvquirks = NVQUIRK_ENABLE_SDHCI_SPEC_300, }; +static struct sdhci_pltfm_data sdhci_tegra114_pdata = { + .quirks = SDHCI_QUIRK_BROKEN_TIMEOUT_VAL | + SDHCI_QUIRK_DATA_TIMEOUT_USES_SDCLK | + SDHCI_QUIRK_SINGLE_POWER_WRITE | + SDHCI_QUIRK_NO_HISPD_BIT | + SDHCI_QUIRK_BROKEN_ADMA_ZEROLEN_DESC, + .ops = &tegra_sdhci_ops, +}; + +static struct sdhci_tegra_soc_data soc_data_tegra114 = { + .pdata = &sdhci_tegra114_pdata, +}; + static const struct of_device_id sdhci_tegra_dt_match[] = { + { .compatible = "nvidia,tegra114-sdhci", .data = &soc_data_tegra114 }, { .compatible = "nvidia,tegra30-sdhci", .data = &soc_data_tegra30 }, { .compatible = "nvidia,tegra20-sdhci", .data = &soc_data_tegra20 }, {} -- cgit v0.10.2 From 9665f7f234d095fc7c28c70df819a3f7b6a7b4e8 Mon Sep 17 00:00:00 2001 From: Sachin Kamat Date: Mon, 18 Feb 2013 14:23:08 +0530 Subject: mmc: dw_mmc: Make dw_mci_exynos_probe static Silences the following sparse warning: drivers/mmc/host/dw_mmc-exynos.c:218:5: warning: symbol 'dw_mci_exynos_probe' was not declared. Should it be static? Signed-off-by: Sachin Kamat Acked-by: Jaehoon Chung Acked-by: Seungwon Jeon Signed-off-by: Chris Ball diff --git a/drivers/mmc/host/dw_mmc-exynos.c b/drivers/mmc/host/dw_mmc-exynos.c index 72fd0f2..5a09c77 100644 --- a/drivers/mmc/host/dw_mmc-exynos.c +++ b/drivers/mmc/host/dw_mmc-exynos.c @@ -215,7 +215,7 @@ static const struct of_device_id dw_mci_exynos_match[] = { }; MODULE_DEVICE_TABLE(of, dw_mci_exynos_match); -int dw_mci_exynos_probe(struct platform_device *pdev) +static int dw_mci_exynos_probe(struct platform_device *pdev) { const struct dw_mci_drv_data *drv_data; const struct of_device_id *match; -- cgit v0.10.2 From 0aacd23ff29a846c7eebbd9db8752fa360f34ad1 Mon Sep 17 00:00:00 2001 From: Joseph Lo Date: Mon, 11 Mar 2013 14:44:11 -0600 Subject: mmc: tegra: use mmc_of_parse to get the support of standard MMC DT bindings Updating the sdhci-tegra driver to use mmc_of_parse to support standard MMC DT bindings. Then we can remove the redundant code that already support in generic MMC core. Signed-off-by: Joseph Lo Tested-by: Thierry Reding Signed-off-by: Stephen Warren Signed-off-by: Chris Ball diff --git a/drivers/mmc/host/sdhci-tegra.c b/drivers/mmc/host/sdhci-tegra.c index ff99b63..c665d1d 100644 --- a/drivers/mmc/host/sdhci-tegra.c +++ b/drivers/mmc/host/sdhci-tegra.c @@ -24,6 +24,7 @@ #include #include #include +#include #include @@ -44,10 +45,7 @@ struct sdhci_tegra_soc_data { struct sdhci_tegra { const struct sdhci_tegra_soc_data *soc_data; - int cd_gpio; - int wp_gpio; int power_gpio; - int is_8bit; }; static u32 tegra_sdhci_readl(struct sdhci_host *host, int reg) @@ -107,23 +105,9 @@ static void tegra_sdhci_writel(struct sdhci_host *host, u32 val, int reg) static unsigned int tegra_sdhci_get_ro(struct sdhci_host *host) { - struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); - struct sdhci_tegra *tegra_host = pltfm_host->priv; - - if (!gpio_is_valid(tegra_host->wp_gpio)) - return -1; - - return gpio_get_value(tegra_host->wp_gpio); + return mmc_gpio_get_ro(host->mmc); } -static irqreturn_t carddetect_irq(int irq, void *data) -{ - struct sdhci_host *sdhost = (struct sdhci_host *)data; - - tasklet_schedule(&sdhost->card_tasklet); - return IRQ_HANDLED; -}; - static void tegra_sdhci_reset_exit(struct sdhci_host *host, u8 mask) { struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); @@ -145,12 +129,11 @@ static void tegra_sdhci_reset_exit(struct sdhci_host *host, u8 mask) static int tegra_sdhci_buswidth(struct sdhci_host *host, int bus_width) { - struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); - struct sdhci_tegra *tegra_host = pltfm_host->priv; u32 ctrl; ctrl = sdhci_readb(host, SDHCI_HOST_CONTROL); - if (tegra_host->is_8bit && bus_width == MMC_BUS_WIDTH_8) { + if ((host->mmc->caps & MMC_CAP_8_BIT_DATA) && + (bus_width == MMC_BUS_WIDTH_8)) { ctrl &= ~SDHCI_CTRL_4BITBUS; ctrl |= SDHCI_CTRL_8BITBUS; } else { @@ -222,19 +205,15 @@ static const struct of_device_id sdhci_tegra_dt_match[] = { }; MODULE_DEVICE_TABLE(of, sdhci_dt_ids); -static void sdhci_tegra_parse_dt(struct device *dev, - struct sdhci_tegra *tegra_host) +static void sdhci_tegra_parse_dt(struct device *dev) { struct device_node *np = dev->of_node; - u32 bus_width; + struct sdhci_host *host = dev_get_drvdata(dev); + struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); + struct sdhci_tegra *tegra_host = pltfm_host->priv; - tegra_host->cd_gpio = of_get_named_gpio(np, "cd-gpios", 0); - tegra_host->wp_gpio = of_get_named_gpio(np, "wp-gpios", 0); tegra_host->power_gpio = of_get_named_gpio(np, "power-gpios", 0); - - if (of_property_read_u32(np, "bus-width", &bus_width) == 0 && - bus_width == 8) - tegra_host->is_8bit = 1; + mmc_of_parse(host->mmc); } static int sdhci_tegra_probe(struct platform_device *pdev) @@ -266,7 +245,7 @@ static int sdhci_tegra_probe(struct platform_device *pdev) tegra_host->soc_data = soc_data; pltfm_host->priv = tegra_host; - sdhci_tegra_parse_dt(&pdev->dev, tegra_host); + sdhci_tegra_parse_dt(&pdev->dev); if (gpio_is_valid(tegra_host->power_gpio)) { rc = gpio_request(tegra_host->power_gpio, "sdhci_power"); @@ -278,37 +257,6 @@ static int sdhci_tegra_probe(struct platform_device *pdev) gpio_direction_output(tegra_host->power_gpio, 1); } - if (gpio_is_valid(tegra_host->cd_gpio)) { - rc = gpio_request(tegra_host->cd_gpio, "sdhci_cd"); - if (rc) { - dev_err(mmc_dev(host->mmc), - "failed to allocate cd gpio\n"); - goto err_cd_req; - } - gpio_direction_input(tegra_host->cd_gpio); - - rc = request_irq(gpio_to_irq(tegra_host->cd_gpio), - carddetect_irq, - IRQF_TRIGGER_FALLING | IRQF_TRIGGER_RISING, - mmc_hostname(host->mmc), host); - - if (rc) { - dev_err(mmc_dev(host->mmc), "request irq error\n"); - goto err_cd_irq_req; - } - - } - - if (gpio_is_valid(tegra_host->wp_gpio)) { - rc = gpio_request(tegra_host->wp_gpio, "sdhci_wp"); - if (rc) { - dev_err(mmc_dev(host->mmc), - "failed to allocate wp gpio\n"); - goto err_wp_req; - } - gpio_direction_input(tegra_host->wp_gpio); - } - clk = clk_get(mmc_dev(host->mmc), NULL); if (IS_ERR(clk)) { dev_err(mmc_dev(host->mmc), "clk err\n"); @@ -318,9 +266,6 @@ static int sdhci_tegra_probe(struct platform_device *pdev) clk_prepare_enable(clk); pltfm_host->clk = clk; - if (tegra_host->is_8bit) - host->mmc->caps |= MMC_CAP_8_BIT_DATA; - rc = sdhci_add_host(host); if (rc) goto err_add_host; @@ -331,15 +276,6 @@ err_add_host: clk_disable_unprepare(pltfm_host->clk); clk_put(pltfm_host->clk); err_clk_get: - if (gpio_is_valid(tegra_host->wp_gpio)) - gpio_free(tegra_host->wp_gpio); -err_wp_req: - if (gpio_is_valid(tegra_host->cd_gpio)) - free_irq(gpio_to_irq(tegra_host->cd_gpio), host); -err_cd_irq_req: - if (gpio_is_valid(tegra_host->cd_gpio)) - gpio_free(tegra_host->cd_gpio); -err_cd_req: if (gpio_is_valid(tegra_host->power_gpio)) gpio_free(tegra_host->power_gpio); err_power_req: @@ -357,14 +293,6 @@ static int sdhci_tegra_remove(struct platform_device *pdev) sdhci_remove_host(host, dead); - if (gpio_is_valid(tegra_host->wp_gpio)) - gpio_free(tegra_host->wp_gpio); - - if (gpio_is_valid(tegra_host->cd_gpio)) { - free_irq(gpio_to_irq(tegra_host->cd_gpio), host); - gpio_free(tegra_host->cd_gpio); - } - if (gpio_is_valid(tegra_host->power_gpio)) gpio_free(tegra_host->power_gpio); -- cgit v0.10.2 From dc642c28d4eb39d1c7f2f85bbf1cea45de4766af Mon Sep 17 00:00:00 2001 From: Jan Luebbe Date: Wed, 30 Jan 2013 10:07:17 +0100 Subject: mmc: omap_hsmmc: support deferred probing for GPIOs If the CD/WP-GPIOs are not provided by the SoC's GPIO controller, we need to handle the case where omap_hsmmc is probed earlier than the GPIO controller chosen in the device tree. Fix this by checking the return value of of_get_named_gpio against -EPROBE_DEFER and passing it through to the probe function. Signed-off-by: Jan Luebbe Acked-by: Balaji T K Signed-off-by: Chris Ball diff --git a/drivers/mmc/host/omap_hsmmc.c b/drivers/mmc/host/omap_hsmmc.c index bc58078..6e44025 100644 --- a/drivers/mmc/host/omap_hsmmc.c +++ b/drivers/mmc/host/omap_hsmmc.c @@ -1717,6 +1717,12 @@ static struct omap_mmc_platform_data *of_get_hsmmc_pdata(struct device *dev) struct omap_mmc_platform_data *pdata; struct device_node *np = dev->of_node; u32 bus_width, max_freq; + int cd_gpio, wp_gpio; + + cd_gpio = of_get_named_gpio(np, "cd-gpios", 0); + wp_gpio = of_get_named_gpio(np, "wp-gpios", 0); + if (cd_gpio == -EPROBE_DEFER || wp_gpio == -EPROBE_DEFER) + return ERR_PTR(-EPROBE_DEFER); pdata = devm_kzalloc(dev, sizeof(*pdata), GFP_KERNEL); if (!pdata) @@ -1727,8 +1733,8 @@ static struct omap_mmc_platform_data *of_get_hsmmc_pdata(struct device *dev) /* This driver only supports 1 slot */ pdata->nr_slots = 1; - pdata->slots[0].switch_pin = of_get_named_gpio(np, "cd-gpios", 0); - pdata->slots[0].gpio_wp = of_get_named_gpio(np, "wp-gpios", 0); + pdata->slots[0].switch_pin = cd_gpio; + pdata->slots[0].gpio_wp = wp_gpio; if (of_find_property(np, "ti,non-removable", NULL)) { pdata->slots[0].nonremovable = true; @@ -1774,6 +1780,10 @@ static int omap_hsmmc_probe(struct platform_device *pdev) match = of_match_device(of_match_ptr(omap_mmc_of_match), &pdev->dev); if (match) { pdata = of_get_hsmmc_pdata(&pdev->dev); + + if (IS_ERR(pdata)) + return PTR_ERR(pdata); + if (match->data) { const u16 *offsetp = match->data; pdata->reg_offset = *offsetp; -- cgit v0.10.2 From 3aaf7ba7fda3cda285a407ad0a2acf1b183342fa Mon Sep 17 00:00:00 2001 From: Jingoo Han Date: Tue, 12 Feb 2013 12:24:39 +0900 Subject: mmc: sdhci-s3c: Use devm_clk_get() Use devm_clk_get() rather than clk_get() to make cleanup paths more simple. Signed-off-by: Jingoo Han Reviewed-by: Ulf Hansson Acked-by: Jaehoon Chung Signed-off-by: Chris Ball diff --git a/drivers/mmc/host/sdhci-s3c.c b/drivers/mmc/host/sdhci-s3c.c index 7363efe..128b650 100644 --- a/drivers/mmc/host/sdhci-s3c.c +++ b/drivers/mmc/host/sdhci-s3c.c @@ -608,7 +608,7 @@ static int sdhci_s3c_probe(struct platform_device *pdev) platform_set_drvdata(pdev, host); - sc->clk_io = clk_get(dev, "hsmmc"); + sc->clk_io = devm_clk_get(dev, "hsmmc"); if (IS_ERR(sc->clk_io)) { dev_err(dev, "failed to get io clock\n"); ret = PTR_ERR(sc->clk_io); @@ -623,7 +623,7 @@ static int sdhci_s3c_probe(struct platform_device *pdev) char name[14]; snprintf(name, 14, "mmc_busclk.%d", ptr); - clk = clk_get(dev, name); + clk = devm_clk_get(dev, name); if (IS_ERR(clk)) continue; @@ -764,15 +764,9 @@ static int sdhci_s3c_probe(struct platform_device *pdev) #ifndef CONFIG_PM_RUNTIME clk_disable_unprepare(sc->clk_bus[sc->cur_clk]); #endif - for (ptr = 0; ptr < MAX_BUS_CLK; ptr++) { - if (sc->clk_bus[ptr]) { - clk_put(sc->clk_bus[ptr]); - } - } err_no_busclks: clk_disable_unprepare(sc->clk_io); - clk_put(sc->clk_io); err_pdata_io_clk: sdhci_free_host(host); @@ -785,7 +779,6 @@ static int sdhci_s3c_remove(struct platform_device *pdev) struct sdhci_host *host = platform_get_drvdata(pdev); struct sdhci_s3c *sc = sdhci_priv(host); struct s3c_sdhci_platdata *pdata = sc->pdata; - int ptr; if (pdata->cd_type == S3C_SDHCI_CD_EXTERNAL && pdata->ext_cd_cleanup) pdata->ext_cd_cleanup(&sdhci_s3c_notify_change); @@ -805,13 +798,7 @@ static int sdhci_s3c_remove(struct platform_device *pdev) #ifndef CONFIG_PM_RUNTIME clk_disable_unprepare(sc->clk_bus[sc->cur_clk]); #endif - for (ptr = 0; ptr < MAX_BUS_CLK; ptr++) { - if (sc->clk_bus[ptr]) { - clk_put(sc->clk_bus[ptr]); - } - } clk_disable_unprepare(sc->clk_io); - clk_put(sc->clk_io); sdhci_free_host(host); platform_set_drvdata(pdev, NULL); -- cgit v0.10.2 From 0cea529d1afeeb120ae3f22fe353d38049caed5f Mon Sep 17 00:00:00 2001 From: Jaehoon Chung Date: Fri, 15 Feb 2013 23:45:45 +0900 Subject: mmc: dw_mmc: return the result of mmc_add_host() Check the result of mmc_add_host() and return the value. Signed-off-by: Jaehoon Chung Acked-by: Seungwon Jeon Signed-off-by: Chris Ball diff --git a/drivers/mmc/host/dw_mmc.c b/drivers/mmc/host/dw_mmc.c index 9834221..6da19c1 100644 --- a/drivers/mmc/host/dw_mmc.c +++ b/drivers/mmc/host/dw_mmc.c @@ -1990,7 +1990,9 @@ static int dw_mci_init_slot(struct dw_mci *host, unsigned int id) slot->wp_gpio = dw_mci_of_get_wp_gpio(host->dev, slot->id); - mmc_add_host(mmc); + ret = mmc_add_host(mmc); + if (ret) + goto err_setup_bus; #if defined(CONFIG_DEBUG_FS) dw_mci_init_debugfs(slot); -- cgit v0.10.2 From 87a74d399a165510b053c406699992af9add0da9 Mon Sep 17 00:00:00 2001 From: Kyoungil Kim Date: Tue, 22 Jan 2013 16:46:30 +0900 Subject: mmc: dw_mmc: empty FIFO after data transfer over interrupt in pio mode In dwc manual, the below contents are described: "During end of packet, interrupt is not generated if threshold programming is larger than any remaining data. It is responsibility of host to read remaining bytes on seeing Data Transfer Done interrupt" We also have seen the data cannot be read fully when "sg_miter->length" is less than FIFO size. Signed-off-by: Kyoungil Kim Signed-off-by: Seungwon Jeon Acked-by: Jaehoon Chung Signed-off-by: Chris Ball diff --git a/drivers/mmc/host/dw_mmc.c b/drivers/mmc/host/dw_mmc.c index 6da19c1..2f4a62f 100644 --- a/drivers/mmc/host/dw_mmc.c +++ b/drivers/mmc/host/dw_mmc.c @@ -1438,7 +1438,7 @@ static void dw_mci_pull_data(struct dw_mci *host, void *buf, int cnt) host->pull_data(host, buf, cnt); } -static void dw_mci_read_data_pio(struct dw_mci *host) +static void dw_mci_read_data_pio(struct dw_mci *host, bool dto) { struct sg_mapping_iter *sg_miter = &host->sg_miter; void *buf; @@ -1473,7 +1473,9 @@ static void dw_mci_read_data_pio(struct dw_mci *host) sg_miter->consumed = offset; status = mci_readl(host, MINTSTS); mci_writel(host, RINTSTS, SDMMC_INT_RXDR); - } while (status & SDMMC_INT_RXDR); /*if the RXDR is ready read again*/ + /* if the RXDR is ready read again */ + } while ((status & SDMMC_INT_RXDR) || + (dto && SDMMC_GET_FCNT(mci_readl(host, STATUS)))); data->bytes_xfered += nbytes; if (!remain) { @@ -1605,7 +1607,7 @@ static irqreturn_t dw_mci_interrupt(int irq, void *dev_id) smp_wmb(); if (host->dir_status == DW_MCI_RECV_STATUS) { if (host->sg != NULL) - dw_mci_read_data_pio(host); + dw_mci_read_data_pio(host, true); } set_bit(EVENT_DATA_COMPLETE, &host->pending_events); tasklet_schedule(&host->tasklet); @@ -1614,7 +1616,7 @@ static irqreturn_t dw_mci_interrupt(int irq, void *dev_id) if (pending & SDMMC_INT_RXDR) { mci_writel(host, RINTSTS, SDMMC_INT_RXDR); if (host->dir_status == DW_MCI_RECV_STATUS && host->sg) - dw_mci_read_data_pio(host); + dw_mci_read_data_pio(host, false); } if (pending & SDMMC_INT_TXDR) { -- cgit v0.10.2 From c69042a51e7d890c373345a7e524e895b266eb72 Mon Sep 17 00:00:00 2001 From: Hyeonsu Kim Date: Fri, 22 Feb 2013 09:32:46 +0900 Subject: mmc: dw_mmc: fixed a wrong UHS_REG 16 bit clear In the legacy code, driver clear not only UHS_REG 16 bit also 0-15bit. If we use UHS-1 mode spec card like SDR50, SDR104. UHS_REG 0-15 should be set by 1 according to slot id. In this case, legacy code can cause problems. In particular, UHS_REG consists of DDR_REG[31:16] and VOLT_REG[15:0]. Before adjusting this patch, bit[15:0] is always cleared. Signed-off-by: Hyeonsu Kim Acked-by: Jaehoon Chung Acked-by: Seungwon Jeon Signed-off-by: Chris Ball diff --git a/drivers/mmc/host/dw_mmc.c b/drivers/mmc/host/dw_mmc.c index 2f4a62f..38732d8 100644 --- a/drivers/mmc/host/dw_mmc.c +++ b/drivers/mmc/host/dw_mmc.c @@ -795,9 +795,9 @@ static void dw_mci_set_ios(struct mmc_host *mmc, struct mmc_ios *ios) /* DDR mode set */ if (ios->timing == MMC_TIMING_UHS_DDR50) - regs |= (0x1 << slot->id) << 16; + regs |= ((0x1 << slot->id) << 16); else - regs &= ~(0x1 << slot->id) << 16; + regs &= ~((0x1 << slot->id) << 16); mci_writel(slot->host, UHS_REG, regs); -- cgit v0.10.2 From e3e020f8acbd39a6feb1b6903725aaf658b0fec4 Mon Sep 17 00:00:00 2001 From: "Manjunathappa, Prakash" Date: Tue, 5 Feb 2013 17:52:24 +0530 Subject: mmc: davinci_mmc: allow driver to work without DMA resource Do not return probe failure with missing DMA resources, allow driver to work in PIO mode. Tested on da850-evm by mounting partition followed by file creation and deletion. Signed-off-by: Manjunathappa, Prakash Tested-by: Sekhar Nori Signed-off-by: Chris Ball diff --git a/drivers/mmc/host/davinci_mmc.c b/drivers/mmc/host/davinci_mmc.c index 2063677..27123f8 100644 --- a/drivers/mmc/host/davinci_mmc.c +++ b/drivers/mmc/host/davinci_mmc.c @@ -1190,13 +1190,15 @@ static int __init davinci_mmcsd_probe(struct platform_device *pdev) r = platform_get_resource(pdev, IORESOURCE_DMA, 0); if (!r) - goto out; - host->rxdma = r->start; + dev_warn(&pdev->dev, "RX DMA resource not specified\n"); + else + host->rxdma = r->start; r = platform_get_resource(pdev, IORESOURCE_DMA, 1); if (!r) - goto out; - host->txdma = r->start; + dev_warn(&pdev->dev, "TX DMA resource not specified\n"); + else + host->txdma = r->start; host->mem_res = mem; host->base = ioremap(mem->start, mem_size); -- cgit v0.10.2 From 51e7e8b632d8e564ba494dfa61358ac1a97e4ceb Mon Sep 17 00:00:00 2001 From: Bernie Thompson Date: Wed, 27 Feb 2013 12:19:17 -0800 Subject: mmc: core: Add in support to expose PRV for v4 MMCs The JEDEC MMC v4 spec defines a new PRV value in place of the original fwrev and hwrev specified in v1. We can expose this in the kernel to enable user space to more easily determine the product revision of a given MMC. Signed-off-by: Bernie Thompson Reviewed-by: Ulf Hansson Signed-off-by: Chris Ball diff --git a/Documentation/mmc/mmc-dev-attrs.txt b/Documentation/mmc/mmc-dev-attrs.txt index 0d98fac..189bab0 100644 --- a/Documentation/mmc/mmc-dev-attrs.txt +++ b/Documentation/mmc/mmc-dev-attrs.txt @@ -22,6 +22,7 @@ All attributes are read-only. manfid Manufacturer ID (from CID Register) name Product Name (from CID Register) oemid OEM/Application ID (from CID Register) + prv Product Revision (from CID Register) (SD and MMCv4 only) serial Product Serial Number (from CID Register) erase_size Erase group size preferred_erase_size Preferred erase size diff --git a/drivers/mmc/core/mmc.c b/drivers/mmc/core/mmc.c index c8f3d6e..d584f7c 100644 --- a/drivers/mmc/core/mmc.c +++ b/drivers/mmc/core/mmc.c @@ -96,6 +96,7 @@ static int mmc_decode_cid(struct mmc_card *card) card->cid.prod_name[3] = UNSTUFF_BITS(resp, 72, 8); card->cid.prod_name[4] = UNSTUFF_BITS(resp, 64, 8); card->cid.prod_name[5] = UNSTUFF_BITS(resp, 56, 8); + card->cid.prv = UNSTUFF_BITS(resp, 48, 8); card->cid.serial = UNSTUFF_BITS(resp, 16, 32); card->cid.month = UNSTUFF_BITS(resp, 12, 4); card->cid.year = UNSTUFF_BITS(resp, 8, 4) + 1997; @@ -627,6 +628,7 @@ MMC_DEV_ATTR(hwrev, "0x%x\n", card->cid.hwrev); MMC_DEV_ATTR(manfid, "0x%06x\n", card->cid.manfid); MMC_DEV_ATTR(name, "%s\n", card->cid.prod_name); MMC_DEV_ATTR(oemid, "0x%04x\n", card->cid.oemid); +MMC_DEV_ATTR(prv, "0x%x\n", card->cid.prv); MMC_DEV_ATTR(serial, "0x%08x\n", card->cid.serial); MMC_DEV_ATTR(enhanced_area_offset, "%llu\n", card->ext_csd.enhanced_area_offset); @@ -645,6 +647,7 @@ static struct attribute *mmc_std_attrs[] = { &dev_attr_manfid.attr, &dev_attr_name.attr, &dev_attr_oemid.attr, + &dev_attr_prv.attr, &dev_attr_serial.attr, &dev_attr_enhanced_area_offset.attr, &dev_attr_enhanced_area_size.attr, diff --git a/include/linux/mmc/card.h b/include/linux/mmc/card.h index 61b2c30..f31725b 100644 --- a/include/linux/mmc/card.h +++ b/include/linux/mmc/card.h @@ -17,6 +17,7 @@ struct mmc_cid { unsigned int manfid; char prod_name[8]; + unsigned char prv; unsigned int serial; unsigned short oemid; unsigned short year; -- cgit v0.10.2 From 1450734ec61cda7bbb77afc8cb412b9d64c62d9a Mon Sep 17 00:00:00 2001 From: Kevin Liu Date: Thu, 28 Feb 2013 15:29:29 +0800 Subject: mmc: core: enhance card removal judgement for slow removal Function _mmc_detect_card_removed will be called to know whether the card is still present when host->bus_ops->detect is called. In current code, the return value of this function generally only depend on the result of sending cmd13 to card, which may not safe for card with detection support like slot gpio detection. Because the communication status between host and card may out of sync with the detect status if remove the card slowly or hands shake during the process. The direct reason is the async between card detect switch and card/slot pad contaction in hardware, which is defined by spec. The spec define card insert/remove sequence as below (both standard size SD card and MicroSD card have the same sequence): "Part 1 Standard Size SD Card Mechanical Addendum Ver4.00 Final, Appendix C: Card Detection Switch" (Take normally open type as example) a)SD card insertion sequence: The card detection switch should be turned on after all SD card contact pads are connected to the host connector contact pads. b)SD removal sequence: The card detection switch should be turned off when the SD card is just going to be removed and before any SD card contact pad is disconnected from the host connector contact pad. Below is the sequence when this issue occur (Take slot gpio detection as example and remove the card slowly during the process): 1. gpio level changed and card detect interrupt triggered. 2. mmc_rescan was launched. 3. the card pads were still contacted with the slot pads because of slow removal. So _mmc_detect_card_removed and mmc_rescan think card was still present (cmd13 succeed). 4. card pads were discontacted from the card slot pads. So the card was actually removed finally but the card removal event has been missed by system. The interval length between step 1 and step 4 depends on the card removal speed. If it's longer than the detect work schedule delay which is 200ms, this issue will likely happen. This patch add the card detect status check in function _mmc_detect_card_removed if cmd13 check succeed and host->ops->get_cd provided. If get_cd detect no card present then schedule another detect work 200ms later. Signed-off-by: Kevin Liu Tested-by: Johan Rudholm Reviewed-by: Philip Rakity Acked-by: Ulf Hansson Signed-off-by: Chris Ball diff --git a/drivers/mmc/core/core.c b/drivers/mmc/core/core.c index 08a3cf2..3bf1c46 100644 --- a/drivers/mmc/core/core.c +++ b/drivers/mmc/core/core.c @@ -2289,6 +2289,19 @@ int _mmc_detect_card_removed(struct mmc_host *host) return 1; ret = host->bus_ops->alive(host); + + /* + * Card detect status and alive check may be out of sync if card is + * removed slowly, when card detect switch changes while card/slot + * pads are still contacted in hardware (refer to "SD Card Mechanical + * Addendum, Appendix C: Card Detection Switch"). So reschedule a + * detect work 200ms later for this case. + */ + if (!ret && host->ops->get_cd && !host->ops->get_cd(host)) { + mmc_detect_change(host, msecs_to_jiffies(200)); + pr_debug("%s: card removed too slowly\n", mmc_hostname(host)); + } + if (ret) { mmc_card_set_removed(host->card); pr_debug("%s: card remove detected\n", mmc_hostname(host)); -- cgit v0.10.2 From 94144a465dd0b34b3249f988a09472d0f57ad2b7 Mon Sep 17 00:00:00 2001 From: Kevin Liu Date: Thu, 28 Feb 2013 17:35:53 +0800 Subject: mmc: sdhci: add get_cd() implementation 1. mmc_rescan will call get_cd to know whether the card is present before mmc_rescan_try_freq to avoid useless trials during card removal or start host is called when card is not present. 2. get_cd needs to be checked to resolve slow card removal issue. Signed-off-by: Kevin Liu Signed-off-by: Chris Ball diff --git a/drivers/mmc/host/sdhci.c b/drivers/mmc/host/sdhci.c index 51bbba4..81d5294 100644 --- a/drivers/mmc/host/sdhci.c +++ b/drivers/mmc/host/sdhci.c @@ -1581,6 +1581,37 @@ static void sdhci_set_ios(struct mmc_host *mmc, struct mmc_ios *ios) sdhci_runtime_pm_put(host); } +static int sdhci_do_get_cd(struct sdhci_host *host) +{ + int gpio_cd = mmc_gpio_get_cd(host->mmc); + + if (host->flags & SDHCI_DEVICE_DEAD) + return 0; + + /* If polling/nonremovable, assume that the card is always present. */ + if ((host->quirks & SDHCI_QUIRK_BROKEN_CARD_DETECTION) || + (host->mmc->caps & MMC_CAP_NONREMOVABLE)) + return 1; + + /* Try slot gpio detect */ + if (!IS_ERR_VALUE(gpio_cd)) + return !!gpio_cd; + + /* Host native card detect */ + return !!(sdhci_readl(host, SDHCI_PRESENT_STATE) & SDHCI_CARD_PRESENT); +} + +static int sdhci_get_cd(struct mmc_host *mmc) +{ + struct sdhci_host *host = mmc_priv(mmc); + int ret; + + sdhci_runtime_pm_get(host); + ret = sdhci_do_get_cd(host); + sdhci_runtime_pm_put(host); + return ret; +} + static int sdhci_check_ro(struct sdhci_host *host) { unsigned long flags; @@ -2038,6 +2069,7 @@ static void sdhci_card_event(struct mmc_host *mmc) static const struct mmc_host_ops sdhci_ops = { .request = sdhci_request, .set_ios = sdhci_set_ios, + .get_cd = sdhci_get_cd, .get_ro = sdhci_get_ro, .hw_reset = sdhci_hw_reset, .enable_sdio_irq = sdhci_enable_sdio_irq, -- cgit v0.10.2 From eed222aca8d077af3600b651176f6fd04d95cce1 Mon Sep 17 00:00:00 2001 From: Aaron Lu Date: Tue, 5 Mar 2013 11:24:52 +0800 Subject: mmc: sdio: bind acpi with sdio function device ACPI spec 5 defined the _ADR encoding for sdio bus as: High word - slot number (0 based) Low word - function number This patch adds support for binding sdio function device with acpi node, and if successful, involve acpi into its power management. Signed-off-by: Aaron Lu Reviewed-by: Adrian Hunter Signed-off-by: Chris Ball diff --git a/drivers/mmc/core/sdio_bus.c b/drivers/mmc/core/sdio_bus.c index 5e57048..8d6bb18 100644 --- a/drivers/mmc/core/sdio_bus.c +++ b/drivers/mmc/core/sdio_bus.c @@ -16,6 +16,7 @@ #include #include #include +#include #include #include @@ -299,6 +300,19 @@ struct sdio_func *sdio_alloc_func(struct mmc_card *card) return func; } +#ifdef CONFIG_ACPI +static void sdio_acpi_set_handle(struct sdio_func *func) +{ + struct mmc_host *host = func->card->host; + u64 addr = (host->slotno << 16) | func->num; + + ACPI_HANDLE_SET(&func->dev, + acpi_get_child(ACPI_HANDLE(host->parent), addr)); +} +#else +static inline void sdio_acpi_set_handle(struct sdio_func *func) {} +#endif + /* * Register a new SDIO function with the driver model. */ @@ -308,9 +322,12 @@ int sdio_add_func(struct sdio_func *func) dev_set_name(&func->dev, "%s:%d", mmc_card_id(func->card), func->num); + sdio_acpi_set_handle(func); ret = device_add(&func->dev); - if (ret == 0) + if (ret == 0) { sdio_func_set_present(func); + acpi_dev_pm_attach(&func->dev, false); + } return ret; } @@ -326,6 +343,7 @@ void sdio_remove_func(struct sdio_func *func) if (!sdio_func_present(func)) return; + acpi_dev_pm_detach(&func->dev, false); device_del(&func->dev); put_device(&func->dev); } diff --git a/drivers/mmc/host/sdhci-pci.c b/drivers/mmc/host/sdhci-pci.c index c7ccf30..3dee22d 100644 --- a/drivers/mmc/host/sdhci-pci.c +++ b/drivers/mmc/host/sdhci-pci.c @@ -1279,6 +1279,7 @@ static struct sdhci_pci_slot *sdhci_pci_probe_slot( } host->mmc->pm_caps = MMC_PM_KEEP_POWER | MMC_PM_WAKE_SDIO_IRQ; + host->mmc->slotno = slotno; ret = sdhci_add_host(host); if (ret) diff --git a/include/linux/mmc/host.h b/include/linux/mmc/host.h index d6f20cc..17d7148 100644 --- a/include/linux/mmc/host.h +++ b/include/linux/mmc/host.h @@ -361,6 +361,8 @@ struct mmc_host { unsigned int actual_clock; /* Actual HC clock rate */ + unsigned int slotno; /* used for sdio acpi binding */ + unsigned long private[0] ____cacheline_aligned; }; -- cgit v0.10.2 From d4bf63251c530be61ae7906dc67ace3af36ff3db Mon Sep 17 00:00:00 2001 From: Jingoo Han Date: Tue, 5 Mar 2013 12:53:23 +0900 Subject: mmc: davinci_mmc: use module_platform_driver_probe() This patch uses module_platform_driver_probe() macro which makes the code smaller and simpler. Signed-off-by: Jingoo Han Signed-off-by: Chris Ball diff --git a/drivers/mmc/host/davinci_mmc.c b/drivers/mmc/host/davinci_mmc.c index 27123f8..4fdc159 100644 --- a/drivers/mmc/host/davinci_mmc.c +++ b/drivers/mmc/host/davinci_mmc.c @@ -1412,18 +1412,7 @@ static struct platform_driver davinci_mmcsd_driver = { .remove = __exit_p(davinci_mmcsd_remove), }; -static int __init davinci_mmcsd_init(void) -{ - return platform_driver_probe(&davinci_mmcsd_driver, - davinci_mmcsd_probe); -} -module_init(davinci_mmcsd_init); - -static void __exit davinci_mmcsd_exit(void) -{ - platform_driver_unregister(&davinci_mmcsd_driver); -} -module_exit(davinci_mmcsd_exit); +module_platform_driver_probe(davinci_mmcsd_driver, davinci_mmcsd_probe); MODULE_AUTHOR("Texas Instruments India"); MODULE_LICENSE("GPL"); -- cgit v0.10.2 From 4a2d8ecce0be8240618e133077724abb5b36c1ef Mon Sep 17 00:00:00 2001 From: Jingoo Han Date: Tue, 5 Mar 2013 12:54:06 +0900 Subject: mmc: mvsdio: use module_platform_driver_probe() This patch uses module_platform_driver_probe() macro which makes the code smaller and simpler. Signed-off-by: Jingoo Han Signed-off-by: Chris Ball diff --git a/drivers/mmc/host/mvsdio.c b/drivers/mmc/host/mvsdio.c index 145cdaf..2b7d5b7 100644 --- a/drivers/mmc/host/mvsdio.c +++ b/drivers/mmc/host/mvsdio.c @@ -881,18 +881,7 @@ static struct platform_driver mvsd_driver = { }, }; -static int __init mvsd_init(void) -{ - return platform_driver_probe(&mvsd_driver, mvsd_probe); -} - -static void __exit mvsd_exit(void) -{ - platform_driver_unregister(&mvsd_driver); -} - -module_init(mvsd_init); -module_exit(mvsd_exit); +module_platform_driver_probe(mvsd_driver, mvsd_probe); /* maximum card clock frequency (default 50MHz) */ module_param(maxfreq, int, 0); -- cgit v0.10.2 From e19499ae10903807acbaa07a28d4b56d508ac339 Mon Sep 17 00:00:00 2001 From: Thomas Abraham Date: Wed, 6 Mar 2013 17:06:16 +0530 Subject: mmc: sdhci-s3c: let device core setup the default pin configuration With device core now able to setup the default pin configuration, the call to devm_pinctrl_get_select_default can be removed. And the pin configuration code based on the deprecated Samsung specific gpio bindings is also removed. Signed-off-by: Thomas Abraham Acked-by: Linus Walleij Signed-off-by: Chris Ball diff --git a/Documentation/devicetree/bindings/mmc/samsung-sdhci.txt b/Documentation/devicetree/bindings/mmc/samsung-sdhci.txt index 3b3a1ee..328e990 100644 --- a/Documentation/devicetree/bindings/mmc/samsung-sdhci.txt +++ b/Documentation/devicetree/bindings/mmc/samsung-sdhci.txt @@ -5,13 +5,6 @@ MMC, SD and eMMC storage mediums. This file documents differences between the core mmc properties described by mmc.txt and the properties used by the Samsung implmentation of the SDHCI controller. -Note: The mmc core bindings documentation states that if none of the core -card-detect bindings are used, then the standard sdhci card detect mechanism -is used. The Samsung's SDHCI controller bindings extends this as listed below. - -[A] The property "samsung,cd-pinmux-gpio" can be used as stated in the - "Optional Board Specific Properties" section below. - Required SoC Specific Properties: - compatible: should be one of the following - "samsung,s3c6410-sdhci": For controllers compatible with s3c6410 sdhci @@ -20,18 +13,8 @@ Required SoC Specific Properties: controller. Required Board Specific Properties: -- Samsung GPIO variant (will be completely replaced by pinctrl): - - gpios: Should specify the gpios used for clock, command and data lines. The - gpio specifier format depends on the gpio controller. -- Pinctrl variant (preferred if available): - - pinctrl-0: Should specify pin control groups used for this controller. - - pinctrl-names: Should contain only one value - "default". - -Optional Board Specific Properties: -- samsung,cd-pinmux-gpio: Specifies the card detect line that is routed - through a pinmux to the card-detect pin of the card slot. This property - should be used only if none of the mmc core card-detect properties are - used. Only for Samsung GPIO variant. +- pinctrl-0: Should specify pin control groups used for this controller. +- pinctrl-names: Should contain only one value - "default". Example: sdhci@12530000 { @@ -39,19 +22,9 @@ Example: reg = <0x12530000 0x100>; interrupts = <0 75 0>; bus-width = <4>; - cd-gpios = <&gpk2 2 2 3 3>; - - /* Samsung GPIO variant */ - gpios = <&gpk2 0 2 0 3>, /* clock line */ - <&gpk2 1 2 0 3>, /* command line */ - <&gpk2 3 2 3 3>, /* data line 0 */ - <&gpk2 4 2 3 3>, /* data line 1 */ - <&gpk2 5 2 3 3>, /* data line 2 */ - <&gpk2 6 2 3 3>; /* data line 3 */ - - /* Pinctrl variant */ - pinctrl-0 = <&sd0_clk &sd0_cmd &sd0_bus4>; + cd-gpios = <&gpk2 2 0>; pinctrl-names = "default"; + pinctrl-0 = <&sd0_clk &sd0_cmd &sd0_bus4>; }; Note: This example shows both SoC specific and board specific properties diff --git a/drivers/mmc/host/sdhci-s3c.c b/drivers/mmc/host/sdhci-s3c.c index 128b650..8cd966d 100644 --- a/drivers/mmc/host/sdhci-s3c.c +++ b/drivers/mmc/host/sdhci-s3c.c @@ -24,7 +24,6 @@ #include #include #include -#include #include @@ -45,7 +44,6 @@ * @ioarea: The resource created when we claimed the IO area. * @pdata: The platform data for this controller. * @cur_clk: The index of the current bus clock. - * @gpios: List of gpio numbers parsed from device tree. * @clk_io: The clock for the internal bus interface. * @clk_bus: The clocks that are available for the SD/MMC bus clock. */ @@ -57,8 +55,6 @@ struct sdhci_s3c { unsigned int cur_clk; int ext_cd_irq; int ext_cd_gpio; - int *gpios; - struct pinctrl *pctrl; struct clk *clk_io; struct clk *clk_bus[MAX_BUS_CLK]; @@ -447,88 +443,39 @@ static int sdhci_s3c_parse_dt(struct device *dev, struct device_node *node = dev->of_node; struct sdhci_s3c *ourhost = to_s3c(host); u32 max_width; - int gpio, cnt, ret; + int gpio; /* if the bus-width property is not specified, assume width as 1 */ if (of_property_read_u32(node, "bus-width", &max_width)) max_width = 1; pdata->max_width = max_width; - ourhost->gpios = devm_kzalloc(dev, NUM_GPIOS(pdata->max_width) * - sizeof(int), GFP_KERNEL); - if (!ourhost->gpios) - return -ENOMEM; - /* get the card detection method */ if (of_get_property(node, "broken-cd", NULL)) { pdata->cd_type = S3C_SDHCI_CD_NONE; - goto setup_bus; + return 0; } if (of_get_property(node, "non-removable", NULL)) { pdata->cd_type = S3C_SDHCI_CD_PERMANENT; - goto setup_bus; + return 0; } gpio = of_get_named_gpio(node, "cd-gpios", 0); if (gpio_is_valid(gpio)) { pdata->cd_type = S3C_SDHCI_CD_GPIO; - goto found_cd; - } else if (gpio != -ENOENT) { - dev_err(dev, "invalid card detect gpio specified\n"); - return -EINVAL; - } - - gpio = of_get_named_gpio(node, "samsung,cd-pinmux-gpio", 0); - if (gpio_is_valid(gpio)) { - pdata->cd_type = S3C_SDHCI_CD_INTERNAL; - goto found_cd; - } else if (gpio != -ENOENT) { - dev_err(dev, "invalid card detect gpio specified\n"); - return -EINVAL; - } - - /* assuming internal card detect that will be configured by pinctrl */ - pdata->cd_type = S3C_SDHCI_CD_INTERNAL; - goto setup_bus; - - found_cd: - if (pdata->cd_type == S3C_SDHCI_CD_GPIO) { pdata->ext_cd_gpio = gpio; ourhost->ext_cd_gpio = -1; if (of_get_property(node, "cd-inverted", NULL)) pdata->ext_cd_gpio_invert = 1; - } else if (pdata->cd_type == S3C_SDHCI_CD_INTERNAL) { - ret = devm_gpio_request(dev, gpio, "sdhci-cd"); - if (ret) { - dev_err(dev, "card detect gpio request failed\n"); - return -EINVAL; - } - ourhost->ext_cd_gpio = gpio; - } - - setup_bus: - if (!IS_ERR(ourhost->pctrl)) return 0; - - /* get the gpios for command, clock and data lines */ - for (cnt = 0; cnt < NUM_GPIOS(pdata->max_width); cnt++) { - gpio = of_get_gpio(node, cnt); - if (!gpio_is_valid(gpio)) { - dev_err(dev, "invalid gpio[%d]\n", cnt); - return -EINVAL; - } - ourhost->gpios[cnt] = gpio; - } - - for (cnt = 0; cnt < NUM_GPIOS(pdata->max_width); cnt++) { - ret = devm_gpio_request(dev, ourhost->gpios[cnt], "sdhci-gpio"); - if (ret) { - dev_err(dev, "gpio[%d] request failed\n", cnt); - return -EINVAL; - } + } else if (gpio != -ENOENT) { + dev_err(dev, "invalid card detect gpio specified\n"); + return -EINVAL; } + /* assuming internal card detect that will be configured by pinctrl */ + pdata->cd_type = S3C_SDHCI_CD_INTERNAL; return 0; } #else @@ -589,8 +536,6 @@ static int sdhci_s3c_probe(struct platform_device *pdev) goto err_pdata_io_clk; } - sc->pctrl = devm_pinctrl_get_select_default(&pdev->dev); - if (pdev->dev.of_node) { ret = sdhci_s3c_parse_dt(&pdev->dev, host, pdata); if (ret) -- cgit v0.10.2 From d88691be7b37c9bba6c5dafbbaff569dd83475da Mon Sep 17 00:00:00 2001 From: Wei WANG Date: Fri, 8 Mar 2013 15:05:57 +0800 Subject: mmc: rtsx_pci_sdmmc: Don't execute power up sequence repeatedly For some Realtek card readers, the power up sequence can only be executed when power has been turned off fully. So the rtsx host should not start power up sequence again when set_ios been called if the power has been turned on. Signed-off-by: Wei WANG Signed-off-by: Chris Ball diff --git a/drivers/mmc/host/rtsx_pci_sdmmc.c b/drivers/mmc/host/rtsx_pci_sdmmc.c index f981f7d..ad13f42 100644 --- a/drivers/mmc/host/rtsx_pci_sdmmc.c +++ b/drivers/mmc/host/rtsx_pci_sdmmc.c @@ -57,6 +57,9 @@ struct realtek_pci_sdmmc { bool eject; bool initial_mode; bool ddr_mode; + int power_state; +#define SDMMC_POWER_ON 1 +#define SDMMC_POWER_OFF 0 }; static inline struct device *sdmmc_dev(struct realtek_pci_sdmmc *host) @@ -765,6 +768,9 @@ static int sd_power_on(struct realtek_pci_sdmmc *host) struct rtsx_pcr *pcr = host->pcr; int err; + if (host->power_state == SDMMC_POWER_ON) + return 0; + rtsx_pci_init_cmd(pcr); rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, CARD_SELECT, 0x07, SD_MOD_SEL); rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, CARD_SHARE_MODE, @@ -787,6 +793,7 @@ static int sd_power_on(struct realtek_pci_sdmmc *host) if (err < 0) return err; + host->power_state = SDMMC_POWER_ON; return 0; } @@ -795,6 +802,8 @@ static int sd_power_off(struct realtek_pci_sdmmc *host) struct rtsx_pcr *pcr = host->pcr; int err; + host->power_state = SDMMC_POWER_OFF; + rtsx_pci_init_cmd(pcr); rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, CARD_CLK_EN, SD_CLK_EN, 0); @@ -1260,6 +1269,7 @@ static int rtsx_pci_sdmmc_drv_probe(struct platform_device *pdev) host->pcr = pcr; host->mmc = mmc; host->pdev = pdev; + host->power_state = SDMMC_POWER_OFF; platform_set_drvdata(pdev, host); pcr->slots[RTSX_SD_CARD].p_dev = pdev; pcr->slots[RTSX_SD_CARD].card_event = rtsx_pci_sdmmc_card_event; -- cgit v0.10.2 From 4590205b9f9379a55b8fb0b6503c15a106a97b12 Mon Sep 17 00:00:00 2001 From: Chunhe Lan Date: Fri, 8 Mar 2013 16:14:10 +0800 Subject: mmc: sdhci-pltfm: Fix timeout on t4240's sdhci controller This patch fixes timeout problems on t4240's sdhci controller: mmc0: Too large timeout requested for CMD25! mmc0: Too large timeout requested for CMD25! mmc0: Too large timeout requested for CMD25! Signed-off-by: Chunhe Lan Signed-off-by: Chris Ball diff --git a/drivers/mmc/host/sdhci-pltfm.c b/drivers/mmc/host/sdhci-pltfm.c index 3145a78..9db7b12 100644 --- a/drivers/mmc/host/sdhci-pltfm.c +++ b/drivers/mmc/host/sdhci-pltfm.c @@ -94,6 +94,7 @@ void sdhci_get_of_property(struct platform_device *pdev) if (of_device_is_compatible(np, "fsl,p2020-esdhc") || of_device_is_compatible(np, "fsl,p1010-esdhc") || + of_device_is_compatible(np, "fsl,t4240-esdhc") || of_device_is_compatible(np, "fsl,mpc8536-esdhc")) host->quirks |= SDHCI_QUIRK_BROKEN_TIMEOUT_VAL; -- cgit v0.10.2 From 8a8396ae218a9e8dd4af285cc9c22951bed9850e Mon Sep 17 00:00:00 2001 From: Wei Yongjun Date: Mon, 11 Mar 2013 22:36:09 +0800 Subject: mmc: wmt-sdmmc: remove unused variable in wmt_complete_data_request() The variable 'mmc' is initialized but never used, so remove it. Signed-off-by: Wei Yongjun Acked-by: Tony Prisk Signed-off-by: Chris Ball diff --git a/drivers/mmc/host/wmt-sdmmc.c b/drivers/mmc/host/wmt-sdmmc.c index c6d0015..74cbc9a 100644 --- a/drivers/mmc/host/wmt-sdmmc.c +++ b/drivers/mmc/host/wmt-sdmmc.c @@ -348,13 +348,11 @@ static void wmt_complete_data_request(struct wmt_mci_priv *priv) static irqreturn_t wmt_mci_dma_isr(int irq_num, void *data) { - struct mmc_host *mmc; struct wmt_mci_priv *priv; int status; priv = (struct wmt_mci_priv *)data; - mmc = priv->mmc; status = readl(priv->sdmmc_base + SDDMA_CCR) & 0x0F; -- cgit v0.10.2 From 22119901621f0aca1fefbb5e7100d76d1879ac16 Mon Sep 17 00:00:00 2001 From: Alexandru Gheorghiu Date: Tue, 12 Mar 2013 01:04:54 +0200 Subject: mmc: wmt-sdmmc: Use resource_size() Used resource_size function instead of explicit computation. Patch found using coccinelle. Signed-off-by: Alexandru Gheorghiu Signed-off-by: Chris Ball diff --git a/drivers/mmc/host/wmt-sdmmc.c b/drivers/mmc/host/wmt-sdmmc.c index 74cbc9a..442f576 100644 --- a/drivers/mmc/host/wmt-sdmmc.c +++ b/drivers/mmc/host/wmt-sdmmc.c @@ -923,7 +923,7 @@ static int wmt_mci_remove(struct platform_device *pdev) clk_put(priv->clk_sdmmc); res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - release_mem_region(res->start, res->end - res->start + 1); + release_mem_region(res->start, resource_size(res)); mmc_free_host(mmc); -- cgit v0.10.2 From a3361abaae810b717fcb7191e0558bcbdaf1c12d Mon Sep 17 00:00:00 2001 From: Chris Ball Date: Mon, 11 Mar 2013 17:51:53 -0400 Subject: mmc: sdhci: Don't ignore regulator_enable() return value Fixes: /git/arm-soc/drivers/mmc/host/sdhci.c: In function 'sdhci_add_host': /git/arm-soc/drivers/mmc/host/sdhci.c:2910:19: warning: ignoring return value of 'regulator_enable', declared with attribute warn_unused_result [-Wunused-result] Reported-by: Arnd Bergmann Signed-off-by: Chris Ball diff --git a/drivers/mmc/host/sdhci.c b/drivers/mmc/host/sdhci.c index 81d5294..2ea429c 100644 --- a/drivers/mmc/host/sdhci.c +++ b/drivers/mmc/host/sdhci.c @@ -2939,12 +2939,17 @@ int sdhci_add_host(struct sdhci_host *host) host->vqmmc = NULL; } } else { - regulator_enable(host->vqmmc); + ret = regulator_enable(host->vqmmc); if (!regulator_is_supported_voltage(host->vqmmc, 1700000, 1950000)) caps[1] &= ~(SDHCI_SUPPORT_SDR104 | SDHCI_SUPPORT_SDR50 | SDHCI_SUPPORT_DDR50); + if (ret) { + pr_warn("%s: Failed to enable vqmmc regulator: %d\n", + mmc_hostname(mmc), ret); + host->vqmmc = NULL; + } } if (host->quirks2 & SDHCI_QUIRK2_NO_1_8_V) -- cgit v0.10.2 From e6f34e2fd3a7c6bc4893c08583d55599ac15eb9d Mon Sep 17 00:00:00 2001 From: James Hogan Date: Tue, 12 Mar 2013 10:43:32 +0000 Subject: mmc: dw_mmc: setpower on MMC_POWER_{UP,OFF} Call the setpower platform callback in response to set_ios with ios->power_mode == MMC_POWER_UP or MMC_POWER_OFF, instead of from the card detect work function. This appears to fix a problem I have where a card stuck in a funny state doesn't get properly cleared by the power being turned off, presumably due to lack of power sequencing. This resulted in the following log messages after boot: mmc0: error -110 whilst initialising SD card mmc_host mmc0: Bus speed (slot 0) = 99840000Hz (slot req 300000Hz, actual 298922HZ div = 167) mmc0: error -110 whilst initialising SD card mmc_host mmc0: Bus speed (slot 0) = 99840000Hz (slot req 200000Hz, actual 199680HZ div = 250) mmc0: error -110 whilst initialising SD card mmc_host mmc0: Bus speed (slot 0) = 99840000Hz (slot req 195765Hz, actual 195764HZ div = 255) mmc0: error -110 whilst initialising SD card mmc_host mmc0: Bus speed (slot 0) = 99840000Hz (slot req 400000Hz, actual 399360HZ div = 125) mmc0: error -110 whilst initialising SD card mmc_host mmc0: Bus speed (slot 0) = 99840000Hz (slot req 300000Hz, actual 298922HZ div = 167) Signed-off-by: James Hogan Acked-by: Seungwon Jeon Acked-by: Jaehoon Chung Signed-off-by: Chris Ball diff --git a/drivers/mmc/host/dw_mmc.c b/drivers/mmc/host/dw_mmc.c index 38732d8..6891fd1 100644 --- a/drivers/mmc/host/dw_mmc.c +++ b/drivers/mmc/host/dw_mmc.c @@ -818,6 +818,14 @@ static void dw_mci_set_ios(struct mmc_host *mmc, struct mmc_ios *ios) switch (ios->power_mode) { case MMC_POWER_UP: set_bit(DW_MMC_CARD_NEED_INIT, &slot->flags); + /* Power up slot */ + if (slot->host->pdata->setpower) + slot->host->pdata->setpower(slot->id, mmc->ocr_avail); + break; + case MMC_POWER_OFF: + /* Power down slot */ + if (slot->host->pdata->setpower) + slot->host->pdata->setpower(slot->id, 0); break; default: break; @@ -1676,10 +1684,6 @@ static void dw_mci_work_routine_card(struct work_struct *work) dev_dbg(&slot->mmc->class_dev, "card %s\n", present ? "inserted" : "removed"); - /* Power up slot (before spin_lock, may sleep) */ - if (present != 0 && host->pdata->setpower) - host->pdata->setpower(slot->id, mmc->ocr_avail); - spin_lock_bh(&host->lock); /* Card change detected */ @@ -1762,10 +1766,6 @@ static void dw_mci_work_routine_card(struct work_struct *work) spin_unlock_bh(&host->lock); - /* Power down slot (after spin_unlock, may sleep) */ - if (present == 0 && host->pdata->setpower) - host->pdata->setpower(slot->id, 0); - present = dw_mci_get_cd(mmc); } -- cgit v0.10.2 From 63008768d2663723b6acea2f8739e1c8460da726 Mon Sep 17 00:00:00 2001 From: James Hogan Date: Tue, 12 Mar 2013 10:43:54 +0000 Subject: mmc: dw_mmc: move host->data_offset init earlier host->data_offset is initialised at the end of the probe function depending on the VERID register, and is used for PIO operations. Move this initialisation earlier, before IRQs or slots are initialised, to be sure that PIO won't occur prior to host->data_offset being initialised. Signed-off-by: James Hogan Acked-by: Jaehoon Chung Acked-by: Seungwon Jeon Signed-off-by: Chris Ball diff --git a/drivers/mmc/host/dw_mmc.c b/drivers/mmc/host/dw_mmc.c index 6891fd1..7716a08 100644 --- a/drivers/mmc/host/dw_mmc.c +++ b/drivers/mmc/host/dw_mmc.c @@ -2293,6 +2293,18 @@ int dw_mci_probe(struct dw_mci *host) mci_writel(host, CLKENA, 0); mci_writel(host, CLKSRC, 0); + /* + * In 2.40a spec, Data offset is changed. + * Need to check the version-id and set data-offset for DATA register. + */ + host->verid = SDMMC_GET_VERID(mci_readl(host, VERID)); + dev_info(host->dev, "Version ID is %04x\n", host->verid); + + if (host->verid < DW_MMC_240A) + host->data_offset = DATA_OFFSET; + else + host->data_offset = DATA_240A_OFFSET; + tasklet_init(&host->tasklet, dw_mci_tasklet_func, (unsigned long)host); host->card_workqueue = alloc_workqueue("dw-mci-card", WQ_MEM_RECLAIM | WQ_NON_REENTRANT, 1); @@ -2341,18 +2353,6 @@ int dw_mci_probe(struct dw_mci *host) goto err_workqueue; } - /* - * In 2.40a spec, Data offset is changed. - * Need to check the version-id and set data-offset for DATA register. - */ - host->verid = SDMMC_GET_VERID(mci_readl(host, VERID)); - dev_info(host->dev, "Version ID is %04x\n", host->verid); - - if (host->verid < DW_MMC_240A) - host->data_offset = DATA_OFFSET; - else - host->data_offset = DATA_240A_OFFSET; - if (host->quirks & DW_MCI_QUIRK_IDMAC_DTO) dev_info(host->dev, "Internal DMAC interrupt fix enabled.\n"); -- cgit v0.10.2 From 1fb5f68addde6d8b79dd7d747814aa1770e6cf21 Mon Sep 17 00:00:00 2001 From: Markos Chandras Date: Tue, 12 Mar 2013 10:53:11 +0000 Subject: mmc: dw_mmc: Don't loop when handling an interrupt There is no reason to loop when handling an interrupt. The "if" clauses will handle all of them sequentially. This also eliminates the extra loop we used to take with no pending interrupts and we ended up breaking out of the while loop. Signed-off-by: Markos Chandras Acked-by: Jaehoon Chung Acked-by: Seungwon Jeon Signed-off-by: Chris Ball diff --git a/drivers/mmc/host/dw_mmc.c b/drivers/mmc/host/dw_mmc.c index 7716a08..e7be402 100644 --- a/drivers/mmc/host/dw_mmc.c +++ b/drivers/mmc/host/dw_mmc.c @@ -1573,11 +1573,11 @@ static irqreturn_t dw_mci_interrupt(int irq, void *dev_id) { struct dw_mci *host = dev_id; u32 pending; - unsigned int pass_count = 0; int i; - do { - pending = mci_readl(host, MINTSTS); /* read-only mask reg */ + pending = mci_readl(host, MINTSTS); /* read-only mask reg */ + + if (pending) { /* * DTO fix - version 2.10a and below, and only if internal DMA @@ -1589,9 +1589,6 @@ static irqreturn_t dw_mci_interrupt(int irq, void *dev_id) pending |= SDMMC_INT_DATA_OVER; } - if (!pending) - break; - if (pending & DW_MCI_CMD_ERROR_FLAGS) { mci_writel(host, RINTSTS, DW_MCI_CMD_ERROR_FLAGS); host->cmd_status = pending; @@ -1652,7 +1649,7 @@ static irqreturn_t dw_mci_interrupt(int irq, void *dev_id) } } - } while (pass_count++ < 5); + } #ifdef CONFIG_MMC_DW_IDMAC /* Handle DMA interrupts */ -- cgit v0.10.2 From 3e4b0d8bdc6ddd68fdc1f4592822af2ae5cc2859 Mon Sep 17 00:00:00 2001 From: Markos Chandras Date: Fri, 22 Mar 2013 12:50:05 -0400 Subject: mmc: dw_mmc: Avoid adding the number of transmitted bytes twice Previously, it was possible to add either 0 bytes or add nbytes twice if we broke out of the outer loop and then carry on to the "done" label. This is now fixed by adding the transferred bytes right after the pull/pop operation Signed-off-by: Markos Chandras Acked-by: Jaehoon Chung Acked-by: Seungwon Jeon Signed-off-by: Chris Ball diff --git a/drivers/mmc/host/dw_mmc.c b/drivers/mmc/host/dw_mmc.c index e7be402..a23b262 100644 --- a/drivers/mmc/host/dw_mmc.c +++ b/drivers/mmc/host/dw_mmc.c @@ -1454,7 +1454,7 @@ static void dw_mci_read_data_pio(struct dw_mci *host, bool dto) struct mmc_data *data = host->data; int shift = host->data_shift; u32 status; - unsigned int nbytes = 0, len; + unsigned int len; unsigned int remain, fcnt; do { @@ -1473,8 +1473,8 @@ static void dw_mci_read_data_pio(struct dw_mci *host, bool dto) if (!len) break; dw_mci_pull_data(host, (void *)(buf + offset), len); + data->bytes_xfered += len; offset += len; - nbytes += len; remain -= len; } while (remain); @@ -1484,7 +1484,6 @@ static void dw_mci_read_data_pio(struct dw_mci *host, bool dto) /* if the RXDR is ready read again */ } while ((status & SDMMC_INT_RXDR) || (dto && SDMMC_GET_FCNT(mci_readl(host, STATUS)))); - data->bytes_xfered += nbytes; if (!remain) { if (!sg_miter_next(sg_miter)) @@ -1495,7 +1494,6 @@ static void dw_mci_read_data_pio(struct dw_mci *host, bool dto) return; done: - data->bytes_xfered += nbytes; sg_miter_stop(sg_miter); host->sg = NULL; smp_wmb(); @@ -1510,7 +1508,7 @@ static void dw_mci_write_data_pio(struct dw_mci *host) struct mmc_data *data = host->data; int shift = host->data_shift; u32 status; - unsigned int nbytes = 0, len; + unsigned int len; unsigned int fifo_depth = host->fifo_depth; unsigned int remain, fcnt; @@ -1531,8 +1529,8 @@ static void dw_mci_write_data_pio(struct dw_mci *host) if (!len) break; host->push_data(host, (void *)(buf + offset), len); + data->bytes_xfered += len; offset += len; - nbytes += len; remain -= len; } while (remain); @@ -1540,7 +1538,6 @@ static void dw_mci_write_data_pio(struct dw_mci *host) status = mci_readl(host, MINTSTS); mci_writel(host, RINTSTS, SDMMC_INT_TXDR); } while (status & SDMMC_INT_TXDR); /* if TXDR write again */ - data->bytes_xfered += nbytes; if (!remain) { if (!sg_miter_next(sg_miter)) @@ -1551,7 +1548,6 @@ static void dw_mci_write_data_pio(struct dw_mci *host) return; done: - data->bytes_xfered += nbytes; sg_miter_stop(sg_miter); host->sg = NULL; smp_wmb(); -- cgit v0.10.2 From cfbeb59c7a818a2ec0008914ce479fe5d6f5978b Mon Sep 17 00:00:00 2001 From: Markos Chandras Date: Tue, 12 Mar 2013 10:53:13 +0000 Subject: mmc: dw_mmc: Handle unaligned data submission correctly Commit f9c2a0dc42a6938ff2a80e55ca2bbd1d5581c72e "mmc: dw_mmc: Fix PIO mode with support of highmem" introduced a regression since v3.2 making the mmc_test hang on test #13 with a "Data starvation by host timeout" interrupt. This is because, sg_mapping_iter is used to iterate through the data which spans on multiple pages. The problem is detected on unaligned data submission where the code previously checked for !(sg_next(host->sg)) which is true because we only have a single scatter/gather list which then expands to multiple pages. Therefore, the driver incorrectly assumed that this was the last list item and submitted unaligned data to the mmc device. This overflowed the FIFO on the device before all the data were written to it. The code was fixed to only submit unaligned data when we are handling the last sg_miter item by checking whether we reached the desired data length or not. The patch was tested against mmc_test and all the tests passed. Signed-off-by: Markos Chandras Acked-by: Jaehoon Chung Acked-by: Seungwon Jeon Signed-off-by: Chris Ball diff --git a/drivers/mmc/host/dw_mmc.c b/drivers/mmc/host/dw_mmc.c index a23b262..a443820 100644 --- a/drivers/mmc/host/dw_mmc.c +++ b/drivers/mmc/host/dw_mmc.c @@ -1199,12 +1199,15 @@ static void dw_mci_pull_final_bytes(struct dw_mci *host, void *buf, int cnt) static void dw_mci_push_data16(struct dw_mci *host, void *buf, int cnt) { + struct mmc_data *data = host->data; + int init_cnt = cnt; + /* try and push anything in the part_buf */ if (unlikely(host->part_buf_count)) { int len = dw_mci_push_part_bytes(host, buf, cnt); buf += len; cnt -= len; - if (!sg_next(host->sg) || host->part_buf_count == 2) { + if (host->part_buf_count == 2) { mci_writew(host, DATA(host->data_offset), host->part_buf16); host->part_buf_count = 0; @@ -1237,9 +1240,11 @@ static void dw_mci_push_data16(struct dw_mci *host, void *buf, int cnt) /* put anything remaining in the part_buf */ if (cnt) { dw_mci_set_part_bytes(host, buf, cnt); - if (!sg_next(host->sg)) + /* Push data if we have reached the expected data length */ + if ((data->bytes_xfered + init_cnt) == + (data->blksz * data->blocks)) mci_writew(host, DATA(host->data_offset), - host->part_buf16); + host->part_buf16); } } @@ -1277,12 +1282,15 @@ static void dw_mci_pull_data16(struct dw_mci *host, void *buf, int cnt) static void dw_mci_push_data32(struct dw_mci *host, void *buf, int cnt) { + struct mmc_data *data = host->data; + int init_cnt = cnt; + /* try and push anything in the part_buf */ if (unlikely(host->part_buf_count)) { int len = dw_mci_push_part_bytes(host, buf, cnt); buf += len; cnt -= len; - if (!sg_next(host->sg) || host->part_buf_count == 4) { + if (host->part_buf_count == 4) { mci_writel(host, DATA(host->data_offset), host->part_buf32); host->part_buf_count = 0; @@ -1315,9 +1323,11 @@ static void dw_mci_push_data32(struct dw_mci *host, void *buf, int cnt) /* put anything remaining in the part_buf */ if (cnt) { dw_mci_set_part_bytes(host, buf, cnt); - if (!sg_next(host->sg)) + /* Push data if we have reached the expected data length */ + if ((data->bytes_xfered + init_cnt) == + (data->blksz * data->blocks)) mci_writel(host, DATA(host->data_offset), - host->part_buf32); + host->part_buf32); } } @@ -1355,12 +1365,15 @@ static void dw_mci_pull_data32(struct dw_mci *host, void *buf, int cnt) static void dw_mci_push_data64(struct dw_mci *host, void *buf, int cnt) { + struct mmc_data *data = host->data; + int init_cnt = cnt; + /* try and push anything in the part_buf */ if (unlikely(host->part_buf_count)) { int len = dw_mci_push_part_bytes(host, buf, cnt); buf += len; cnt -= len; - if (!sg_next(host->sg) || host->part_buf_count == 8) { + if (host->part_buf_count == 8) { mci_writew(host, DATA(host->data_offset), host->part_buf); host->part_buf_count = 0; @@ -1393,9 +1406,11 @@ static void dw_mci_push_data64(struct dw_mci *host, void *buf, int cnt) /* put anything remaining in the part_buf */ if (cnt) { dw_mci_set_part_bytes(host, buf, cnt); - if (!sg_next(host->sg)) + /* Push data if we have reached the expected data length */ + if ((data->bytes_xfered + init_cnt) == + (data->blksz * data->blocks)) mci_writeq(host, DATA(host->data_offset), - host->part_buf); + host->part_buf); } } -- cgit v0.10.2 From 6a966e060978c82cf6d0baf3c200cbd4f692dc97 Mon Sep 17 00:00:00 2001 From: Silviu-Mihai Popescu Date: Tue, 12 Mar 2013 20:21:26 +0200 Subject: mmc: android-goldfish: use resource_size() Use resource_size() instead of explicit calculation. This was found via make coccicheck. Signed-off-by: Silviu-Mihai Popescu Signed-off-by: Chris Ball diff --git a/drivers/mmc/host/android-goldfish.c b/drivers/mmc/host/android-goldfish.c index ef3aef0..7780c14 100644 --- a/drivers/mmc/host/android-goldfish.c +++ b/drivers/mmc/host/android-goldfish.c @@ -476,7 +476,7 @@ static int goldfish_mmc_probe(struct platform_device *pdev) host->mmc = mmc; pr_err("mmc: Mapping %lX to %lX\n", (long)res->start, (long)res->end); - host->reg_base = ioremap(res->start, res->end - res->start + 1); + host->reg_base = ioremap(res->start, resource_size(res)); if (host->reg_base == NULL) { ret = -ENOMEM; goto ioremap_failed; -- cgit v0.10.2 From 20183d509cadfaee3b2b3ebe368431d566403c3d Mon Sep 17 00:00:00 2001 From: Sachin Kamat Date: Mon, 18 Feb 2013 14:23:09 +0530 Subject: mmc: dw_mmc: exynos: Remove unnecessary use of of_match_ptr() 'dw_mci_exynos_match' is always compiled in. Hence of_match_ptr is not required. Signed-off-by: Sachin Kamat Acked-by: Jaehoon Chung Acked-by: Seungwon Jeon Signed-off-by: Chris Ball diff --git a/drivers/mmc/host/dw_mmc-exynos.c b/drivers/mmc/host/dw_mmc-exynos.c index 5a09c77..517a603 100644 --- a/drivers/mmc/host/dw_mmc-exynos.c +++ b/drivers/mmc/host/dw_mmc-exynos.c @@ -230,7 +230,7 @@ static struct platform_driver dw_mci_exynos_pltfm_driver = { .remove = __exit_p(dw_mci_pltfm_remove), .driver = { .name = "dwmmc_exynos", - .of_match_table = of_match_ptr(dw_mci_exynos_match), + .of_match_table = dw_mci_exynos_match, .pm = &dw_mci_pltfm_pmops, }, }; -- cgit v0.10.2 From 0f6e73d0abde95973354b4921b4d08acf01a8b5c Mon Sep 17 00:00:00 2001 From: Dongjin Kim Date: Sat, 23 Feb 2013 00:17:45 +0900 Subject: mmc: dw_mmc: Add MSHC compatible for Exynos4412 This patch adds the compatible string for MSHC controller of Exynos4412. And exynos5250_dwmmc_caps is renamed to exynos_dwmmc_caps, since it has the capabilities of common features supported by Exynos4 and Exynos5. Signed-off-by: Dongjin Kim Acked-by: Seungwon Jeon Signed-off-by: Chris Ball diff --git a/drivers/mmc/host/dw_mmc-exynos.c b/drivers/mmc/host/dw_mmc-exynos.c index 517a603..c7f0976 100644 --- a/drivers/mmc/host/dw_mmc-exynos.c +++ b/drivers/mmc/host/dw_mmc-exynos.c @@ -189,8 +189,8 @@ static int dw_mci_exynos_setup_bus(struct dw_mci *host, return 0; } -/* Exynos5250 controller specific capabilities */ -static unsigned long exynos5250_dwmmc_caps[4] = { +/* Common capabilities of Exynos4/Exynos5 SoC */ +static unsigned long exynos_dwmmc_caps[4] = { MMC_CAP_UHS_DDR50 | MMC_CAP_1_8V_DDR | MMC_CAP_8_BIT_DATA | MMC_CAP_CMD23, MMC_CAP_CMD23, @@ -198,8 +198,8 @@ static unsigned long exynos5250_dwmmc_caps[4] = { MMC_CAP_CMD23, }; -static const struct dw_mci_drv_data exynos5250_drv_data = { - .caps = exynos5250_dwmmc_caps, +static const struct dw_mci_drv_data exynos_drv_data = { + .caps = exynos_dwmmc_caps, .init = dw_mci_exynos_priv_init, .setup_clock = dw_mci_exynos_setup_clock, .prepare_command = dw_mci_exynos_prepare_command, @@ -209,8 +209,10 @@ static const struct dw_mci_drv_data exynos5250_drv_data = { }; static const struct of_device_id dw_mci_exynos_match[] = { + { .compatible = "samsung,exynos4412-dw-mshc", + .data = &exynos_drv_data, }, { .compatible = "samsung,exynos5250-dw-mshc", - .data = &exynos5250_drv_data, }, + .data = &exynos_drv_data, }, {}, }; MODULE_DEVICE_TABLE(of, dw_mci_exynos_match); -- cgit v0.10.2 From 91cf54feecf815bec0b6a8d6d9dbd0e219f2f2cc Mon Sep 17 00:00:00 2001 From: Johan Hovold Date: Wed, 13 Mar 2013 17:11:59 +0100 Subject: mmc: at91/avr32/atmel-mci: fix DMA-channel leak on module unload Fix regression introduced by commit 796211b7953 ("mmc: atmel-mci: add pdc support and runtime capabilities detection") which removed the need for CONFIG_MMC_ATMELMCI_DMA but kept the Kconfig-entry as well as the compile guards around dma_release_channel() in remove(). Consequently, DMA is always enabled (if supported), but the DMA-channel is not released on module unload unless the DMA-config option is selected. Remove the no longer used CONFIG_MMC_ATMELMCI_DMA option completely. Signed-off-by: Johan Hovold Acked-by: Ludovic Desroches Cc: stable Signed-off-by: Chris Ball diff --git a/arch/arm/configs/at91sam9g45_defconfig b/arch/arm/configs/at91sam9g45_defconfig index 606d48f..8aab786 100644 --- a/arch/arm/configs/at91sam9g45_defconfig +++ b/arch/arm/configs/at91sam9g45_defconfig @@ -173,7 +173,6 @@ CONFIG_MMC=y # CONFIG_MMC_BLOCK_BOUNCE is not set CONFIG_SDIO_UART=m CONFIG_MMC_ATMELMCI=y -CONFIG_MMC_ATMELMCI_DMA=y CONFIG_LEDS_ATMEL_PWM=y CONFIG_LEDS_GPIO=y CONFIG_LEDS_TRIGGER_TIMER=y diff --git a/arch/avr32/configs/favr-32_defconfig b/arch/avr32/configs/favr-32_defconfig index 0421498..9791820 100644 --- a/arch/avr32/configs/favr-32_defconfig +++ b/arch/avr32/configs/favr-32_defconfig @@ -122,7 +122,6 @@ CONFIG_USB_G_SERIAL=m CONFIG_USB_CDC_COMPOSITE=m CONFIG_MMC=y CONFIG_MMC_ATMELMCI=y -CONFIG_MMC_ATMELMCI_DMA=y CONFIG_NEW_LEDS=y CONFIG_LEDS_CLASS=y CONFIG_LEDS_ATMEL_PWM=m diff --git a/arch/avr32/configs/merisc_defconfig b/arch/avr32/configs/merisc_defconfig index 3befab9..65de443 100644 --- a/arch/avr32/configs/merisc_defconfig +++ b/arch/avr32/configs/merisc_defconfig @@ -102,7 +102,6 @@ CONFIG_FRAMEBUFFER_CONSOLE=y CONFIG_LOGO=y CONFIG_MMC=y CONFIG_MMC_ATMELMCI=y -CONFIG_MMC_ATMELMCI_DMA=y CONFIG_NEW_LEDS=y CONFIG_LEDS_CLASS=y CONFIG_LEDS_ATMEL_PWM=y diff --git a/drivers/mmc/host/Kconfig b/drivers/mmc/host/Kconfig index d88219e..9c581c2 100644 --- a/drivers/mmc/host/Kconfig +++ b/drivers/mmc/host/Kconfig @@ -300,16 +300,6 @@ config MMC_ATMELMCI If unsure, say N. -config MMC_ATMELMCI_DMA - bool "Atmel MCI DMA support" - depends on MMC_ATMELMCI && (AVR32 || ARCH_AT91SAM9G45) && DMA_ENGINE - help - Say Y here to have the Atmel MCI driver use a DMA engine to - do data transfers and thus increase the throughput and - reduce the CPU utilization. - - If unsure, say N. - config MMC_MSM tristate "Qualcomm SDCC Controller Support" depends on MMC && ARCH_MSM diff --git a/drivers/mmc/host/atmel-mci.c b/drivers/mmc/host/atmel-mci.c index 722af1d..10f8b73 100644 --- a/drivers/mmc/host/atmel-mci.c +++ b/drivers/mmc/host/atmel-mci.c @@ -2487,10 +2487,8 @@ static int __exit atmci_remove(struct platform_device *pdev) atmci_readl(host, ATMCI_SR); clk_disable(host->mck); -#ifdef CONFIG_MMC_ATMELMCI_DMA if (host->dma.chan) dma_release_channel(host->dma.chan); -#endif free_irq(platform_get_irq(pdev, 0), host); iounmap(host->regs); -- cgit v0.10.2 From 1db5eebf22f86a87c3fcbbb085a4abbcfd09ee7d Mon Sep 17 00:00:00 2001 From: Lars-Peter Clausen Date: Wed, 13 Mar 2013 19:26:03 +0100 Subject: mmc: sdhci_pltfm: Constify sdhci_pltfm_data The sdhci_pltfm_data struct is never modified within the sdhci_pltfm module. So make the pdata parameter to sdhci_pltfm_init and sdhci_pltfm_register const. This allows drivers to declare their sdhci_pltfm_data struct as const. This patch also makes the sdhci_pltfm_data declarations const where possible. Signed-off-by: Lars-Peter Clausen Acked-by: Shawn Guo Signed-off-by: Chris Ball diff --git a/drivers/mmc/host/sdhci-bcm2835.c b/drivers/mmc/host/sdhci-bcm2835.c index 8ffea05..29e9e40 100644 --- a/drivers/mmc/host/sdhci-bcm2835.c +++ b/drivers/mmc/host/sdhci-bcm2835.c @@ -135,7 +135,7 @@ static struct sdhci_ops bcm2835_sdhci_ops = { .get_min_clock = bcm2835_sdhci_get_min_clock, }; -static struct sdhci_pltfm_data bcm2835_sdhci_pdata = { +static const struct sdhci_pltfm_data bcm2835_sdhci_pdata = { .quirks = SDHCI_QUIRK_BROKEN_CARD_DETECTION | SDHCI_QUIRK_DATA_TIMEOUT_USES_SDCLK, .ops = &bcm2835_sdhci_ops, diff --git a/drivers/mmc/host/sdhci-cns3xxx.c b/drivers/mmc/host/sdhci-cns3xxx.c index 30bfdc4..15a936a 100644 --- a/drivers/mmc/host/sdhci-cns3xxx.c +++ b/drivers/mmc/host/sdhci-cns3xxx.c @@ -85,7 +85,7 @@ static struct sdhci_ops sdhci_cns3xxx_ops = { .set_clock = sdhci_cns3xxx_set_clock, }; -static struct sdhci_pltfm_data sdhci_cns3xxx_pdata = { +static const struct sdhci_pltfm_data sdhci_cns3xxx_pdata = { .ops = &sdhci_cns3xxx_ops, .quirks = SDHCI_QUIRK_BROKEN_DMA | SDHCI_QUIRK_DATA_TIMEOUT_USES_SDCLK | diff --git a/drivers/mmc/host/sdhci-dove.c b/drivers/mmc/host/sdhci-dove.c index 169fab9..b514f68 100644 --- a/drivers/mmc/host/sdhci-dove.c +++ b/drivers/mmc/host/sdhci-dove.c @@ -88,7 +88,7 @@ static struct sdhci_ops sdhci_dove_ops = { .read_l = sdhci_dove_readl, }; -static struct sdhci_pltfm_data sdhci_dove_pdata = { +static const struct sdhci_pltfm_data sdhci_dove_pdata = { .ops = &sdhci_dove_ops, .quirks = SDHCI_QUIRK_NO_SIMULT_VDD_AND_POWER | SDHCI_QUIRK_NO_BUSY_IRQ | diff --git a/drivers/mmc/host/sdhci-esdhc-imx.c b/drivers/mmc/host/sdhci-esdhc-imx.c index 78ac002..68c301d 100644 --- a/drivers/mmc/host/sdhci-esdhc-imx.c +++ b/drivers/mmc/host/sdhci-esdhc-imx.c @@ -412,7 +412,7 @@ static struct sdhci_ops sdhci_esdhc_ops = { .platform_bus_width = esdhc_pltfm_bus_width, }; -static struct sdhci_pltfm_data sdhci_esdhc_imx_pdata = { +static const struct sdhci_pltfm_data sdhci_esdhc_imx_pdata = { .quirks = ESDHC_DEFAULT_QUIRKS | SDHCI_QUIRK_NO_HISPD_BIT | SDHCI_QUIRK_NO_ENDATTR_IN_NOPDESC | SDHCI_QUIRK_BROKEN_ADMA_ZEROLEN_DESC diff --git a/drivers/mmc/host/sdhci-of-esdhc.c b/drivers/mmc/host/sdhci-of-esdhc.c index f32526d..b98b919 100644 --- a/drivers/mmc/host/sdhci-of-esdhc.c +++ b/drivers/mmc/host/sdhci-of-esdhc.c @@ -249,7 +249,7 @@ static struct sdhci_ops sdhci_esdhc_ops = { .adma_workaround = esdhci_of_adma_workaround, }; -static struct sdhci_pltfm_data sdhci_esdhc_pdata = { +static const struct sdhci_pltfm_data sdhci_esdhc_pdata = { /* * card detection could be handled via GPIO * eSDHC cannot support End Attribute in NOP ADMA descriptor diff --git a/drivers/mmc/host/sdhci-of-hlwd.c b/drivers/mmc/host/sdhci-of-hlwd.c index c3d3715..7ea5c02 100644 --- a/drivers/mmc/host/sdhci-of-hlwd.c +++ b/drivers/mmc/host/sdhci-of-hlwd.c @@ -60,7 +60,7 @@ static struct sdhci_ops sdhci_hlwd_ops = { .write_b = sdhci_hlwd_writeb, }; -static struct sdhci_pltfm_data sdhci_hlwd_pdata = { +static const struct sdhci_pltfm_data sdhci_hlwd_pdata = { .quirks = SDHCI_QUIRK_32BIT_DMA_ADDR | SDHCI_QUIRK_32BIT_DMA_SIZE, .ops = &sdhci_hlwd_ops, diff --git a/drivers/mmc/host/sdhci-pltfm.c b/drivers/mmc/host/sdhci-pltfm.c index 9db7b12..3893fd6 100644 --- a/drivers/mmc/host/sdhci-pltfm.c +++ b/drivers/mmc/host/sdhci-pltfm.c @@ -115,7 +115,7 @@ void sdhci_get_of_property(struct platform_device *pdev) {} EXPORT_SYMBOL_GPL(sdhci_get_of_property); struct sdhci_host *sdhci_pltfm_init(struct platform_device *pdev, - struct sdhci_pltfm_data *pdata) + const struct sdhci_pltfm_data *pdata) { struct sdhci_host *host; struct sdhci_pltfm_host *pltfm_host; @@ -202,7 +202,7 @@ void sdhci_pltfm_free(struct platform_device *pdev) EXPORT_SYMBOL_GPL(sdhci_pltfm_free); int sdhci_pltfm_register(struct platform_device *pdev, - struct sdhci_pltfm_data *pdata) + const struct sdhci_pltfm_data *pdata) { struct sdhci_host *host; int ret = 0; diff --git a/drivers/mmc/host/sdhci-pltfm.h b/drivers/mmc/host/sdhci-pltfm.h index 153b6c5..a3bfc1e 100644 --- a/drivers/mmc/host/sdhci-pltfm.h +++ b/drivers/mmc/host/sdhci-pltfm.h @@ -91,11 +91,11 @@ static inline void sdhci_be32bs_writeb(struct sdhci_host *host, u8 val, int reg) extern void sdhci_get_of_property(struct platform_device *pdev); extern struct sdhci_host *sdhci_pltfm_init(struct platform_device *pdev, - struct sdhci_pltfm_data *pdata); + const struct sdhci_pltfm_data *pdata); extern void sdhci_pltfm_free(struct platform_device *pdev); extern int sdhci_pltfm_register(struct platform_device *pdev, - struct sdhci_pltfm_data *pdata); + const struct sdhci_pltfm_data *pdata); extern int sdhci_pltfm_unregister(struct platform_device *pdev); extern unsigned int sdhci_pltfm_clk_get_max_clock(struct sdhci_host *host); diff --git a/drivers/mmc/host/sdhci-tegra.c b/drivers/mmc/host/sdhci-tegra.c index c665d1d..f8ac50c 100644 --- a/drivers/mmc/host/sdhci-tegra.c +++ b/drivers/mmc/host/sdhci-tegra.c @@ -39,7 +39,7 @@ #define NVQUIRK_ENABLE_SDHCI_SPEC_300 BIT(2) struct sdhci_tegra_soc_data { - struct sdhci_pltfm_data *pdata; + const struct sdhci_pltfm_data *pdata; u32 nvquirks; }; @@ -156,7 +156,7 @@ static struct sdhci_ops tegra_sdhci_ops = { .platform_reset_exit = tegra_sdhci_reset_exit, }; -static struct sdhci_pltfm_data sdhci_tegra20_pdata = { +static const struct sdhci_pltfm_data sdhci_tegra20_pdata = { .quirks = SDHCI_QUIRK_BROKEN_TIMEOUT_VAL | SDHCI_QUIRK_SINGLE_POWER_WRITE | SDHCI_QUIRK_NO_HISPD_BIT | @@ -170,7 +170,7 @@ static struct sdhci_tegra_soc_data soc_data_tegra20 = { NVQUIRK_ENABLE_BLOCK_GAP_DET, }; -static struct sdhci_pltfm_data sdhci_tegra30_pdata = { +static const struct sdhci_pltfm_data sdhci_tegra30_pdata = { .quirks = SDHCI_QUIRK_BROKEN_TIMEOUT_VAL | SDHCI_QUIRK_DATA_TIMEOUT_USES_SDCLK | SDHCI_QUIRK_SINGLE_POWER_WRITE | @@ -184,7 +184,7 @@ static struct sdhci_tegra_soc_data soc_data_tegra30 = { .nvquirks = NVQUIRK_ENABLE_SDHCI_SPEC_300, }; -static struct sdhci_pltfm_data sdhci_tegra114_pdata = { +static const struct sdhci_pltfm_data sdhci_tegra114_pdata = { .quirks = SDHCI_QUIRK_BROKEN_TIMEOUT_VAL | SDHCI_QUIRK_DATA_TIMEOUT_USES_SDCLK | SDHCI_QUIRK_SINGLE_POWER_WRITE | -- cgit v0.10.2 From ad1df8c25ecdf0bd2632c0825ecf8e8748c8154a Mon Sep 17 00:00:00 2001 From: Lars-Peter Clausen Date: Wed, 13 Mar 2013 19:26:04 +0100 Subject: mmc: sdhci-pltfm: Constify the ops field of sdhci_pltfm_data struct All users of the sdhci_ops struct in the sdhci core already treat it as const. The sdhci-pltfm code itself never actually looks at the ops field of the sdhci_pltfm_data struct and merely passes it on to the sdhci core, so make we can make it const in the sdhci_pltfm_data struct as well. This allows us to declare sdhci_ops structs as const in drivers using the sdhci-pltfm helper code. Signed-off-by: Lars-Peter Clausen Acked-by: Shawn Guo Signed-off-by: Chris Ball diff --git a/drivers/mmc/host/sdhci-pltfm.h b/drivers/mmc/host/sdhci-pltfm.h index a3bfc1e..1210ed1 100644 --- a/drivers/mmc/host/sdhci-pltfm.h +++ b/drivers/mmc/host/sdhci-pltfm.h @@ -16,7 +16,7 @@ #include "sdhci.h" struct sdhci_pltfm_data { - struct sdhci_ops *ops; + const struct sdhci_ops *ops; unsigned int quirks; }; -- cgit v0.10.2 From c915568d99f12898aea4e15845cf891a8b5cc575 Mon Sep 17 00:00:00 2001 From: Lars-Peter Clausen Date: Wed, 13 Mar 2013 19:26:05 +0100 Subject: mmc: sdhci: Constify sdhci_ops structs where possible Basically all drivers can have sdhci_ops struct const, but almost none do. This patch constifies all sdhci_ops struct declarations where possible. The patch was auto-generated with the following coccinelle semantic patch: // @r1@ identifier ops; identifier fld; @@ ops.fld = ...; @disable optional_qualifier@ identifier ops != r1.ops; @@ static +const struct sdhci_ops ops = { ... }; // Signed-off-by: Lars-Peter Clausen Acked-by: Shawn Guo Signed-off-by: Chris Ball diff --git a/drivers/mmc/host/sdhci-bcm2835.c b/drivers/mmc/host/sdhci-bcm2835.c index 29e9e40..d49bc95 100644 --- a/drivers/mmc/host/sdhci-bcm2835.c +++ b/drivers/mmc/host/sdhci-bcm2835.c @@ -124,7 +124,7 @@ unsigned int bcm2835_sdhci_get_min_clock(struct sdhci_host *host) return MIN_FREQ; } -static struct sdhci_ops bcm2835_sdhci_ops = { +static const struct sdhci_ops bcm2835_sdhci_ops = { .write_l = bcm2835_sdhci_writel, .write_w = bcm2835_sdhci_writew, .write_b = bcm2835_sdhci_writeb, diff --git a/drivers/mmc/host/sdhci-cns3xxx.c b/drivers/mmc/host/sdhci-cns3xxx.c index 15a936a..4fa26de 100644 --- a/drivers/mmc/host/sdhci-cns3xxx.c +++ b/drivers/mmc/host/sdhci-cns3xxx.c @@ -80,7 +80,7 @@ out: host->clock = clock; } -static struct sdhci_ops sdhci_cns3xxx_ops = { +static const struct sdhci_ops sdhci_cns3xxx_ops = { .get_max_clock = sdhci_cns3xxx_get_max_clk, .set_clock = sdhci_cns3xxx_set_clock, }; diff --git a/drivers/mmc/host/sdhci-dove.c b/drivers/mmc/host/sdhci-dove.c index b514f68..15e7803 100644 --- a/drivers/mmc/host/sdhci-dove.c +++ b/drivers/mmc/host/sdhci-dove.c @@ -83,7 +83,7 @@ static u32 sdhci_dove_readl(struct sdhci_host *host, int reg) return ret; } -static struct sdhci_ops sdhci_dove_ops = { +static const struct sdhci_ops sdhci_dove_ops = { .read_w = sdhci_dove_readw, .read_l = sdhci_dove_readl, }; diff --git a/drivers/mmc/host/sdhci-esdhc-imx.c b/drivers/mmc/host/sdhci-esdhc-imx.c index 68c301d..67d6dde 100644 --- a/drivers/mmc/host/sdhci-esdhc-imx.c +++ b/drivers/mmc/host/sdhci-esdhc-imx.c @@ -399,7 +399,7 @@ static int esdhc_pltfm_bus_width(struct sdhci_host *host, int width) return 0; } -static struct sdhci_ops sdhci_esdhc_ops = { +static const struct sdhci_ops sdhci_esdhc_ops = { .read_l = esdhc_readl_le, .read_w = esdhc_readw_le, .write_l = esdhc_writel_le, diff --git a/drivers/mmc/host/sdhci-of-esdhc.c b/drivers/mmc/host/sdhci-of-esdhc.c index b98b919..5e68adc 100644 --- a/drivers/mmc/host/sdhci-of-esdhc.c +++ b/drivers/mmc/host/sdhci-of-esdhc.c @@ -230,7 +230,7 @@ static void esdhc_of_platform_init(struct sdhci_host *host) host->quirks &= ~SDHCI_QUIRK_NO_BUSY_IRQ; } -static struct sdhci_ops sdhci_esdhc_ops = { +static const struct sdhci_ops sdhci_esdhc_ops = { .read_l = esdhc_readl, .read_w = esdhc_readw, .read_b = esdhc_readb, diff --git a/drivers/mmc/host/sdhci-of-hlwd.c b/drivers/mmc/host/sdhci-of-hlwd.c index 7ea5c02..200a6a9 100644 --- a/drivers/mmc/host/sdhci-of-hlwd.c +++ b/drivers/mmc/host/sdhci-of-hlwd.c @@ -51,7 +51,7 @@ static void sdhci_hlwd_writeb(struct sdhci_host *host, u8 val, int reg) udelay(SDHCI_HLWD_WRITE_DELAY); } -static struct sdhci_ops sdhci_hlwd_ops = { +static const struct sdhci_ops sdhci_hlwd_ops = { .read_l = sdhci_be32bs_readl, .read_w = sdhci_be32bs_readw, .read_b = sdhci_be32bs_readb, diff --git a/drivers/mmc/host/sdhci-pci.c b/drivers/mmc/host/sdhci-pci.c index 3dee22d..c1f0372 100644 --- a/drivers/mmc/host/sdhci-pci.c +++ b/drivers/mmc/host/sdhci-pci.c @@ -975,7 +975,7 @@ static void sdhci_pci_hw_reset(struct sdhci_host *host) usleep_range(300, 1000); } -static struct sdhci_ops sdhci_pci_ops = { +static const struct sdhci_ops sdhci_pci_ops = { .enable_dma = sdhci_pci_enable_dma, .platform_bus_width = sdhci_pci_bus_width, .hw_reset = sdhci_pci_hw_reset, diff --git a/drivers/mmc/host/sdhci-pltfm.c b/drivers/mmc/host/sdhci-pltfm.c index 3893fd6..cd0f1f6 100644 --- a/drivers/mmc/host/sdhci-pltfm.c +++ b/drivers/mmc/host/sdhci-pltfm.c @@ -44,7 +44,7 @@ unsigned int sdhci_pltfm_clk_get_max_clock(struct sdhci_host *host) } EXPORT_SYMBOL_GPL(sdhci_pltfm_clk_get_max_clock); -static struct sdhci_ops sdhci_pltfm_ops = { +static const struct sdhci_ops sdhci_pltfm_ops = { }; #ifdef CONFIG_OF diff --git a/drivers/mmc/host/sdhci-pxav2.c b/drivers/mmc/host/sdhci-pxav2.c index eeb7d43..6a3f702 100644 --- a/drivers/mmc/host/sdhci-pxav2.c +++ b/drivers/mmc/host/sdhci-pxav2.c @@ -111,7 +111,7 @@ static int pxav2_mmc_set_width(struct sdhci_host *host, int width) return 0; } -static struct sdhci_ops pxav2_sdhci_ops = { +static const struct sdhci_ops pxav2_sdhci_ops = { .get_max_clock = sdhci_pltfm_clk_get_max_clock, .platform_reset_exit = pxav2_set_private_registers, .platform_bus_width = pxav2_mmc_set_width, diff --git a/drivers/mmc/host/sdhci-pxav3.c b/drivers/mmc/host/sdhci-pxav3.c index a0cdbc5..5663a6e 100644 --- a/drivers/mmc/host/sdhci-pxav3.c +++ b/drivers/mmc/host/sdhci-pxav3.c @@ -167,7 +167,7 @@ static int pxav3_set_uhs_signaling(struct sdhci_host *host, unsigned int uhs) return 0; } -static struct sdhci_ops pxav3_sdhci_ops = { +static const struct sdhci_ops pxav3_sdhci_ops = { .platform_reset_exit = pxav3_set_private_registers, .set_uhs_signaling = pxav3_set_uhs_signaling, .platform_send_init_74_clocks = pxav3_gen_init_74_clocks, diff --git a/drivers/mmc/host/sdhci-spear.c b/drivers/mmc/host/sdhci-spear.c index c6ece0b..8d28334 100644 --- a/drivers/mmc/host/sdhci-spear.c +++ b/drivers/mmc/host/sdhci-spear.c @@ -36,7 +36,7 @@ struct spear_sdhci { }; /* sdhci ops */ -static struct sdhci_ops sdhci_pltfm_ops = { +static const struct sdhci_ops sdhci_pltfm_ops = { /* Nothing to do for now. */ }; diff --git a/drivers/mmc/host/sdhci-tegra.c b/drivers/mmc/host/sdhci-tegra.c index f8ac50c..45048d1 100644 --- a/drivers/mmc/host/sdhci-tegra.c +++ b/drivers/mmc/host/sdhci-tegra.c @@ -147,7 +147,7 @@ static int tegra_sdhci_buswidth(struct sdhci_host *host, int bus_width) return 0; } -static struct sdhci_ops tegra_sdhci_ops = { +static const struct sdhci_ops tegra_sdhci_ops = { .get_ro = tegra_sdhci_get_ro, .read_l = tegra_sdhci_readl, .read_w = tegra_sdhci_readw, -- cgit v0.10.2 From 3500ed90b26a9935b943b5e2e4cd3226600d6b58 Mon Sep 17 00:00:00 2001 From: Sergey Yanovich Date: Thu, 14 Mar 2013 05:23:13 +0400 Subject: mmc: core: wait while adding MMC host to ensure root mounts successfully MMC hosts are added asynchronously. We need to wait until detect returns to avoid failed root filesystem mounts. VFS: Cannot open root device "mmcblk0p1" or unknown-block(0,0): error -6 Please append a correct "root=" boot option; here are the available partitions: mmc0: host does not support reading read-only switch. assuming write-enable. 1f00 256 mtdblock0 (driver?) 1f01 256 mtdblock1 (driver?) 1f02 2560 mtdblock2 mmc0: new SDHC card at address b368 (driver?) 1f03 29696 mtdblock3 (driver?) 1f04 16384 mtdblock4 mmcblk0: mmc0:b368 USD 3.72 GiB (driver?) mmcblk0: p1 b300 3910656 mmcblk0 driver: mmcblk b301 3906560 mmcblk0p1 00000000-01 Kernel panic - not syncing: VFS: Unable to mount root fs on unknown-block(0,0) Signed-off-by: Sergey Yanovich Signed-off-by: Chris Ball diff --git a/drivers/mmc/core/core.c b/drivers/mmc/core/core.c index 3bf1c46..ad7decc 100644 --- a/drivers/mmc/core/core.c +++ b/drivers/mmc/core/core.c @@ -2418,6 +2418,7 @@ void mmc_start_host(struct mmc_host *host) host->rescan_disable = 0; mmc_power_up(host); mmc_detect_change(host, 0); + mmc_flush_scheduled_work(); } void mmc_stop_host(struct mmc_host *host) -- cgit v0.10.2 From ef3a69c7a40d5350adeaed7f0f4b4dcf6362dbbd Mon Sep 17 00:00:00 2001 From: Seungwon Jeon Date: Thu, 14 Mar 2013 15:17:13 +0900 Subject: mmc: block: fix the host's claim-release in special request For normal request mmc_blk_issue_rq is called twice with asynchronous transfer(cur and prev). Host's claim and release can be done in each mmc_blk_issue_rq. However, Special request is currently excluded in asynchronous transfer. After special request is finished, if there is no new request, mmc_release_host won't be called in mmc_blk_issue_rq. The problem is founded during mmc_suspend. [] (__schedule+0x0/0x78c) from [] (schedule+0x38/0x78) [] (schedule+0x0/0x78) from [] (__mmc_claim_host+0xac/0x1b4) [] (__mmc_claim_host+0x0/0x1b4) from [] (mmc_suspend+0x28/0x9c) [] (mmc_suspend+0x0/0x9c) from [] (mmc_suspend_host+0xb4/0x194) ... Reported-by: Johan Rudholm Signed-off-by: Seungwon Jeon Tested-by: Johan Rudholm Signed-off-by: Chris Ball diff --git a/drivers/mmc/card/block.c b/drivers/mmc/card/block.c index 5bab73b..e12a03c 100644 --- a/drivers/mmc/card/block.c +++ b/drivers/mmc/card/block.c @@ -1932,8 +1932,14 @@ static int mmc_blk_issue_rq(struct mmc_queue *mq, struct request *req) } out: - if (!req && !(mq->flags & MMC_QUEUE_NEW_REQUEST)) - /* release host only when there are no more requests */ + if ((!req && !(mq->flags & MMC_QUEUE_NEW_REQUEST)) || + (req && (req->cmd_flags & MMC_REQ_SPECIAL_MASK))) + /* + * Release host when there are no more requests + * and after special request(discard, flush) is done. + * In case sepecial request, there is no reentry to + * the 'mmc_blk_issue_rq' with 'mqrq_prev->req'. + */ mmc_release_host(card->host); return ret; } diff --git a/drivers/mmc/card/queue.c b/drivers/mmc/card/queue.c index fa4e44e..9447a0e 100644 --- a/drivers/mmc/card/queue.c +++ b/drivers/mmc/card/queue.c @@ -22,9 +22,6 @@ #define MMC_QUEUE_BOUNCESZ 65536 - -#define MMC_REQ_SPECIAL_MASK (REQ_DISCARD | REQ_FLUSH) - /* * Prepare a MMC request. This just filters out odd stuff. */ diff --git a/drivers/mmc/card/queue.h b/drivers/mmc/card/queue.h index 031bf63..5752d50 100644 --- a/drivers/mmc/card/queue.h +++ b/drivers/mmc/card/queue.h @@ -1,6 +1,8 @@ #ifndef MMC_QUEUE_H #define MMC_QUEUE_H +#define MMC_REQ_SPECIAL_MASK (REQ_DISCARD | REQ_FLUSH) + struct request; struct task_struct; -- cgit v0.10.2 From b3b665b0a9d13d731a61aeed92a02c1c9c55cd70 Mon Sep 17 00:00:00 2001 From: Barry Song Date: Thu, 21 Mar 2013 16:27:19 +0800 Subject: mmc: sdhci-sirf: add mmc host sdhci-pltfm based driver for SiRF SoCs This patch adds the new driver for CSR SiRF SoCs: SiRFprimaII: unicore ARM Cortex-A9 SiRFatlas6: unicore ARM Cortex-A9 SiRFmarco: dual core ARM Cortex-A9 SMP Signed-off-by: Barry Song Signed-off-by: Bin Shi Acked-by: Arnd Bergmann Signed-off-by: Chris Ball diff --git a/Documentation/devicetree/bindings/mmc/sdhci-sirf.txt b/Documentation/devicetree/bindings/mmc/sdhci-sirf.txt new file mode 100644 index 0000000..dd6ed46 --- /dev/null +++ b/Documentation/devicetree/bindings/mmc/sdhci-sirf.txt @@ -0,0 +1,18 @@ +* SiRFprimII/marco/atlas6 SDHCI Controller + +This file documents differences between the core properties in mmc.txt +and the properties used by the sdhci-sirf driver. + +Required properties: +- compatible: sirf,prima2-sdhc + +Optional properties: +- cd-gpios: card detect gpio, with zero flags. + +Example: + + sd0: sdhci@56000000 { + compatible = "sirf,prima2-sdhc"; + reg = <0xcd000000 0x100000>; + cd-gpios = <&gpio 6 0>; + }; diff --git a/MAINTAINERS b/MAINTAINERS index e95b1e9..21b1678 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -805,6 +805,7 @@ S: Maintained F: arch/arm/mach-prima2/ F: drivers/dma/sirf-dma.c F: drivers/i2c/busses/i2c-sirf.c +F: drivers/mmc/host/sdhci-sirf.c F: drivers/pinctrl/pinctrl-sirf.c F: drivers/spi/spi-sirf.c diff --git a/drivers/mmc/host/Kconfig b/drivers/mmc/host/Kconfig index 9c581c2..f83f245 100644 --- a/drivers/mmc/host/Kconfig +++ b/drivers/mmc/host/Kconfig @@ -190,6 +190,17 @@ config MMC_SDHCI_S3C If unsure, say N. +config MMC_SDHCI_SIRF + tristate "SDHCI support on CSR SiRFprimaII and SiRFmarco SoCs" + depends on ARCH_SIRF + depends on MMC_SDHCI_PLTFM + help + This selects the SDHCI support for SiRF System-on-Chip devices. + + If you have a controller with this interface, say Y or M here. + + If unsure, say N. + config MMC_SDHCI_PXAV3 tristate "Marvell MMP2 SD Host Controller support (PXAV3)" depends on CLKDEV_LOOKUP diff --git a/drivers/mmc/host/Makefile b/drivers/mmc/host/Makefile index c380e3c..cd32280 100644 --- a/drivers/mmc/host/Makefile +++ b/drivers/mmc/host/Makefile @@ -13,6 +13,7 @@ obj-$(CONFIG_MMC_SDHCI_ACPI) += sdhci-acpi.o obj-$(CONFIG_MMC_SDHCI_PXAV3) += sdhci-pxav3.o obj-$(CONFIG_MMC_SDHCI_PXAV2) += sdhci-pxav2.o obj-$(CONFIG_MMC_SDHCI_S3C) += sdhci-s3c.o +obj-$(CONFIG_MMC_SDHCI_SIRF) += sdhci-sirf.o obj-$(CONFIG_MMC_SDHCI_SPEAR) += sdhci-spear.o obj-$(CONFIG_MMC_WBSD) += wbsd.o obj-$(CONFIG_MMC_AU1X) += au1xmmc.o diff --git a/drivers/mmc/host/sdhci-sirf.c b/drivers/mmc/host/sdhci-sirf.c new file mode 100644 index 0000000..09805af --- /dev/null +++ b/drivers/mmc/host/sdhci-sirf.c @@ -0,0 +1,193 @@ +/* + * SDHCI support for SiRF primaII and marco SoCs + * + * Copyright (c) 2011 Cambridge Silicon Radio Limited, a CSR plc group company. + * + * Licensed under GPLv2 or later. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include "sdhci-pltfm.h" + +struct sdhci_sirf_priv { + struct clk *clk; + int gpio_cd; +}; + +static unsigned int sdhci_sirf_get_max_clk(struct sdhci_host *host) +{ + struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); + struct sdhci_sirf_priv *priv = pltfm_host->priv; + return clk_get_rate(priv->clk); +} + +static struct sdhci_ops sdhci_sirf_ops = { + .get_max_clock = sdhci_sirf_get_max_clk, +}; + +static struct sdhci_pltfm_data sdhci_sirf_pdata = { + .ops = &sdhci_sirf_ops, + .quirks = SDHCI_QUIRK_BROKEN_TIMEOUT_VAL | + SDHCI_QUIRK_DATA_TIMEOUT_USES_SDCLK | + SDHCI_QUIRK_CAP_CLOCK_BASE_BROKEN | + SDHCI_QUIRK_INVERTED_WRITE_PROTECT | + SDHCI_QUIRK_DELAY_AFTER_POWER, +}; + +static int sdhci_sirf_probe(struct platform_device *pdev) +{ + struct sdhci_host *host; + struct sdhci_pltfm_host *pltfm_host; + struct sdhci_sirf_priv *priv; + struct pinctrl *pinctrl; + int ret; + + pinctrl = devm_pinctrl_get_select_default(&pdev->dev); + if (IS_ERR(pinctrl)) { + dev_err(&pdev->dev, "unable to get pinmux"); + return PTR_ERR(pinctrl); + } + + priv = devm_kzalloc(&pdev->dev, sizeof(struct sdhci_sirf_priv), + GFP_KERNEL); + if (!priv) { + dev_err(&pdev->dev, "unable to allocate private data"); + return -ENOMEM; + } + + priv->clk = devm_clk_get(&pdev->dev, NULL); + if (IS_ERR(priv->clk)) { + dev_err(&pdev->dev, "unable to get clock"); + return PTR_ERR(priv->clk); + } + + if (pdev->dev.of_node) { + priv->gpio_cd = of_get_named_gpio(pdev->dev.of_node, + "cd-gpios", 0); + } else { + priv->gpio_cd = -EINVAL; + } + + host = sdhci_pltfm_init(pdev, &sdhci_sirf_pdata); + if (IS_ERR(host)) { + ret = PTR_ERR(host); + goto err_sdhci_pltfm_init; + } + + pltfm_host = sdhci_priv(host); + pltfm_host->priv = priv; + + sdhci_get_of_property(pdev); + + clk_prepare_enable(priv->clk); + + ret = sdhci_add_host(host); + if (ret) + goto err_sdhci_add; + + /* + * We must request the IRQ after sdhci_add_host(), as the tasklet only + * gets setup in sdhci_add_host() and we oops. + */ + if (gpio_is_valid(priv->gpio_cd)) { + ret = mmc_gpio_request_cd(host->mmc, priv->gpio_cd); + if (ret) { + dev_err(&pdev->dev, "card detect irq request failed: %d\n", + ret); + goto err_request_cd; + } + } + + return 0; + +err_request_cd: + sdhci_remove_host(host, 0); +err_sdhci_add: + clk_disable_unprepare(priv->clk); + sdhci_pltfm_free(pdev); +err_sdhci_pltfm_init: + return ret; +} + +static int sdhci_sirf_remove(struct platform_device *pdev) +{ + struct sdhci_host *host = platform_get_drvdata(pdev); + struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); + struct sdhci_sirf_priv *priv = pltfm_host->priv; + + sdhci_pltfm_unregister(pdev); + + if (gpio_is_valid(priv->gpio_cd)) + mmc_gpio_free_cd(host->mmc); + + clk_disable_unprepare(priv->clk); + return 0; +} + +#ifdef CONFIG_PM_SLEEP +static int sdhci_sirf_suspend(struct device *dev) +{ + struct sdhci_host *host = dev_get_drvdata(dev); + struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); + struct sdhci_sirf_priv *priv = pltfm_host->priv; + int ret; + + ret = sdhci_suspend_host(host); + if (ret) + return ret; + + clk_disable(priv->clk); + + return 0; +} + +static int sdhci_sirf_resume(struct device *dev) +{ + struct sdhci_host *host = dev_get_drvdata(dev); + struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); + struct sdhci_sirf_priv *priv = pltfm_host->priv; + int ret; + + ret = clk_enable(priv->clk); + if (ret) { + dev_dbg(dev, "Resume: Error enabling clock\n"); + return ret; + } + + return sdhci_resume_host(host); +} + +static SIMPLE_DEV_PM_OPS(sdhci_sirf_pm_ops, sdhci_sirf_suspend, sdhci_sirf_resume); +#endif + +static const struct of_device_id sdhci_sirf_of_match[] = { + { .compatible = "sirf,prima2-sdhc" }, + { } +}; +MODULE_DEVICE_TABLE(of, sdhci_sirf_of_match); + +static struct platform_driver sdhci_sirf_driver = { + .driver = { + .name = "sdhci-sirf", + .owner = THIS_MODULE, + .of_match_table = sdhci_sirf_of_match, +#ifdef CONFIG_PM_SLEEP + .pm = &sdhci_sirf_pm_ops, +#endif + }, + .probe = sdhci_sirf_probe, + .remove = sdhci_sirf_remove, +}; + +module_platform_driver(sdhci_sirf_driver); + +MODULE_DESCRIPTION("SDHCI driver for SiRFprimaII/SiRFmarco"); +MODULE_AUTHOR("Barry Song <21cnbao@gmail.com>"); +MODULE_LICENSE("GPL v2"); -- cgit v0.10.2 From 5e81441e24336f8fa475ab3eae12c2195e0d9064 Mon Sep 17 00:00:00 2001 From: Thomas Petazzoni Date: Fri, 22 Mar 2013 14:30:23 +0100 Subject: mmc: mvsdio: fix non-DT probing of GPIOs Ralph Droms reported that 3.9-rc was breaking the SDIO interface on his Sheevaplug platform, and that the recent changes to the mvsdio driver are responsible for this breakage. Precisely, the regression has been introduced by 07728b77c03d (mmc: mvsdio: use slot-gpio for card detect gpio). After investigation, is turns out that the Sheevaplug does not have any "card detect" GPIO, and the Sheevaplug has not been converted to the Device Tree. Therefore, the Sheevaplug board code does not define a value for the .gpio_card_detect field of the mvsdio_platform_data structure, which means that its value is 0. Unfortunately, gpio_is_valid() considers 0 as a valid GPIO, and therefore calls mmc_gpio_request_cd(), which fails and makes the entire probing of the driver fail. In fact, in the previous mvsdio code, before the Device Tree binding was introduced, 0 was not considered as a valid GPIO. Therefore, this fix revert back to this behavior in the non-DT case, by setting the gpio_card_detect and gpio_write_protect local variables to -EINVAL when the corresponding fields of the mvsdio_platform_data structure are set to zero (i.e, left undefined). Of course, it prevents to use GPIO 0 as a card detect or write protect GPIO, but it was a defiency of the previous non-DT code, and the fix moving forward is to convert platforms to the Device Tree. The problem has been reproduced successfully on the Kirkwood-based Marvell DB-88F6281-BP Development Board (that doesn't use the Device Tree) and the fix has proven to work properly, after of course removing the gpio_card_detect field of the mvsdio_platform_data instance for this board. Reported-by: Ralph Droms Tested-by: Ralph Droms Signed-off-by: Thomas Petazzoni Signed-off-by: Chris Ball diff --git a/drivers/mmc/host/mvsdio.c b/drivers/mmc/host/mvsdio.c index 2b7d5b7..ae08b32 100644 --- a/drivers/mmc/host/mvsdio.c +++ b/drivers/mmc/host/mvsdio.c @@ -741,8 +741,8 @@ static int __init mvsd_probe(struct platform_device *pdev) goto out; } host->base_clock = mvsd_data->clock / 2; - gpio_card_detect = mvsd_data->gpio_card_detect; - gpio_write_protect = mvsd_data->gpio_write_protect; + gpio_card_detect = mvsd_data->gpio_card_detect ? : -EINVAL; + gpio_write_protect = mvsd_data->gpio_write_protect ? : -EINVAL; } mmc->ops = &mvsd_ops; -- cgit v0.10.2 From e573d6985e315fd307862c2142dfd41731e9f209 Mon Sep 17 00:00:00 2001 From: Thomas Petazzoni Date: Fri, 22 Mar 2013 14:37:21 +0100 Subject: mmc: mvsdio: use dev_*() API instead of pr_*() API The mvsdio driver was already using some dev_*() functions to print some messages, but still using pr_*() functions for some others. This patch converts all messages to use dev_*() functions. Many of the pr_*() function calls were printing the output of mmc_hostname() to preprend the message with an identifier for the device. Since the dev_*() functions do that automatically, this patch also gets rid of those string prefixes. Signed-off-by: Thomas Petazzoni Signed-off-by: Chris Ball diff --git a/drivers/mmc/host/mvsdio.c b/drivers/mmc/host/mvsdio.c index ae08b32..8960fc8 100644 --- a/drivers/mmc/host/mvsdio.c +++ b/drivers/mmc/host/mvsdio.c @@ -119,10 +119,8 @@ static int mvsd_setup_data(struct mvsd_host *host, struct mmc_data *data) host->pio_size = data->blocks * data->blksz; host->pio_ptr = sg_virt(data->sg); if (!nodma) - pr_debug("%s: fallback to PIO for data " - "at 0x%p size %d\n", - mmc_hostname(host->mmc), - host->pio_ptr, host->pio_size); + dev_dbg(host->dev, "fallback to PIO for data at 0x%p size %d\n", + host->pio_ptr, host->pio_size); return 1; } else { dma_addr_t phys_addr; @@ -473,8 +471,8 @@ static irqreturn_t mvsd_irq(int irq, void *dev) if (mrq->data) err_status = mvsd_finish_data(host, mrq->data, err_status); if (err_status) { - pr_err("%s: unhandled error status %#04x\n", - mmc_hostname(host->mmc), err_status); + dev_err(host->dev, "unhandled error status %#04x\n", + err_status); cmd->error = -ENOMSG; } @@ -491,9 +489,8 @@ static irqreturn_t mvsd_irq(int irq, void *dev) if (irq_handled) return IRQ_HANDLED; - pr_err("%s: unhandled interrupt status=0x%04x en=0x%04x " - "pio=%d\n", mmc_hostname(host->mmc), intr_status, - host->intr_en, host->pio_size); + dev_err(host->dev, "unhandled interrupt status=0x%04x en=0x%04x pio=%d\n", + intr_status, host->intr_en, host->pio_size); return IRQ_NONE; } @@ -507,13 +504,11 @@ static void mvsd_timeout_timer(unsigned long data) spin_lock_irqsave(&host->lock, flags); mrq = host->mrq; if (mrq) { - pr_err("%s: Timeout waiting for hardware interrupt.\n", - mmc_hostname(host->mmc)); - pr_err("%s: hw_state=0x%04x, intr_status=0x%04x " - "intr_en=0x%04x\n", mmc_hostname(host->mmc), - mvsd_read(MVSD_HW_STATE), - mvsd_read(MVSD_NOR_INTR_STATUS), - mvsd_read(MVSD_NOR_INTR_EN)); + dev_err(host->dev, "Timeout waiting for hardware interrupt.\n"); + dev_err(host->dev, "hw_state=0x%04x, intr_status=0x%04x intr_en=0x%04x\n", + mvsd_read(MVSD_HW_STATE), + mvsd_read(MVSD_NOR_INTR_STATUS), + mvsd_read(MVSD_NOR_INTR_EN)); host->mrq = NULL; @@ -778,7 +773,7 @@ static int __init mvsd_probe(struct platform_device *pdev) ret = devm_request_irq(&pdev->dev, irq, mvsd_irq, 0, DRIVER_NAME, host); if (ret) { - pr_err("%s: cannot assign irq %d\n", DRIVER_NAME, irq); + dev_err(&pdev->dev, "cannot assign irq %d\n", irq); goto out; } @@ -797,13 +792,11 @@ static int __init mvsd_probe(struct platform_device *pdev) if (ret) goto out; - pr_notice("%s: %s driver initialized, ", - mmc_hostname(mmc), DRIVER_NAME); if (!(mmc->caps & MMC_CAP_NEEDS_POLL)) - printk("using GPIO %d for card detection\n", - gpio_card_detect); + dev_notice(&pdev->dev, "using GPIO %d for card detection\n", + gpio_card_detect); else - printk("lacking card detect (fall back to polling)\n"); + dev_notice(&pdev->dev, "lacking card detect (fall back to polling)\n"); return 0; out: -- cgit v0.10.2 From c09fbd7451b797213b3df8bf077776b9ec33f954 Mon Sep 17 00:00:00 2001 From: Seungwon Jeon Date: Mon, 25 Mar 2013 16:28:22 +0900 Subject: mmc: dw_mmc: fix fifo access for 64-bit mci_writew causes a failure of fifo access for 64-bit. mci_writeq is correct. Signed-off-by: Seungwon Jeon Acked-by: Jaehoon Chung Signed-off-by: Chris Ball diff --git a/drivers/mmc/host/dw_mmc.c b/drivers/mmc/host/dw_mmc.c index a443820..753c55c 100644 --- a/drivers/mmc/host/dw_mmc.c +++ b/drivers/mmc/host/dw_mmc.c @@ -1373,8 +1373,9 @@ static void dw_mci_push_data64(struct dw_mci *host, void *buf, int cnt) int len = dw_mci_push_part_bytes(host, buf, cnt); buf += len; cnt -= len; + if (host->part_buf_count == 8) { - mci_writew(host, DATA(host->data_offset), + mci_writeq(host, DATA(host->data_offset), host->part_buf); host->part_buf_count = 0; } -- cgit v0.10.2 From 73b7afb9764b77fca99d515b8d9cbeeaae5fe55c Mon Sep 17 00:00:00 2001 From: Kevin Liu Date: Mon, 25 Mar 2013 17:42:56 +0800 Subject: mmc: sdhci-pxav3: transfer sdhci_pltfm_data as args to sdhci_pltfm_init sdhci_pltfm_init can set host->ops and host->quirks if sdhci_pltfm_data is transfered as arguments. Then no need to set them manually in sdhci_pxav3_probe. Signed-off-by: Kevin Liu Acked-by: Haojian Zhuang Signed-off-by: Chris Ball diff --git a/drivers/mmc/host/sdhci-pxav3.c b/drivers/mmc/host/sdhci-pxav3.c index 5663a6e..14437fc 100644 --- a/drivers/mmc/host/sdhci-pxav3.c +++ b/drivers/mmc/host/sdhci-pxav3.c @@ -174,6 +174,14 @@ static const struct sdhci_ops pxav3_sdhci_ops = { .get_max_clock = sdhci_pltfm_clk_get_max_clock, }; +static struct sdhci_pltfm_data sdhci_pxav3_pdata = { + .quirks = SDHCI_QUIRK_BROKEN_TIMEOUT_VAL + | SDHCI_QUIRK_NO_ENDATTR_IN_NOPDESC + | SDHCI_QUIRK_32BIT_ADMA_SIZE + | SDHCI_QUIRK_CAP_CLOCK_BASE_BROKEN, + .ops = &pxav3_sdhci_ops, +}; + #ifdef CONFIG_OF static const struct of_device_id sdhci_pxav3_of_match[] = { { @@ -235,7 +243,7 @@ static int sdhci_pxav3_probe(struct platform_device *pdev) if (!pxa) return -ENOMEM; - host = sdhci_pltfm_init(pdev, NULL); + host = sdhci_pltfm_init(pdev, &sdhci_pxav3_pdata); if (IS_ERR(host)) { kfree(pxa); return PTR_ERR(host); @@ -252,11 +260,6 @@ static int sdhci_pxav3_probe(struct platform_device *pdev) pltfm_host->clk = clk; clk_prepare_enable(clk); - host->quirks = SDHCI_QUIRK_BROKEN_TIMEOUT_VAL - | SDHCI_QUIRK_NO_ENDATTR_IN_NOPDESC - | SDHCI_QUIRK_32BIT_ADMA_SIZE - | SDHCI_QUIRK_CAP_CLOCK_BASE_BROKEN; - /* enable 1/8V DDR capable */ host->mmc->caps |= MMC_CAP_1_8V_DDR; @@ -296,8 +299,6 @@ static int sdhci_pxav3_probe(struct platform_device *pdev) } } - host->ops = &pxav3_sdhci_ops; - sdhci_get_of_property(pdev); pm_runtime_set_active(&pdev->dev); -- cgit v0.10.2 From c844a46f135e493ffda0bd770e16f6c3dd6c7eb7 Mon Sep 17 00:00:00 2001 From: Kevin Liu Date: Mon, 25 Mar 2013 17:42:57 +0800 Subject: mmc: sdhci-pxav3: remove cd-broken quirk for permanently present card Flag PXA_FLAG_CARD_PERMANENT is set in sdhci_pxa_platdata flags to indicate that the card is always wired to host, like on-chip emmc, which is permanently present and don't need detection. So only MMC_CAP_NONREMOVABLE should be set for this case. But current code also sets SDHCI_QUIRK_BROKEN_CARD_DETECTION, which doesn't make sense. Signed-off-by: Kevin Liu Acked-by: Haojian Zhuang Signed-off-by: Chris Ball diff --git a/drivers/mmc/host/sdhci-pxav3.c b/drivers/mmc/host/sdhci-pxav3.c index 14437fc..56d6a2e 100644 --- a/drivers/mmc/host/sdhci-pxav3.c +++ b/drivers/mmc/host/sdhci-pxav3.c @@ -268,11 +268,9 @@ static int sdhci_pxav3_probe(struct platform_device *pdev) pdata = pxav3_get_mmc_pdata(dev); if (pdata) { - if (pdata->flags & PXA_FLAG_CARD_PERMANENT) { - /* on-chip device */ - host->quirks |= SDHCI_QUIRK_BROKEN_CARD_DETECTION; + /* on-chip device */ + if (pdata->flags & PXA_FLAG_CARD_PERMANENT) host->mmc->caps |= MMC_CAP_NONREMOVABLE; - } /* If slot design supports 8 bit data, indicate this to MMC. */ if (pdata->flags & PXA_FLAG_SD_8_BIT_CAPABLE_SLOT) -- cgit v0.10.2 From 943647f6fe3aa7217d13cacac830c88455a88326 Mon Sep 17 00:00:00 2001 From: Kevin Liu Date: Mon, 25 Mar 2013 17:42:58 +0800 Subject: mmc: sdhci-pxav3: enhance device tree parser code 1. seperate device tree parsing from platform data handling which can make further work easy when platform data can be removed. 2. add calling mmc_of_parse which can parse more of property and pxav3_get_mmc_pdata can be shrinked a lot. Signed-off-by: Kevin Liu Acked-by: Haojian Zhuang Signed-off-by: Chris Ball diff --git a/drivers/mmc/host/sdhci-pxav3.c b/drivers/mmc/host/sdhci-pxav3.c index 56d6a2e..fb0d23c 100644 --- a/drivers/mmc/host/sdhci-pxav3.c +++ b/drivers/mmc/host/sdhci-pxav3.c @@ -195,29 +195,16 @@ static struct sdhci_pxa_platdata *pxav3_get_mmc_pdata(struct device *dev) { struct sdhci_pxa_platdata *pdata; struct device_node *np = dev->of_node; - u32 bus_width; u32 clk_delay_cycles; - enum of_gpio_flags gpio_flags; pdata = devm_kzalloc(dev, sizeof(*pdata), GFP_KERNEL); if (!pdata) return NULL; - if (of_find_property(np, "non-removable", NULL)) - pdata->flags |= PXA_FLAG_CARD_PERMANENT; - - of_property_read_u32(np, "bus-width", &bus_width); - if (bus_width == 8) - pdata->flags |= PXA_FLAG_SD_8_BIT_CAPABLE_SLOT; - of_property_read_u32(np, "mrvl,clk-delay-cycles", &clk_delay_cycles); if (clk_delay_cycles > 0) pdata->clk_delay_cycles = clk_delay_cycles; - pdata->ext_cd_gpio = of_get_named_gpio_flags(np, "cd-gpios", 0, &gpio_flags); - if (gpio_flags != OF_GPIO_ACTIVE_LOW) - pdata->host_caps2 |= MMC_CAP2_CD_ACTIVE_HIGH; - return pdata; } #else @@ -264,10 +251,11 @@ static int sdhci_pxav3_probe(struct platform_device *pdev) host->mmc->caps |= MMC_CAP_1_8V_DDR; match = of_match_device(of_match_ptr(sdhci_pxav3_of_match), &pdev->dev); - if (match) + if (match) { + mmc_of_parse(host->mmc); + sdhci_get_of_property(pdev); pdata = pxav3_get_mmc_pdata(dev); - - if (pdata) { + } else if (pdata) { /* on-chip device */ if (pdata->flags & PXA_FLAG_CARD_PERMANENT) host->mmc->caps |= MMC_CAP_NONREMOVABLE; @@ -297,8 +285,6 @@ static int sdhci_pxav3_probe(struct platform_device *pdev) } } - sdhci_get_of_property(pdev); - pm_runtime_set_active(&pdev->dev); pm_runtime_enable(&pdev->dev); pm_runtime_set_autosuspend_delay(&pdev->dev, PXAV3_RPM_DELAY_MS); @@ -316,7 +302,7 @@ static int sdhci_pxav3_probe(struct platform_device *pdev) platform_set_drvdata(pdev, host); - if (pdata->pm_caps & MMC_PM_KEEP_POWER) { + if (host->mmc->pm_caps & MMC_PM_KEEP_POWER) { device_init_wakeup(&pdev->dev, 1); host->mmc->pm_flags |= MMC_PM_WAKE_SDIO_IRQ; } else { -- cgit v0.10.2 From e065162ae476f55376ba06f9e80f41b28f769938 Mon Sep 17 00:00:00 2001 From: Kevin Liu Date: Mon, 25 Mar 2013 17:42:59 +0800 Subject: mmc: sdhci-pxav3: controller should use SDCLK for timeout calculation sdhci-pxav3 host controller used SDCLK for data timeout. Signed-off-by: Kevin Liu Acked-by: Haojian Zhuang Signed-off-by: Chris Ball diff --git a/drivers/mmc/host/sdhci-pxav3.c b/drivers/mmc/host/sdhci-pxav3.c index fb0d23c..1ae358e 100644 --- a/drivers/mmc/host/sdhci-pxav3.c +++ b/drivers/mmc/host/sdhci-pxav3.c @@ -175,7 +175,7 @@ static const struct sdhci_ops pxav3_sdhci_ops = { }; static struct sdhci_pltfm_data sdhci_pxav3_pdata = { - .quirks = SDHCI_QUIRK_BROKEN_TIMEOUT_VAL + .quirks = SDHCI_QUIRK_DATA_TIMEOUT_USES_SDCLK | SDHCI_QUIRK_NO_ENDATTR_IN_NOPDESC | SDHCI_QUIRK_32BIT_ADMA_SIZE | SDHCI_QUIRK_CAP_CLOCK_BASE_BROKEN, -- cgit v0.10.2 From 4366dcc52a43746066e43c3eb8b3c5e0cca2e6f6 Mon Sep 17 00:00:00 2001 From: Jaehoon Chung Date: Tue, 26 Mar 2013 21:36:14 +0900 Subject: mmc: dw_mmc: control the power-enable register When card is power-on/off, need to control the power-enable register. Signed-off-by: Jaehoon Chung Signed-off-by: Kyungmin Park Reviewed-by: James Hogan Acked-by: Seungwon Jeon Signed-off-by: Chris Ball diff --git a/drivers/mmc/host/dw_mmc.c b/drivers/mmc/host/dw_mmc.c index 753c55c..c6caedc 100644 --- a/drivers/mmc/host/dw_mmc.c +++ b/drivers/mmc/host/dw_mmc.c @@ -821,11 +821,17 @@ static void dw_mci_set_ios(struct mmc_host *mmc, struct mmc_ios *ios) /* Power up slot */ if (slot->host->pdata->setpower) slot->host->pdata->setpower(slot->id, mmc->ocr_avail); + regs = mci_readl(slot->host, PWREN); + regs |= (1 << slot->id); + mci_writel(slot->host, PWREN, regs); break; case MMC_POWER_OFF: /* Power down slot */ if (slot->host->pdata->setpower) slot->host->pdata->setpower(slot->id, 0); + regs = mci_readl(slot->host, PWREN); + regs &= ~(1 << slot->id); + mci_writel(slot->host, PWREN, regs); break; default: break; -- cgit v0.10.2 From b0dd099ceb04146b68aa7109bcd426dc74cb64ac Mon Sep 17 00:00:00 2001 From: Jingoo Han Date: Fri, 29 Mar 2013 16:08:00 +0900 Subject: mmc: sdhci-spear: add CONFIG_PM_SLEEP to suspend/resume functions Add CONFIG_PM_SLEEP to suspend/resume functions to fix the following build warning when CONFIG_PM_SLEEP is not selected. This is because sleep PM callbacks defined by SIMPLE_DEV_PM_OPS are only used when the CONFIG_PM_SLEEP is enabled. drivers/mmc/host/sdhci-spear.c:295:12: warning: 'sdhci_suspend' defined but not used [-Wunused-function] drivers/mmc/host/sdhci-spear.c:308:12: warning: 'sdhci_resume' defined but not used [-Wunused-function] Signed-off-by: Jingoo Han Acked-by: Viresh Kumar Signed-off-by: Chris Ball diff --git a/drivers/mmc/host/sdhci-spear.c b/drivers/mmc/host/sdhci-spear.c index 8d28334..7ae5b3a 100644 --- a/drivers/mmc/host/sdhci-spear.c +++ b/drivers/mmc/host/sdhci-spear.c @@ -291,7 +291,7 @@ static int sdhci_remove(struct platform_device *pdev) return 0; } -#ifdef CONFIG_PM +#ifdef CONFIG_PM_SLEEP static int sdhci_suspend(struct device *dev) { struct sdhci_host *host = dev_get_drvdata(dev); -- cgit v0.10.2 From f2f942ce4a800b2179a5a5023922517b875a6787 Mon Sep 17 00:00:00 2001 From: Sachin Kamat Date: Thu, 4 Apr 2013 11:25:10 +0530 Subject: mmc: dw_mmc: Check return value of regulator_enable MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit regulator_enable() is declared with __must_check attribute. Hence check the return value to ensure that the regulator is enabled. Fixes the following warning: drivers/mmc/host/dw_mmc.c:2461:19: warning: ignoring return value of ‘regulator_enable’, declared with attribute warn_unused_result [-Wunused-result] drivers/mmc/host/dw_mmc.c: In function ‘dw_mci_init_slot’: drivers/mmc/host/dw_mmc.c:1994:19: warning: ignoring return value of ‘regulator_enable’, declared with attribute warn_unused_result [-Wunused-result] Signed-off-by: Sachin Kamat Acked-by: Jaehoon Chung Acked-by: Seungwon Jeon Signed-off-by: Chris Ball diff --git a/drivers/mmc/host/dw_mmc.c b/drivers/mmc/host/dw_mmc.c index c6caedc..a63766a 100644 --- a/drivers/mmc/host/dw_mmc.c +++ b/drivers/mmc/host/dw_mmc.c @@ -1997,8 +1997,14 @@ static int dw_mci_init_slot(struct dw_mci *host, unsigned int id) if (IS_ERR(host->vmmc)) { pr_info("%s: no vmmc regulator found\n", mmc_hostname(mmc)); host->vmmc = NULL; - } else - regulator_enable(host->vmmc); + } else { + ret = regulator_enable(host->vmmc); + if (ret) { + dev_err(host->dev, + "failed to enable regulator: %d\n", ret); + goto err_setup_bus; + } + } if (dw_mci_get_cd(mmc)) set_bit(DW_MMC_CARD_PRESENT, &slot->flags); @@ -2464,8 +2470,14 @@ int dw_mci_resume(struct dw_mci *host) { int i, ret; - if (host->vmmc) - regulator_enable(host->vmmc); + if (host->vmmc) { + ret = regulator_enable(host->vmmc); + if (ret) { + dev_err(host->dev, + "failed to enable regulator: %d\n", ret); + return ret; + } + } if (!mci_wait_reset(host->dev, host)) { ret = -ENODEV; -- cgit v0.10.2 From 8e1c4e4d732666ace4c5e0cd122e7217ded910aa Mon Sep 17 00:00:00 2001 From: Sachin Kamat Date: Thu, 4 Apr 2013 11:25:11 +0530 Subject: mmc: dw_mmc: Use pr_info instead of printk pr_info(... is preferred to printk(KERN_INFO ... Signed-off-by: Sachin Kamat Acked-by: Jaehoon Chung Acked-by: Seungwon Jeon Signed-off-by: Chris Ball diff --git a/drivers/mmc/host/dw_mmc.c b/drivers/mmc/host/dw_mmc.c index a63766a..45d9216 100644 --- a/drivers/mmc/host/dw_mmc.c +++ b/drivers/mmc/host/dw_mmc.c @@ -2516,7 +2516,7 @@ EXPORT_SYMBOL(dw_mci_resume); static int __init dw_mci_init(void) { - printk(KERN_INFO "Synopsys Designware Multimedia Card Interface Driver"); + pr_info("Synopsys Designware Multimedia Card Interface Driver\n"); return 0; } -- cgit v0.10.2 From 836dc2fe89c968c10cada87e0dfae6626f8f9da3 Mon Sep 17 00:00:00 2001 From: Philip Rakity Date: Thu, 4 Apr 2013 20:18:11 +0100 Subject: mmc: core: Fix bit width test failing on old eMMC cards PARTITION_SUPPORT needs to be set before doing the compare on version number so the bit width test does not get invalid data. Before this patch, a Sandisk iNAND eMMC card would detect 1-bit width although the hardware supports 4-bit. Only affects old emmc devices - pre 4.4 devices. Reported-by: Elad Yi Signed-off-by: Philip Rakity Cc: stable Signed-off-by: Chris Ball diff --git a/drivers/mmc/core/mmc.c b/drivers/mmc/core/mmc.c index d584f7c..0cbd1ef 100644 --- a/drivers/mmc/core/mmc.c +++ b/drivers/mmc/core/mmc.c @@ -369,13 +369,13 @@ static int mmc_read_ext_csd(struct mmc_card *card, u8 *ext_csd) ext_csd[EXT_CSD_SEC_FEATURE_SUPPORT]; card->ext_csd.raw_trim_mult = ext_csd[EXT_CSD_TRIM_MULT]; + card->ext_csd.raw_partition_support = ext_csd[EXT_CSD_PARTITION_SUPPORT]; if (card->ext_csd.rev >= 4) { /* * Enhanced area feature support -- check whether the eMMC * card has the Enhanced area enabled. If so, export enhanced * area offset and size to user by adding sysfs interface. */ - card->ext_csd.raw_partition_support = ext_csd[EXT_CSD_PARTITION_SUPPORT]; if ((ext_csd[EXT_CSD_PARTITION_SUPPORT] & 0x2) && (ext_csd[EXT_CSD_PARTITION_ATTRIBUTE] & 0x1)) { hc_erase_grp_sz = -- cgit v0.10.2 From bdbc5d0c60f3e9de3eeccf1c1a18bdc11dca62cc Mon Sep 17 00:00:00 2001 From: Terry Barnaby Date: Mon, 8 Apr 2013 12:05:47 -0400 Subject: mmc: atmel-mci: pio hang on block errors The driver is doing, by default, multi-block reads. When a block error occurs, card/block.c instigates a single block read: "mmcblk0: retrying using single block read". It leaves the sg chain intact and just changes the length attribute for the first sg entry and the overall sg_len parameter. When atmci_read_data_pio is called to read the single block of data it ignores the sg_len and expects to read more than 512 bytes as it sees there are multiple items in the sg list. No more data comes as the controller has only been commanded to get one block. Signed-off-by: Terry Barnaby Acked-by: Ludovic Desroches Cc: stable # 3.2+ Signed-off-by: Chris Ball diff --git a/drivers/mmc/host/atmel-mci.c b/drivers/mmc/host/atmel-mci.c index 10f8b73..e75774f 100644 --- a/drivers/mmc/host/atmel-mci.c +++ b/drivers/mmc/host/atmel-mci.c @@ -178,6 +178,7 @@ struct atmel_mci { void __iomem *regs; struct scatterlist *sg; + unsigned int sg_len; unsigned int pio_offset; unsigned int *buffer; unsigned int buf_size; @@ -892,6 +893,7 @@ static u32 atmci_prepare_data(struct atmel_mci *host, struct mmc_data *data) data->error = -EINPROGRESS; host->sg = data->sg; + host->sg_len = data->sg_len; host->data = data; host->data_chan = NULL; @@ -1826,7 +1828,8 @@ static void atmci_read_data_pio(struct atmel_mci *host) if (offset == sg->length) { flush_dcache_page(sg_page(sg)); host->sg = sg = sg_next(sg); - if (!sg) + host->sg_len--; + if (!sg || !host->sg_len) goto done; offset = 0; @@ -1839,7 +1842,8 @@ static void atmci_read_data_pio(struct atmel_mci *host) flush_dcache_page(sg_page(sg)); host->sg = sg = sg_next(sg); - if (!sg) + host->sg_len--; + if (!sg || !host->sg_len) goto done; offset = 4 - remaining; @@ -1890,7 +1894,8 @@ static void atmci_write_data_pio(struct atmel_mci *host) nbytes += 4; if (offset == sg->length) { host->sg = sg = sg_next(sg); - if (!sg) + host->sg_len--; + if (!sg || !host->sg_len) goto done; offset = 0; @@ -1904,7 +1909,8 @@ static void atmci_write_data_pio(struct atmel_mci *host) nbytes += remaining; host->sg = sg = sg_next(sg); - if (!sg) { + host->sg_len--; + if (!sg || !host->sg_len) { atmci_writel(host, ATMCI_TDR, value); goto done; } -- cgit v0.10.2 From f9a94e0a3f18ae4c0245d4a16d0ee20e93fd7bad Mon Sep 17 00:00:00 2001 From: Adrian Hunter Date: Thu, 4 Apr 2013 16:41:05 +0300 Subject: Revert "mmc: core: wait while adding MMC host to ensure root mounts successfully" This reverts commit 3500ed90b26a9935b943b5e2e4cd3226600d6b58. The reverted patch caused a significant performance regression when booting with the root file system on eMMC. Before the patch: [ 1.625623] VFS: Mounted root (ext4 filesystem) readonly on device 179:2. After the patch: [ 1.935851] VFS: Mounted root (ext4 filesystem) readonly on device 179:2. That was an addition of 310 ms which is a 19% performance degradation. Signed-off-by: Adrian Hunter Signed-off-by: Chris Ball diff --git a/drivers/mmc/core/core.c b/drivers/mmc/core/core.c index ad7decc..3bf1c46 100644 --- a/drivers/mmc/core/core.c +++ b/drivers/mmc/core/core.c @@ -2418,7 +2418,6 @@ void mmc_start_host(struct mmc_host *host) host->rescan_disable = 0; mmc_power_up(host); mmc_detect_change(host, 0); - mmc_flush_scheduled_work(); } void mmc_stop_host(struct mmc_host *host) -- cgit v0.10.2 From 0d3e3350d5871c53464be4c92d57198744247005 Mon Sep 17 00:00:00 2001 From: Adrian Hunter Date: Thu, 4 Apr 2013 16:41:06 +0300 Subject: mmc: core: fix performance regression initializing MMC host controllers Commit fa5501890d8974301042e0202d342a6cbe8609f4 introduced a performance regression by adding mmc_power_up() to mmc_start_host(). mmc_power_up() is not necessary to host controller initialization, it is part of card initialization and is performed anyway asynchronously. This patch allows a driver to leave the power up in asynchronous code (as it was before). On my current target platform this reduces driver initialization from: [ 1.313220] initcall sdhci_acpi_driver_init+0x0/0x12 returned 0 after 102008 usecs to this: [ 1.217209] initcall sdhci_acpi_driver_init+0x0/0x12 returned 0 after 8331 usecs Signed-off-by: Adrian Hunter Acked-by: Ulf Hansson Signed-off-by: Chris Ball diff --git a/drivers/mmc/core/core.c b/drivers/mmc/core/core.c index 3bf1c46..c1893c9 100644 --- a/drivers/mmc/core/core.c +++ b/drivers/mmc/core/core.c @@ -2416,7 +2416,8 @@ void mmc_start_host(struct mmc_host *host) { host->f_init = max(freqs[0], host->f_min); host->rescan_disable = 0; - mmc_power_up(host); + if (!(host->caps2 & MMC_CAP2_NO_PRESCAN_POWERUP)) + mmc_power_up(host); mmc_detect_change(host, 0); } diff --git a/drivers/mmc/host/sdhci-acpi.c b/drivers/mmc/host/sdhci-acpi.c index 2592ddd..7bcf74b 100644 --- a/drivers/mmc/host/sdhci-acpi.c +++ b/drivers/mmc/host/sdhci-acpi.c @@ -195,6 +195,8 @@ static int sdhci_acpi_probe(struct platform_device *pdev) host->mmc->pm_caps |= c->slot->pm_caps; } + host->mmc->caps2 |= MMC_CAP2_NO_PRESCAN_POWERUP; + err = sdhci_add_host(host); if (err) goto err_free; diff --git a/include/linux/mmc/host.h b/include/linux/mmc/host.h index 17d7148..8873e83 100644 --- a/include/linux/mmc/host.h +++ b/include/linux/mmc/host.h @@ -280,6 +280,7 @@ struct mmc_host { #define MMC_CAP2_PACKED_WR (1 << 13) /* Allow packed write */ #define MMC_CAP2_PACKED_CMD (MMC_CAP2_PACKED_RD | \ MMC_CAP2_PACKED_WR) +#define MMC_CAP2_NO_PRESCAN_POWERUP (1 << 14) /* Don't power up before scan */ mmc_pm_flag_t pm_caps; /* supported pm features */ -- cgit v0.10.2 From abd4190f0c820b7f118450b52bb95c0be3a441bd Mon Sep 17 00:00:00 2001 From: Alexander Shiyan Date: Sat, 6 Apr 2013 10:13:31 +0400 Subject: mmc: mxcmmc: Fix bug when card is present during boot This patch fixes bug when card is present during boot. Bug was introduced due commit "mmc: mxcmmc: fix bug that may block a data transfer forever". When a card is present "mxcmci_setup_data" function is executed, but the timer is not initialized. ... i.MX SDHC driver mmc0: SD Status: Invalid Allocation Unit size. mmc0: new SD card at address b368 mmcblk0: mmc0:b368 SDC 1.91 GiB ------------[ cut here ]------------ kernel BUG at kernel/timer.c:729! Internal error: Oops - BUG: 0 [#1] PREEMPT ARM CPU: 0 Not tainted (3.9.0-rc5-next-20130404 #2) PC is at mod_timer+0x168/0x198 LR is at mxcmci_request+0x21c/0x328 ... Signed-off-by: Alexander Shiyan Acked-by: Sascha Hauer Signed-off-by: Chris Ball diff --git a/drivers/mmc/host/mxcmmc.c b/drivers/mmc/host/mxcmmc.c index a72936e..28e527e 100644 --- a/drivers/mmc/host/mxcmmc.c +++ b/drivers/mmc/host/mxcmmc.c @@ -1052,12 +1052,12 @@ static int mxcmci_probe(struct platform_device *pdev) goto out_free_irq; } - mmc_add_host(mmc); - init_timer(&host->watchdog); host->watchdog.function = &mxcmci_watchdog; host->watchdog.data = (unsigned long)mmc; + mmc_add_host(mmc); + return 0; out_free_irq: -- cgit v0.10.2 From 3bffb800b91bb128b61d83deb01ce63c455d108f Mon Sep 17 00:00:00 2001 From: Li Fei Date: Mon, 8 Apr 2013 09:36:39 +0800 Subject: mmc: core: call pm_runtime_put_noidle in pm_runtime_get_sync failed case Even in failed case of pm_runtime_get_sync, the usage_count is incremented. In order to keep the usage_count with correct value and runtime power management to behave correctly, call pm_runtime_put_noidle in such case. Signed-off-by: Liu Chuansheng Signed-off-by: Li Fei Acked-by: Ohad Ben-Cohen Signed-off-by: Chris Ball diff --git a/drivers/mmc/core/sdio.c b/drivers/mmc/core/sdio.c index aa0719a..6889a82 100644 --- a/drivers/mmc/core/sdio.c +++ b/drivers/mmc/core/sdio.c @@ -861,8 +861,10 @@ static void mmc_sdio_detect(struct mmc_host *host) /* Make sure card is powered before detecting it */ if (host->caps & MMC_CAP_POWER_OFF_CARD) { err = pm_runtime_get_sync(&host->card->dev); - if (err < 0) + if (err < 0) { + pm_runtime_put_noidle(&host->card->dev); goto out; + } } mmc_claim_host(host); diff --git a/drivers/mmc/core/sdio_bus.c b/drivers/mmc/core/sdio_bus.c index 8d6bb18..546c67c 100644 --- a/drivers/mmc/core/sdio_bus.c +++ b/drivers/mmc/core/sdio_bus.c @@ -138,7 +138,7 @@ static int sdio_bus_probe(struct device *dev) if (func->card->host->caps & MMC_CAP_POWER_OFF_CARD) { ret = pm_runtime_get_sync(dev); if (ret < 0) - goto out; + goto disable_runtimepm; } /* Set the default block size so the driver is sure it's something @@ -158,7 +158,6 @@ static int sdio_bus_probe(struct device *dev) disable_runtimepm: if (func->card->host->caps & MMC_CAP_POWER_OFF_CARD) pm_runtime_put_noidle(dev); -out: return ret; } -- cgit v0.10.2 From 4c0c9be05004d1eb674b7586216b3d93cc04531c Mon Sep 17 00:00:00 2001 From: Marc Kleine-Budde Date: Wed, 10 Apr 2013 11:13:43 +0200 Subject: mmc: mxs-mmc: add cd-inverted property The card-detect GPIO is inverted on some boards. Handle such case. Acked-by: Shawn Guo Signed-off-by: Marc Kleine-Budde Signed-off-by: Chris Ball diff --git a/drivers/mmc/host/mxs-mmc.c b/drivers/mmc/host/mxs-mmc.c index 4efe302..0cdf1f6 100644 --- a/drivers/mmc/host/mxs-mmc.c +++ b/drivers/mmc/host/mxs-mmc.c @@ -72,6 +72,7 @@ struct mxs_mmc_host { int sdio_irq_en; int wp_gpio; bool wp_inverted; + bool cd_inverted; }; static int mxs_mmc_get_ro(struct mmc_host *mmc) @@ -96,7 +97,7 @@ static int mxs_mmc_get_cd(struct mmc_host *mmc) struct mxs_ssp *ssp = &host->ssp; return !(readl(ssp->base + HW_SSP_STATUS(ssp)) & - BM_SSP_STATUS_CARD_DETECT); + BM_SSP_STATUS_CARD_DETECT)) ^ host->cd_inverted; } static void mxs_mmc_reset(struct mxs_mmc_host *host) @@ -691,6 +692,8 @@ static int mxs_mmc_probe(struct platform_device *pdev) if (flags & OF_GPIO_ACTIVE_LOW) host->wp_inverted = 1; + host->cd_inverted = of_property_read_bool(np, "cd-inverted"); + mmc->f_min = 400000; mmc->f_max = 288000000; mmc->ocr_avail = MMC_VDD_32_33 | MMC_VDD_33_34; -- cgit v0.10.2 From 5086e5f41fd107539911edf62f2d202753ed1980 Mon Sep 17 00:00:00 2001 From: Marc Kleine-Budde Date: Wed, 10 Apr 2013 11:13:44 +0200 Subject: mmc: mxs-mmc: add non-removable property Some boards have non removable cards like eMMC. Handle such case. Signed-off-by: Marc Kleine-Budde Acked-by: Shawn Guo Signed-off-by: Chris Ball diff --git a/drivers/mmc/host/mxs-mmc.c b/drivers/mmc/host/mxs-mmc.c index 0cdf1f6..c231881 100644 --- a/drivers/mmc/host/mxs-mmc.c +++ b/drivers/mmc/host/mxs-mmc.c @@ -73,6 +73,7 @@ struct mxs_mmc_host { int wp_gpio; bool wp_inverted; bool cd_inverted; + bool non_removable; }; static int mxs_mmc_get_ro(struct mmc_host *mmc) @@ -96,8 +97,9 @@ static int mxs_mmc_get_cd(struct mmc_host *mmc) struct mxs_mmc_host *host = mmc_priv(mmc); struct mxs_ssp *ssp = &host->ssp; - return !(readl(ssp->base + HW_SSP_STATUS(ssp)) & - BM_SSP_STATUS_CARD_DETECT)) ^ host->cd_inverted; + return host->non_removable || + !(readl(ssp->base + HW_SSP_STATUS(ssp)) & + BM_SSP_STATUS_CARD_DETECT) ^ host->cd_inverted; } static void mxs_mmc_reset(struct mxs_mmc_host *host) @@ -687,8 +689,10 @@ static int mxs_mmc_probe(struct platform_device *pdev) mmc->caps |= MMC_CAP_4_BIT_DATA; else if (bus_width == 8) mmc->caps |= MMC_CAP_4_BIT_DATA | MMC_CAP_8_BIT_DATA; + host->non_removable = of_property_read_bool(np, "non-removable"); + if (host->non_removable) + mmc->caps |= MMC_CAP_NONREMOVABLE; host->wp_gpio = of_get_named_gpio_flags(np, "wp-gpios", 0, &flags); - if (flags & OF_GPIO_ACTIVE_LOW) host->wp_inverted = 1; -- cgit v0.10.2 From 1d53196a0d604fcf636203fac21e944b6a9cf275 Mon Sep 17 00:00:00 2001 From: Hector Palacios Date: Wed, 10 Apr 2013 11:13:45 +0200 Subject: mmc: mxs-mmc: add broken-cd property According to bindings documentation for mmc, the property 'broken-cd' can be used to indicate card-detection is not available and polling must be used instead. This patch retrieves this property and sets a custom flag. On the get_cd() hook, it returns 1 if the flag is set, to always assume the card is present. Signed-off-by: Hector Palacios Signed-off-by: Marc Kleine-Budde Signed-off-by: Chris Ball diff --git a/drivers/mmc/host/mxs-mmc.c b/drivers/mmc/host/mxs-mmc.c index c231881..146a53b 100644 --- a/drivers/mmc/host/mxs-mmc.c +++ b/drivers/mmc/host/mxs-mmc.c @@ -73,6 +73,7 @@ struct mxs_mmc_host { int wp_gpio; bool wp_inverted; bool cd_inverted; + bool broken_cd; bool non_removable; }; @@ -97,7 +98,7 @@ static int mxs_mmc_get_cd(struct mmc_host *mmc) struct mxs_mmc_host *host = mmc_priv(mmc); struct mxs_ssp *ssp = &host->ssp; - return host->non_removable || + return host->non_removable || host->broken_cd || !(readl(ssp->base + HW_SSP_STATUS(ssp)) & BM_SSP_STATUS_CARD_DETECT) ^ host->cd_inverted; } @@ -689,6 +690,7 @@ static int mxs_mmc_probe(struct platform_device *pdev) mmc->caps |= MMC_CAP_4_BIT_DATA; else if (bus_width == 8) mmc->caps |= MMC_CAP_4_BIT_DATA | MMC_CAP_8_BIT_DATA; + host->broken_cd = of_property_read_bool(np, "broken-cd"); host->non_removable = of_property_read_bool(np, "non-removable"); if (host->non_removable) mmc->caps |= MMC_CAP_NONREMOVABLE; -- cgit v0.10.2 From 32d781a310785dcc86c41b6793b2bd4f41015d73 Mon Sep 17 00:00:00 2001 From: Thomas Abraham Date: Thu, 11 Apr 2013 17:54:07 +0530 Subject: mmc: dw_mmc: let device core setup the default pin configuration With device core now able to setup the default pin configuration, the pin configuration code based on the deprecated Samsung specific gpio bindings is removed. Signed-off-by: Thomas Abraham Acked-by: Linus Walleij Reviewed-by: Doug Anderson Tested-by: Doug Anderson Acked-by: Seungwon Jeon Signed-off-by: Chris Ball diff --git a/drivers/mmc/host/dw_mmc-exynos.c b/drivers/mmc/host/dw_mmc-exynos.c index c7f0976..f013e7e 100644 --- a/drivers/mmc/host/dw_mmc-exynos.c +++ b/drivers/mmc/host/dw_mmc-exynos.c @@ -152,43 +152,6 @@ static int dw_mci_exynos_parse_dt(struct dw_mci *host) return 0; } -static int dw_mci_exynos_setup_bus(struct dw_mci *host, - struct device_node *slot_np, u8 bus_width) -{ - int idx, gpio, ret; - - if (!slot_np) - return -EINVAL; - - /* cmd + clock + bus-width pins */ - for (idx = 0; idx < NUM_PINS(bus_width); idx++) { - gpio = of_get_gpio(slot_np, idx); - if (!gpio_is_valid(gpio)) { - dev_err(host->dev, "invalid gpio: %d\n", gpio); - return -EINVAL; - } - - ret = devm_gpio_request(host->dev, gpio, "dw-mci-bus"); - if (ret) { - dev_err(host->dev, "gpio [%d] request failed\n", gpio); - return -EBUSY; - } - } - - if (host->pdata->quirks & DW_MCI_QUIRK_BROKEN_CARD_DETECTION) - return 0; - - gpio = of_get_named_gpio(slot_np, "samsung,cd-pinmux-gpio", 0); - if (gpio_is_valid(gpio)) { - if (devm_gpio_request(host->dev, gpio, "dw-mci-cd")) - dev_err(host->dev, "gpio [%d] request failed\n", gpio); - } else { - dev_info(host->dev, "cd gpio not available"); - } - - return 0; -} - /* Common capabilities of Exynos4/Exynos5 SoC */ static unsigned long exynos_dwmmc_caps[4] = { MMC_CAP_UHS_DDR50 | MMC_CAP_1_8V_DDR | @@ -205,7 +168,6 @@ static const struct dw_mci_drv_data exynos_drv_data = { .prepare_command = dw_mci_exynos_prepare_command, .set_ios = dw_mci_exynos_set_ios, .parse_dt = dw_mci_exynos_parse_dt, - .setup_bus = dw_mci_exynos_setup_bus, }; static const struct of_device_id dw_mci_exynos_match[] = { diff --git a/drivers/mmc/host/dw_mmc.c b/drivers/mmc/host/dw_mmc.c index 45d9216..bc3a1bc 100644 --- a/drivers/mmc/host/dw_mmc.c +++ b/drivers/mmc/host/dw_mmc.c @@ -1952,14 +1952,6 @@ static int dw_mci_init_slot(struct dw_mci *host, unsigned int id) else bus_width = 1; - if (drv_data && drv_data->setup_bus) { - struct device_node *slot_np; - slot_np = dw_mci_of_find_slot_node(host->dev, slot->id); - ret = drv_data->setup_bus(host, slot_np, bus_width); - if (ret) - goto err_setup_bus; - } - switch (bus_width) { case 8: mmc->caps |= MMC_CAP_8_BIT_DATA; diff --git a/drivers/mmc/host/dw_mmc.h b/drivers/mmc/host/dw_mmc.h index 53b8fd9..0b74189 100644 --- a/drivers/mmc/host/dw_mmc.h +++ b/drivers/mmc/host/dw_mmc.h @@ -190,7 +190,6 @@ extern int dw_mci_resume(struct dw_mci *host); * @prepare_command: handle CMD register extensions. * @set_ios: handle bus specific extensions. * @parse_dt: parse implementation specific device tree properties. - * @setup_bus: initialize io-interface * * Provide controller implementation specific extensions. The usage of this * data structure is fully optional and usage of each member in this structure @@ -203,7 +202,5 @@ struct dw_mci_drv_data { void (*prepare_command)(struct dw_mci *host, u32 *cmdr); void (*set_ios)(struct dw_mci *host, struct mmc_ios *ios); int (*parse_dt)(struct dw_mci *host); - int (*setup_bus)(struct dw_mci *host, - struct device_node *slot_np, u8 bus_width); }; #endif /* _DW_MMC_H_ */ -- cgit v0.10.2 From 7ff747c45908abb4fb894b21a8752a3e48acf02b Mon Sep 17 00:00:00 2001 From: Markus Pargmann Date: Sun, 31 Mar 2013 20:07:38 +0200 Subject: mmc: mxcmmc: DT support Adding devicetree support for imx21-mmc and imx31-mmc. Based on generic gpio helper functions by Guennadi and generic DMA devicetree bindings. Signed-off-by: Markus Pargmann Signed-off-by: Anatolij Gustschin Acked-by: Arnd Bergmann Signed-off-by: Chris Ball diff --git a/Documentation/devicetree/bindings/mmc/fsl-imx-mmc.txt b/Documentation/devicetree/bindings/mmc/fsl-imx-mmc.txt new file mode 100644 index 0000000..db44235 --- /dev/null +++ b/Documentation/devicetree/bindings/mmc/fsl-imx-mmc.txt @@ -0,0 +1,24 @@ +* Freescale Secure Digital Host Controller for i.MX2/3 series + +This file documents differences to the properties defined in mmc.txt. + +Required properties: +- compatible : Should be "fsl,-mmc", chip can be imx21 or imx31 + +Optional properties: +- dmas: One DMA phandle with arguments as defined by the devicetree bindings + of the used DMA controller. +- dma-names: Has to be "rx-tx". + +Example: + +sdhci1: sdhci@10014000 { + compatible = "fsl,imx27-mmc", "fsl,imx21-mmc"; + reg = <0x10014000 0x1000>; + interrupts = <11>; + dmas = <&dma 7>; + dma-names = "rx-tx"; + bus-width = <4>; + cd-gpios = <&gpio3 29>; + status = "okay"; +}; diff --git a/drivers/mmc/host/mxcmmc.c b/drivers/mmc/host/mxcmmc.c index 28e527e..848ab2c 100644 --- a/drivers/mmc/host/mxcmmc.c +++ b/drivers/mmc/host/mxcmmc.c @@ -34,6 +34,10 @@ #include #include #include +#include +#include +#include +#include #include #include @@ -173,6 +177,19 @@ static struct platform_device_id mxcmci_devtype[] = { }; MODULE_DEVICE_TABLE(platform, mxcmci_devtype); +static const struct of_device_id mxcmci_of_match[] = { + { + .compatible = "fsl,imx21-mmc", + .data = &mxcmci_devtype[IMX21_MMC], + }, { + .compatible = "fsl,imx31-mmc", + .data = &mxcmci_devtype[IMX31_MMC], + }, { + /* sentinel */ + } +}; +MODULE_DEVICE_TABLE(of, mxcmci_of_match); + static inline int is_imx31_mmc(struct mxcmci_host *host) { return host->devtype == IMX31_MMC; @@ -935,10 +952,15 @@ static int mxcmci_probe(struct platform_device *pdev) struct mxcmci_host *host = NULL; struct resource *iores, *r; int ret = 0, irq; + bool dat3_card_detect = false; dma_cap_mask_t mask; + const struct of_device_id *of_id; + struct imxmmc_platform_data *pdata = pdev->dev.platform_data; pr_info("i.MX SDHC driver\n"); + of_id = of_match_device(mxcmci_of_match, &pdev->dev); + iores = platform_get_resource(pdev, IORESOURCE_MEM, 0); irq = platform_get_irq(pdev, 0); if (!iores || irq < 0) @@ -954,8 +976,14 @@ static int mxcmci_probe(struct platform_device *pdev) goto out_release_mem; } + mmc_of_parse(mmc); mmc->ops = &mxcmci_ops; - mmc->caps = MMC_CAP_4_BIT_DATA | MMC_CAP_SDIO_IRQ; + + /* For devicetree parsing, the bus width is read from devicetree */ + if (pdata) + mmc->caps = MMC_CAP_4_BIT_DATA | MMC_CAP_SDIO_IRQ; + else + mmc->caps |= MMC_CAP_SDIO_IRQ; /* MMC core transfer sizes tunable parameters */ mmc->max_segs = 64; @@ -971,14 +999,25 @@ static int mxcmci_probe(struct platform_device *pdev) goto out_free; } + if (of_id) { + const struct platform_device_id *id_entry = of_id->data; + host->devtype = id_entry->driver_data; + } else { + host->devtype = pdev->id_entry->driver_data; + } host->mmc = mmc; - host->pdata = pdev->dev.platform_data; - host->devtype = pdev->id_entry->driver_data; + host->pdata = pdata; spin_lock_init(&host->lock); + if (pdata) + dat3_card_detect = pdata->dat3_card_detect; + else if (!(mmc->caps & MMC_CAP_NONREMOVABLE) + && !of_property_read_bool(pdev->dev.of_node, "cd-gpios")) + dat3_card_detect = true; + mxcmci_init_ocr(host); - if (host->pdata && host->pdata->dat3_card_detect) + if (dat3_card_detect) host->default_irq_mask = INT_CARD_INSERTION_EN | INT_CARD_REMOVAL_EN; else @@ -1020,21 +1059,24 @@ static int mxcmci_probe(struct platform_device *pdev) writel(host->default_irq_mask, host->base + MMC_REG_INT_CNTR); - r = platform_get_resource(pdev, IORESOURCE_DMA, 0); - if (r) { - host->dmareq = r->start; - host->dma_data.peripheral_type = IMX_DMATYPE_SDHC; - host->dma_data.priority = DMA_PRIO_LOW; - host->dma_data.dma_request = host->dmareq; - dma_cap_zero(mask); - dma_cap_set(DMA_SLAVE, mask); - host->dma = dma_request_channel(mask, filter, host); - if (host->dma) - mmc->max_seg_size = dma_get_max_seg_size( - host->dma->device->dev); + if (!host->pdata) { + host->dma = dma_request_slave_channel(&pdev->dev, "rx-tx"); + } else { + r = platform_get_resource(pdev, IORESOURCE_DMA, 0); + if (r) { + host->dmareq = r->start; + host->dma_data.peripheral_type = IMX_DMATYPE_SDHC; + host->dma_data.priority = DMA_PRIO_LOW; + host->dma_data.dma_request = host->dmareq; + dma_cap_zero(mask); + dma_cap_set(DMA_SLAVE, mask); + host->dma = dma_request_channel(mask, filter, host); + } } - - if (!host->dma) + if (host->dma) + mmc->max_seg_size = dma_get_max_seg_size( + host->dma->device->dev); + else dev_info(mmc_dev(host->mmc), "dma not available. Using PIO\n"); INIT_WORK(&host->datawork, mxcmci_datawork); @@ -1153,6 +1195,7 @@ static struct platform_driver mxcmci_driver = { #ifdef CONFIG_PM .pm = &mxcmci_pm_ops, #endif + .of_match_table = mxcmci_of_match, } }; -- cgit v0.10.2 From 70aa6109597ea6955a93f16430b588b5ee5ba547 Mon Sep 17 00:00:00 2001 From: Anatolij Gustschin Date: Mon, 8 Apr 2013 23:28:05 +0200 Subject: mmc: mxcmmc: fix race conditions for host->req and host->data access mxcmci_dma_callback() is invoked by DMA drivers in soft-irq context and can be interrupted by the mxcmci_irq() interrupt which can finish the mmc request or data transfer and set host->req or host->data pointers to NULL. Then mxcmci_data_done() crashes with a null pointer dereferences. Protect all accesses to host->req and host->data by spin locks. Also check host->data pointer in mxcmci_watchdog() before dereferencing it. Signed-off-by: Anatolij Gustschin Acked-by: Sascha Hauer Signed-off-by: Chris Ball diff --git a/drivers/mmc/host/mxcmmc.c b/drivers/mmc/host/mxcmmc.c index 848ab2c..b82e37a 100644 --- a/drivers/mmc/host/mxcmmc.c +++ b/drivers/mmc/host/mxcmmc.c @@ -623,24 +623,40 @@ static void mxcmci_datawork(struct work_struct *work) static void mxcmci_data_done(struct mxcmci_host *host, unsigned int stat) { - struct mmc_data *data = host->data; + struct mmc_request *req; int data_error; + unsigned long flags; + + spin_lock_irqsave(&host->lock, flags); - if (!data) + if (!host->data) { + spin_unlock_irqrestore(&host->lock, flags); return; + } + + if (!host->req) { + spin_unlock_irqrestore(&host->lock, flags); + return; + } + + req = host->req; + if (!req->stop) + host->req = NULL; /* we will handle finish req below */ data_error = mxcmci_finish_data(host, stat); + spin_unlock_irqrestore(&host->lock, flags); + mxcmci_read_response(host, stat); host->cmd = NULL; - if (host->req->stop) { - if (mxcmci_start_cmd(host, host->req->stop, 0)) { - mxcmci_finish_request(host, host->req); + if (req->stop) { + if (mxcmci_start_cmd(host, req->stop, 0)) { + mxcmci_finish_request(host, req); return; } } else { - mxcmci_finish_request(host, host->req); + mxcmci_finish_request(host, req); } } @@ -931,7 +947,8 @@ static void mxcmci_watchdog(unsigned long data) /* Mark transfer as erroneus and inform the upper layers */ - host->data->error = -ETIMEDOUT; + if (host->data) + host->data->error = -ETIMEDOUT; host->req = NULL; host->cmd = NULL; host->data = NULL; -- cgit v0.10.2 From c7ceab02543f8a03b4df3d4465b089c8117a5e09 Mon Sep 17 00:00:00 2001 From: Anatolij Gustschin Date: Mon, 8 Apr 2013 23:28:06 +0200 Subject: mmc: mxcmmc: add mpc512x SDHC support The SDHC controller on mpc512x is compatible with i.MX31 SDHC, so the mxcmmc driver can be used on mpc512x, too. Extend the driver to support mpc512x as well. Signed-off-by: Anatolij Gustschin Acked-by: Sascha Hauer Signed-off-by: Chris Ball diff --git a/drivers/mmc/host/Kconfig b/drivers/mmc/host/Kconfig index f83f245..9ab8f8d 100644 --- a/drivers/mmc/host/Kconfig +++ b/drivers/mmc/host/Kconfig @@ -320,12 +320,12 @@ config MMC_MSM support for SDIO devices. config MMC_MXC - tristate "Freescale i.MX21/27/31 Multimedia Card Interface support" - depends on ARCH_MXC + tristate "Freescale i.MX21/27/31 or MPC512x Multimedia Card support" + depends on ARCH_MXC || PPC_MPC512x help - This selects the Freescale i.MX21, i.MX27 and i.MX31 Multimedia card - Interface. If you have a i.MX platform with a Multimedia Card slot, - say Y or M here. + This selects the Freescale i.MX21, i.MX27, i.MX31 or MPC512x + Multimedia Card Interface. If you have an i.MX or MPC512x platform + with a Multimedia Card slot, say Y or M here. If unsure, say N. diff --git a/drivers/mmc/host/mxcmmc.c b/drivers/mmc/host/mxcmmc.c index b82e37a..3f8d339 100644 --- a/drivers/mmc/host/mxcmmc.c +++ b/drivers/mmc/host/mxcmmc.c @@ -41,7 +41,6 @@ #include #include -#include #include #include @@ -119,6 +118,7 @@ enum mxcmci_type { IMX21_MMC, IMX31_MMC, + MPC512X_MMC, }; struct mxcmci_host { @@ -172,6 +172,9 @@ static struct platform_device_id mxcmci_devtype[] = { .name = "imx31-mmc", .driver_data = IMX31_MMC, }, { + .name = "mpc512x-sdhc", + .driver_data = MPC512X_MMC, + }, { /* sentinel */ } }; @@ -185,6 +188,9 @@ static const struct of_device_id mxcmci_of_match[] = { .compatible = "fsl,imx31-mmc", .data = &mxcmci_devtype[IMX31_MMC], }, { + .compatible = "fsl,mpc5121-sdhc", + .data = &mxcmci_devtype[MPC512X_MMC], + }, { /* sentinel */ } }; @@ -195,6 +201,43 @@ static inline int is_imx31_mmc(struct mxcmci_host *host) return host->devtype == IMX31_MMC; } +static inline int is_mpc512x_mmc(struct mxcmci_host *host) +{ + return host->devtype == MPC512X_MMC; +} + +static inline u32 mxcmci_readl(struct mxcmci_host *host, int reg) +{ + if (IS_ENABLED(CONFIG_PPC_MPC512x)) + return ioread32be(host->base + reg); + else + return readl(host->base + reg); +} + +static inline void mxcmci_writel(struct mxcmci_host *host, u32 val, int reg) +{ + if (IS_ENABLED(CONFIG_PPC_MPC512x)) + iowrite32be(val, host->base + reg); + else + writel(val, host->base + reg); +} + +static inline u16 mxcmci_readw(struct mxcmci_host *host, int reg) +{ + if (IS_ENABLED(CONFIG_PPC_MPC512x)) + return ioread32be(host->base + reg); + else + return readw(host->base + reg); +} + +static inline void mxcmci_writew(struct mxcmci_host *host, u16 val, int reg) +{ + if (IS_ENABLED(CONFIG_PPC_MPC512x)) + iowrite32be(val, host->base + reg); + else + writew(val, host->base + reg); +} + static void mxcmci_set_clk_rate(struct mxcmci_host *host, unsigned int clk_ios); static inline void mxcmci_init_ocr(struct mxcmci_host *host) @@ -246,14 +289,14 @@ static void mxcmci_softreset(struct mxcmci_host *host) dev_dbg(mmc_dev(host->mmc), "mxcmci_softreset\n"); /* reset sequence */ - writew(STR_STP_CLK_RESET, host->base + MMC_REG_STR_STP_CLK); - writew(STR_STP_CLK_RESET | STR_STP_CLK_START_CLK, - host->base + MMC_REG_STR_STP_CLK); + mxcmci_writew(host, STR_STP_CLK_RESET, MMC_REG_STR_STP_CLK); + mxcmci_writew(host, STR_STP_CLK_RESET | STR_STP_CLK_START_CLK, + MMC_REG_STR_STP_CLK); for (i = 0; i < 8; i++) - writew(STR_STP_CLK_START_CLK, host->base + MMC_REG_STR_STP_CLK); + mxcmci_writew(host, STR_STP_CLK_START_CLK, MMC_REG_STR_STP_CLK); - writew(0xff, host->base + MMC_REG_RES_TO); + mxcmci_writew(host, 0xff, MMC_REG_RES_TO); } static int mxcmci_setup_dma(struct mmc_host *mmc); @@ -272,8 +315,8 @@ static int mxcmci_setup_data(struct mxcmci_host *host, struct mmc_data *data) host->data = data; data->bytes_xfered = 0; - writew(nob, host->base + MMC_REG_NOB); - writew(blksz, host->base + MMC_REG_BLK_LEN); + mxcmci_writew(host, nob, MMC_REG_NOB); + mxcmci_writew(host, blksz, MMC_REG_BLK_LEN); host->datasize = datasize; if (!mxcmci_use_dma(host)) @@ -329,13 +372,13 @@ static void mxcmci_dma_callback(void *data) del_timer(&host->watchdog); - stat = readl(host->base + MMC_REG_STATUS); - writel(stat & ~STATUS_DATA_TRANS_DONE, host->base + MMC_REG_STATUS); + stat = mxcmci_readl(host, MMC_REG_STATUS); + mxcmci_writel(host, stat & ~STATUS_DATA_TRANS_DONE, MMC_REG_STATUS); dev_dbg(mmc_dev(host->mmc), "%s: 0x%08x\n", __func__, stat); if (stat & STATUS_READ_OP_DONE) - writel(STATUS_READ_OP_DONE, host->base + MMC_REG_STATUS); + mxcmci_writel(host, STATUS_READ_OP_DONE, MMC_REG_STATUS); mxcmci_data_done(host, stat); } @@ -383,12 +426,12 @@ static int mxcmci_start_cmd(struct mxcmci_host *host, struct mmc_command *cmd, spin_lock_irqsave(&host->lock, flags); if (host->use_sdio) int_cntr |= INT_SDIO_IRQ_EN; - writel(int_cntr, host->base + MMC_REG_INT_CNTR); + mxcmci_writel(host, int_cntr, MMC_REG_INT_CNTR); spin_unlock_irqrestore(&host->lock, flags); - writew(cmd->opcode, host->base + MMC_REG_CMD); - writel(cmd->arg, host->base + MMC_REG_ARG); - writew(cmdat, host->base + MMC_REG_CMD_DAT_CONT); + mxcmci_writew(host, cmd->opcode, MMC_REG_CMD); + mxcmci_writel(host, cmd->arg, MMC_REG_ARG); + mxcmci_writew(host, cmdat, MMC_REG_CMD_DAT_CONT); return 0; } @@ -402,7 +445,7 @@ static void mxcmci_finish_request(struct mxcmci_host *host, spin_lock_irqsave(&host->lock, flags); if (host->use_sdio) int_cntr |= INT_SDIO_IRQ_EN; - writel(int_cntr, host->base + MMC_REG_INT_CNTR); + mxcmci_writel(host, int_cntr, MMC_REG_INT_CNTR); spin_unlock_irqrestore(&host->lock, flags); host->req = NULL; @@ -477,14 +520,14 @@ static void mxcmci_read_response(struct mxcmci_host *host, unsigned int stat) if (cmd->flags & MMC_RSP_PRESENT) { if (cmd->flags & MMC_RSP_136) { for (i = 0; i < 4; i++) { - a = readw(host->base + MMC_REG_RES_FIFO); - b = readw(host->base + MMC_REG_RES_FIFO); + a = mxcmci_readw(host, MMC_REG_RES_FIFO); + b = mxcmci_readw(host, MMC_REG_RES_FIFO); cmd->resp[i] = a << 16 | b; } } else { - a = readw(host->base + MMC_REG_RES_FIFO); - b = readw(host->base + MMC_REG_RES_FIFO); - c = readw(host->base + MMC_REG_RES_FIFO); + a = mxcmci_readw(host, MMC_REG_RES_FIFO); + b = mxcmci_readw(host, MMC_REG_RES_FIFO); + c = mxcmci_readw(host, MMC_REG_RES_FIFO); cmd->resp[0] = a << 24 | b << 8 | c >> 8; } } @@ -496,7 +539,7 @@ static int mxcmci_poll_status(struct mxcmci_host *host, u32 mask) unsigned long timeout = jiffies + HZ; do { - stat = readl(host->base + MMC_REG_STATUS); + stat = mxcmci_readl(host, MMC_REG_STATUS); if (stat & STATUS_ERR_MASK) return stat; if (time_after(jiffies, timeout)) { @@ -520,7 +563,7 @@ static int mxcmci_pull(struct mxcmci_host *host, void *_buf, int bytes) STATUS_BUF_READ_RDY | STATUS_READ_OP_DONE); if (stat) return stat; - *buf++ = readl(host->base + MMC_REG_BUFFER_ACCESS); + *buf++ = cpu_to_le32(mxcmci_readl(host, MMC_REG_BUFFER_ACCESS)); bytes -= 4; } @@ -532,7 +575,7 @@ static int mxcmci_pull(struct mxcmci_host *host, void *_buf, int bytes) STATUS_BUF_READ_RDY | STATUS_READ_OP_DONE); if (stat) return stat; - tmp = readl(host->base + MMC_REG_BUFFER_ACCESS); + tmp = cpu_to_le32(mxcmci_readl(host, MMC_REG_BUFFER_ACCESS)); memcpy(b, &tmp, bytes); } @@ -548,7 +591,7 @@ static int mxcmci_push(struct mxcmci_host *host, void *_buf, int bytes) stat = mxcmci_poll_status(host, STATUS_BUF_WRITE_RDY); if (stat) return stat; - writel(*buf++, host->base + MMC_REG_BUFFER_ACCESS); + mxcmci_writel(host, cpu_to_le32(*buf++), MMC_REG_BUFFER_ACCESS); bytes -= 4; } @@ -561,7 +604,7 @@ static int mxcmci_push(struct mxcmci_host *host, void *_buf, int bytes) return stat; memcpy(&tmp, b, bytes); - writel(tmp, host->base + MMC_REG_BUFFER_ACCESS); + mxcmci_writel(host, cpu_to_le32(tmp), MMC_REG_BUFFER_ACCESS); } stat = mxcmci_poll_status(host, STATUS_BUF_WRITE_RDY); @@ -607,8 +650,8 @@ static void mxcmci_datawork(struct work_struct *work) datawork); int datastat = mxcmci_transfer_data(host); - writel(STATUS_READ_OP_DONE | STATUS_WRITE_OP_DONE, - host->base + MMC_REG_STATUS); + mxcmci_writel(host, STATUS_READ_OP_DONE | STATUS_WRITE_OP_DONE, + MMC_REG_STATUS); mxcmci_finish_data(host, datastat); if (host->req->stop) { @@ -686,9 +729,11 @@ static irqreturn_t mxcmci_irq(int irq, void *devid) bool sdio_irq; u32 stat; - stat = readl(host->base + MMC_REG_STATUS); - writel(stat & ~(STATUS_SDIO_INT_ACTIVE | STATUS_DATA_TRANS_DONE | - STATUS_WRITE_OP_DONE), host->base + MMC_REG_STATUS); + stat = mxcmci_readl(host, MMC_REG_STATUS); + mxcmci_writel(host, + stat & ~(STATUS_SDIO_INT_ACTIVE | STATUS_DATA_TRANS_DONE | + STATUS_WRITE_OP_DONE), + MMC_REG_STATUS); dev_dbg(mmc_dev(host->mmc), "%s: 0x%08x\n", __func__, stat); @@ -698,11 +743,11 @@ static irqreturn_t mxcmci_irq(int irq, void *devid) if (mxcmci_use_dma(host) && (stat & (STATUS_READ_OP_DONE | STATUS_WRITE_OP_DONE))) - writel(STATUS_READ_OP_DONE | STATUS_WRITE_OP_DONE, - host->base + MMC_REG_STATUS); + mxcmci_writel(host, STATUS_READ_OP_DONE | STATUS_WRITE_OP_DONE, + MMC_REG_STATUS); if (sdio_irq) { - writel(STATUS_SDIO_INT_ACTIVE, host->base + MMC_REG_STATUS); + mxcmci_writel(host, STATUS_SDIO_INT_ACTIVE, MMC_REG_STATUS); mmc_signal_sdio_irq(host->mmc); } @@ -784,7 +829,7 @@ static void mxcmci_set_clk_rate(struct mxcmci_host *host, unsigned int clk_ios) prescaler <<= 1; } - writew((prescaler << 4) | divider, host->base + MMC_REG_CLK_RATE); + mxcmci_writew(host, (prescaler << 4) | divider, MMC_REG_CLK_RATE); dev_dbg(mmc_dev(host->mmc), "scaler: %d divider: %d in: %d out: %d\n", prescaler, divider, clk_in, clk_ios); @@ -847,9 +892,9 @@ static void mxcmci_set_ios(struct mmc_host *mmc, struct mmc_ios *ios) if (ios->clock) { mxcmci_set_clk_rate(host, ios->clock); - writew(STR_STP_CLK_START_CLK, host->base + MMC_REG_STR_STP_CLK); + mxcmci_writew(host, STR_STP_CLK_START_CLK, MMC_REG_STR_STP_CLK); } else { - writew(STR_STP_CLK_STOP_CLK, host->base + MMC_REG_STR_STP_CLK); + mxcmci_writew(host, STR_STP_CLK_STOP_CLK, MMC_REG_STR_STP_CLK); } host->clock = ios->clock; @@ -886,14 +931,14 @@ static void mxcmci_enable_sdio_irq(struct mmc_host *mmc, int enable) spin_lock_irqsave(&host->lock, flags); host->use_sdio = enable; - int_cntr = readl(host->base + MMC_REG_INT_CNTR); + int_cntr = mxcmci_readl(host, MMC_REG_INT_CNTR); if (enable) int_cntr |= INT_SDIO_IRQ_EN; else int_cntr &= ~INT_SDIO_IRQ_EN; - writel(int_cntr, host->base + MMC_REG_INT_CNTR); + mxcmci_writel(host, int_cntr, MMC_REG_INT_CNTR); spin_unlock_irqrestore(&host->lock, flags); } @@ -931,7 +976,7 @@ static void mxcmci_watchdog(unsigned long data) struct mmc_host *mmc = (struct mmc_host *)data; struct mxcmci_host *host = mmc_priv(mmc); struct mmc_request *req = host->req; - unsigned int stat = readl(host->base + MMC_REG_STATUS); + unsigned int stat = mxcmci_readl(host, MMC_REG_STATUS); if (host->dma_dir == DMA_FROM_DEVICE) { dmaengine_terminate_all(host->dma); @@ -974,7 +1019,7 @@ static int mxcmci_probe(struct platform_device *pdev) const struct of_device_id *of_id; struct imxmmc_platform_data *pdata = pdev->dev.platform_data; - pr_info("i.MX SDHC driver\n"); + pr_info("i.MX/MPC512x SDHC driver\n"); of_id = of_match_device(mxcmci_of_match, &pdev->dev); @@ -1060,7 +1105,7 @@ static int mxcmci_probe(struct platform_device *pdev) mxcmci_softreset(host); - host->rev_no = readw(host->base + MMC_REG_REV_NO); + host->rev_no = mxcmci_readw(host, MMC_REG_REV_NO); if (host->rev_no != 0x400) { ret = -ENODEV; dev_err(mmc_dev(host->mmc), "wrong rev.no. 0x%08x. aborting.\n", @@ -1072,9 +1117,9 @@ static int mxcmci_probe(struct platform_device *pdev) mmc->f_max = clk_get_rate(host->clk_per) >> 1; /* recommended in data sheet */ - writew(0x2db4, host->base + MMC_REG_READ_TO); + mxcmci_writew(host, 0x2db4, MMC_REG_READ_TO); - writel(host->default_irq_mask, host->base + MMC_REG_INT_CNTR); + mxcmci_writel(host, host->default_irq_mask, MMC_REG_INT_CNTR); if (!host->pdata) { host->dma = dma_request_slave_channel(&pdev->dev, "rx-tx"); -- cgit v0.10.2 From bcf53524ac4532da546cb87099a6e164d5394004 Mon Sep 17 00:00:00 2001 From: Anatolij Gustschin Date: Mon, 8 Apr 2013 23:28:07 +0200 Subject: mmc: mxcmmc: use slot-gpio API for write-protect detection slot-gpio API suppors read-only detection when "wp-gpios" property is present in the device tree mmc node. Use this API for write-protect detection. Signed-off-by: Anatolij Gustschin Acked-by: Sascha Hauer Signed-off-by: Chris Ball diff --git a/drivers/mmc/host/mxcmmc.c b/drivers/mmc/host/mxcmmc.c index 3f8d339..df28ebf 100644 --- a/drivers/mmc/host/mxcmmc.c +++ b/drivers/mmc/host/mxcmmc.c @@ -38,6 +38,7 @@ #include #include #include +#include #include #include @@ -917,10 +918,11 @@ static int mxcmci_get_ro(struct mmc_host *mmc) if (host->pdata && host->pdata->get_ro) return !!host->pdata->get_ro(mmc_dev(mmc)); /* - * Board doesn't support read only detection; let the mmc core - * decide what to do. + * If board doesn't support read only detection (no mmc_gpio + * context or gpio is invalid), then let the mmc core decide + * what to do. */ - return -ENOSYS; + return mmc_gpio_get_ro(mmc); } static void mxcmci_enable_sdio_irq(struct mmc_host *mmc, int enable) -- cgit v0.10.2 From 42477053c389900f28e200c198830c838989809f Mon Sep 17 00:00:00 2001 From: Anatolij Gustschin Date: Mon, 8 Apr 2013 23:28:08 +0200 Subject: mmc: mxcmmc: constify mxcmci_devtype mxcmci_devtype struct contains constant data, so constify this struct. Signed-off-by: Anatolij Gustschin Acked-by: Sascha Hauer Signed-off-by: Chris Ball diff --git a/drivers/mmc/host/mxcmmc.c b/drivers/mmc/host/mxcmmc.c index df28ebf..5d52826 100644 --- a/drivers/mmc/host/mxcmmc.c +++ b/drivers/mmc/host/mxcmmc.c @@ -165,7 +165,7 @@ struct mxcmci_host { enum mxcmci_type devtype; }; -static struct platform_device_id mxcmci_devtype[] = { +static const struct platform_device_id mxcmci_devtype[] = { { .name = "imx21-mmc", .driver_data = IMX21_MMC, -- cgit v0.10.2 From e48fc15aa205f380b2fc6d565724a55b1efd8083 Mon Sep 17 00:00:00 2001 From: Anatolij Gustschin Date: Mon, 8 Apr 2013 23:28:09 +0200 Subject: mmc: mxcmmc: enable DMA support on mpc512x Add SDHC DMA channel description to the mpc512x device tree to enable slave channel requesting in the mxcmmc driver. mpc512x DMA engine doesn't support endianness conversion when reading/writing data from peripheral's FIFO, so we have to swap data buffers before each DMA write and after each DMA read transfer manually. Since chained SDHC DMA transfers are not supported on mpc512x, limit 'max_segs' tunable parameter to one and initialise it to 64 only when running on i.MX platforms. Signed-off-by: Anatolij Gustschin Acked-by: Sascha Hauer Signed-off-by: Chris Ball diff --git a/arch/powerpc/boot/dts/mpc5121.dtsi b/arch/powerpc/boot/dts/mpc5121.dtsi index 723e292..710aae6 100644 --- a/arch/powerpc/boot/dts/mpc5121.dtsi +++ b/arch/powerpc/boot/dts/mpc5121.dtsi @@ -152,6 +152,8 @@ compatible = "fsl,mpc5121-sdhc"; reg = <0x1500 0x100>; interrupts = <8 0x8>; + dmas = <&dma0 30>; + dma-names = "rx-tx"; }; i2c@1700 { diff --git a/drivers/mmc/host/mxcmmc.c b/drivers/mmc/host/mxcmmc.c index 5d52826..d503635 100644 --- a/drivers/mmc/host/mxcmmc.c +++ b/drivers/mmc/host/mxcmmc.c @@ -301,6 +301,29 @@ static void mxcmci_softreset(struct mxcmci_host *host) } static int mxcmci_setup_dma(struct mmc_host *mmc); +#if IS_ENABLED(CONFIG_PPC_MPC512x) +static inline void buffer_swap32(u32 *buf, int len) +{ + int i; + + for (i = 0; i < ((len + 3) / 4); i++) { + st_le32(buf, *buf); + buf++; + } +} + +static void mxcmci_swap_buffers(struct mmc_data *data) +{ + struct scatterlist *sg; + int i; + + for_each_sg(data->sg, sg, data->sg_len, i) + buffer_swap32(sg_virt(sg), sg->length); +} +#else +static inline void mxcmci_swap_buffers(struct mmc_data *data) {} +#endif + static int mxcmci_setup_data(struct mxcmci_host *host, struct mmc_data *data) { unsigned int nob = data->blocks; @@ -336,6 +359,8 @@ static int mxcmci_setup_data(struct mxcmci_host *host, struct mmc_data *data) } else { host->dma_dir = DMA_TO_DEVICE; slave_dirn = DMA_MEM_TO_DEV; + + mxcmci_swap_buffers(data); } nents = dma_map_sg(host->dma->device->dev, data->sg, @@ -461,9 +486,11 @@ static int mxcmci_finish_data(struct mxcmci_host *host, unsigned int stat) struct mmc_data *data = host->data; int data_error; - if (mxcmci_use_dma(host)) + if (mxcmci_use_dma(host)) { dma_unmap_sg(host->dma->device->dev, data->sg, data->sg_len, host->dma_dir); + mxcmci_swap_buffers(data); + } if (stat & STATUS_ERR_MASK) { dev_dbg(mmc_dev(host->mmc), "request failed. status: 0x%08x\n", @@ -1050,7 +1077,6 @@ static int mxcmci_probe(struct platform_device *pdev) mmc->caps |= MMC_CAP_SDIO_IRQ; /* MMC core transfer sizes tunable parameters */ - mmc->max_segs = 64; mmc->max_blk_size = 2048; mmc->max_blk_count = 65535; mmc->max_req_size = mmc->max_blk_size * mmc->max_blk_count; @@ -1069,6 +1095,11 @@ static int mxcmci_probe(struct platform_device *pdev) } else { host->devtype = pdev->id_entry->driver_data; } + + /* adjust max_segs after devtype detection */ + if (!is_mpc512x_mmc(host)) + mmc->max_segs = 64; + host->mmc = mmc; host->pdata = pdata; spin_lock_init(&host->lock); -- cgit v0.10.2 From a08b17be8b984a7c51cd5a480cd977363df353f9 Mon Sep 17 00:00:00 2001 From: Adrian Hunter Date: Mon, 15 Apr 2013 11:27:25 -0400 Subject: mmc: core: fix init controller performance regression, updated patch Add MMC_CAP2_NO_PRESCAN_POWERUP to sdhci-pci.c also, use mmc_power_off() for MMC_CAP2_NO_PRESCAN_POWERUP. Signed-off-by: Adrian Hunter [cjb: previously applied v1 of this patch instead of v4] Signed-off-by: Chris Ball diff --git a/drivers/mmc/core/core.c b/drivers/mmc/core/core.c index c1893c9..65f9ca7 100644 --- a/drivers/mmc/core/core.c +++ b/drivers/mmc/core/core.c @@ -2416,7 +2416,9 @@ void mmc_start_host(struct mmc_host *host) { host->f_init = max(freqs[0], host->f_min); host->rescan_disable = 0; - if (!(host->caps2 & MMC_CAP2_NO_PRESCAN_POWERUP)) + if (host->caps2 & MMC_CAP2_NO_PRESCAN_POWERUP) + mmc_power_off(host); + else mmc_power_up(host); mmc_detect_change(host, 0); } diff --git a/drivers/mmc/host/sdhci-pci.c b/drivers/mmc/host/sdhci-pci.c index c1f0372..0012d3f 100644 --- a/drivers/mmc/host/sdhci-pci.c +++ b/drivers/mmc/host/sdhci-pci.c @@ -1280,6 +1280,7 @@ static struct sdhci_pci_slot *sdhci_pci_probe_slot( host->mmc->pm_caps = MMC_PM_KEEP_POWER | MMC_PM_WAKE_SDIO_IRQ; host->mmc->slotno = slotno; + host->mmc->caps2 |= MMC_CAP2_NO_PRESCAN_POWERUP; ret = sdhci_add_host(host); if (ret) -- cgit v0.10.2 From e4404fab2e0b70287a471a1e760c9338ce683fde Mon Sep 17 00:00:00 2001 From: Arnd Bergmann Date: Tue, 23 Apr 2013 15:05:57 -0400 Subject: mmc: sdhci-tegra: fix MODULE_DEVICE_TABLE The symbol referenced in MODULE_DEVICE_TABLE must match the actual table, otherwise we get a build error like: sdhci-tegra.c:206:34: error: '__mod_of_device_table' aliased to undefined symbol 'sdhci_dt_ids' Signed-off-by: Arnd Bergmann Cc: Stephen Warren Signed-off-by: Chris Ball diff --git a/drivers/mmc/host/sdhci-tegra.c b/drivers/mmc/host/sdhci-tegra.c index 45048d1..e0dba74 100644 --- a/drivers/mmc/host/sdhci-tegra.c +++ b/drivers/mmc/host/sdhci-tegra.c @@ -203,7 +203,7 @@ static const struct of_device_id sdhci_tegra_dt_match[] = { { .compatible = "nvidia,tegra20-sdhci", .data = &soc_data_tegra20 }, {} }; -MODULE_DEVICE_TABLE(of, sdhci_dt_ids); +MODULE_DEVICE_TABLE(of, sdhci_tegra_dt_match); static void sdhci_tegra_parse_dt(struct device *dev) { -- cgit v0.10.2