Blame view
drivers/of/platform.c
20 KB
af6074fc9 of: Use SPDX lice... |
1 |
// SPDX-License-Identifier: GPL-2.0+ |
3f23de10f Create drivers/of... |
2 3 4 5 6 7 |
/* * 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 |
3f23de10f Create drivers/of... |
8 |
*/ |
606ad42aa of: use pr_fmt pr... |
9 10 |
#define pr_fmt(fmt) "OF: " fmt |
3f23de10f Create drivers/of... |
11 |
#include <linux/errno.h> |
5c4570835 [SPARC/64]: Conso... |
12 |
#include <linux/module.h> |
5de1540b7 drivers/amba: cre... |
13 |
#include <linux/amba/bus.h> |
3f23de10f Create drivers/of... |
14 |
#include <linux/device.h> |
5fd200f3b of/device: Merge ... |
15 |
#include <linux/dma-mapping.h> |
50ef5284e of: Fix missing i... |
16 |
#include <linux/slab.h> |
9e3288dc9 of/device: Fix bu... |
17 |
#include <linux/of_address.h> |
3f23de10f Create drivers/of... |
18 |
#include <linux/of_device.h> |
09515ef5d of/acpi: Configur... |
19 |
#include <linux/of_iommu.h> |
9e3288dc9 of/device: Fix bu... |
20 |
#include <linux/of_irq.h> |
3f23de10f Create drivers/of... |
21 |
#include <linux/of_platform.h> |
eca393016 of: Merge of_plat... |
22 |
#include <linux/platform_device.h> |
cbb49c266 dt: Add default m... |
23 24 |
const struct of_device_id of_default_bus_match_table[] = { { .compatible = "simple-bus", }, |
22869a9ec MFD/OF: document ... |
25 |
{ .compatible = "simple-mfd", }, |
ecd76eded of/platform: Prob... |
26 |
{ .compatible = "isa", }, |
cbb49c266 dt: Add default m... |
27 28 29 30 31 |
#ifdef CONFIG_ARM_AMBA { .compatible = "arm,amba-bus", }, #endif /* CONFIG_ARM_AMBA */ {} /* Empty terminated list */ }; |
4550fe637 of: Don't create ... |
32 33 34 35 |
static const struct of_device_id of_skipped_node_table[] = { { .compatible = "operating-points-v2", }, {} /* Empty terminated list */ }; |
c60855840 of: make of_find_... |
36 37 38 39 |
/** * of_find_device_by_node - Find the platform_device associated with a node * @np: Pointer to device tree node * |
4fb373dfa of/platform: clar... |
40 41 42 |
* Takes a reference to the embedded struct device which needs to be dropped * after use. * |
c60855840 of: make of_find_... |
43 44 45 46 47 |
* Returns platform_device pointer, or NULL if not found */ struct platform_device *of_find_device_by_node(struct device_node *np) { struct device *dev; |
cfba5de9b drivers: Introduc... |
48 |
dev = bus_find_device_by_of_node(&platform_bus_type, np); |
c60855840 of: make of_find_... |
49 50 51 |
return dev ? to_platform_device(dev) : NULL; } EXPORT_SYMBOL(of_find_device_by_node); |
964dba283 devicetree: Add e... |
52 |
#ifdef CONFIG_OF_ADDRESS |
5fd200f3b of/device: Merge ... |
53 54 55 56 57 58 59 60 61 |
/* * 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... |
62 63 64 |
* 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... |
65 66 67 |
* 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... |
68 |
*/ |
e553f539f of: make of_devic... |
69 |
static void of_device_make_bus_id(struct device *dev) |
94c093198 of: Merge of_devi... |
70 |
{ |
94c093198 of: Merge of_devi... |
71 |
struct device_node *node = dev->of_node; |
24fb530f9 of/platform: spar... |
72 |
const __be32 *reg; |
94c093198 of: Merge of_devi... |
73 |
u64 addr; |
94c093198 of: Merge of_devi... |
74 |
|
07e461cd7 of: Ensure unique... |
75 76 77 78 79 80 81 82 |
/* 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) { |
a613b26a5 of: Convert to us... |
83 |
dev_set_name(dev, dev_name(dev) ? "%llx.%pOFn:%s" : "%llx.%pOFn", |
d88590dc2 of/platform: Drop... |
84 |
addr, node, dev_name(dev)); |
94c093198 of: Merge of_devi... |
85 86 |
return; } |
94c093198 of: Merge of_devi... |
87 |
|
07e461cd7 of: Ensure unique... |
88 89 |
/* format arguments only used if dev_name() resolves to NULL */ dev_set_name(dev, dev_name(dev) ? "%s:%s" : "%s", |
95e6b1fa3 of: use kbasename... |
90 |
kbasename(node->full_name), dev_name(dev)); |
07e461cd7 of: Ensure unique... |
91 92 |
node = node->parent; } |
94c093198 of: Merge of_devi... |
93 94 95 96 97 98 99 100 |
} /** * 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... |
101 |
struct platform_device *of_device_alloc(struct device_node *np, |
94c093198 of: Merge of_devi... |
102 103 104 |
const char *bus_id, struct device *parent) { |
94a0cb1fc of/device: Replac... |
105 |
struct platform_device *dev; |
52f6537cb of/irq: remove re... |
106 |
int rc, i, num_reg = 0, num_irq; |
ac80a51e2 of/device: popula... |
107 |
struct resource *res, temp_res; |
6d7e3bf8d of: Use PLATFORM_... |
108 |
dev = platform_device_alloc("", PLATFORM_DEVID_NONE); |
7096d0422 of/device: Rework... |
109 110 111 112 |
if (!dev) return NULL; /* count the io and irq resources */ |
d9c6866be of: kill off of_c... |
113 114 |
while (of_address_to_resource(np, num_reg, &temp_res) == 0) num_reg++; |
52f6537cb of/irq: remove re... |
115 |
num_irq = of_irq_count(np); |
ac80a51e2 of/device: popula... |
116 |
|
ac80a51e2 of/device: popula... |
117 118 |
/* Populate the resource table */ if (num_irq || num_reg) { |
6396bb221 treewide: kzalloc... |
119 |
res = kcalloc(num_irq + num_reg, sizeof(*res), GFP_KERNEL); |
7096d0422 of/device: Rework... |
120 121 122 123 |
if (!res) { platform_device_put(dev); return NULL; } |
ac80a51e2 of/device: popula... |
124 125 126 127 128 129 |
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... |
130 |
if (of_irq_to_resource_table(np, res, num_irq) != num_irq) |
a613b26a5 of: Convert to us... |
131 132 133 |
pr_debug("not all legacy IRQ resources mapped for %pOFn ", np); |
ac80a51e2 of/device: popula... |
134 |
} |
94c093198 of: Merge of_devi... |
135 136 |
dev->dev.of_node = of_node_get(np); |
f94277af0 of/platform: Init... |
137 |
dev->dev.fwnode = &np->fwnode; |
43c0767e1 of/platform: Move... |
138 |
dev->dev.parent = parent ? : &platform_bus; |
94c093198 of: Merge of_devi... |
139 140 141 142 143 144 145 146 147 |
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); |
591c1ee46 of: configure the... |
148 |
/** |
15c3597d6 dt/platform: allo... |
149 |
* of_platform_device_create_pdata - Alloc, initialize and register an of_device |
5fd200f3b of/device: Merge ... |
150 151 |
* @np: pointer to node to create device for * @bus_id: name to assign device |
15c3597d6 dt/platform: allo... |
152 |
* @platform_data: pointer to populate platform_data pointer with |
5fd200f3b of/device: Merge ... |
153 |
* @parent: Linux device model parent device. |
cd1e65044 of/device: Don't ... |
154 155 156 |
* * Returns pointer to created platform device, or NULL if a device was not * registered. Unavailable devices will not get registered. |
5fd200f3b of/device: Merge ... |
157 |
*/ |
245d96419 of/platform: Stat... |
158 |
static struct platform_device *of_platform_device_create_pdata( |
15c3597d6 dt/platform: allo... |
159 160 161 162 |
struct device_node *np, const char *bus_id, void *platform_data, struct device *parent) |
5fd200f3b of/device: Merge ... |
163 |
{ |
94a0cb1fc of/device: Replac... |
164 |
struct platform_device *dev; |
5fd200f3b of/device: Merge ... |
165 |
|
c6e126de4 of: Keep track of... |
166 167 |
if (!of_device_is_available(np) || of_node_test_and_set_flag(np, OF_POPULATED)) |
cd1e65044 of/device: Don't ... |
168 |
return NULL; |
5fd200f3b of/device: Merge ... |
169 170 |
dev = of_device_alloc(np, bus_id, parent); if (!dev) |
c6e126de4 of: Keep track of... |
171 |
goto err_clear_flag; |
5fd200f3b of/device: Merge ... |
172 |
|
a5516219b of/platform: Init... |
173 174 175 |
dev->dev.coherent_dma_mask = DMA_BIT_MASK(32); if (!dev->dev.dma_mask) dev->dev.dma_mask = &dev->dev.coherent_dma_mask; |
eca393016 of: Merge of_plat... |
176 |
dev->dev.bus = &platform_bus_type; |
15c3597d6 dt/platform: allo... |
177 |
dev->dev.platform_data = platform_data; |
c706c239a of/platform: Assi... |
178 |
of_msi_configure(&dev->dev, dev->dev.of_node); |
5fd200f3b of/device: Merge ... |
179 |
|
7096d0422 of/device: Rework... |
180 181 |
if (of_device_add(dev) != 0) { platform_device_put(dev); |
c6e126de4 of: Keep track of... |
182 |
goto err_clear_flag; |
5fd200f3b of/device: Merge ... |
183 184 185 |
} return dev; |
c6e126de4 of: Keep track of... |
186 187 188 189 |
err_clear_flag: of_node_clear_flag(np, OF_POPULATED); return NULL; |
5fd200f3b of/device: Merge ... |
190 |
} |
15c3597d6 dt/platform: allo... |
191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 |
/** * 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 ... |
207 |
EXPORT_SYMBOL(of_platform_device_create); |
5de1540b7 drivers/amba: cre... |
208 209 210 211 212 213 214 215 216 |
#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; |
0d638a07d of: Convert to us... |
217 218 |
pr_debug("Creating amba device %pOF ", node); |
5de1540b7 drivers/amba: cre... |
219 |
|
c6e126de4 of: Keep track of... |
220 221 |
if (!of_device_is_available(node) || of_node_test_and_set_flag(node, OF_POPULATED)) |
5de1540b7 drivers/amba: cre... |
222 |
return NULL; |
c0f72f8a9 ARM: amba: of: co... |
223 |
dev = amba_device_alloc(NULL, 0, 0); |
606ad42aa of: use pr_fmt pr... |
224 |
if (!dev) |
c6e126de4 of: Keep track of... |
225 |
goto err_clear_flag; |
5de1540b7 drivers/amba: cre... |
226 |
|
8c89ef7b6 of/platform: init... |
227 228 229 |
/* AMBA devices only support a single DMA mask */ dev->dev.coherent_dma_mask = DMA_BIT_MASK(32); dev->dev.dma_mask = &dev->dev.coherent_dma_mask; |
5de1540b7 drivers/amba: cre... |
230 |
/* setup generic device info */ |
5de1540b7 drivers/amba: cre... |
231 |
dev->dev.of_node = of_node_get(node); |
f94277af0 of/platform: Init... |
232 |
dev->dev.fwnode = &node->fwnode; |
43c0767e1 of/platform: Move... |
233 |
dev->dev.parent = parent ? : &platform_bus; |
5de1540b7 drivers/amba: cre... |
234 235 236 237 238 |
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); |
5de1540b7 drivers/amba: cre... |
239 240 241 242 243 244 245 246 247 248 |
/* 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 ... |
249 |
if (ret) { |
0d638a07d of: Convert to us... |
250 251 252 |
pr_err("amba: of_address_to_resource() failed (%d) for %pOF ", ret, node); |
5de1540b7 drivers/amba: cre... |
253 |
goto err_free; |
2bc552df7 of/platform: add ... |
254 |
} |
5de1540b7 drivers/amba: cre... |
255 |
|
c0f72f8a9 ARM: amba: of: co... |
256 |
ret = amba_device_add(dev, &iomem_resource); |
2bc552df7 of/platform: add ... |
257 |
if (ret) { |
0d638a07d of: Convert to us... |
258 259 260 |
pr_err("amba_device_add() failed (%d) for %pOF ", ret, node); |
5de1540b7 drivers/amba: cre... |
261 |
goto err_free; |
2bc552df7 of/platform: add ... |
262 |
} |
5de1540b7 drivers/amba: cre... |
263 264 265 266 |
return dev; err_free: |
c0f72f8a9 ARM: amba: of: co... |
267 |
amba_device_put(dev); |
c6e126de4 of: Keep track of... |
268 269 |
err_clear_flag: of_node_clear_flag(node, OF_POPULATED); |
5de1540b7 drivers/amba: cre... |
270 271 272 273 274 275 276 277 278 279 280 |
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 ... |
281 |
/** |
15c3597d6 dt/platform: allo... |
282 283 284 285 286 |
* 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... |
287 |
const struct of_dev_auxdata *auxdata; |
15c3597d6 dt/platform: allo... |
288 |
struct resource res; |
fc5cf80ac of/platform: Allo... |
289 |
int compatible = 0; |
303f59d1a dt/platform: mino... |
290 291 292 |
if (!lookup) return NULL; |
fc5cf80ac of/platform: Allo... |
293 294 295 |
auxdata = lookup; for (; auxdata->compatible; auxdata++) { if (!of_device_is_compatible(np, auxdata->compatible)) |
303f59d1a dt/platform: mino... |
296 |
continue; |
fc5cf80ac of/platform: Allo... |
297 |
compatible++; |
84774e615 of: address: Don'... |
298 |
if (!of_address_to_resource(np, 0, &res)) |
fc5cf80ac of/platform: Allo... |
299 |
if (res.start != auxdata->phys_addr) |
84774e615 of: address: Don'... |
300 |
continue; |
0d638a07d of: Convert to us... |
301 302 |
pr_debug("%pOF: devname=%s ", np, auxdata->name); |
fc5cf80ac of/platform: Allo... |
303 304 305 306 307 308 309 310 311 312 313 314 |
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) { |
0d638a07d of: Convert to us... |
315 316 |
pr_debug("%pOF: compatible match ", np); |
fc5cf80ac of/platform: Allo... |
317 318 |
return auxdata; } |
15c3597d6 dt/platform: allo... |
319 |
} |
303f59d1a dt/platform: mino... |
320 |
|
15c3597d6 dt/platform: allo... |
321 322 323 324 |
return NULL; } /** |
38e9e21da dt: Refactor of_p... |
325 |
* of_platform_bus_create() - Create a device for a node and its children. |
5fd200f3b of/device: Merge ... |
326 |
* @bus: device node of the bus to instantiate |
1eed4c077 dt: eliminate OF_... |
327 |
* @matches: match table for bus nodes |
303f59d1a dt/platform: mino... |
328 |
* @lookup: auxdata table for matching id and platform_data with device nodes |
38e9e21da dt: Refactor of_p... |
329 |
* @parent: parent for new device, or NULL for top level. |
303f59d1a dt/platform: mino... |
330 |
* @strict: require compatible property |
38e9e21da dt: Refactor of_p... |
331 332 333 |
* * Creates a platform_device for the provided device_node, and optionally * recursively create devices for all the child nodes. |
5fd200f3b of/device: Merge ... |
334 |
*/ |
38e9e21da dt: Refactor of_p... |
335 |
static int of_platform_bus_create(struct device_node *bus, |
5fd200f3b of/device: Merge ... |
336 |
const struct of_device_id *matches, |
15c3597d6 dt/platform: allo... |
337 |
const struct of_dev_auxdata *lookup, |
29d4f8a49 dt: add of_platfo... |
338 |
struct device *parent, bool strict) |
5fd200f3b of/device: Merge ... |
339 |
{ |
15c3597d6 dt/platform: allo... |
340 |
const struct of_dev_auxdata *auxdata; |
5fd200f3b of/device: Merge ... |
341 |
struct device_node *child; |
94a0cb1fc of/device: Replac... |
342 |
struct platform_device *dev; |
15c3597d6 dt/platform: allo... |
343 344 |
const char *bus_id = NULL; void *platform_data = NULL; |
5fd200f3b of/device: Merge ... |
345 |
int rc = 0; |
29d4f8a49 dt: add of_platfo... |
346 347 |
/* Make sure it has a compatible property */ if (strict && (!of_get_property(bus, "compatible", NULL))) { |
0d638a07d of: Convert to us... |
348 349 350 |
pr_debug("%s() - skipping %pOF, no compatible prop ", __func__, bus); |
29d4f8a49 dt: add of_platfo... |
351 352 |
return 0; } |
4550fe637 of: Don't create ... |
353 354 355 356 357 358 |
/* Skip nodes for which we don't want to create devices */ if (unlikely(of_match_node(of_skipped_node_table, bus))) { pr_debug("%s() - skipping %pOF node ", __func__, bus); return 0; } |
44a7185c2 of/platform: Add ... |
359 |
if (of_node_check_flag(bus, OF_POPULATED_BUS)) { |
0d638a07d of: Convert to us... |
360 361 362 |
pr_debug("%s() - skipping %pOF, already populated ", __func__, bus); |
44a7185c2 of/platform: Add ... |
363 364 |
return 0; } |
15c3597d6 dt/platform: allo... |
365 366 367 368 369 |
auxdata = of_dev_lookup(lookup, bus); if (auxdata) { bus_id = auxdata->name; platform_data = auxdata->platform_data; } |
5de1540b7 drivers/amba: cre... |
370 |
if (of_device_is_compatible(bus, "arm,primecell")) { |
2bc552df7 of/platform: add ... |
371 372 373 374 |
/* * Don't return an error here to keep compatibility with older * device tree files. */ |
15c3597d6 dt/platform: allo... |
375 |
of_amba_device_create(bus, bus_id, platform_data, parent); |
5de1540b7 drivers/amba: cre... |
376 377 |
return 0; } |
15c3597d6 dt/platform: allo... |
378 |
dev = of_platform_device_create_pdata(bus, bus_id, platform_data, parent); |
38e9e21da dt: Refactor of_p... |
379 380 |
if (!dev || !of_match_node(matches, bus)) return 0; |
5fd200f3b of/device: Merge ... |
381 |
for_each_child_of_node(bus, child) { |
0d638a07d of: Convert to us... |
382 383 |
pr_debug(" create child: %pOF ", child); |
15c3597d6 dt/platform: allo... |
384 |
rc = of_platform_bus_create(child, matches, lookup, &dev->dev, strict); |
5fd200f3b of/device: Merge ... |
385 386 387 388 389 |
if (rc) { of_node_put(child); break; } } |
75f353b61 of/platform: Fix ... |
390 |
of_node_set_flag(bus, OF_POPULATED_BUS); |
5fd200f3b of/device: Merge ... |
391 392 393 394 |
return rc; } /** |
38e9e21da dt: Refactor of_p... |
395 |
* of_platform_bus_probe() - Probe the device-tree for platform buses |
5fd200f3b of/device: Merge ... |
396 |
* @root: parent of the first level to probe or NULL for the root of the tree |
1eed4c077 dt: eliminate OF_... |
397 |
* @matches: match table for bus nodes |
5fd200f3b of/device: Merge ... |
398 399 400 401 402 403 404 405 406 407 |
* @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 ... |
408 |
int rc = 0; |
1eed4c077 dt: eliminate OF_... |
409 410 |
root = root ? of_node_get(root) : of_find_node_by_path("/"); if (!root) |
60d599133 of/flattree: Fix ... |
411 |
return -EINVAL; |
5fd200f3b of/device: Merge ... |
412 |
|
44a7185c2 of/platform: Add ... |
413 414 |
pr_debug("%s() ", __func__); |
0d638a07d of: Convert to us... |
415 416 |
pr_debug(" starting at: %pOF ", root); |
5fd200f3b of/device: Merge ... |
417 |
|
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 |
pr_debug("%s() ", __func__); |
0d638a07d of: Convert to us... |
468 469 |
pr_debug(" starting at: %pOF ", root); |
44a7185c2 of/platform: Add ... |
470 |
|
5e6669387 of/platform: Paus... |
471 |
device_links_supplier_sync_state_pause(); |
29d4f8a49 dt: add of_platfo... |
472 |
for_each_child_of_node(root, child) { |
15c3597d6 dt/platform: allo... |
473 |
rc = of_platform_bus_create(child, matches, lookup, parent, true); |
7fad948a7 of/platform: add ... |
474 475 |
if (rc) { of_node_put(child); |
29d4f8a49 dt: add of_platfo... |
476 |
break; |
7fad948a7 of/platform: add ... |
477 |
} |
29d4f8a49 dt: add of_platfo... |
478 |
} |
5e6669387 of/platform: Paus... |
479 |
device_links_supplier_sync_state_resume(); |
2d0747c4b of: Properly set ... |
480 |
of_node_set_flag(root, OF_POPULATED_BUS); |
29d4f8a49 dt: add of_platfo... |
481 482 483 484 |
of_node_put(root); return rc; } |
e001f1c8e of: export of_pla... |
485 |
EXPORT_SYMBOL_GPL(of_platform_populate); |
c6e126de4 of: Keep track of... |
486 |
|
43443ad69 of/platform: add ... |
487 488 489 490 491 492 493 494 |
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... |
495 |
#ifndef CONFIG_PPC |
a50ff19d0 of/platform: Gene... |
496 |
static const struct of_device_id reserved_mem_matches[] = { |
d1de6d6c6 soc: qcom: Remote... |
497 |
{ .compatible = "qcom,rmtfs-mem" }, |
312416d91 drivers: qcom: ad... |
498 |
{ .compatible = "qcom,cmd-db" }, |
a50ff19d0 of/platform: Gene... |
499 500 501 |
{ .compatible = "ramoops" }, {} }; |
44a7185c2 of/platform: Add ... |
502 503 |
static int __init of_platform_default_populate_init(void) { |
529182e20 ramoops: use DT r... |
504 |
struct device_node *node; |
ee9b280e1 of/platform: Unco... |
505 |
device_links_supplier_sync_state_pause(); |
529182e20 ramoops: use DT r... |
506 507 508 509 |
if (!of_have_populated_dt()) return -ENODEV; /* |
a50ff19d0 of/platform: Gene... |
510 511 512 |
* Handle certain compatibles explicitly, since we don't want to create * platform_devices for every node in /reserved-memory with a * "compatible", |
529182e20 ramoops: use DT r... |
513 |
*/ |
a50ff19d0 of/platform: Gene... |
514 515 |
for_each_matching_node(node, reserved_mem_matches) of_platform_device_create(node, NULL, NULL); |
529182e20 ramoops: use DT r... |
516 |
|
3aa0582fd of: platform: pop... |
517 |
node = of_find_node_by_path("/firmware"); |
e2105ca8b of: platform: fix... |
518 |
if (node) { |
3aa0582fd of: platform: pop... |
519 |
of_platform_populate(node, NULL, NULL, NULL); |
e2105ca8b of: platform: fix... |
520 521 |
of_node_put(node); } |
3aa0582fd of: platform: pop... |
522 |
|
529182e20 ramoops: use DT r... |
523 524 |
/* Populate everything else. */ of_platform_default_populate(NULL, NULL, NULL); |
44a7185c2 of/platform: Add ... |
525 526 527 528 |
return 0; } arch_initcall_sync(of_platform_default_populate_init); |
5e6669387 of/platform: Paus... |
529 530 531 |
static int __init of_platform_sync_state_init(void) { |
ee9b280e1 of/platform: Unco... |
532 |
device_links_supplier_sync_state_resume(); |
5e6669387 of/platform: Paus... |
533 534 535 |
return 0; } late_initcall_sync(of_platform_sync_state_init); |
fc520f8b4 of/platform: disa... |
536 |
#endif |
44a7185c2 of/platform: Add ... |
537 |
|
c2372c204 of/platform: Make... |
538 |
int of_platform_device_destroy(struct device *dev, void *data) |
c6e126de4 of: Keep track of... |
539 |
{ |
c6e126de4 of: Keep track of... |
540 |
/* Do not touch devices not populated from the device tree */ |
75f353b61 of/platform: Fix ... |
541 |
if (!dev->of_node || !of_node_check_flag(dev->of_node, OF_POPULATED)) |
c6e126de4 of: Keep track of... |
542 |
return 0; |
c6e126de4 of: Keep track of... |
543 |
|
75f353b61 of/platform: Fix ... |
544 545 546 |
/* 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... |
547 |
|
522811e94 of: platform: sto... |
548 549 |
of_node_clear_flag(dev->of_node, OF_POPULATED); of_node_clear_flag(dev->of_node, OF_POPULATED_BUS); |
c6e126de4 of: Keep track of... |
550 551 552 553 554 555 |
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... |
556 |
|
c6e126de4 of: Keep track of... |
557 558 |
return 0; } |
c2372c204 of/platform: Make... |
559 |
EXPORT_SYMBOL_GPL(of_platform_device_destroy); |
c6e126de4 of: Keep track of... |
560 561 562 |
/** * of_platform_depopulate() - Remove devices populated from device tree |
75f353b61 of/platform: Fix ... |
563 |
* @parent: device which children will be removed |
c6e126de4 of: Keep track of... |
564 565 566 567 568 |
* * 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). |
c6e126de4 of: Keep track of... |
569 |
*/ |
75f353b61 of/platform: Fix ... |
570 |
void of_platform_depopulate(struct device *parent) |
c6e126de4 of: Keep track of... |
571 |
{ |
2d0747c4b of: Properly set ... |
572 573 574 575 |
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... |
576 577 |
} EXPORT_SYMBOL_GPL(of_platform_depopulate); |
38b0b219f of: add devm_ fun... |
578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 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 623 624 625 626 627 628 629 630 631 632 633 634 635 636 637 638 639 640 641 642 643 644 645 646 647 |
static void devm_of_platform_populate_release(struct device *dev, void *res) { of_platform_depopulate(*(struct device **)res); } /** * devm_of_platform_populate() - Populate platform_devices from device tree data * @dev: device that requested to populate from device tree data * * Similar to of_platform_populate(), but will automatically call * of_platform_depopulate() when the device is unbound from the bus. * * Returns 0 on success, < 0 on failure. */ int devm_of_platform_populate(struct device *dev) { struct device **ptr; int ret; if (!dev) return -EINVAL; ptr = devres_alloc(devm_of_platform_populate_release, sizeof(*ptr), GFP_KERNEL); if (!ptr) return -ENOMEM; ret = of_platform_populate(dev->of_node, NULL, NULL, dev); if (ret) { devres_free(ptr); } else { *ptr = dev; devres_add(dev, ptr); } return ret; } EXPORT_SYMBOL_GPL(devm_of_platform_populate); static int devm_of_platform_match(struct device *dev, void *res, void *data) { struct device **ptr = res; if (!ptr) { WARN_ON(!ptr); return 0; } return *ptr == data; } /** * devm_of_platform_depopulate() - Remove devices populated from device tree * @dev: device that requested to depopulate from device tree data * * Complementary to devm_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). */ void devm_of_platform_depopulate(struct device *dev) { int ret; ret = devres_release(dev, devm_of_platform_populate_release, devm_of_platform_match, dev); WARN_ON(ret); } EXPORT_SYMBOL_GPL(devm_of_platform_depopulate); |
801d728c1 of/reconfig: Add ... |
648 649 650 651 652 653 654 655 656 657 658 659 660 |
#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... |
661 662 663 |
/* already populated? (driver using of_populate manually) */ if (of_node_check_flag(rd->dn, OF_POPULATED)) return NOTIFY_OK; |
801d728c1 of/reconfig: Add ... |
664 665 666 667 668 669 670 |
/* 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) { |
0d638a07d of: Convert to us... |
671 672 673 |
pr_err("%s: failed to create for '%pOF' ", __func__, rd->dn); |
801d728c1 of/reconfig: Add ... |
674 675 676 677 678 679 |
/* of_platform_device_create tosses the error code */ return notifier_from_errno(-EINVAL); } break; case OF_RECONFIG_CHANGE_REMOVE: |
15204ab1e of/platform: Hand... |
680 681 682 683 |
/* already depopulated? */ if (!of_node_check_flag(rd->dn, OF_POPULATED)) return NOTIFY_OK; |
801d728c1 of/reconfig: Add ... |
684 685 686 687 688 689 690 691 692 693 694 695 696 697 698 699 700 701 702 703 704 705 706 707 708 |
/* 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... |
709 |
#endif /* CONFIG_OF_ADDRESS */ |