]> git.karo-electronics.de Git - karo-tx-linux.git/blobdiff - drivers/of/platform.c
Merge branch 'for-linus' of git://ftp.arm.linux.org.uk/~rmk/linux-arm into next
[karo-tx-linux.git] / drivers / of / platform.c
index 4e91583a390883a387e7e2934a0c489b3b7821ed..d90a02d89f51ab245995871d672fa89187afceec 100644 (file)
@@ -51,10 +51,6 @@ struct platform_device *of_find_device_by_node(struct device_node *np)
 }
 EXPORT_SYMBOL(of_find_device_by_node);
 
-#if defined(CONFIG_PPC_DCR)
-#include <asm/dcr.h>
-#endif
-
 #ifdef CONFIG_OF_ADDRESS
 /*
  * The following routines scan a subtree and registers a device for
@@ -68,66 +64,35 @@ EXPORT_SYMBOL(of_find_device_by_node);
  * of_device_make_bus_id - Use the device node data to assign a unique name
  * @dev: pointer to device structure that is linked to a device tree node
  *
- * This routine will first try using either the dcr-reg or the reg property
- * value to derive a unique name.  As a last resort it will use the node
- * name followed by a unique number.
+ * This routine will first try using the translated bus address to
+ * derive a unique name. If it cannot, then it will prepend names from
+ * parent nodes until a unique name can be derived.
  */
 void of_device_make_bus_id(struct device *dev)
 {
-       static atomic_t bus_no_reg_magic;
        struct device_node *node = dev->of_node;
        const __be32 *reg;
        u64 addr;
-       const __be32 *addrp;
-       int magic;
 
-#ifdef CONFIG_PPC_DCR
-       /*
-        * If it's a DCR based device, use 'd' for native DCRs
-        * and 'D' for MMIO DCRs.
-        */
-       reg = of_get_property(node, "dcr-reg", NULL);
-       if (reg) {
-#ifdef CONFIG_PPC_DCR_NATIVE
-               dev_set_name(dev, "d%x.%s", *reg, node->name);
-#else /* CONFIG_PPC_DCR_NATIVE */
-               u64 addr = of_translate_dcr_address(node, *reg, NULL);
-               if (addr != OF_BAD_ADDR) {
-                       dev_set_name(dev, "D%llx.%s",
-                                    (unsigned long long)addr, node->name);
+       /* Construct the name, using parent nodes if necessary to ensure uniqueness */
+       while (node->parent) {
+               /*
+                * If the address can be translated, then that is as much
+                * uniqueness as we need. Make it the first component and return
+                */
+               reg = of_get_property(node, "reg", NULL);
+               if (reg && (addr = of_translate_address(node, reg)) != OF_BAD_ADDR) {
+                       dev_set_name(dev, dev_name(dev) ? "%llx.%s:%s" : "%llx.%s",
+                                    (unsigned long long)addr, node->name,
+                                    dev_name(dev));
                        return;
                }
-#endif /* !CONFIG_PPC_DCR_NATIVE */
-       }
-#endif /* CONFIG_PPC_DCR */
 
-       /*
-        * For MMIO, get the physical address
-        */
-       reg = of_get_property(node, "reg", NULL);
-       if (reg) {
-               if (of_can_translate_address(node)) {
-                       addr = of_translate_address(node, reg);
-               } else {
-                       addrp = of_get_address(node, 0, NULL, NULL);
-                       if (addrp)
-                               addr = of_read_number(addrp, 1);
-                       else
-                               addr = OF_BAD_ADDR;
-               }
-               if (addr != OF_BAD_ADDR) {
-                       dev_set_name(dev, "%llx.%s",
-                                    (unsigned long long)addr, node->name);
-                       return;
-               }
+               /* format arguments only used if dev_name() resolves to NULL */
+               dev_set_name(dev, dev_name(dev) ? "%s:%s" : "%s",
+                            strrchr(node->full_name, '/') + 1, dev_name(dev));
+               node = node->parent;
        }
-
-       /*
-        * No BusID, use the node name and add a globally incremented
-        * counter (and pray...)
-        */
-       magic = atomic_add_return(1, &bus_no_reg_magic);
-       dev_set_name(dev, "%s.%d", node->name, magic - 1);
 }
 
 /**
@@ -149,9 +114,8 @@ struct platform_device *of_device_alloc(struct device_node *np,
                return NULL;
 
        /* count the io and irq resources */
-       if (of_can_translate_address(np))
-               while (of_address_to_resource(np, num_reg, &temp_res) == 0)
-                       num_reg++;
+       while (of_address_to_resource(np, num_reg, &temp_res) == 0)
+               num_reg++;
        num_irq = of_irq_count(np);
 
        /* Populate the resource table */
@@ -264,12 +228,13 @@ static struct platform_device *of_platform_device_create_pdata(
 {
        struct platform_device *dev;
 
-       if (!of_device_is_available(np))
+       if (!of_device_is_available(np) ||
+           of_node_test_and_set_flag(np, OF_POPULATED))
                return NULL;
 
        dev = of_device_alloc(np, bus_id, parent);
        if (!dev)
-               return NULL;
+               goto err_clear_flag;
 
        of_dma_configure(dev);
        dev->dev.bus = &platform_bus_type;
@@ -282,10 +247,14 @@ static struct platform_device *of_platform_device_create_pdata(
 
        if (of_device_add(dev) != 0) {
                platform_device_put(dev);
-               return NULL;
+               goto err_clear_flag;
        }
 
        return dev;
+
+err_clear_flag:
+       of_node_clear_flag(np, OF_POPULATED);
+       return NULL;
 }
 
 /**
@@ -317,14 +286,15 @@ static struct amba_device *of_amba_device_create(struct device_node *node,
 
        pr_debug("Creating amba device %s\n", node->full_name);
 
-       if (!of_device_is_available(node))
+       if (!of_device_is_available(node) ||
+           of_node_test_and_set_flag(node, OF_POPULATED))
                return NULL;
 
        dev = amba_device_alloc(NULL, 0, 0);
        if (!dev) {
                pr_err("%s(): amba_device_alloc() failed for %s\n",
                       __func__, node->full_name);
-               return NULL;
+               goto err_clear_flag;
        }
 
        /* setup generic device info */
@@ -364,6 +334,8 @@ static struct amba_device *of_amba_device_create(struct device_node *node,
 
 err_free:
        amba_device_put(dev);
+err_clear_flag:
+       of_node_clear_flag(node, OF_POPULATED);
        return NULL;
 }
 #else /* CONFIG_ARM_AMBA */
@@ -540,4 +512,60 @@ int of_platform_populate(struct device_node *root,
        return rc;
 }
 EXPORT_SYMBOL_GPL(of_platform_populate);
+
+static int of_platform_device_destroy(struct device *dev, void *data)
+{
+       bool *children_left = data;
+
+       /* Do not touch devices not populated from the device tree */
+       if (!dev->of_node || !of_node_check_flag(dev->of_node, OF_POPULATED)) {
+               *children_left = true;
+               return 0;
+       }
+
+       /* Recurse, but don't touch this device if it has any children left */
+       if (of_platform_depopulate(dev) != 0) {
+               *children_left = true;
+               return 0;
+       }
+
+       if (dev->bus == &platform_bus_type)
+               platform_device_unregister(to_platform_device(dev));
+#ifdef CONFIG_ARM_AMBA
+       else if (dev->bus == &amba_bustype)
+               amba_device_unregister(to_amba_device(dev));
+#endif
+       else {
+               *children_left = true;
+               return 0;
+       }
+
+       of_node_clear_flag(dev->of_node, OF_POPULATED);
+
+       return 0;
+}
+
+/**
+ * of_platform_depopulate() - Remove devices populated from device tree
+ * @parent: device which childred will be removed
+ *
+ * Complementary to of_platform_populate(), this function removes children
+ * of the given device (and, recurrently, their children) that have been
+ * created from their respective device tree nodes (and only those,
+ * leaving others - eg. manually created - unharmed).
+ *
+ * Returns 0 when all children devices have been removed or
+ * -EBUSY when some children remained.
+ */
+int of_platform_depopulate(struct device *parent)
+{
+       bool children_left = false;
+
+       device_for_each_child(parent, &children_left,
+                             of_platform_device_destroy);
+
+       return children_left ? -EBUSY : 0;
+}
+EXPORT_SYMBOL_GPL(of_platform_depopulate);
+
 #endif /* CONFIG_OF_ADDRESS */