mmc: Add SDIO function devicetree subnode parsing
authorSascha Hauer <s.hauer@pengutronix.de>
Mon, 30 Jun 2014 09:07:25 +0000 (11:07 +0200)
committerUlf Hansson <ulf.hansson@linaro.org>
Mon, 19 Jan 2015 08:56:26 +0000 (09:56 +0100)
This adds SDIO devicetree subnode parsing to the mmc core. While
SDIO devices are runtime probable they sometimes need nonprobable
additional information on embedded systems, like an additional gpio
interrupt or a clock. This patch makes it possible to supply this
information from the devicetree. SDIO drivers will find a pointer
to the devicenode in their devices of_node pointer.

Signed-off-by: Sascha Hauer <s.hauer@pengutronix.de>
[hdegoede@redhat.com: Misc. cleanups]
Signed-off-by: Hans de Goede <hdegoede@redhat.com>
Signed-off-by: Ulf Hansson <ulf.hansson@linaro.org>
drivers/mmc/core/bus.c
drivers/mmc/core/core.c
drivers/mmc/core/core.h
drivers/mmc/core/sdio_bus.c

index 86d271148528862a0facaf7721816e078be06904..c5ef10065a4ae5785047381ee44597f6f5b43b4e 100644 (file)
@@ -16,6 +16,7 @@
 #include <linux/err.h>
 #include <linux/slab.h>
 #include <linux/stat.h>
+#include <linux/of.h>
 #include <linux/pm_runtime.h>
 
 #include <linux/mmc/card.h>
@@ -321,6 +322,8 @@ int mmc_add_card(struct mmc_card *card)
 #endif
        mmc_init_context_info(card->host);
 
+       card->dev.of_node = mmc_of_find_child_device(card->host, 0);
+
        ret = device_add(&card->dev);
        if (ret)
                return ret;
@@ -349,6 +352,7 @@ void mmc_remove_card(struct mmc_card *card)
                                mmc_hostname(card->host), card->rca);
                }
                device_del(&card->dev);
+               of_node_put(card->dev.of_node);
        }
 
        put_device(&card->dev);
index 9584bffa8b227ed01ea7286542eb269d4b59a5b8..d3bfbdfab05212810cf8f3059bb5c948d428f866 100644 (file)
@@ -1232,6 +1232,34 @@ EXPORT_SYMBOL(mmc_of_parse_voltage);
 
 #endif /* CONFIG_OF */
 
+static int mmc_of_get_func_num(struct device_node *node)
+{
+       u32 reg;
+       int ret;
+
+       ret = of_property_read_u32(node, "reg", &reg);
+       if (ret < 0)
+               return ret;
+
+       return reg;
+}
+
+struct device_node *mmc_of_find_child_device(struct mmc_host *host,
+               unsigned func_num)
+{
+       struct device_node *node;
+
+       if (!host->parent || !host->parent->of_node)
+               return NULL;
+
+       for_each_child_of_node(host->parent->of_node, node) {
+               if (mmc_of_get_func_num(node) == func_num)
+                       return node;
+       }
+
+       return NULL;
+}
+
 #ifdef CONFIG_REGULATOR
 
 /**
index d76597c65e3a64105e9f6728b7a81b417ab2b969..b528c0e5b264185c22118889bfed9c48a8de749a 100644 (file)
@@ -32,6 +32,9 @@ struct mmc_bus_ops {
 void mmc_attach_bus(struct mmc_host *host, const struct mmc_bus_ops *ops);
 void mmc_detach_bus(struct mmc_host *host);
 
+struct device_node *mmc_of_find_child_device(struct mmc_host *host,
+               unsigned func_num);
+
 void mmc_init_erase(struct mmc_card *card);
 
 void mmc_set_chip_select(struct mmc_host *host, int mode);
index 60885316afbae7051390b0c86fcf5659173b9376..bee02e644d620b956e8bd4a21a856f373393ac47 100644 (file)
@@ -22,7 +22,9 @@
 #include <linux/mmc/card.h>
 #include <linux/mmc/host.h>
 #include <linux/mmc/sdio_func.h>
+#include <linux/of.h>
 
+#include "core.h"
 #include "sdio_cis.h"
 #include "sdio_bus.h"
 
@@ -295,6 +297,13 @@ static void sdio_acpi_set_handle(struct sdio_func *func)
 static inline void sdio_acpi_set_handle(struct sdio_func *func) {}
 #endif
 
+static void sdio_set_of_node(struct sdio_func *func)
+{
+       struct mmc_host *host = func->card->host;
+
+       func->dev.of_node = mmc_of_find_child_device(host, func->num);
+}
+
 /*
  * Register a new SDIO function with the driver model.
  */
@@ -304,6 +313,7 @@ int sdio_add_func(struct sdio_func *func)
 
        dev_set_name(&func->dev, "%s:%d", mmc_card_id(func->card), func->num);
 
+       sdio_set_of_node(func);
        sdio_acpi_set_handle(func);
        ret = device_add(&func->dev);
        if (ret == 0) {
@@ -327,6 +337,7 @@ void sdio_remove_func(struct sdio_func *func)
 
        dev_pm_domain_detach(&func->dev, false);
        device_del(&func->dev);
+       of_node_put(func->dev.of_node);
        put_device(&func->dev);
 }