summaryrefslogtreecommitdiffstats
path: root/drivers/of/platform.c
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@linux-foundation.org>2014-06-03 01:14:07 +0200
committerLinus Torvalds <torvalds@linux-foundation.org>2014-06-03 01:14:07 +0200
commit0a58471541cc823ef8056d23945c39fec154481c (patch)
tree04a8499be0659ac16f82f3b0d0d8d2c2ccafe4dd /drivers/of/platform.c
parentMerge tag 'fixes-for-3.16' of git://git.kernel.org/pub/scm/linux/kernel/git/a... (diff)
parentARM: kconfig: allow PCI support to be selected with ARCH_MULTIPLATFORM (diff)
downloadlinux-0a58471541cc823ef8056d23945c39fec154481c.tar.xz
linux-0a58471541cc823ef8056d23945c39fec154481c.zip
Merge tag 'cleanup-for-3.16' of git://git.kernel.org/pub/scm/linux/kernel/git/arm/arm-soc into next
Pull ARM SoC cleanups from Olof Johansson: "Cleanups for 3.16. Among these are: - a bunch of misc cleanups for Broadcom platforms, mostly housekeeping - enabling Common Clock Framework on the older s3c24xx Samsung chipsets - cleanup of the Versatile Express system controller code, moving it to syscon - power management cleanups for OMAP platforms plus a handful of other cleanups across the place" * tag 'cleanup-for-3.16' of git://git.kernel.org/pub/scm/linux/kernel/git/arm/arm-soc: (87 commits) ARM: kconfig: allow PCI support to be selected with ARCH_MULTIPLATFORM clk: samsung: fix build error ARM: vexpress: refine dependencies for new code clk: samsung: clk-s3c2410-dlck: do not use PNAME macro as it declares __initdata cpufreq: exynos: Fix the compile error ARM: S3C24XX: move debug-macro.S into the common space ARM: S3C24XX: use generic DEBUG_UART_PHY/_VIRT in debug macro ARM: S3C24XX: trim down debug uart handling ARM: compressed/head.S: remove s3c24xx special case ARM: EXYNOS: Remove unnecessary inclusion of cpu.h ARM: EXYNOS: Migrate Exynos specific macros from plat to mach ARM: EXYNOS: Remove exynos_subsys registration ARM: EXYNOS: Remove duplicate lines in Makefile ARM: EXYNOS: use v7_exit_coherency_flush macro for cache disabling ARM: OMAP4: PRCM: remove references to cm-regbits-44xx.h from PRCM core files ARM: OMAP3/4: PRM: add support of late_init call to prm_ll_ops ARM: OMAP3/OMAP4: PRM: add prm_features flags and add IO wakeup under it ARM: OMAP3/4: PRM: provide io chain reconfig function through irq setup ARM: OMAP2+: PRM: remove unnecessary cpu_is_XXX calls from prm_init / exit ARM: OMAP2+: PRCM: cleanup some header includes ...
Diffstat (limited to 'drivers/of/platform.c')
-rw-r--r--drivers/of/platform.c74
1 files changed, 69 insertions, 5 deletions
diff --git a/drivers/of/platform.c b/drivers/of/platform.c
index bd47fbc53dc9..e8376d646d98 100644
--- a/drivers/of/platform.c
+++ b/drivers/of/platform.c
@@ -206,12 +206,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;
#if defined(CONFIG_MICROBLAZE)
dev->archdata.dma_mask = 0xffffffffUL;
@@ -229,10 +230,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;
}
/**
@@ -264,14 +269,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 */
@@ -311,6 +317,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 */
@@ -487,4 +495,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 */