From 6c56e7a0fff166904ce2715f7ab1746460c1f11b Mon Sep 17 00:00:00 2001 From: Guennadi Liakhovetski Date: Sat, 16 Feb 2013 16:21:16 +0100 Subject: mmc: provide a standard MMC device-tree binding parser centrally MMC defines a number of standard DT bindings. Having each driver parse them individually adds code redundancy and is error prone. Provide a standard function to unify the parsing. After all drivers are converted to using it instead of their own parsers, this function can be integrated into mmc_alloc_host(). Signed-off-by: Guennadi Liakhovetski Signed-off-by: Chris Ball --- drivers/mmc/core/host.c | 110 ++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 110 insertions(+) (limited to 'drivers/mmc/core/host.c') diff --git a/drivers/mmc/core/host.c b/drivers/mmc/core/host.c index ee2e16b17017..9c53452e73e1 100644 --- a/drivers/mmc/core/host.c +++ b/drivers/mmc/core/host.c @@ -15,6 +15,8 @@ #include #include #include +#include +#include #include #include #include @@ -23,6 +25,7 @@ #include #include +#include #include "core.h" #include "host.h" @@ -294,6 +297,113 @@ static inline void mmc_host_clk_sysfs_init(struct mmc_host *host) #endif +/** + * mmc_of_parse() - parse host's device-tree node + * @host: host whose node should be parsed. + * + * To keep the rest of the MMC subsystem unaware of whether DT has been + * used to to instantiate and configure this host instance or not, we + * parse the properties and set respective generic mmc-host flags and + * parameters. + */ +void mmc_of_parse(struct mmc_host *host) +{ + struct device_node *np; + u32 bus_width; + bool explicit_inv_wp, gpio_inv_wp = false; + enum of_gpio_flags flags; + int len, ret, gpio; + + if (!host->parent || !host->parent->of_node) + return; + + np = host->parent->of_node; + + /* "bus-width" is translated to MMC_CAP_*_BIT_DATA flags */ + if (of_property_read_u32(np, "bus-width", &bus_width) < 0) { + dev_dbg(host->parent, + "\"bus-width\" property is missing, assuming 1 bit.\n"); + bus_width = 1; + } + + switch (bus_width) { + case 8: + host->caps |= MMC_CAP_8_BIT_DATA; + /* Hosts capable of 8-bit transfers can also do 4 bits */ + case 4: + host->caps |= MMC_CAP_4_BIT_DATA; + break; + case 1: + break; + default: + dev_err(host->parent, + "Invalid \"bus-width\" value %ud!\n", bus_width); + } + + /* f_max is obtained from the optional "max-frequency" property */ + of_property_read_u32(np, "max-frequency", &host->f_max); + + /* + * Configure CD and WP pins. They are both by default active low to + * match the SDHCI spec. If GPIOs are provided for CD and / or WP, the + * mmc-gpio helpers are used to attach, configure and use them. If + * polarity inversion is specified in DT, one of MMC_CAP2_CD_ACTIVE_HIGH + * and MMC_CAP2_RO_ACTIVE_HIGH capability-2 flags is set. If the + * "broken-cd" property is provided, the MMC_CAP_NEEDS_POLL capability + * is set. If the "non-removable" property is found, the + * MMC_CAP_NONREMOVABLE capability is set and no card-detection + * configuration is performed. + */ + + /* Parse Card Detection */ + if (of_find_property(np, "non-removable", &len)) { + host->caps |= MMC_CAP_NONREMOVABLE; + } else { + bool explicit_inv_cd, gpio_inv_cd = false; + + explicit_inv_cd = of_property_read_bool(np, "cd-inverted"); + + if (of_find_property(np, "broken-cd", &len)) + host->caps |= MMC_CAP_NEEDS_POLL; + + gpio = of_get_named_gpio_flags(np, "cd-gpios", 0, &flags); + if (gpio_is_valid(gpio)) { + if (!(flags & OF_GPIO_ACTIVE_LOW)) + gpio_inv_cd = true; + + ret = mmc_gpio_request_cd(host, gpio); + if (ret < 0) + dev_err(host->parent, + "Failed to request CD GPIO #%d: %d!\n", + gpio, ret); + else + dev_info(host->parent, "Got CD GPIO #%d.\n", + gpio); + } + + if (explicit_inv_cd ^ gpio_inv_cd) + host->caps2 |= MMC_CAP2_CD_ACTIVE_HIGH; + } + + /* Parse Write Protection */ + explicit_inv_wp = of_property_read_bool(np, "wp-inverted"); + + gpio = of_get_named_gpio_flags(np, "wp-gpios", 0, &flags); + if (gpio_is_valid(gpio)) { + if (!(flags & OF_GPIO_ACTIVE_LOW)) + gpio_inv_wp = true; + + ret = mmc_gpio_request_ro(host, gpio); + if (ret < 0) + dev_err(host->parent, + "Failed to request WP GPIO: %d!\n", ret); + } + if (explicit_inv_wp ^ gpio_inv_wp) + host->caps2 |= MMC_CAP2_RO_ACTIVE_HIGH; +} + +EXPORT_SYMBOL(mmc_of_parse); + /** * mmc_alloc_host - initialise the per-host structure. * @extra: sizeof private data structure -- cgit v1.2.3 From 2fdb6e2d9bf4b599d1cf8bc2b7874a06608fc7ee Mon Sep 17 00:00:00 2001 From: Guennadi Liakhovetski Date: Fri, 15 Feb 2013 16:14:01 +0100 Subject: mmc: add DT bindings for more MMC capability flags Many MMC capability flags are platform-dependent and are traditionally set in platform data. With DT often each such capability requires a special binding. Add bindings for MMC_CAP_SD_HIGHSPEED, MMC_CAP_MMC_HIGHSPEED, MMC_CAP_POWER_OFF_CARD and MMC_CAP_SDIO_IRQ capabilities. Also add code to DT parser to look up "keep-power-in-suspend" and "enable-sdio-wakeup" bindings and set MMC_PM_KEEP_POWER and MMC_PM_WAKE_SDIO_IRQ respectively, if found. Signed-off-by: Guennadi Liakhovetski Signed-off-by: Chris Ball --- Documentation/devicetree/bindings/mmc/mmc.txt | 4 ++++ drivers/mmc/core/host.c | 13 +++++++++++++ 2 files changed, 17 insertions(+) (limited to 'drivers/mmc/core/host.c') diff --git a/Documentation/devicetree/bindings/mmc/mmc.txt b/Documentation/devicetree/bindings/mmc/mmc.txt index 654b705fc5b7..85aada2263d5 100644 --- a/Documentation/devicetree/bindings/mmc/mmc.txt +++ b/Documentation/devicetree/bindings/mmc/mmc.txt @@ -24,6 +24,10 @@ Optional properties: - max-frequency: maximum operating clock frequency - no-1-8-v: when present, denotes that 1.8v card voltage is not supported on this system, even if the controller claims it is. +- cap-sd-highspeed: SD high-speed timing is supported +- cap-mmc-highspeed: MMC high-speed timing is supported +- cap-power-off-card: powering off the card is safe +- cap-sdio-irq: enable SDIO IRQ signalling on this interface *NOTE* on CD and WP polarity. To use common for all SD/MMC host controllers line polarity properties, we have to fix the meaning of the "normal" and "inverted" diff --git a/drivers/mmc/core/host.c b/drivers/mmc/core/host.c index 9c53452e73e1..821cd8224137 100644 --- a/drivers/mmc/core/host.c +++ b/drivers/mmc/core/host.c @@ -400,6 +400,19 @@ void mmc_of_parse(struct mmc_host *host) } if (explicit_inv_wp ^ gpio_inv_wp) host->caps2 |= MMC_CAP2_RO_ACTIVE_HIGH; + + if (of_find_property(np, "cap-sd-highspeed", &len)) + host->caps |= MMC_CAP_SD_HIGHSPEED; + if (of_find_property(np, "cap-mmc-highspeed", &len)) + host->caps |= MMC_CAP_MMC_HIGHSPEED; + if (of_find_property(np, "cap-power-off-card", &len)) + host->caps |= MMC_CAP_POWER_OFF_CARD; + if (of_find_property(np, "cap-sdio-irq", &len)) + host->caps |= MMC_CAP_SDIO_IRQ; + if (of_find_property(np, "keep-power-in-suspend", &len)) + host->pm_caps |= MMC_PM_KEEP_POWER; + if (of_find_property(np, "enable-sdio-wakeup", &len)) + host->pm_caps |= MMC_PM_WAKE_SDIO_IRQ; } EXPORT_SYMBOL(mmc_of_parse); -- cgit v1.2.3 From 803d9e043dc31ea2d26442618f0eb020550f8e08 Mon Sep 17 00:00:00 2001 From: Tejun Heo Date: Wed, 27 Feb 2013 17:04:32 -0800 Subject: mmc: convert to idr_alloc() Convert to the much saner new idr interface. Signed-off-by: Tejun Heo Cc: Chris Ball Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/mmc/core/host.c | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) (limited to 'drivers/mmc/core/host.c') diff --git a/drivers/mmc/core/host.c b/drivers/mmc/core/host.c index 821cd8224137..2a3593d9f87d 100644 --- a/drivers/mmc/core/host.c +++ b/drivers/mmc/core/host.c @@ -429,19 +429,20 @@ struct mmc_host *mmc_alloc_host(int extra, struct device *dev) int err; struct mmc_host *host; - if (!idr_pre_get(&mmc_host_idr, GFP_KERNEL)) - return NULL; - host = kzalloc(sizeof(struct mmc_host) + extra, GFP_KERNEL); if (!host) return NULL; /* scanning will be enabled when we're ready */ host->rescan_disable = 1; + idr_preload(GFP_KERNEL); spin_lock(&mmc_host_lock); - err = idr_get_new(&mmc_host_idr, host, &host->index); + err = idr_alloc(&mmc_host_idr, host, 0, 0, GFP_NOWAIT); + if (err >= 0) + host->index = err; spin_unlock(&mmc_host_lock); - if (err) + idr_preload_end(); + if (err < 0) goto free; dev_set_name(&host->class_dev, "mmc%d", host->index); -- cgit v1.2.3