Blame view
drivers/of/platform.c
17.7 KB
3f23de10f Create drivers/of... |
1 2 3 4 5 6 7 8 9 10 11 12 13 |
/* * Copyright (C) 2006 Benjamin Herrenschmidt, IBM Corp. * <benh@kernel.crashing.org> * and Arnd Bergmann, IBM Corp. * Merged from powerpc/kernel/of_platform.c and * sparc{,64}/kernel/of_device.c by Stephen Rothwell * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version * 2 of the License, or (at your option) any later version. * */ |
606ad42aa of: use pr_fmt pr... |
14 15 |
#define pr_fmt(fmt) "OF: " fmt |
3f23de10f Create drivers/of... |
16 |
#include <linux/errno.h> |
5c4570835 [SPARC/64]: Conso... |
17 |
#include <linux/module.h> |
5de1540b7 drivers/amba: cre... |
18 |
#include <linux/amba/bus.h> |
3f23de10f Create drivers/of... |
19 |
#include <linux/device.h> |
5fd200f3b of/device: Merge ... |
20 |
#include <linux/dma-mapping.h> |
50ef5284e of: Fix missing i... |
21 |
#include <linux/slab.h> |
9e3288dc9 of/device: Fix bu... |
22 |
#include <linux/of_address.h> |
3f23de10f Create drivers/of... |
23 |
#include <linux/of_device.h> |
9e3288dc9 of/device: Fix bu... |
24 |
#include <linux/of_irq.h> |
3f23de10f Create drivers/of... |
25 |
#include <linux/of_platform.h> |
eca393016 of: Merge of_plat... |
26 |
#include <linux/platform_device.h> |
cbb49c266 dt: Add default m... |
27 28 |
const struct of_device_id of_default_bus_match_table[] = { { .compatible = "simple-bus", }, |
22869a9ec MFD/OF: document ... |
29 |
{ .compatible = "simple-mfd", }, |
ecd76eded of/platform: Prob... |
30 |
{ .compatible = "isa", }, |
cbb49c266 dt: Add default m... |
31 32 33 34 35 |
#ifdef CONFIG_ARM_AMBA { .compatible = "arm,amba-bus", }, #endif /* CONFIG_ARM_AMBA */ {} /* Empty terminated list */ }; |
c60855840 of: make of_find_... |
36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 |
static int of_dev_node_match(struct device *dev, void *data) { return dev->of_node == data; } /** * of_find_device_by_node - Find the platform_device associated with a node * @np: Pointer to device tree node * * Returns platform_device pointer, or NULL if not found */ struct platform_device *of_find_device_by_node(struct device_node *np) { struct device *dev; dev = bus_find_device(&platform_bus_type, NULL, np, of_dev_node_match); return dev ? to_platform_device(dev) : NULL; } EXPORT_SYMBOL(of_find_device_by_node); |
964dba283 devicetree: Add e... |
55 |
#ifdef CONFIG_OF_ADDRESS |
5fd200f3b of/device: Merge ... |
56 57 58 59 60 61 62 63 64 |
/* * The following routines scan a subtree and registers a device for * each applicable node. * * Note: sparc doesn't use these routines because it has a different * mechanism for creating devices from device tree nodes. */ /** |
94c093198 of: Merge of_devi... |
65 66 67 |
* 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 * |
07e461cd7 of: Ensure unique... |
68 69 70 |
* 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. |
94c093198 of: Merge of_devi... |
71 |
*/ |
c66012253 of/device: Make o... |
72 |
void of_device_make_bus_id(struct device *dev) |
94c093198 of: Merge of_devi... |
73 |
{ |
94c093198 of: Merge of_devi... |
74 |
struct device_node *node = dev->of_node; |
24fb530f9 of/platform: spar... |
75 |
const __be32 *reg; |
94c093198 of: Merge of_devi... |
76 |
u64 addr; |
94c093198 of: Merge of_devi... |
77 |
|
07e461cd7 of: Ensure unique... |
78 79 80 81 82 83 84 85 86 87 88 |
/* 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)); |
94c093198 of: Merge of_devi... |
89 90 |
return; } |
94c093198 of: Merge of_devi... |
91 |
|
07e461cd7 of: Ensure unique... |
92 93 94 95 96 |
/* 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; } |
94c093198 of: Merge of_devi... |
97 98 99 100 101 102 103 104 |
} /** * of_device_alloc - Allocate and initialize an of_device * @np: device node to assign to device * @bus_id: Name to assign to the device. May be null to use default name. * @parent: Parent device. */ |
94a0cb1fc of/device: Replac... |
105 |
struct platform_device *of_device_alloc(struct device_node *np, |
94c093198 of: Merge of_devi... |
106 107 108 |
const char *bus_id, struct device *parent) { |
94a0cb1fc of/device: Replac... |
109 |
struct platform_device *dev; |
52f6537cb of/irq: remove re... |
110 |
int rc, i, num_reg = 0, num_irq; |
ac80a51e2 of/device: popula... |
111 |
struct resource *res, temp_res; |
7096d0422 of/device: Rework... |
112 113 114 115 116 |
dev = platform_device_alloc("", -1); if (!dev) return NULL; /* count the io and irq resources */ |
d9c6866be of: kill off of_c... |
117 118 |
while (of_address_to_resource(np, num_reg, &temp_res) == 0) num_reg++; |
52f6537cb of/irq: remove re... |
119 |
num_irq = of_irq_count(np); |
ac80a51e2 of/device: popula... |
120 |
|
ac80a51e2 of/device: popula... |
121 122 |
/* Populate the resource table */ if (num_irq || num_reg) { |
7096d0422 of/device: Rework... |
123 124 125 126 127 |
res = kzalloc(sizeof(*res) * (num_irq + num_reg), GFP_KERNEL); if (!res) { platform_device_put(dev); return NULL; } |
ac80a51e2 of/device: popula... |
128 129 130 131 132 133 |
dev->num_resources = num_reg + num_irq; dev->resource = res; for (i = 0; i < num_reg; i++, res++) { rc = of_address_to_resource(np, i, res); WARN_ON(rc); } |
9ec36cafe of/irq: do irq re... |
134 135 136 137 |
if (of_irq_to_resource_table(np, res, num_irq) != num_irq) pr_debug("not all legacy IRQ resources mapped for %s ", np->name); |
ac80a51e2 of/device: popula... |
138 |
} |
94c093198 of: Merge of_devi... |
139 140 |
dev->dev.of_node = of_node_get(np); |
f94277af0 of/platform: Init... |
141 |
dev->dev.fwnode = &np->fwnode; |
43c0767e1 of/platform: Move... |
142 |
dev->dev.parent = parent ? : &platform_bus; |
94c093198 of: Merge of_devi... |
143 144 145 146 147 148 149 150 151 |
if (bus_id) dev_set_name(&dev->dev, "%s", bus_id); else of_device_make_bus_id(&dev->dev); return dev; } EXPORT_SYMBOL(of_device_alloc); |
97890ba92 dma-mapping: dete... |
152 153 154 |
static void of_dma_deconfigure(struct device *dev) { arch_teardown_dma_ops(dev); |
591c1ee46 of: configure the... |
155 156 157 |
} /** |
15c3597d6 dt/platform: allo... |
158 |
* of_platform_device_create_pdata - Alloc, initialize and register an of_device |
5fd200f3b of/device: Merge ... |
159 160 |
* @np: pointer to node to create device for * @bus_id: name to assign device |
15c3597d6 dt/platform: allo... |
161 |
* @platform_data: pointer to populate platform_data pointer with |
5fd200f3b of/device: Merge ... |
162 |
* @parent: Linux device model parent device. |
cd1e65044 of/device: Don't ... |
163 164 165 |
* * Returns pointer to created platform device, or NULL if a device was not * registered. Unavailable devices will not get registered. |
5fd200f3b of/device: Merge ... |
166 |
*/ |
245d96419 of/platform: Stat... |
167 |
static struct platform_device *of_platform_device_create_pdata( |
15c3597d6 dt/platform: allo... |
168 169 170 171 |
struct device_node *np, const char *bus_id, void *platform_data, struct device *parent) |
5fd200f3b of/device: Merge ... |
172 |
{ |
94a0cb1fc of/device: Replac... |
173 |
struct platform_device *dev; |
5fd200f3b of/device: Merge ... |
174 |
|
c6e126de4 of: Keep track of... |
175 176 |
if (!of_device_is_available(np) || of_node_test_and_set_flag(np, OF_POPULATED)) |
cd1e65044 of/device: Don't ... |
177 |
return NULL; |
5fd200f3b of/device: Merge ... |
178 179 |
dev = of_device_alloc(np, bus_id, parent); if (!dev) |
c6e126de4 of: Keep track of... |
180 |
goto err_clear_flag; |
5fd200f3b of/device: Merge ... |
181 |
|
eca393016 of: Merge of_plat... |
182 |
dev->dev.bus = &platform_bus_type; |
15c3597d6 dt/platform: allo... |
183 |
dev->dev.platform_data = platform_data; |
1f5c69aa5 of: Move of_dma_c... |
184 |
of_dma_configure(&dev->dev, dev->dev.of_node); |
c706c239a of/platform: Assi... |
185 |
of_msi_configure(&dev->dev, dev->dev.of_node); |
5fd200f3b of/device: Merge ... |
186 |
|
7096d0422 of/device: Rework... |
187 |
if (of_device_add(dev) != 0) { |
97890ba92 dma-mapping: dete... |
188 |
of_dma_deconfigure(&dev->dev); |
7096d0422 of/device: Rework... |
189 |
platform_device_put(dev); |
c6e126de4 of: Keep track of... |
190 |
goto err_clear_flag; |
5fd200f3b of/device: Merge ... |
191 192 193 |
} return dev; |
c6e126de4 of: Keep track of... |
194 195 196 197 |
err_clear_flag: of_node_clear_flag(np, OF_POPULATED); return NULL; |
5fd200f3b of/device: Merge ... |
198 |
} |
15c3597d6 dt/platform: allo... |
199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 |
/** * of_platform_device_create - Alloc, initialize and register an of_device * @np: pointer to node to create device for * @bus_id: name to assign device * @parent: Linux device model parent device. * * Returns pointer to created platform device, or NULL if a device was not * registered. Unavailable devices will not get registered. */ struct platform_device *of_platform_device_create(struct device_node *np, const char *bus_id, struct device *parent) { return of_platform_device_create_pdata(np, bus_id, NULL, parent); } |
5fd200f3b of/device: Merge ... |
215 |
EXPORT_SYMBOL(of_platform_device_create); |
5de1540b7 drivers/amba: cre... |
216 217 218 219 220 221 222 223 224 225 226 227 |
#ifdef CONFIG_ARM_AMBA static struct amba_device *of_amba_device_create(struct device_node *node, const char *bus_id, void *platform_data, struct device *parent) { struct amba_device *dev; const void *prop; int i, ret; pr_debug("Creating amba device %s ", node->full_name); |
c6e126de4 of: Keep track of... |
228 229 |
if (!of_device_is_available(node) || of_node_test_and_set_flag(node, OF_POPULATED)) |
5de1540b7 drivers/amba: cre... |
230 |
return NULL; |
c0f72f8a9 ARM: amba: of: co... |
231 |
dev = amba_device_alloc(NULL, 0, 0); |
606ad42aa of: use pr_fmt pr... |
232 |
if (!dev) |
c6e126de4 of: Keep track of... |
233 |
goto err_clear_flag; |
5de1540b7 drivers/amba: cre... |
234 235 |
/* setup generic device info */ |
5de1540b7 drivers/amba: cre... |
236 |
dev->dev.of_node = of_node_get(node); |
f94277af0 of/platform: Init... |
237 |
dev->dev.fwnode = &node->fwnode; |
43c0767e1 of/platform: Move... |
238 |
dev->dev.parent = parent ? : &platform_bus; |
5de1540b7 drivers/amba: cre... |
239 240 241 242 243 |
dev->dev.platform_data = platform_data; if (bus_id) dev_set_name(&dev->dev, "%s", bus_id); else of_device_make_bus_id(&dev->dev); |
1f5c69aa5 of: Move of_dma_c... |
244 |
of_dma_configure(&dev->dev, dev->dev.of_node); |
5de1540b7 drivers/amba: cre... |
245 |
|
5de1540b7 drivers/amba: cre... |
246 247 248 249 250 251 252 253 254 255 |
/* Allow the HW Peripheral ID to be overridden */ prop = of_get_property(node, "arm,primecell-periphid", NULL); if (prop) dev->periphid = of_read_ulong(prop, 1); /* Decode the IRQs and address ranges */ for (i = 0; i < AMBA_NR_IRQS; i++) dev->irq[i] = irq_of_parse_and_map(node, i); ret = of_address_to_resource(node, 0, &dev->res); |
2bc552df7 of/platform: add ... |
256 |
if (ret) { |
606ad42aa of: use pr_fmt pr... |
257 258 259 |
pr_err("amba: of_address_to_resource() failed (%d) for %s ", ret, node->full_name); |
5de1540b7 drivers/amba: cre... |
260 |
goto err_free; |
2bc552df7 of/platform: add ... |
261 |
} |
5de1540b7 drivers/amba: cre... |
262 |
|
c0f72f8a9 ARM: amba: of: co... |
263 |
ret = amba_device_add(dev, &iomem_resource); |
2bc552df7 of/platform: add ... |
264 |
if (ret) { |
606ad42aa of: use pr_fmt pr... |
265 266 267 |
pr_err("amba_device_add() failed (%d) for %s ", ret, node->full_name); |
5de1540b7 drivers/amba: cre... |
268 |
goto err_free; |
2bc552df7 of/platform: add ... |
269 |
} |
5de1540b7 drivers/amba: cre... |
270 271 272 273 |
return dev; err_free: |
c0f72f8a9 ARM: amba: of: co... |
274 |
amba_device_put(dev); |
c6e126de4 of: Keep track of... |
275 276 |
err_clear_flag: of_node_clear_flag(node, OF_POPULATED); |
5de1540b7 drivers/amba: cre... |
277 278 279 280 281 282 283 284 285 286 287 |
return NULL; } #else /* CONFIG_ARM_AMBA */ static struct amba_device *of_amba_device_create(struct device_node *node, const char *bus_id, void *platform_data, struct device *parent) { return NULL; } #endif /* CONFIG_ARM_AMBA */ |
5fd200f3b of/device: Merge ... |
288 |
/** |
15c3597d6 dt/platform: allo... |
289 290 291 292 293 |
* of_devname_lookup() - Given a device node, lookup the preferred Linux name */ static const struct of_dev_auxdata *of_dev_lookup(const struct of_dev_auxdata *lookup, struct device_node *np) { |
fc5cf80ac of/platform: Allo... |
294 |
const struct of_dev_auxdata *auxdata; |
15c3597d6 dt/platform: allo... |
295 |
struct resource res; |
fc5cf80ac of/platform: Allo... |
296 |
int compatible = 0; |
303f59d1a dt/platform: mino... |
297 298 299 |
if (!lookup) return NULL; |
fc5cf80ac of/platform: Allo... |
300 301 302 |
auxdata = lookup; for (; auxdata->compatible; auxdata++) { if (!of_device_is_compatible(np, auxdata->compatible)) |
303f59d1a dt/platform: mino... |
303 |
continue; |
fc5cf80ac of/platform: Allo... |
304 |
compatible++; |
84774e615 of: address: Don'... |
305 |
if (!of_address_to_resource(np, 0, &res)) |
fc5cf80ac of/platform: Allo... |
306 |
if (res.start != auxdata->phys_addr) |
84774e615 of: address: Don'... |
307 |
continue; |
fc5cf80ac of/platform: Allo... |
308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 |
pr_debug("%s: devname=%s ", np->full_name, auxdata->name); return auxdata; } if (!compatible) return NULL; /* Try compatible match if no phys_addr and name are specified */ auxdata = lookup; for (; auxdata->compatible; auxdata++) { if (!of_device_is_compatible(np, auxdata->compatible)) continue; if (!auxdata->phys_addr && !auxdata->name) { pr_debug("%s: compatible match ", np->full_name); return auxdata; } |
15c3597d6 dt/platform: allo... |
326 |
} |
303f59d1a dt/platform: mino... |
327 |
|
15c3597d6 dt/platform: allo... |
328 329 330 331 |
return NULL; } /** |
38e9e21da dt: Refactor of_p... |
332 |
* of_platform_bus_create() - Create a device for a node and its children. |
5fd200f3b of/device: Merge ... |
333 |
* @bus: device node of the bus to instantiate |
1eed4c077 dt: eliminate OF_... |
334 |
* @matches: match table for bus nodes |
303f59d1a dt/platform: mino... |
335 |
* @lookup: auxdata table for matching id and platform_data with device nodes |
38e9e21da dt: Refactor of_p... |
336 |
* @parent: parent for new device, or NULL for top level. |
303f59d1a dt/platform: mino... |
337 |
* @strict: require compatible property |
38e9e21da dt: Refactor of_p... |
338 339 340 |
* * Creates a platform_device for the provided device_node, and optionally * recursively create devices for all the child nodes. |
5fd200f3b of/device: Merge ... |
341 |
*/ |
38e9e21da dt: Refactor of_p... |
342 |
static int of_platform_bus_create(struct device_node *bus, |
5fd200f3b of/device: Merge ... |
343 |
const struct of_device_id *matches, |
15c3597d6 dt/platform: allo... |
344 |
const struct of_dev_auxdata *lookup, |
29d4f8a49 dt: add of_platfo... |
345 |
struct device *parent, bool strict) |
5fd200f3b of/device: Merge ... |
346 |
{ |
15c3597d6 dt/platform: allo... |
347 |
const struct of_dev_auxdata *auxdata; |
5fd200f3b of/device: Merge ... |
348 |
struct device_node *child; |
94a0cb1fc of/device: Replac... |
349 |
struct platform_device *dev; |
15c3597d6 dt/platform: allo... |
350 351 |
const char *bus_id = NULL; void *platform_data = NULL; |
5fd200f3b of/device: Merge ... |
352 |
int rc = 0; |
29d4f8a49 dt: add of_platfo... |
353 354 355 356 357 358 359 |
/* Make sure it has a compatible property */ if (strict && (!of_get_property(bus, "compatible", NULL))) { pr_debug("%s() - skipping %s, no compatible prop ", __func__, bus->full_name); return 0; } |
44a7185c2 of/platform: Add ... |
360 361 362 363 364 365 |
if (of_node_check_flag(bus, OF_POPULATED_BUS)) { pr_debug("%s() - skipping %s, already populated ", __func__, bus->full_name); return 0; } |
15c3597d6 dt/platform: allo... |
366 367 368 369 370 |
auxdata = of_dev_lookup(lookup, bus); if (auxdata) { bus_id = auxdata->name; platform_data = auxdata->platform_data; } |
5de1540b7 drivers/amba: cre... |
371 |
if (of_device_is_compatible(bus, "arm,primecell")) { |
2bc552df7 of/platform: add ... |
372 373 374 375 |
/* * Don't return an error here to keep compatibility with older * device tree files. */ |
15c3597d6 dt/platform: allo... |
376 |
of_amba_device_create(bus, bus_id, platform_data, parent); |
5de1540b7 drivers/amba: cre... |
377 378 |
return 0; } |
15c3597d6 dt/platform: allo... |
379 |
dev = of_platform_device_create_pdata(bus, bus_id, platform_data, parent); |
38e9e21da dt: Refactor of_p... |
380 381 |
if (!dev || !of_match_node(matches, bus)) return 0; |
5fd200f3b of/device: Merge ... |
382 383 384 |
for_each_child_of_node(bus, child) { pr_debug(" create child: %s ", child->full_name); |
15c3597d6 dt/platform: allo... |
385 |
rc = of_platform_bus_create(child, matches, lookup, &dev->dev, strict); |
5fd200f3b of/device: Merge ... |
386 387 388 389 390 |
if (rc) { of_node_put(child); break; } } |
75f353b61 of/platform: Fix ... |
391 |
of_node_set_flag(bus, OF_POPULATED_BUS); |
5fd200f3b of/device: Merge ... |
392 393 394 395 |
return rc; } /** |
38e9e21da dt: Refactor of_p... |
396 |
* of_platform_bus_probe() - Probe the device-tree for platform buses |
5fd200f3b of/device: Merge ... |
397 |
* @root: parent of the first level to probe or NULL for the root of the tree |
1eed4c077 dt: eliminate OF_... |
398 |
* @matches: match table for bus nodes |
5fd200f3b of/device: Merge ... |
399 400 401 402 403 404 405 406 407 408 |
* @parent: parent to hook devices from, NULL for toplevel * * Note that children of the provided root are not instantiated as devices * unless the specified root itself matches the bus list and is not NULL. */ int of_platform_bus_probe(struct device_node *root, const struct of_device_id *matches, struct device *parent) { struct device_node *child; |
5fd200f3b of/device: Merge ... |
409 |
int rc = 0; |
1eed4c077 dt: eliminate OF_... |
410 411 |
root = root ? of_node_get(root) : of_find_node_by_path("/"); if (!root) |
60d599133 of/flattree: Fix ... |
412 |
return -EINVAL; |
5fd200f3b of/device: Merge ... |
413 |
|
44a7185c2 of/platform: Add ... |
414 415 |
pr_debug("%s() ", __func__); |
5fd200f3b of/device: Merge ... |
416 417 |
pr_debug(" starting at: %s ", root->full_name); |
1eed4c077 dt: eliminate OF_... |
418 |
/* Do a self check of bus type, if there's a match, create children */ |
5fd200f3b of/device: Merge ... |
419 |
if (of_match_node(matches, root)) { |
15c3597d6 dt/platform: allo... |
420 |
rc = of_platform_bus_create(root, matches, NULL, parent, false); |
38e9e21da dt: Refactor of_p... |
421 |
} else for_each_child_of_node(root, child) { |
5fd200f3b of/device: Merge ... |
422 423 |
if (!of_match_node(matches, child)) continue; |
15c3597d6 dt/platform: allo... |
424 |
rc = of_platform_bus_create(child, matches, NULL, parent, false); |
7fad948a7 of/platform: add ... |
425 426 |
if (rc) { of_node_put(child); |
5fd200f3b of/device: Merge ... |
427 |
break; |
7fad948a7 of/platform: add ... |
428 |
} |
5fd200f3b of/device: Merge ... |
429 |
} |
38e9e21da dt: Refactor of_p... |
430 |
|
5fd200f3b of/device: Merge ... |
431 432 433 434 |
of_node_put(root); return rc; } EXPORT_SYMBOL(of_platform_bus_probe); |
29d4f8a49 dt: add of_platfo... |
435 436 437 438 439 |
/** * of_platform_populate() - Populate platform_devices from device tree data * @root: parent of the first level to probe or NULL for the root of the tree * @matches: match table, NULL to use the default |
92039ed12 of: add missing d... |
440 |
* @lookup: auxdata table for matching id and platform_data with device nodes |
29d4f8a49 dt: add of_platfo... |
441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 |
* @parent: parent to hook devices from, NULL for toplevel * * Similar to of_platform_bus_probe(), this function walks the device tree * and creates devices from nodes. It differs in that it follows the modern * convention of requiring all device nodes to have a 'compatible' property, * and it is suitable for creating devices which are children of the root * node (of_platform_bus_probe will only create children of the root which * are selected by the @matches argument). * * New board support should be using this function instead of * of_platform_bus_probe(). * * Returns 0 on success, < 0 on failure. */ int of_platform_populate(struct device_node *root, const struct of_device_id *matches, |
15c3597d6 dt/platform: allo... |
457 |
const struct of_dev_auxdata *lookup, |
29d4f8a49 dt: add of_platfo... |
458 459 460 461 462 463 464 465 |
struct device *parent) { struct device_node *child; int rc = 0; root = root ? of_node_get(root) : of_find_node_by_path("/"); if (!root) return -EINVAL; |
44a7185c2 of/platform: Add ... |
466 467 468 469 |
pr_debug("%s() ", __func__); pr_debug(" starting at: %s ", root->full_name); |
29d4f8a49 dt: add of_platfo... |
470 |
for_each_child_of_node(root, child) { |
15c3597d6 dt/platform: allo... |
471 |
rc = of_platform_bus_create(child, matches, lookup, parent, true); |
7fad948a7 of/platform: add ... |
472 473 |
if (rc) { of_node_put(child); |
29d4f8a49 dt: add of_platfo... |
474 |
break; |
7fad948a7 of/platform: add ... |
475 |
} |
29d4f8a49 dt: add of_platfo... |
476 |
} |
2d0747c4b of: Properly set ... |
477 |
of_node_set_flag(root, OF_POPULATED_BUS); |
29d4f8a49 dt: add of_platfo... |
478 479 480 481 |
of_node_put(root); return rc; } |
e001f1c8e of: export of_pla... |
482 |
EXPORT_SYMBOL_GPL(of_platform_populate); |
c6e126de4 of: Keep track of... |
483 |
|
43443ad69 of/platform: add ... |
484 485 486 487 488 489 490 491 |
int of_platform_default_populate(struct device_node *root, const struct of_dev_auxdata *lookup, struct device *parent) { return of_platform_populate(root, of_default_bus_match_table, lookup, parent); } EXPORT_SYMBOL_GPL(of_platform_default_populate); |
fc520f8b4 of/platform: disa... |
492 |
#ifndef CONFIG_PPC |
44a7185c2 of/platform: Add ... |
493 494 |
static int __init of_platform_default_populate_init(void) { |
529182e20 ramoops: use DT r... |
495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 |
struct device_node *node; if (!of_have_populated_dt()) return -ENODEV; /* * Handle ramoops explicitly, since it is inside /reserved-memory, * which lacks a "compatible" property. */ node = of_find_node_by_path("/reserved-memory"); if (node) { node = of_find_compatible_node(node, NULL, "ramoops"); if (node) of_platform_device_create(node, NULL, NULL); } /* Populate everything else. */ of_platform_default_populate(NULL, NULL, NULL); |
44a7185c2 of/platform: Add ... |
513 514 515 516 |
return 0; } arch_initcall_sync(of_platform_default_populate_init); |
fc520f8b4 of/platform: disa... |
517 |
#endif |
44a7185c2 of/platform: Add ... |
518 |
|
c6e126de4 of: Keep track of... |
519 520 |
static int of_platform_device_destroy(struct device *dev, void *data) { |
c6e126de4 of: Keep track of... |
521 |
/* Do not touch devices not populated from the device tree */ |
75f353b61 of/platform: Fix ... |
522 |
if (!dev->of_node || !of_node_check_flag(dev->of_node, OF_POPULATED)) |
c6e126de4 of: Keep track of... |
523 |
return 0; |
c6e126de4 of: Keep track of... |
524 |
|
75f353b61 of/platform: Fix ... |
525 526 527 |
/* Recurse for any nodes that were treated as busses */ if (of_node_check_flag(dev->of_node, OF_POPULATED_BUS)) device_for_each_child(dev, NULL, of_platform_device_destroy); |
c6e126de4 of: Keep track of... |
528 529 530 531 532 533 534 |
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 |
c6e126de4 of: Keep track of... |
535 |
|
0495cb75e of/platform: tear... |
536 |
of_dma_deconfigure(dev); |
c6e126de4 of: Keep track of... |
537 |
of_node_clear_flag(dev->of_node, OF_POPULATED); |
75f353b61 of/platform: Fix ... |
538 |
of_node_clear_flag(dev->of_node, OF_POPULATED_BUS); |
c6e126de4 of: Keep track of... |
539 540 541 542 543 |
return 0; } /** * of_platform_depopulate() - Remove devices populated from device tree |
75f353b61 of/platform: Fix ... |
544 |
* @parent: device which children will be removed |
c6e126de4 of: Keep track of... |
545 546 547 548 549 550 551 552 553 |
* * 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. */ |
75f353b61 of/platform: Fix ... |
554 |
void of_platform_depopulate(struct device *parent) |
c6e126de4 of: Keep track of... |
555 |
{ |
2d0747c4b of: Properly set ... |
556 557 558 559 |
if (parent->of_node && of_node_check_flag(parent->of_node, OF_POPULATED_BUS)) { device_for_each_child(parent, NULL, of_platform_device_destroy); of_node_clear_flag(parent->of_node, OF_POPULATED_BUS); } |
c6e126de4 of: Keep track of... |
560 561 |
} EXPORT_SYMBOL_GPL(of_platform_depopulate); |
801d728c1 of/reconfig: Add ... |
562 563 564 565 566 567 568 569 570 571 572 573 574 |
#ifdef CONFIG_OF_DYNAMIC static int of_platform_notify(struct notifier_block *nb, unsigned long action, void *arg) { struct of_reconfig_data *rd = arg; struct platform_device *pdev_parent, *pdev; bool children_left; switch (of_reconfig_get_state_change(action, rd)) { case OF_RECONFIG_CHANGE_ADD: /* verify that the parent is a bus */ if (!of_node_check_flag(rd->dn->parent, OF_POPULATED_BUS)) return NOTIFY_OK; /* not for us */ |
15204ab1e of/platform: Hand... |
575 576 577 |
/* already populated? (driver using of_populate manually) */ if (of_node_check_flag(rd->dn, OF_POPULATED)) return NOTIFY_OK; |
801d728c1 of/reconfig: Add ... |
578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 |
/* pdev_parent may be NULL when no bus platform device */ pdev_parent = of_find_device_by_node(rd->dn->parent); pdev = of_platform_device_create(rd->dn, NULL, pdev_parent ? &pdev_parent->dev : NULL); of_dev_put(pdev_parent); if (pdev == NULL) { pr_err("%s: failed to create for '%s' ", __func__, rd->dn->full_name); /* of_platform_device_create tosses the error code */ return notifier_from_errno(-EINVAL); } break; case OF_RECONFIG_CHANGE_REMOVE: |
15204ab1e of/platform: Hand... |
594 595 596 597 |
/* already depopulated? */ if (!of_node_check_flag(rd->dn, OF_POPULATED)) return NOTIFY_OK; |
801d728c1 of/reconfig: Add ... |
598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 614 615 616 617 618 619 620 621 622 |
/* find our device by node */ pdev = of_find_device_by_node(rd->dn); if (pdev == NULL) return NOTIFY_OK; /* no? not meant for us */ /* unregister takes one ref away */ of_platform_device_destroy(&pdev->dev, &children_left); /* and put the reference of the find */ of_dev_put(pdev); break; } return NOTIFY_OK; } static struct notifier_block platform_of_notifier = { .notifier_call = of_platform_notify, }; void of_platform_register_reconfig_notifier(void) { WARN_ON(of_reconfig_notifier_register(&platform_of_notifier)); } #endif /* CONFIG_OF_DYNAMIC */ |
964dba283 devicetree: Add e... |
623 |
#endif /* CONFIG_OF_ADDRESS */ |