diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2011-07-22 17:53:38 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2011-07-22 17:53:38 -0400 |
commit | 8181780c163e7111f15619067cfa044172d532e1 (patch) | |
tree | 7eec99ddd1b20e9018edfba5c05a179b317c27fe /drivers/of/platform.c | |
parent | 7235dd74a4733d4b3651349b5261d2e06996427d (diff) | |
parent | 99ce39e359fa29e4b609a6a13485e7573eda5dfb (diff) |
Merge branch 'devicetree/next' of git://git.secretlab.ca/git/linux-2.6
* 'devicetree/next' of git://git.secretlab.ca/git/linux-2.6:
dt: include linux/errno.h in linux/of_address.h
of/address: Add of_find_matching_node_by_address helper
dt: remove extra xsysace platform_driver registration
tty/serial: Add devicetree support for nVidia Tegra serial ports
dt: add empty of_property_read_u32[_array] for non-dt
dt: bindings: move SEC node under new crypto/
dt: add helper function to read u32 arrays
tty/serial: change of_serial to use new of_property_read_u32() api
dt: add 'const' for of_property_read_string parameter **out_string
dt: add helper functions to read u32 and string property values
tty: of_serial: support for 32 bit accesses
dt: document the of_serial bindings
dt/platform: allow device name to be overridden
drivers/amba: create devices from device tree
dt: add of_platform_populate() for creating device from the device tree
dt: Add default match table for bus ids
Diffstat (limited to 'drivers/of/platform.c')
-rw-r--r-- | drivers/of/platform.c | 196 |
1 files changed, 187 insertions, 9 deletions
diff --git a/drivers/of/platform.c b/drivers/of/platform.c index 63d3cb73bdb9..e75af391e286 100644 --- a/drivers/of/platform.c +++ b/drivers/of/platform.c | |||
@@ -13,6 +13,7 @@ | |||
13 | */ | 13 | */ |
14 | #include <linux/errno.h> | 14 | #include <linux/errno.h> |
15 | #include <linux/module.h> | 15 | #include <linux/module.h> |
16 | #include <linux/amba/bus.h> | ||
16 | #include <linux/device.h> | 17 | #include <linux/device.h> |
17 | #include <linux/dma-mapping.h> | 18 | #include <linux/dma-mapping.h> |
18 | #include <linux/slab.h> | 19 | #include <linux/slab.h> |
@@ -22,6 +23,14 @@ | |||
22 | #include <linux/of_platform.h> | 23 | #include <linux/of_platform.h> |
23 | #include <linux/platform_device.h> | 24 | #include <linux/platform_device.h> |
24 | 25 | ||
26 | const struct of_device_id of_default_bus_match_table[] = { | ||
27 | { .compatible = "simple-bus", }, | ||
28 | #ifdef CONFIG_ARM_AMBA | ||
29 | { .compatible = "arm,amba-bus", }, | ||
30 | #endif /* CONFIG_ARM_AMBA */ | ||
31 | {} /* Empty terminated list */ | ||
32 | }; | ||
33 | |||
25 | static int of_dev_node_match(struct device *dev, void *data) | 34 | static int of_dev_node_match(struct device *dev, void *data) |
26 | { | 35 | { |
27 | return dev->of_node == data; | 36 | return dev->of_node == data; |
@@ -168,17 +177,20 @@ struct platform_device *of_device_alloc(struct device_node *np, | |||
168 | EXPORT_SYMBOL(of_device_alloc); | 177 | EXPORT_SYMBOL(of_device_alloc); |
169 | 178 | ||
170 | /** | 179 | /** |
171 | * of_platform_device_create - Alloc, initialize and register an of_device | 180 | * of_platform_device_create_pdata - Alloc, initialize and register an of_device |
172 | * @np: pointer to node to create device for | 181 | * @np: pointer to node to create device for |
173 | * @bus_id: name to assign device | 182 | * @bus_id: name to assign device |
183 | * @platform_data: pointer to populate platform_data pointer with | ||
174 | * @parent: Linux device model parent device. | 184 | * @parent: Linux device model parent device. |
175 | * | 185 | * |
176 | * Returns pointer to created platform device, or NULL if a device was not | 186 | * Returns pointer to created platform device, or NULL if a device was not |
177 | * registered. Unavailable devices will not get registered. | 187 | * registered. Unavailable devices will not get registered. |
178 | */ | 188 | */ |
179 | struct platform_device *of_platform_device_create(struct device_node *np, | 189 | struct platform_device *of_platform_device_create_pdata( |
180 | const char *bus_id, | 190 | struct device_node *np, |
181 | struct device *parent) | 191 | const char *bus_id, |
192 | void *platform_data, | ||
193 | struct device *parent) | ||
182 | { | 194 | { |
183 | struct platform_device *dev; | 195 | struct platform_device *dev; |
184 | 196 | ||
@@ -194,6 +206,7 @@ struct platform_device *of_platform_device_create(struct device_node *np, | |||
194 | #endif | 206 | #endif |
195 | dev->dev.coherent_dma_mask = DMA_BIT_MASK(32); | 207 | dev->dev.coherent_dma_mask = DMA_BIT_MASK(32); |
196 | dev->dev.bus = &platform_bus_type; | 208 | dev->dev.bus = &platform_bus_type; |
209 | dev->dev.platform_data = platform_data; | ||
197 | 210 | ||
198 | /* We do not fill the DMA ops for platform devices by default. | 211 | /* We do not fill the DMA ops for platform devices by default. |
199 | * This is currently the responsibility of the platform code | 212 | * This is currently the responsibility of the platform code |
@@ -207,8 +220,111 @@ struct platform_device *of_platform_device_create(struct device_node *np, | |||
207 | 220 | ||
208 | return dev; | 221 | return dev; |
209 | } | 222 | } |
223 | |||
224 | /** | ||
225 | * of_platform_device_create - Alloc, initialize and register an of_device | ||
226 | * @np: pointer to node to create device for | ||
227 | * @bus_id: name to assign device | ||
228 | * @parent: Linux device model parent device. | ||
229 | * | ||
230 | * Returns pointer to created platform device, or NULL if a device was not | ||
231 | * registered. Unavailable devices will not get registered. | ||
232 | */ | ||
233 | struct platform_device *of_platform_device_create(struct device_node *np, | ||
234 | const char *bus_id, | ||
235 | struct device *parent) | ||
236 | { | ||
237 | return of_platform_device_create_pdata(np, bus_id, NULL, parent); | ||
238 | } | ||
210 | EXPORT_SYMBOL(of_platform_device_create); | 239 | EXPORT_SYMBOL(of_platform_device_create); |
211 | 240 | ||
241 | #ifdef CONFIG_ARM_AMBA | ||
242 | static struct amba_device *of_amba_device_create(struct device_node *node, | ||
243 | const char *bus_id, | ||
244 | void *platform_data, | ||
245 | struct device *parent) | ||
246 | { | ||
247 | struct amba_device *dev; | ||
248 | const void *prop; | ||
249 | int i, ret; | ||
250 | |||
251 | pr_debug("Creating amba device %s\n", node->full_name); | ||
252 | |||
253 | if (!of_device_is_available(node)) | ||
254 | return NULL; | ||
255 | |||
256 | dev = kzalloc(sizeof(*dev), GFP_KERNEL); | ||
257 | if (!dev) | ||
258 | return NULL; | ||
259 | |||
260 | /* setup generic device info */ | ||
261 | dev->dev.coherent_dma_mask = ~0; | ||
262 | dev->dev.of_node = of_node_get(node); | ||
263 | dev->dev.parent = parent; | ||
264 | dev->dev.platform_data = platform_data; | ||
265 | if (bus_id) | ||
266 | dev_set_name(&dev->dev, "%s", bus_id); | ||
267 | else | ||
268 | of_device_make_bus_id(&dev->dev); | ||
269 | |||
270 | /* setup amba-specific device info */ | ||
271 | dev->dma_mask = ~0; | ||
272 | |||
273 | /* Allow the HW Peripheral ID to be overridden */ | ||
274 | prop = of_get_property(node, "arm,primecell-periphid", NULL); | ||
275 | if (prop) | ||
276 | dev->periphid = of_read_ulong(prop, 1); | ||
277 | |||
278 | /* Decode the IRQs and address ranges */ | ||
279 | for (i = 0; i < AMBA_NR_IRQS; i++) | ||
280 | dev->irq[i] = irq_of_parse_and_map(node, i); | ||
281 | |||
282 | ret = of_address_to_resource(node, 0, &dev->res); | ||
283 | if (ret) | ||
284 | goto err_free; | ||
285 | |||
286 | ret = amba_device_register(dev, &iomem_resource); | ||
287 | if (ret) | ||
288 | goto err_free; | ||
289 | |||
290 | return dev; | ||
291 | |||
292 | err_free: | ||
293 | kfree(dev); | ||
294 | return NULL; | ||
295 | } | ||
296 | #else /* CONFIG_ARM_AMBA */ | ||
297 | static struct amba_device *of_amba_device_create(struct device_node *node, | ||
298 | const char *bus_id, | ||
299 | void *platform_data, | ||
300 | struct device *parent) | ||
301 | { | ||
302 | return NULL; | ||
303 | } | ||
304 | #endif /* CONFIG_ARM_AMBA */ | ||
305 | |||
306 | /** | ||
307 | * of_devname_lookup() - Given a device node, lookup the preferred Linux name | ||
308 | */ | ||
309 | static const struct of_dev_auxdata *of_dev_lookup(const struct of_dev_auxdata *lookup, | ||
310 | struct device_node *np) | ||
311 | { | ||
312 | struct resource res; | ||
313 | if (lookup) { | ||
314 | for(; lookup->name != NULL; lookup++) { | ||
315 | if (!of_device_is_compatible(np, lookup->compatible)) | ||
316 | continue; | ||
317 | if (of_address_to_resource(np, 0, &res)) | ||
318 | continue; | ||
319 | if (res.start != lookup->phys_addr) | ||
320 | continue; | ||
321 | pr_debug("%s: devname=%s\n", np->full_name, lookup->name); | ||
322 | return lookup; | ||
323 | } | ||
324 | } | ||
325 | return NULL; | ||
326 | } | ||
327 | |||
212 | /** | 328 | /** |
213 | * of_platform_bus_create() - Create a device for a node and its children. | 329 | * of_platform_bus_create() - Create a device for a node and its children. |
214 | * @bus: device node of the bus to instantiate | 330 | * @bus: device node of the bus to instantiate |
@@ -221,19 +337,41 @@ EXPORT_SYMBOL(of_platform_device_create); | |||
221 | */ | 337 | */ |
222 | static int of_platform_bus_create(struct device_node *bus, | 338 | static int of_platform_bus_create(struct device_node *bus, |
223 | const struct of_device_id *matches, | 339 | const struct of_device_id *matches, |
224 | struct device *parent) | 340 | const struct of_dev_auxdata *lookup, |
341 | struct device *parent, bool strict) | ||
225 | { | 342 | { |
343 | const struct of_dev_auxdata *auxdata; | ||
226 | struct device_node *child; | 344 | struct device_node *child; |
227 | struct platform_device *dev; | 345 | struct platform_device *dev; |
346 | const char *bus_id = NULL; | ||
347 | void *platform_data = NULL; | ||
228 | int rc = 0; | 348 | int rc = 0; |
229 | 349 | ||
230 | dev = of_platform_device_create(bus, NULL, parent); | 350 | /* Make sure it has a compatible property */ |
351 | if (strict && (!of_get_property(bus, "compatible", NULL))) { | ||
352 | pr_debug("%s() - skipping %s, no compatible prop\n", | ||
353 | __func__, bus->full_name); | ||
354 | return 0; | ||
355 | } | ||
356 | |||
357 | auxdata = of_dev_lookup(lookup, bus); | ||
358 | if (auxdata) { | ||
359 | bus_id = auxdata->name; | ||
360 | platform_data = auxdata->platform_data; | ||
361 | } | ||
362 | |||
363 | if (of_device_is_compatible(bus, "arm,primecell")) { | ||
364 | of_amba_device_create(bus, bus_id, platform_data, parent); | ||
365 | return 0; | ||
366 | } | ||
367 | |||
368 | dev = of_platform_device_create_pdata(bus, bus_id, platform_data, parent); | ||
231 | if (!dev || !of_match_node(matches, bus)) | 369 | if (!dev || !of_match_node(matches, bus)) |
232 | return 0; | 370 | return 0; |
233 | 371 | ||
234 | for_each_child_of_node(bus, child) { | 372 | for_each_child_of_node(bus, child) { |
235 | pr_debug(" create child: %s\n", child->full_name); | 373 | pr_debug(" create child: %s\n", child->full_name); |
236 | rc = of_platform_bus_create(child, matches, &dev->dev); | 374 | rc = of_platform_bus_create(child, matches, lookup, &dev->dev, strict); |
237 | if (rc) { | 375 | if (rc) { |
238 | of_node_put(child); | 376 | of_node_put(child); |
239 | break; | 377 | break; |
@@ -267,11 +405,11 @@ int of_platform_bus_probe(struct device_node *root, | |||
267 | 405 | ||
268 | /* Do a self check of bus type, if there's a match, create children */ | 406 | /* Do a self check of bus type, if there's a match, create children */ |
269 | if (of_match_node(matches, root)) { | 407 | if (of_match_node(matches, root)) { |
270 | rc = of_platform_bus_create(root, matches, parent); | 408 | rc = of_platform_bus_create(root, matches, NULL, parent, false); |
271 | } else for_each_child_of_node(root, child) { | 409 | } else for_each_child_of_node(root, child) { |
272 | if (!of_match_node(matches, child)) | 410 | if (!of_match_node(matches, child)) |
273 | continue; | 411 | continue; |
274 | rc = of_platform_bus_create(child, matches, parent); | 412 | rc = of_platform_bus_create(child, matches, NULL, parent, false); |
275 | if (rc) | 413 | if (rc) |
276 | break; | 414 | break; |
277 | } | 415 | } |
@@ -280,4 +418,44 @@ int of_platform_bus_probe(struct device_node *root, | |||
280 | return rc; | 418 | return rc; |
281 | } | 419 | } |
282 | EXPORT_SYMBOL(of_platform_bus_probe); | 420 | EXPORT_SYMBOL(of_platform_bus_probe); |
421 | |||
422 | /** | ||
423 | * of_platform_populate() - Populate platform_devices from device tree data | ||
424 | * @root: parent of the first level to probe or NULL for the root of the tree | ||
425 | * @matches: match table, NULL to use the default | ||
426 | * @parent: parent to hook devices from, NULL for toplevel | ||
427 | * | ||
428 | * Similar to of_platform_bus_probe(), this function walks the device tree | ||
429 | * and creates devices from nodes. It differs in that it follows the modern | ||
430 | * convention of requiring all device nodes to have a 'compatible' property, | ||
431 | * and it is suitable for creating devices which are children of the root | ||
432 | * node (of_platform_bus_probe will only create children of the root which | ||
433 | * are selected by the @matches argument). | ||
434 | * | ||
435 | * New board support should be using this function instead of | ||
436 | * of_platform_bus_probe(). | ||
437 | * | ||
438 | * Returns 0 on success, < 0 on failure. | ||
439 | */ | ||
440 | int of_platform_populate(struct device_node *root, | ||
441 | const struct of_device_id *matches, | ||
442 | const struct of_dev_auxdata *lookup, | ||
443 | struct device *parent) | ||
444 | { | ||
445 | struct device_node *child; | ||
446 | int rc = 0; | ||
447 | |||
448 | root = root ? of_node_get(root) : of_find_node_by_path("/"); | ||
449 | if (!root) | ||
450 | return -EINVAL; | ||
451 | |||
452 | for_each_child_of_node(root, child) { | ||
453 | rc = of_platform_bus_create(child, matches, lookup, parent, true); | ||
454 | if (rc) | ||
455 | break; | ||
456 | } | ||
457 | |||
458 | of_node_put(root); | ||
459 | return rc; | ||
460 | } | ||
283 | #endif /* !CONFIG_SPARC */ | 461 | #endif /* !CONFIG_SPARC */ |