From 42dcc89a914722635814ae405cfdacfeccad82d1 Mon Sep 17 00:00:00 2001 From: Ulf Hansson Date: Thu, 23 Jan 2014 00:19:38 +0100 Subject: mmc: mmci: Mask IRQs for all variants during runtime suspend In runtime suspended state, we are not expecting IRQs and thus we can safely mask them, not only for pwrreg_nopower variants but for all. Obviously we then also need to make sure we restore the IRQ mask while becoming runtime resumed. Cc: Russell King Signed-off-by: Ulf Hansson --- drivers/mmc/host/mmci.c | 23 +++++++++++------------ 1 file changed, 11 insertions(+), 12 deletions(-) (limited to 'drivers/mmc') diff --git a/drivers/mmc/host/mmci.c b/drivers/mmc/host/mmci.c index 771c60ab4a32..0f10e3ccb944 100644 --- a/drivers/mmc/host/mmci.c +++ b/drivers/mmc/host/mmci.c @@ -1794,35 +1794,34 @@ static void mmci_save(struct mmci_host *host) { unsigned long flags; - if (host->variant->pwrreg_nopower) { - spin_lock_irqsave(&host->lock, flags); + spin_lock_irqsave(&host->lock, flags); - writel(0, host->base + MMCIMASK0); + writel(0, host->base + MMCIMASK0); + if (host->variant->pwrreg_nopower) { writel(0, host->base + MMCIDATACTRL); writel(0, host->base + MMCIPOWER); writel(0, host->base + MMCICLOCK); - mmci_reg_delay(host); - - spin_unlock_irqrestore(&host->lock, flags); } + mmci_reg_delay(host); + spin_unlock_irqrestore(&host->lock, flags); } static void mmci_restore(struct mmci_host *host) { unsigned long flags; - if (host->variant->pwrreg_nopower) { - spin_lock_irqsave(&host->lock, flags); + spin_lock_irqsave(&host->lock, flags); + if (host->variant->pwrreg_nopower) { writel(host->clk_reg, host->base + MMCICLOCK); writel(host->datactrl_reg, host->base + MMCIDATACTRL); writel(host->pwr_reg, host->base + MMCIPOWER); - writel(MCI_IRQENABLE, host->base + MMCIMASK0); - mmci_reg_delay(host); - - spin_unlock_irqrestore(&host->lock, flags); } + writel(MCI_IRQENABLE, host->base + MMCIMASK0); + mmci_reg_delay(host); + + spin_unlock_irqrestore(&host->lock, flags); } static int mmci_runtime_suspend(struct device *dev) -- cgit v1.2.3 From 571dce4f105cf2b8e57ec4330da71bd0cb6d38bb Mon Sep 17 00:00:00 2001 From: Ulf Hansson Date: Thu, 23 Jan 2014 00:38:00 +0100 Subject: mmc: mmci: Let runtime PM callbacks be available for CONFIG_PM Convert to the SET_PM_RUNTIME_PM macro while defining the runtime PM callbacks. This means the callbacks becomes available for both CONFIG_PM_SLEEP and CONFIG_PM_RUNTIME, which is needed to handle the combinations of these scenarios. Cc: Russell King Signed-off-by: Ulf Hansson --- drivers/mmc/host/mmci.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers/mmc') diff --git a/drivers/mmc/host/mmci.c b/drivers/mmc/host/mmci.c index 0f10e3ccb944..eb23c89b2717 100644 --- a/drivers/mmc/host/mmci.c +++ b/drivers/mmc/host/mmci.c @@ -1789,7 +1789,7 @@ static int mmci_resume(struct device *dev) } #endif -#ifdef CONFIG_PM_RUNTIME +#ifdef CONFIG_PM static void mmci_save(struct mmci_host *host) { unsigned long flags; @@ -1857,7 +1857,7 @@ static int mmci_runtime_resume(struct device *dev) static const struct dev_pm_ops mmci_dev_pm_ops = { SET_SYSTEM_SLEEP_PM_OPS(mmci_suspend, mmci_resume) - SET_RUNTIME_PM_OPS(mmci_runtime_suspend, mmci_runtime_resume, NULL) + SET_PM_RUNTIME_PM_OPS(mmci_runtime_suspend, mmci_runtime_resume, NULL) }; static struct amba_id mmci_ids[] = { -- cgit v1.2.3 From f3737fa388388bc864bc63b1c70e3679fe839a52 Mon Sep 17 00:00:00 2001 From: Ulf Hansson Date: Thu, 23 Jan 2014 01:11:33 +0100 Subject: mmc: mmci: Put the device into low power state at system suspend For CONFIG_PM_SLEEP, the device were always left in full power state after system suspend. We solely relied on a power domain to put it into low power state, which is an unreasonable requirement to put on SOCs to implement. Especially for those SOCs not supporting power domains at all. Use pm_runtime_force_suspend|resume() as the system suspend callbacks, to resolve the issue. Cc: Russell King Signed-off-by: Ulf Hansson --- drivers/mmc/host/mmci.c | 33 ++------------------------------- 1 file changed, 2 insertions(+), 31 deletions(-) (limited to 'drivers/mmc') diff --git a/drivers/mmc/host/mmci.c b/drivers/mmc/host/mmci.c index eb23c89b2717..a40bf70170fd 100644 --- a/drivers/mmc/host/mmci.c +++ b/drivers/mmc/host/mmci.c @@ -1759,36 +1759,6 @@ static int mmci_remove(struct amba_device *dev) return 0; } -#ifdef CONFIG_SUSPEND -static int mmci_suspend(struct device *dev) -{ - struct amba_device *adev = to_amba_device(dev); - struct mmc_host *mmc = amba_get_drvdata(adev); - - if (mmc) { - struct mmci_host *host = mmc_priv(mmc); - pm_runtime_get_sync(dev); - writel(0, host->base + MMCIMASK0); - } - - return 0; -} - -static int mmci_resume(struct device *dev) -{ - struct amba_device *adev = to_amba_device(dev); - struct mmc_host *mmc = amba_get_drvdata(adev); - - if (mmc) { - struct mmci_host *host = mmc_priv(mmc); - writel(MCI_IRQENABLE, host->base + MMCIMASK0); - pm_runtime_put(dev); - } - - return 0; -} -#endif - #ifdef CONFIG_PM static void mmci_save(struct mmci_host *host) { @@ -1856,7 +1826,8 @@ static int mmci_runtime_resume(struct device *dev) #endif static const struct dev_pm_ops mmci_dev_pm_ops = { - SET_SYSTEM_SLEEP_PM_OPS(mmci_suspend, mmci_resume) + SET_SYSTEM_SLEEP_PM_OPS(pm_runtime_force_suspend, + pm_runtime_force_resume) SET_PM_RUNTIME_PM_OPS(mmci_runtime_suspend, mmci_runtime_resume, NULL) }; -- cgit v1.2.3 From d2762090153053bca984ce5f8978953f63390401 Mon Sep 17 00:00:00 2001 From: Ulf Hansson Date: Mon, 17 Mar 2014 13:56:19 +0100 Subject: mmc: mmci: Convert to the mmc gpio API To avoid duplication of code while handling card detect and write protect GPIO pins/irqs, let's convert to use the mmc gpio API. Signed-off-by: Ulf Hansson --- drivers/mmc/host/mmci.c | 97 ++++++++----------------------------------------- drivers/mmc/host/mmci.h | 3 -- 2 files changed, 15 insertions(+), 85 deletions(-) (limited to 'drivers/mmc') diff --git a/drivers/mmc/host/mmci.c b/drivers/mmc/host/mmci.c index a40bf70170fd..ebe991628295 100644 --- a/drivers/mmc/host/mmci.c +++ b/drivers/mmc/host/mmci.c @@ -23,6 +23,7 @@ #include #include #include +#include #include #include #include @@ -1326,35 +1327,18 @@ static void mmci_set_ios(struct mmc_host *mmc, struct mmc_ios *ios) pm_runtime_put_autosuspend(mmc_dev(mmc)); } -static int mmci_get_ro(struct mmc_host *mmc) -{ - struct mmci_host *host = mmc_priv(mmc); - - if (host->gpio_wp == -ENOSYS) - return -ENOSYS; - - return gpio_get_value_cansleep(host->gpio_wp); -} - static int mmci_get_cd(struct mmc_host *mmc) { struct mmci_host *host = mmc_priv(mmc); struct mmci_platform_data *plat = host->plat; - unsigned int status; + unsigned int status = mmc_gpio_get_cd(mmc); - if (host->gpio_cd == -ENOSYS) { + if (status == -ENOSYS) { if (!plat->status) return 1; /* Assume always present */ status = plat->status(mmc_dev(host->mmc)); - } else - status = !!gpio_get_value_cansleep(host->gpio_cd) - ^ plat->cd_invert; - - /* - * Use positive logic throughout - status is zero for no card, - * non-zero for card inserted. - */ + } return status; } @@ -1391,21 +1375,12 @@ static int mmci_sig_volt_switch(struct mmc_host *mmc, struct mmc_ios *ios) return ret; } -static irqreturn_t mmci_cd_irq(int irq, void *dev_id) -{ - struct mmci_host *host = dev_id; - - mmc_detect_change(host->mmc, msecs_to_jiffies(500)); - - return IRQ_HANDLED; -} - static struct mmc_host_ops mmci_ops = { .request = mmci_request, .pre_req = mmci_pre_request, .post_req = mmci_post_request, .set_ios = mmci_set_ios, - .get_ro = mmci_get_ro, + .get_ro = mmc_gpio_get_ro, .get_cd = mmci_get_cd, .start_signal_voltage_switch = mmci_sig_volt_switch, }; @@ -1494,10 +1469,6 @@ static int mmci_probe(struct amba_device *dev, host = mmc_priv(mmc); host->mmc = mmc; - host->gpio_wp = -ENOSYS; - host->gpio_cd = -ENOSYS; - host->gpio_cd_irq = -1; - host->hw_designer = amba_manf(dev); host->hw_revision = amba_rev(dev); dev_dbg(mmc_dev(mmc), "designer ID = 0x%02x\n", host->hw_designer); @@ -1568,6 +1539,9 @@ static int mmci_probe(struct amba_device *dev, mmc->caps = plat->capabilities; mmc->caps2 = plat->capabilities2; + if (!plat->cd_invert) + mmc->caps2 |= MMC_CAP2_CD_ACTIVE_HIGH; + mmc->caps2 |= MMC_CAP2_RO_ACTIVE_HIGH; if (variant->busy_detect) { mmci_ops.card_busy = mmci_card_busy; @@ -1621,49 +1595,23 @@ static int mmci_probe(struct amba_device *dev, goto err_gpio_cd; } if (gpio_is_valid(plat->gpio_cd)) { - ret = gpio_request(plat->gpio_cd, DRIVER_NAME " (cd)"); - if (ret == 0) - ret = gpio_direction_input(plat->gpio_cd); - if (ret == 0) - host->gpio_cd = plat->gpio_cd; - else if (ret != -ENOSYS) + ret = mmc_gpio_request_cd(mmc, plat->gpio_cd, 0); + if (ret) goto err_gpio_cd; - - /* - * A gpio pin that will detect cards when inserted and removed - * will most likely want to trigger on the edges if it is - * 0 when ejected and 1 when inserted (or mutatis mutandis - * for the inverted case) so we request triggers on both - * edges. - */ - ret = request_any_context_irq(gpio_to_irq(plat->gpio_cd), - mmci_cd_irq, - IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING, - DRIVER_NAME " (cd)", host); - if (ret >= 0) - host->gpio_cd_irq = gpio_to_irq(plat->gpio_cd); } if (plat->gpio_wp == -EPROBE_DEFER) { ret = -EPROBE_DEFER; - goto err_gpio_wp; + goto err_gpio_cd; } if (gpio_is_valid(plat->gpio_wp)) { - ret = gpio_request(plat->gpio_wp, DRIVER_NAME " (wp)"); - if (ret == 0) - ret = gpio_direction_input(plat->gpio_wp); - if (ret == 0) - host->gpio_wp = plat->gpio_wp; - else if (ret != -ENOSYS) - goto err_gpio_wp; + ret = mmc_gpio_request_ro(mmc, plat->gpio_wp); + if (ret) + goto err_gpio_cd; } - if ((host->plat->status || host->gpio_cd != -ENOSYS) - && host->gpio_cd_irq < 0) - mmc->caps |= MMC_CAP_NEEDS_POLL; - ret = request_irq(dev->irq[0], mmci_irq, IRQF_SHARED, DRIVER_NAME " (cmd)", host); if (ret) - goto unmap; + goto err_gpio_cd; if (!dev->irq[1]) host->singleirq = true; @@ -1695,14 +1643,6 @@ static int mmci_probe(struct amba_device *dev, irq0_free: free_irq(dev->irq[0], host); - unmap: - if (host->gpio_wp != -ENOSYS) - gpio_free(host->gpio_wp); - err_gpio_wp: - if (host->gpio_cd_irq >= 0) - free_irq(host->gpio_cd_irq, host); - if (host->gpio_cd != -ENOSYS) - gpio_free(host->gpio_cd); err_gpio_cd: iounmap(host->base); clk_disable: @@ -1741,13 +1681,6 @@ static int mmci_remove(struct amba_device *dev) if (!host->singleirq) free_irq(dev->irq[1], host); - if (host->gpio_wp != -ENOSYS) - gpio_free(host->gpio_wp); - if (host->gpio_cd_irq >= 0) - free_irq(host->gpio_cd_irq, host); - if (host->gpio_cd != -ENOSYS) - gpio_free(host->gpio_cd); - iounmap(host->base); clk_disable_unprepare(host->clk); diff --git a/drivers/mmc/host/mmci.h b/drivers/mmc/host/mmci.h index 58b1b8896bf2..8fc5814f938a 100644 --- a/drivers/mmc/host/mmci.h +++ b/drivers/mmc/host/mmci.h @@ -176,9 +176,6 @@ struct mmci_host { struct mmc_data *data; struct mmc_host *mmc; struct clk *clk; - int gpio_cd; - int gpio_wp; - int gpio_cd_irq; bool singleirq; spinlock_t lock; -- cgit v1.2.3 From ef289982f2cf9f36c64b3e64d584b74b6ea2e70b Mon Sep 17 00:00:00 2001 From: Ulf Hansson Date: Mon, 17 Mar 2014 13:56:32 +0100 Subject: mmc: mmci: Convert to devm functions Converting to devm functions to simplify error handling in ->probe() and to cleanup ->remove(). Signed-off-by: Ulf Hansson --- drivers/mmc/host/mmci.c | 52 ++++++++++++++++--------------------------------- 1 file changed, 17 insertions(+), 35 deletions(-) (limited to 'drivers/mmc') diff --git a/drivers/mmc/host/mmci.c b/drivers/mmc/host/mmci.c index ebe991628295..57cfd5f7cb24 100644 --- a/drivers/mmc/host/mmci.c +++ b/drivers/mmc/host/mmci.c @@ -13,6 +13,7 @@ #include #include #include +#include #include #include #include @@ -1456,15 +1457,9 @@ static int mmci_probe(struct amba_device *dev, if (np) mmci_dt_populate_generic_pdata(np, plat); - ret = amba_request_regions(dev, DRIVER_NAME); - if (ret) - goto out; - mmc = mmc_alloc_host(sizeof(struct mmci_host), &dev->dev); - if (!mmc) { - ret = -ENOMEM; - goto rel_regions; - } + if (!mmc) + return -ENOMEM; host = mmc_priv(mmc); host->mmc = mmc; @@ -1500,10 +1495,11 @@ static int mmci_probe(struct amba_device *dev, dev_dbg(mmc_dev(mmc), "eventual mclk rate: %u Hz\n", host->mclk); } + host->phybase = dev->res.start; - host->base = ioremap(dev->res.start, resource_size(&dev->res)); - if (!host->base) { - ret = -ENOMEM; + host->base = devm_ioremap_resource(&dev->dev, &dev->res); + if (IS_ERR(host->base)) { + ret = PTR_ERR(host->base); goto clk_disable; } @@ -1592,34 +1588,35 @@ static int mmci_probe(struct amba_device *dev, if (plat->gpio_cd == -EPROBE_DEFER) { ret = -EPROBE_DEFER; - goto err_gpio_cd; + goto clk_disable; } if (gpio_is_valid(plat->gpio_cd)) { ret = mmc_gpio_request_cd(mmc, plat->gpio_cd, 0); if (ret) - goto err_gpio_cd; + goto clk_disable; } if (plat->gpio_wp == -EPROBE_DEFER) { ret = -EPROBE_DEFER; - goto err_gpio_cd; + goto clk_disable; } if (gpio_is_valid(plat->gpio_wp)) { ret = mmc_gpio_request_ro(mmc, plat->gpio_wp); if (ret) - goto err_gpio_cd; + goto clk_disable; } - ret = request_irq(dev->irq[0], mmci_irq, IRQF_SHARED, DRIVER_NAME " (cmd)", host); + ret = devm_request_irq(&dev->dev, dev->irq[0], mmci_irq, IRQF_SHARED, + DRIVER_NAME " (cmd)", host); if (ret) - goto err_gpio_cd; + goto clk_disable; if (!dev->irq[1]) host->singleirq = true; else { - ret = request_irq(dev->irq[1], mmci_pio_irq, IRQF_SHARED, - DRIVER_NAME " (pio)", host); + ret = devm_request_irq(&dev->dev, dev->irq[1], mmci_pio_irq, + IRQF_SHARED, DRIVER_NAME " (pio)", host); if (ret) - goto irq0_free; + goto clk_disable; } writel(MCI_IRQENABLE, host->base + MMCIMASK0); @@ -1641,17 +1638,10 @@ static int mmci_probe(struct amba_device *dev, return 0; - irq0_free: - free_irq(dev->irq[0], host); - err_gpio_cd: - iounmap(host->base); clk_disable: clk_disable_unprepare(host->clk); host_free: mmc_free_host(mmc); - rel_regions: - amba_release_regions(dev); - out: return ret; } @@ -1677,16 +1667,8 @@ static int mmci_remove(struct amba_device *dev) writel(0, host->base + MMCIDATACTRL); mmci_dma_release(host); - free_irq(dev->irq[0], host); - if (!host->singleirq) - free_irq(dev->irq[1], host); - - iounmap(host->base); clk_disable_unprepare(host->clk); - mmc_free_host(mmc); - - amba_release_regions(dev); } return 0; -- cgit v1.2.3 From ae94cafe293343c2680c638c7af8499d708e4d71 Mon Sep 17 00:00:00 2001 From: Ulf Hansson Date: Tue, 18 Mar 2014 10:46:37 +0100 Subject: mmc: mmci: Add DT bindings for signal direction Some variants have support for indicating the bus signal directions, which currently are configured through platform data. Add corresponding DT bindings to enable us to move away from using the platform data. Signed-off-by: Ulf Hansson Reviewed-by: Linus Walleij --- Documentation/devicetree/bindings/mmc/mmci.txt | 11 ++++++++++- drivers/mmc/host/mmci.c | 11 +++++++++++ 2 files changed, 21 insertions(+), 1 deletion(-) (limited to 'drivers/mmc') diff --git a/Documentation/devicetree/bindings/mmc/mmci.txt b/Documentation/devicetree/bindings/mmc/mmci.txt index ff233d1eb190..9bd2ffa704a7 100644 --- a/Documentation/devicetree/bindings/mmc/mmci.txt +++ b/Documentation/devicetree/bindings/mmc/mmci.txt @@ -4,7 +4,8 @@ The ARM PrimeCell MMCI PL180 and PL181 provides an interface for reading and writing to MultiMedia and SD cards alike. This file documents differences between the core properties described -by mmc.txt and the properties used by the mmci driver. +by mmc.txt and the properties used by the mmci driver. Using "st" as +the prefix for a property, indicates support by the ST Micro variant. Required properties: - compatible : contains "arm,pl18x", "arm,primecell". @@ -18,6 +19,11 @@ Optional properties: - mmc-cap-sd-highspeed : indicates whether SD is high speed capable. - vqmmc-supply : phandle to the regulator device tree node, mentioned as the VCCQ/VDD_IO supply in the eMMC/SD specs. +- st,sig-dir-dat0 : bus signal direction pin used for DAT[0]. +- st,sig-dir-dat2 : bus signal direction pin used for DAT[2]. +- st,sig-dir-dat31 : bus signal direction pin used for DAT[3] and DAT[1]. +- st,sig-dir-dat74 : bus signal direction pin used for DAT[4] to DAT[7]. +- st,sig-dir-cmd : cmd signal direction pin used for CMD. Example: @@ -38,6 +44,9 @@ sdi0_per1@80126000 { mmc-cap-sd-highspeed; mmc-cap-mmc-highspeed; cd-gpios = <&gpio2 31 0x4>; // 95 + st,sig-dir-dat0; + st,sig-dir-dat2; + st,sig-dir-cmd; vmmc-supply = <&ab8500_ldo_aux3_reg>; vqmmc-supply = <&vmmci>; diff --git a/drivers/mmc/host/mmci.c b/drivers/mmc/host/mmci.c index 57cfd5f7cb24..aa26e810b7ad 100644 --- a/drivers/mmc/host/mmci.c +++ b/drivers/mmc/host/mmci.c @@ -1392,6 +1392,17 @@ static void mmci_dt_populate_generic_pdata(struct device_node *np, { int bus_width = 0; + if (of_get_property(np, "st,sig-dir-dat0", NULL)) + pdata->sigdir |= MCI_ST_DATA0DIREN; + if (of_get_property(np, "st,sig-dir-dat2", NULL)) + pdata->sigdir |= MCI_ST_DATA2DIREN; + if (of_get_property(np, "st,sig-dir-dat31", NULL)) + pdata->sigdir |= MCI_ST_DATA31DIREN; + if (of_get_property(np, "st,sig-dir-dat74", NULL)) + pdata->sigdir |= MCI_ST_DATA74DIREN; + if (of_get_property(np, "st,sig-dir-cmd", NULL)) + pdata->sigdir |= MCI_ST_CMDDIREN; + pdata->gpio_wp = of_get_named_gpio(np, "wp-gpios", 0); pdata->gpio_cd = of_get_named_gpio(np, "cd-gpios", 0); -- cgit v1.2.3 From 1a7e99c1fe080cc75ab34e1cbf788ed09b2f58b5 Mon Sep 17 00:00:00 2001 From: Ulf Hansson Date: Mon, 31 Mar 2014 14:19:21 +0200 Subject: mmc: mmci: Add DT bindings for feedback clock pin The ST Micro variant supports the option of using a feedback clock signal in favor of the clockout pin when latching incoming signals on the data bus. Since this is matter of how pins are being routed we need to provide a new DT binding to be able to configure this through DT. Signed-off-by: Ulf Hansson Reviewed-by: Linus Walleij --- Documentation/devicetree/bindings/mmc/mmci.txt | 2 ++ drivers/mmc/host/mmci.c | 2 ++ 2 files changed, 4 insertions(+) (limited to 'drivers/mmc') diff --git a/Documentation/devicetree/bindings/mmc/mmci.txt b/Documentation/devicetree/bindings/mmc/mmci.txt index 9bd2ffa704a7..2c8756fb7755 100644 --- a/Documentation/devicetree/bindings/mmc/mmci.txt +++ b/Documentation/devicetree/bindings/mmc/mmci.txt @@ -24,6 +24,7 @@ Optional properties: - st,sig-dir-dat31 : bus signal direction pin used for DAT[3] and DAT[1]. - st,sig-dir-dat74 : bus signal direction pin used for DAT[4] to DAT[7]. - st,sig-dir-cmd : cmd signal direction pin used for CMD. +- st,sig-pin-fbclk : feedback clock signal pin used. Example: @@ -47,6 +48,7 @@ sdi0_per1@80126000 { st,sig-dir-dat0; st,sig-dir-dat2; st,sig-dir-cmd; + st,sig-pin-fbclk; vmmc-supply = <&ab8500_ldo_aux3_reg>; vqmmc-supply = <&vmmci>; diff --git a/drivers/mmc/host/mmci.c b/drivers/mmc/host/mmci.c index aa26e810b7ad..2ce9111c4627 100644 --- a/drivers/mmc/host/mmci.c +++ b/drivers/mmc/host/mmci.c @@ -1402,6 +1402,8 @@ static void mmci_dt_populate_generic_pdata(struct device_node *np, pdata->sigdir |= MCI_ST_DATA74DIREN; if (of_get_property(np, "st,sig-dir-cmd", NULL)) pdata->sigdir |= MCI_ST_CMDDIREN; + if (of_get_property(np, "st,sig-pin-fbclk", NULL)) + pdata->sigdir |= MCI_ST_FBCLKEN; pdata->gpio_wp = of_get_named_gpio(np, "wp-gpios", 0); pdata->gpio_cd = of_get_named_gpio(np, "cd-gpios", 0); -- cgit v1.2.3 From 78f87df2b4f8760954d7d80603d0cfcbd4759683 Mon Sep 17 00:00:00 2001 From: Ulf Hansson Date: Mon, 17 Mar 2014 15:53:07 +0100 Subject: mmc: mmci: Use the common mmc DT parser Let mmci DT parser only handle the specific bindings related to mmci and extend the DT support by converting to the common mmc DT parser. While both DT and platform data exist, DT takes precedence. If there are supplied DT data, the card detect and write protect GPIOS are enforced to be provided through it. Signed-off-by: Ulf Hansson --- drivers/mmc/host/mmci.c | 92 ++++++++++++++++++------------------------------- 1 file changed, 33 insertions(+), 59 deletions(-) (limited to 'drivers/mmc') diff --git a/drivers/mmc/host/mmci.c b/drivers/mmc/host/mmci.c index 2ce9111c4627..c522308a7343 100644 --- a/drivers/mmc/host/mmci.c +++ b/drivers/mmc/host/mmci.c @@ -1386,12 +1386,9 @@ static struct mmc_host_ops mmci_ops = { .start_signal_voltage_switch = mmci_sig_volt_switch, }; -#ifdef CONFIG_OF static void mmci_dt_populate_generic_pdata(struct device_node *np, struct mmci_platform_data *pdata) { - int bus_width = 0; - if (of_get_property(np, "st,sig-dir-dat0", NULL)) pdata->sigdir |= MCI_ST_DATA0DIREN; if (of_get_property(np, "st,sig-dir-dat2", NULL)) @@ -1404,46 +1401,22 @@ static void mmci_dt_populate_generic_pdata(struct device_node *np, pdata->sigdir |= MCI_ST_CMDDIREN; if (of_get_property(np, "st,sig-pin-fbclk", NULL)) pdata->sigdir |= MCI_ST_FBCLKEN; +} - pdata->gpio_wp = of_get_named_gpio(np, "wp-gpios", 0); - pdata->gpio_cd = of_get_named_gpio(np, "cd-gpios", 0); - - if (of_get_property(np, "cd-inverted", NULL)) - pdata->cd_invert = true; - else - pdata->cd_invert = false; +static int mmci_of_parse(struct device_node *np, struct mmc_host *mmc) +{ + int ret = mmc_of_parse(mmc); - of_property_read_u32(np, "max-frequency", &pdata->f_max); - if (!pdata->f_max) - pr_warn("%s has no 'max-frequency' property\n", np->full_name); + if (ret) + return ret; if (of_get_property(np, "mmc-cap-mmc-highspeed", NULL)) - pdata->capabilities |= MMC_CAP_MMC_HIGHSPEED; + mmc->caps |= MMC_CAP_MMC_HIGHSPEED; if (of_get_property(np, "mmc-cap-sd-highspeed", NULL)) - pdata->capabilities |= MMC_CAP_SD_HIGHSPEED; + mmc->caps |= MMC_CAP_SD_HIGHSPEED; - of_property_read_u32(np, "bus-width", &bus_width); - switch (bus_width) { - case 0 : - /* No bus-width supplied. */ - break; - case 4 : - pdata->capabilities |= MMC_CAP_4_BIT_DATA; - break; - case 8 : - pdata->capabilities |= MMC_CAP_8_BIT_DATA; - break; - default : - pr_warn("%s: Unsupported bus width\n", np->full_name); - } -} -#else -static void mmci_dt_populate_generic_pdata(struct device_node *np, - struct mmci_platform_data *pdata) -{ - return; + return 0; } -#endif static int mmci_probe(struct amba_device *dev, const struct amba_id *id) @@ -1474,6 +1447,10 @@ static int mmci_probe(struct amba_device *dev, if (!mmc) return -ENOMEM; + ret = mmci_of_parse(np, mmc); + if (ret) + goto host_free; + host = mmc_priv(mmc); host->mmc = mmc; @@ -1526,14 +1503,15 @@ static int mmci_probe(struct amba_device *dev, else mmc->f_min = DIV_ROUND_UP(host->mclk, 512); /* - * If the platform data supplies a maximum operating - * frequency, this takes precedence. Else, we fall back - * to using the module parameter, which has a (low) - * default value in case it is not specified. Either - * value must not exceed the clock rate into the block, - * of course. + * If no maximum operating frequency is supplied, fall back to use + * the module parameter, which has a (low) default value in case it + * is not specified. Either value must not exceed the clock rate into + * the block, of course. Also note that DT takes precedence over + * platform data. */ - if (plat->f_max) + if (mmc->f_max) + mmc->f_max = min(host->mclk, mmc->f_max); + else if (plat->f_max) mmc->f_max = min(host->mclk, plat->f_max); else mmc->f_max = min(host->mclk, fmax); @@ -1546,11 +1524,14 @@ static int mmci_probe(struct amba_device *dev, else if (plat->ocr_mask) dev_warn(mmc_dev(mmc), "Platform OCR mask is ignored\n"); - mmc->caps = plat->capabilities; - mmc->caps2 = plat->capabilities2; - if (!plat->cd_invert) - mmc->caps2 |= MMC_CAP2_CD_ACTIVE_HIGH; - mmc->caps2 |= MMC_CAP2_RO_ACTIVE_HIGH; + /* DT takes precedence over platform data. */ + mmc->caps = np ? mmc->caps : plat->capabilities; + mmc->caps2 = np ? mmc->caps2 : plat->capabilities2; + if (!np) { + if (!plat->cd_invert) + mmc->caps2 |= MMC_CAP2_CD_ACTIVE_HIGH; + mmc->caps2 |= MMC_CAP2_RO_ACTIVE_HIGH; + } if (variant->busy_detect) { mmci_ops.card_busy = mmci_card_busy; @@ -1562,7 +1543,7 @@ static int mmci_probe(struct amba_device *dev, mmc->ops = &mmci_ops; /* We support these PM capabilities. */ - mmc->pm_caps = MMC_PM_KEEP_POWER; + mmc->pm_caps |= MMC_PM_KEEP_POWER; /* * We can do SGIO @@ -1599,20 +1580,13 @@ static int mmci_probe(struct amba_device *dev, writel(0, host->base + MMCIMASK1); writel(0xfff, host->base + MMCICLEAR); - if (plat->gpio_cd == -EPROBE_DEFER) { - ret = -EPROBE_DEFER; - goto clk_disable; - } - if (gpio_is_valid(plat->gpio_cd)) { + /* If DT, cd/wp gpios must be supplied through it. */ + if (!np && gpio_is_valid(plat->gpio_cd)) { ret = mmc_gpio_request_cd(mmc, plat->gpio_cd, 0); if (ret) goto clk_disable; } - if (plat->gpio_wp == -EPROBE_DEFER) { - ret = -EPROBE_DEFER; - goto clk_disable; - } - if (gpio_is_valid(plat->gpio_wp)) { + if (!np && gpio_is_valid(plat->gpio_wp)) { ret = mmc_gpio_request_ro(mmc, plat->gpio_wp); if (ret) goto clk_disable; -- cgit v1.2.3 From 9dd8a8b81c7c947e9be29ca047f10ac9910a41bb Mon Sep 17 00:00:00 2001 From: Ulf Hansson Date: Wed, 19 Mar 2014 13:54:18 +0100 Subject: mmc: mmci: Enable MMC_CAP_CMD23 This is pure software configuration, which mmci has been supporting for a while. Let's enable it as default so we can take benefit from it. Signed-off-by: Ulf Hansson --- drivers/mmc/host/mmci.c | 3 +++ 1 file changed, 3 insertions(+) (limited to 'drivers/mmc') diff --git a/drivers/mmc/host/mmci.c b/drivers/mmc/host/mmci.c index c522308a7343..0d3ee08662a9 100644 --- a/drivers/mmc/host/mmci.c +++ b/drivers/mmc/host/mmci.c @@ -1533,6 +1533,9 @@ static int mmci_probe(struct amba_device *dev, mmc->caps2 |= MMC_CAP2_RO_ACTIVE_HIGH; } + /* We support these capabilities. */ + mmc->caps |= MMC_CAP_CMD23; + if (variant->busy_detect) { mmci_ops.card_busy = mmci_card_busy; mmci_write_datactrlreg(host, MCI_ST_DPSM_BUSYMODE); -- cgit v1.2.3 From 4593df29b94b31de931dc20d7da2e6c468c8d473 Mon Sep 17 00:00:00 2001 From: Ulf Hansson Date: Fri, 21 Mar 2014 10:13:05 +0100 Subject: mmc: mmci: Enforce DT for signal direction and feedback clock Remove the option to provide signal direction configuration and feeback clock as platform data, enforce it through DT. Signed-off-by: Ulf Hansson --- drivers/mmc/host/mmci.c | 34 ++++++++++++++-------------------- drivers/mmc/host/mmci.h | 11 +++++++++++ include/linux/amba/mmci.h | 16 ---------------- 3 files changed, 25 insertions(+), 36 deletions(-) (limited to 'drivers/mmc') diff --git a/drivers/mmc/host/mmci.c b/drivers/mmc/host/mmci.c index 0d3ee08662a9..c0353f84d5be 100644 --- a/drivers/mmc/host/mmci.c +++ b/drivers/mmc/host/mmci.c @@ -1287,7 +1287,7 @@ static void mmci_set_ios(struct mmc_host *mmc, struct mmc_ios *ios) * indicating signal direction for the signals in * the SD/MMC bus and feedback-clock usage. */ - pwr |= host->plat->sigdir; + pwr |= host->pwr_reg_add; if (ios->bus_width == MMC_BUS_WIDTH_4) pwr &= ~MCI_ST_DATA74DIREN; @@ -1386,29 +1386,26 @@ static struct mmc_host_ops mmci_ops = { .start_signal_voltage_switch = mmci_sig_volt_switch, }; -static void mmci_dt_populate_generic_pdata(struct device_node *np, - struct mmci_platform_data *pdata) +static int mmci_of_parse(struct device_node *np, struct mmc_host *mmc) { + struct mmci_host *host = mmc_priv(mmc); + int ret = mmc_of_parse(mmc); + + if (ret) + return ret; + if (of_get_property(np, "st,sig-dir-dat0", NULL)) - pdata->sigdir |= MCI_ST_DATA0DIREN; + host->pwr_reg_add |= MCI_ST_DATA0DIREN; if (of_get_property(np, "st,sig-dir-dat2", NULL)) - pdata->sigdir |= MCI_ST_DATA2DIREN; + host->pwr_reg_add |= MCI_ST_DATA2DIREN; if (of_get_property(np, "st,sig-dir-dat31", NULL)) - pdata->sigdir |= MCI_ST_DATA31DIREN; + host->pwr_reg_add |= MCI_ST_DATA31DIREN; if (of_get_property(np, "st,sig-dir-dat74", NULL)) - pdata->sigdir |= MCI_ST_DATA74DIREN; + host->pwr_reg_add |= MCI_ST_DATA74DIREN; if (of_get_property(np, "st,sig-dir-cmd", NULL)) - pdata->sigdir |= MCI_ST_CMDDIREN; + host->pwr_reg_add |= MCI_ST_CMDDIREN; if (of_get_property(np, "st,sig-pin-fbclk", NULL)) - pdata->sigdir |= MCI_ST_FBCLKEN; -} - -static int mmci_of_parse(struct device_node *np, struct mmc_host *mmc) -{ - int ret = mmc_of_parse(mmc); - - if (ret) - return ret; + host->pwr_reg_add |= MCI_ST_FBCLKEN; if (of_get_property(np, "mmc-cap-mmc-highspeed", NULL)) mmc->caps |= MMC_CAP_MMC_HIGHSPEED; @@ -1440,9 +1437,6 @@ static int mmci_probe(struct amba_device *dev, return -ENOMEM; } - if (np) - mmci_dt_populate_generic_pdata(np, plat); - mmc = mmc_alloc_host(sizeof(struct mmci_host), &dev->dev); if (!mmc) return -ENOMEM; diff --git a/drivers/mmc/host/mmci.h b/drivers/mmc/host/mmci.h index 8fc5814f938a..347d942d740b 100644 --- a/drivers/mmc/host/mmci.h +++ b/drivers/mmc/host/mmci.h @@ -13,6 +13,16 @@ #define MCI_PWR_ON 0x03 #define MCI_OD (1 << 6) #define MCI_ROD (1 << 7) +/* + * The ST Micro version does not have ROD and reuse the voltage registers for + * direction settings. + */ +#define MCI_ST_DATA2DIREN (1 << 2) +#define MCI_ST_CMDDIREN (1 << 3) +#define MCI_ST_DATA0DIREN (1 << 4) +#define MCI_ST_DATA31DIREN (1 << 5) +#define MCI_ST_FBCLKEN (1 << 7) +#define MCI_ST_DATA74DIREN (1 << 8) #define MMCICLOCK 0x004 #define MCI_CLK_ENABLE (1 << 8) @@ -183,6 +193,7 @@ struct mmci_host { unsigned int mclk; unsigned int cclk; u32 pwr_reg; + u32 pwr_reg_add; u32 clk_reg; u32 datactrl_reg; u32 busy_status; diff --git a/include/linux/amba/mmci.h b/include/linux/amba/mmci.h index 32a89cf5ec45..0d3ff95b3b4c 100644 --- a/include/linux/amba/mmci.h +++ b/include/linux/amba/mmci.h @@ -6,19 +6,6 @@ #include - -/* - * These defines is places here due to access is needed from machine - * configuration files. The ST Micro version does not have ROD and - * reuse the voltage registers for direction settings. - */ -#define MCI_ST_DATA2DIREN (1 << 2) -#define MCI_ST_CMDDIREN (1 << 3) -#define MCI_ST_DATA0DIREN (1 << 4) -#define MCI_ST_DATA31DIREN (1 << 5) -#define MCI_ST_FBCLKEN (1 << 7) -#define MCI_ST_DATA74DIREN (1 << 8) - /* Just some dummy forwarding */ struct dma_chan; @@ -45,8 +32,6 @@ struct dma_chan; * @capabilities: the capabilities of the block as implemented in * this platform, signify anything MMC_CAP_* from mmc/host.h * @capabilities2: more capabilities, MMC_CAP2_* from mmc/host.h - * @sigdir: a bit field indicating for what bits in the MMC bus the host - * should enable signal direction indication. * @dma_filter: function used to select an appropriate RX and TX * DMA channel to be used for DMA, if and only if you're deploying the * generic DMA engine @@ -69,7 +54,6 @@ struct mmci_platform_data { bool cd_invert; unsigned long capabilities; unsigned long capabilities2; - u32 sigdir; bool (*dma_filter)(struct dma_chan *chan, void *filter_param); void *dma_rx_param; void *dma_tx_param; -- cgit v1.2.3 From 3faf80dfa342e98b5780e0b78b7a670c7b61a9be Mon Sep 17 00:00:00 2001 From: Ulf Hansson Date: Fri, 21 Mar 2014 10:29:10 +0100 Subject: mmc: mmci: Enforce mmc capabilities through DT Remove the option to provide the flags for mmc capabilities as platform data, enforce it through DT. Signed-off-by: Ulf Hansson --- drivers/mmc/host/mmci.c | 2 -- include/linux/amba/mmci.h | 5 ----- 2 files changed, 7 deletions(-) (limited to 'drivers/mmc') diff --git a/drivers/mmc/host/mmci.c b/drivers/mmc/host/mmci.c index c0353f84d5be..9c60325f1a30 100644 --- a/drivers/mmc/host/mmci.c +++ b/drivers/mmc/host/mmci.c @@ -1519,8 +1519,6 @@ static int mmci_probe(struct amba_device *dev, dev_warn(mmc_dev(mmc), "Platform OCR mask is ignored\n"); /* DT takes precedence over platform data. */ - mmc->caps = np ? mmc->caps : plat->capabilities; - mmc->caps2 = np ? mmc->caps2 : plat->capabilities2; if (!np) { if (!plat->cd_invert) mmc->caps2 |= MMC_CAP2_CD_ACTIVE_HIGH; diff --git a/include/linux/amba/mmci.h b/include/linux/amba/mmci.h index 0d3ff95b3b4c..b992fc931295 100644 --- a/include/linux/amba/mmci.h +++ b/include/linux/amba/mmci.h @@ -29,9 +29,6 @@ struct dma_chan; * @gpio_wp: read this GPIO pin to see if the card is write protected * @gpio_cd: read this GPIO pin to detect card insertion * @cd_invert: true if the gpio_cd pin value is active low - * @capabilities: the capabilities of the block as implemented in - * this platform, signify anything MMC_CAP_* from mmc/host.h - * @capabilities2: more capabilities, MMC_CAP2_* from mmc/host.h * @dma_filter: function used to select an appropriate RX and TX * DMA channel to be used for DMA, if and only if you're deploying the * generic DMA engine @@ -52,8 +49,6 @@ struct mmci_platform_data { int gpio_wp; int gpio_cd; bool cd_invert; - unsigned long capabilities; - unsigned long capabilities2; bool (*dma_filter)(struct dma_chan *chan, void *filter_param); void *dma_rx_param; void *dma_tx_param; -- cgit v1.2.3 From 5080a08d0f8a4b2ba3a15e5ddc5ece84a444cad8 Mon Sep 17 00:00:00 2001 From: Ulf Hansson Date: Fri, 21 Mar 2014 10:46:39 +0100 Subject: mmc: mmci: Enforce max frequency configuration through DT Remove the option to provide a maximum frequency as platform data, enforce it through DT. Signed-off-by: Ulf Hansson --- drivers/mmc/host/mmci.c | 5 +---- include/linux/amba/mmci.h | 4 ---- 2 files changed, 1 insertion(+), 8 deletions(-) (limited to 'drivers/mmc') diff --git a/drivers/mmc/host/mmci.c b/drivers/mmc/host/mmci.c index 9c60325f1a30..758efea184c9 100644 --- a/drivers/mmc/host/mmci.c +++ b/drivers/mmc/host/mmci.c @@ -1500,13 +1500,10 @@ static int mmci_probe(struct amba_device *dev, * If no maximum operating frequency is supplied, fall back to use * the module parameter, which has a (low) default value in case it * is not specified. Either value must not exceed the clock rate into - * the block, of course. Also note that DT takes precedence over - * platform data. + * the block, of course. */ if (mmc->f_max) mmc->f_max = min(host->mclk, mmc->f_max); - else if (plat->f_max) - mmc->f_max = min(host->mclk, plat->f_max); else mmc->f_max = min(host->mclk, fmax); dev_dbg(mmc_dev(mmc), "clocking block at %u Hz\n", mmc->f_max); diff --git a/include/linux/amba/mmci.h b/include/linux/amba/mmci.h index b992fc931295..3f95d32d5277 100644 --- a/include/linux/amba/mmci.h +++ b/include/linux/amba/mmci.h @@ -12,9 +12,6 @@ struct dma_chan; /** * struct mmci_platform_data - platform configuration for the MMCI * (also known as PL180) block. - * @f_max: the maximum operational frequency for this host in this - * platform configuration. When this is specified it takes precedence - * over the module parameter for the same frequency. * @ocr_mask: available voltages on the 4 pins from the block, this * is ignored if a regulator is used, see the MMC_VDD_* masks in * mmc/host.h @@ -42,7 +39,6 @@ struct dma_chan; * bidirectional channel */ struct mmci_platform_data { - unsigned int f_max; unsigned int ocr_mask; int (*ios_handler)(struct device *, struct mmc_ios *); unsigned int (*status)(struct device *); -- cgit v1.2.3 From 8c3a05b489ef097f86bf87c64192456553f57781 Mon Sep 17 00:00:00 2001 From: Ulf Hansson Date: Tue, 20 May 2014 06:45:54 +0200 Subject: mmc: mmci: Enforce DMA configuration through DT Remove the option to provide DMA configuration as platform data, enforce it through DT. Signed-off-by: Ulf Hansson Cc: Russell King Cc: Roland Stigge Acked-by: Arnd Bergmann --- arch/arm/mach-lpc32xx/phy3250.c | 3 --- drivers/mmc/host/mmci.c | 24 +----------------------- include/linux/amba/mmci.h | 17 ----------------- 3 files changed, 1 insertion(+), 43 deletions(-) (limited to 'drivers/mmc') diff --git a/arch/arm/mach-lpc32xx/phy3250.c b/arch/arm/mach-lpc32xx/phy3250.c index 34932e0e31fa..7858d5b6f6ce 100644 --- a/arch/arm/mach-lpc32xx/phy3250.c +++ b/arch/arm/mach-lpc32xx/phy3250.c @@ -202,9 +202,6 @@ static struct mmci_platform_data lpc32xx_mmci_data = { .ocr_mask = MMC_VDD_30_31 | MMC_VDD_31_32 | MMC_VDD_32_33 | MMC_VDD_33_34, .ios_handler = mmc_handle_ios, - .dma_filter = NULL, - /* No DMA for now since AMBA PL080 dmaengine driver only does scatter - * gather, and the MMCI driver doesn't do it this way */ }; static struct lpc32xx_slc_platform_data lpc32xx_slc_data = { diff --git a/drivers/mmc/host/mmci.c b/drivers/mmc/host/mmci.c index 758efea184c9..a084edd37af5 100644 --- a/drivers/mmc/host/mmci.c +++ b/drivers/mmc/host/mmci.c @@ -366,7 +366,6 @@ static void mmci_init_sg(struct mmci_host *host, struct mmc_data *data) #ifdef CONFIG_DMA_ENGINE static void mmci_dma_setup(struct mmci_host *host) { - struct mmci_platform_data *plat = host->plat; const char *rxname, *txname; dma_cap_mask_t mask; @@ -380,25 +379,6 @@ static void mmci_dma_setup(struct mmci_host *host) dma_cap_zero(mask); dma_cap_set(DMA_SLAVE, mask); - if (plat && plat->dma_filter) { - if (!host->dma_rx_channel && plat->dma_rx_param) { - host->dma_rx_channel = dma_request_channel(mask, - plat->dma_filter, - plat->dma_rx_param); - /* E.g if no DMA hardware is present */ - if (!host->dma_rx_channel) - dev_err(mmc_dev(host->mmc), "no RX DMA channel\n"); - } - - if (!host->dma_tx_channel && plat->dma_tx_param) { - host->dma_tx_channel = dma_request_channel(mask, - plat->dma_filter, - plat->dma_tx_param); - if (!host->dma_tx_channel) - dev_warn(mmc_dev(host->mmc), "no TX DMA channel\n"); - } - } - /* * If only an RX channel is specified, the driver will * attempt to use it bidirectionally, however if it is @@ -446,11 +426,9 @@ static void mmci_dma_setup(struct mmci_host *host) */ static inline void mmci_dma_release(struct mmci_host *host) { - struct mmci_platform_data *plat = host->plat; - if (host->dma_rx_channel) dma_release_channel(host->dma_rx_channel); - if (host->dma_tx_channel && plat->dma_tx_param) + if (host->dma_tx_channel) dma_release_channel(host->dma_tx_channel); host->dma_rx_channel = host->dma_tx_channel = NULL; } diff --git a/include/linux/amba/mmci.h b/include/linux/amba/mmci.h index 3f95d32d5277..8c98113069ce 100644 --- a/include/linux/amba/mmci.h +++ b/include/linux/amba/mmci.h @@ -6,9 +6,6 @@ #include -/* Just some dummy forwarding */ -struct dma_chan; - /** * struct mmci_platform_data - platform configuration for the MMCI * (also known as PL180) block. @@ -26,17 +23,6 @@ struct dma_chan; * @gpio_wp: read this GPIO pin to see if the card is write protected * @gpio_cd: read this GPIO pin to detect card insertion * @cd_invert: true if the gpio_cd pin value is active low - * @dma_filter: function used to select an appropriate RX and TX - * DMA channel to be used for DMA, if and only if you're deploying the - * generic DMA engine - * @dma_rx_param: parameter passed to the DMA allocation - * filter in order to select an appropriate RX channel. If - * there is a bidirectional RX+TX channel, then just specify - * this and leave dma_tx_param set to NULL - * @dma_tx_param: parameter passed to the DMA allocation - * filter in order to select an appropriate TX channel. If this - * is NULL the driver will attempt to use the RX channel as a - * bidirectional channel */ struct mmci_platform_data { unsigned int ocr_mask; @@ -45,9 +31,6 @@ struct mmci_platform_data { int gpio_wp; int gpio_cd; bool cd_invert; - bool (*dma_filter)(struct dma_chan *chan, void *filter_param); - void *dma_rx_param; - void *dma_tx_param; }; #endif -- cgit v1.2.3