diff options
Diffstat (limited to 'drivers/of/platform.c')
-rw-r--r-- | drivers/of/platform.c | 573 |
1 files changed, 45 insertions, 528 deletions
diff --git a/drivers/of/platform.c b/drivers/of/platform.c index bb72223c22ae..63d3cb73bdb9 100644 --- a/drivers/of/platform.c +++ b/drivers/of/platform.c | |||
@@ -42,471 +42,10 @@ struct platform_device *of_find_device_by_node(struct device_node *np) | |||
42 | } | 42 | } |
43 | EXPORT_SYMBOL(of_find_device_by_node); | 43 | EXPORT_SYMBOL(of_find_device_by_node); |
44 | 44 | ||
45 | static int platform_driver_probe_shim(struct platform_device *pdev) | ||
46 | { | ||
47 | struct platform_driver *pdrv; | ||
48 | struct of_platform_driver *ofpdrv; | ||
49 | const struct of_device_id *match; | ||
50 | |||
51 | pdrv = container_of(pdev->dev.driver, struct platform_driver, driver); | ||
52 | ofpdrv = container_of(pdrv, struct of_platform_driver, platform_driver); | ||
53 | |||
54 | /* There is an unlikely chance that an of_platform driver might match | ||
55 | * on a non-OF platform device. If so, then of_match_device() will | ||
56 | * come up empty. Return -EINVAL in this case so other drivers get | ||
57 | * the chance to bind. */ | ||
58 | match = of_match_device(pdev->dev.driver->of_match_table, &pdev->dev); | ||
59 | return match ? ofpdrv->probe(pdev, match) : -EINVAL; | ||
60 | } | ||
61 | |||
62 | static void platform_driver_shutdown_shim(struct platform_device *pdev) | ||
63 | { | ||
64 | struct platform_driver *pdrv; | ||
65 | struct of_platform_driver *ofpdrv; | ||
66 | |||
67 | pdrv = container_of(pdev->dev.driver, struct platform_driver, driver); | ||
68 | ofpdrv = container_of(pdrv, struct of_platform_driver, platform_driver); | ||
69 | ofpdrv->shutdown(pdev); | ||
70 | } | ||
71 | |||
72 | /** | ||
73 | * of_register_platform_driver | ||
74 | */ | ||
75 | int of_register_platform_driver(struct of_platform_driver *drv) | ||
76 | { | ||
77 | char *of_name; | ||
78 | |||
79 | /* setup of_platform_driver to platform_driver adaptors */ | ||
80 | drv->platform_driver.driver = drv->driver; | ||
81 | |||
82 | /* Prefix the driver name with 'of:' to avoid namespace collisions | ||
83 | * and bogus matches. There are some drivers in the tree that | ||
84 | * register both an of_platform_driver and a platform_driver with | ||
85 | * the same name. This is a temporary measure until they are all | ||
86 | * cleaned up --gcl July 29, 2010 */ | ||
87 | of_name = kmalloc(strlen(drv->driver.name) + 5, GFP_KERNEL); | ||
88 | if (!of_name) | ||
89 | return -ENOMEM; | ||
90 | sprintf(of_name, "of:%s", drv->driver.name); | ||
91 | drv->platform_driver.driver.name = of_name; | ||
92 | |||
93 | if (drv->probe) | ||
94 | drv->platform_driver.probe = platform_driver_probe_shim; | ||
95 | drv->platform_driver.remove = drv->remove; | ||
96 | if (drv->shutdown) | ||
97 | drv->platform_driver.shutdown = platform_driver_shutdown_shim; | ||
98 | drv->platform_driver.suspend = drv->suspend; | ||
99 | drv->platform_driver.resume = drv->resume; | ||
100 | |||
101 | return platform_driver_register(&drv->platform_driver); | ||
102 | } | ||
103 | EXPORT_SYMBOL(of_register_platform_driver); | ||
104 | |||
105 | void of_unregister_platform_driver(struct of_platform_driver *drv) | ||
106 | { | ||
107 | platform_driver_unregister(&drv->platform_driver); | ||
108 | kfree(drv->platform_driver.driver.name); | ||
109 | drv->platform_driver.driver.name = NULL; | ||
110 | } | ||
111 | EXPORT_SYMBOL(of_unregister_platform_driver); | ||
112 | |||
113 | #if defined(CONFIG_PPC_DCR) | 45 | #if defined(CONFIG_PPC_DCR) |
114 | #include <asm/dcr.h> | 46 | #include <asm/dcr.h> |
115 | #endif | 47 | #endif |
116 | 48 | ||
117 | extern struct device_attribute of_platform_device_attrs[]; | ||
118 | |||
119 | static int of_platform_bus_match(struct device *dev, struct device_driver *drv) | ||
120 | { | ||
121 | const struct of_device_id *matches = drv->of_match_table; | ||
122 | |||
123 | if (!matches) | ||
124 | return 0; | ||
125 | |||
126 | return of_match_device(matches, dev) != NULL; | ||
127 | } | ||
128 | |||
129 | static int of_platform_device_probe(struct device *dev) | ||
130 | { | ||
131 | int error = -ENODEV; | ||
132 | struct of_platform_driver *drv; | ||
133 | struct platform_device *of_dev; | ||
134 | const struct of_device_id *match; | ||
135 | |||
136 | drv = to_of_platform_driver(dev->driver); | ||
137 | of_dev = to_platform_device(dev); | ||
138 | |||
139 | if (!drv->probe) | ||
140 | return error; | ||
141 | |||
142 | of_dev_get(of_dev); | ||
143 | |||
144 | match = of_match_device(drv->driver.of_match_table, dev); | ||
145 | if (match) | ||
146 | error = drv->probe(of_dev, match); | ||
147 | if (error) | ||
148 | of_dev_put(of_dev); | ||
149 | |||
150 | return error; | ||
151 | } | ||
152 | |||
153 | static int of_platform_device_remove(struct device *dev) | ||
154 | { | ||
155 | struct platform_device *of_dev = to_platform_device(dev); | ||
156 | struct of_platform_driver *drv = to_of_platform_driver(dev->driver); | ||
157 | |||
158 | if (dev->driver && drv->remove) | ||
159 | drv->remove(of_dev); | ||
160 | return 0; | ||
161 | } | ||
162 | |||
163 | static void of_platform_device_shutdown(struct device *dev) | ||
164 | { | ||
165 | struct platform_device *of_dev = to_platform_device(dev); | ||
166 | struct of_platform_driver *drv = to_of_platform_driver(dev->driver); | ||
167 | |||
168 | if (dev->driver && drv->shutdown) | ||
169 | drv->shutdown(of_dev); | ||
170 | } | ||
171 | |||
172 | #ifdef CONFIG_PM_SLEEP | ||
173 | |||
174 | static int of_platform_legacy_suspend(struct device *dev, pm_message_t mesg) | ||
175 | { | ||
176 | struct platform_device *of_dev = to_platform_device(dev); | ||
177 | struct of_platform_driver *drv = to_of_platform_driver(dev->driver); | ||
178 | int ret = 0; | ||
179 | |||
180 | if (dev->driver && drv->suspend) | ||
181 | ret = drv->suspend(of_dev, mesg); | ||
182 | return ret; | ||
183 | } | ||
184 | |||
185 | static int of_platform_legacy_resume(struct device *dev) | ||
186 | { | ||
187 | struct platform_device *of_dev = to_platform_device(dev); | ||
188 | struct of_platform_driver *drv = to_of_platform_driver(dev->driver); | ||
189 | int ret = 0; | ||
190 | |||
191 | if (dev->driver && drv->resume) | ||
192 | ret = drv->resume(of_dev); | ||
193 | return ret; | ||
194 | } | ||
195 | |||
196 | static int of_platform_pm_prepare(struct device *dev) | ||
197 | { | ||
198 | struct device_driver *drv = dev->driver; | ||
199 | int ret = 0; | ||
200 | |||
201 | if (drv && drv->pm && drv->pm->prepare) | ||
202 | ret = drv->pm->prepare(dev); | ||
203 | |||
204 | return ret; | ||
205 | } | ||
206 | |||
207 | static void of_platform_pm_complete(struct device *dev) | ||
208 | { | ||
209 | struct device_driver *drv = dev->driver; | ||
210 | |||
211 | if (drv && drv->pm && drv->pm->complete) | ||
212 | drv->pm->complete(dev); | ||
213 | } | ||
214 | |||
215 | #ifdef CONFIG_SUSPEND | ||
216 | |||
217 | static int of_platform_pm_suspend(struct device *dev) | ||
218 | { | ||
219 | struct device_driver *drv = dev->driver; | ||
220 | int ret = 0; | ||
221 | |||
222 | if (!drv) | ||
223 | return 0; | ||
224 | |||
225 | if (drv->pm) { | ||
226 | if (drv->pm->suspend) | ||
227 | ret = drv->pm->suspend(dev); | ||
228 | } else { | ||
229 | ret = of_platform_legacy_suspend(dev, PMSG_SUSPEND); | ||
230 | } | ||
231 | |||
232 | return ret; | ||
233 | } | ||
234 | |||
235 | static int of_platform_pm_suspend_noirq(struct device *dev) | ||
236 | { | ||
237 | struct device_driver *drv = dev->driver; | ||
238 | int ret = 0; | ||
239 | |||
240 | if (!drv) | ||
241 | return 0; | ||
242 | |||
243 | if (drv->pm) { | ||
244 | if (drv->pm->suspend_noirq) | ||
245 | ret = drv->pm->suspend_noirq(dev); | ||
246 | } | ||
247 | |||
248 | return ret; | ||
249 | } | ||
250 | |||
251 | static int of_platform_pm_resume(struct device *dev) | ||
252 | { | ||
253 | struct device_driver *drv = dev->driver; | ||
254 | int ret = 0; | ||
255 | |||
256 | if (!drv) | ||
257 | return 0; | ||
258 | |||
259 | if (drv->pm) { | ||
260 | if (drv->pm->resume) | ||
261 | ret = drv->pm->resume(dev); | ||
262 | } else { | ||
263 | ret = of_platform_legacy_resume(dev); | ||
264 | } | ||
265 | |||
266 | return ret; | ||
267 | } | ||
268 | |||
269 | static int of_platform_pm_resume_noirq(struct device *dev) | ||
270 | { | ||
271 | struct device_driver *drv = dev->driver; | ||
272 | int ret = 0; | ||
273 | |||
274 | if (!drv) | ||
275 | return 0; | ||
276 | |||
277 | if (drv->pm) { | ||
278 | if (drv->pm->resume_noirq) | ||
279 | ret = drv->pm->resume_noirq(dev); | ||
280 | } | ||
281 | |||
282 | return ret; | ||
283 | } | ||
284 | |||
285 | #else /* !CONFIG_SUSPEND */ | ||
286 | |||
287 | #define of_platform_pm_suspend NULL | ||
288 | #define of_platform_pm_resume NULL | ||
289 | #define of_platform_pm_suspend_noirq NULL | ||
290 | #define of_platform_pm_resume_noirq NULL | ||
291 | |||
292 | #endif /* !CONFIG_SUSPEND */ | ||
293 | |||
294 | #ifdef CONFIG_HIBERNATION | ||
295 | |||
296 | static int of_platform_pm_freeze(struct device *dev) | ||
297 | { | ||
298 | struct device_driver *drv = dev->driver; | ||
299 | int ret = 0; | ||
300 | |||
301 | if (!drv) | ||
302 | return 0; | ||
303 | |||
304 | if (drv->pm) { | ||
305 | if (drv->pm->freeze) | ||
306 | ret = drv->pm->freeze(dev); | ||
307 | } else { | ||
308 | ret = of_platform_legacy_suspend(dev, PMSG_FREEZE); | ||
309 | } | ||
310 | |||
311 | return ret; | ||
312 | } | ||
313 | |||
314 | static int of_platform_pm_freeze_noirq(struct device *dev) | ||
315 | { | ||
316 | struct device_driver *drv = dev->driver; | ||
317 | int ret = 0; | ||
318 | |||
319 | if (!drv) | ||
320 | return 0; | ||
321 | |||
322 | if (drv->pm) { | ||
323 | if (drv->pm->freeze_noirq) | ||
324 | ret = drv->pm->freeze_noirq(dev); | ||
325 | } | ||
326 | |||
327 | return ret; | ||
328 | } | ||
329 | |||
330 | static int of_platform_pm_thaw(struct device *dev) | ||
331 | { | ||
332 | struct device_driver *drv = dev->driver; | ||
333 | int ret = 0; | ||
334 | |||
335 | if (!drv) | ||
336 | return 0; | ||
337 | |||
338 | if (drv->pm) { | ||
339 | if (drv->pm->thaw) | ||
340 | ret = drv->pm->thaw(dev); | ||
341 | } else { | ||
342 | ret = of_platform_legacy_resume(dev); | ||
343 | } | ||
344 | |||
345 | return ret; | ||
346 | } | ||
347 | |||
348 | static int of_platform_pm_thaw_noirq(struct device *dev) | ||
349 | { | ||
350 | struct device_driver *drv = dev->driver; | ||
351 | int ret = 0; | ||
352 | |||
353 | if (!drv) | ||
354 | return 0; | ||
355 | |||
356 | if (drv->pm) { | ||
357 | if (drv->pm->thaw_noirq) | ||
358 | ret = drv->pm->thaw_noirq(dev); | ||
359 | } | ||
360 | |||
361 | return ret; | ||
362 | } | ||
363 | |||
364 | static int of_platform_pm_poweroff(struct device *dev) | ||
365 | { | ||
366 | struct device_driver *drv = dev->driver; | ||
367 | int ret = 0; | ||
368 | |||
369 | if (!drv) | ||
370 | return 0; | ||
371 | |||
372 | if (drv->pm) { | ||
373 | if (drv->pm->poweroff) | ||
374 | ret = drv->pm->poweroff(dev); | ||
375 | } else { | ||
376 | ret = of_platform_legacy_suspend(dev, PMSG_HIBERNATE); | ||
377 | } | ||
378 | |||
379 | return ret; | ||
380 | } | ||
381 | |||
382 | static int of_platform_pm_poweroff_noirq(struct device *dev) | ||
383 | { | ||
384 | struct device_driver *drv = dev->driver; | ||
385 | int ret = 0; | ||
386 | |||
387 | if (!drv) | ||
388 | return 0; | ||
389 | |||
390 | if (drv->pm) { | ||
391 | if (drv->pm->poweroff_noirq) | ||
392 | ret = drv->pm->poweroff_noirq(dev); | ||
393 | } | ||
394 | |||
395 | return ret; | ||
396 | } | ||
397 | |||
398 | static int of_platform_pm_restore(struct device *dev) | ||
399 | { | ||
400 | struct device_driver *drv = dev->driver; | ||
401 | int ret = 0; | ||
402 | |||
403 | if (!drv) | ||
404 | return 0; | ||
405 | |||
406 | if (drv->pm) { | ||
407 | if (drv->pm->restore) | ||
408 | ret = drv->pm->restore(dev); | ||
409 | } else { | ||
410 | ret = of_platform_legacy_resume(dev); | ||
411 | } | ||
412 | |||
413 | return ret; | ||
414 | } | ||
415 | |||
416 | static int of_platform_pm_restore_noirq(struct device *dev) | ||
417 | { | ||
418 | struct device_driver *drv = dev->driver; | ||
419 | int ret = 0; | ||
420 | |||
421 | if (!drv) | ||
422 | return 0; | ||
423 | |||
424 | if (drv->pm) { | ||
425 | if (drv->pm->restore_noirq) | ||
426 | ret = drv->pm->restore_noirq(dev); | ||
427 | } | ||
428 | |||
429 | return ret; | ||
430 | } | ||
431 | |||
432 | #else /* !CONFIG_HIBERNATION */ | ||
433 | |||
434 | #define of_platform_pm_freeze NULL | ||
435 | #define of_platform_pm_thaw NULL | ||
436 | #define of_platform_pm_poweroff NULL | ||
437 | #define of_platform_pm_restore NULL | ||
438 | #define of_platform_pm_freeze_noirq NULL | ||
439 | #define of_platform_pm_thaw_noirq NULL | ||
440 | #define of_platform_pm_poweroff_noirq NULL | ||
441 | #define of_platform_pm_restore_noirq NULL | ||
442 | |||
443 | #endif /* !CONFIG_HIBERNATION */ | ||
444 | |||
445 | static struct dev_pm_ops of_platform_dev_pm_ops = { | ||
446 | .prepare = of_platform_pm_prepare, | ||
447 | .complete = of_platform_pm_complete, | ||
448 | .suspend = of_platform_pm_suspend, | ||
449 | .resume = of_platform_pm_resume, | ||
450 | .freeze = of_platform_pm_freeze, | ||
451 | .thaw = of_platform_pm_thaw, | ||
452 | .poweroff = of_platform_pm_poweroff, | ||
453 | .restore = of_platform_pm_restore, | ||
454 | .suspend_noirq = of_platform_pm_suspend_noirq, | ||
455 | .resume_noirq = of_platform_pm_resume_noirq, | ||
456 | .freeze_noirq = of_platform_pm_freeze_noirq, | ||
457 | .thaw_noirq = of_platform_pm_thaw_noirq, | ||
458 | .poweroff_noirq = of_platform_pm_poweroff_noirq, | ||
459 | .restore_noirq = of_platform_pm_restore_noirq, | ||
460 | }; | ||
461 | |||
462 | #define OF_PLATFORM_PM_OPS_PTR (&of_platform_dev_pm_ops) | ||
463 | |||
464 | #else /* !CONFIG_PM_SLEEP */ | ||
465 | |||
466 | #define OF_PLATFORM_PM_OPS_PTR NULL | ||
467 | |||
468 | #endif /* !CONFIG_PM_SLEEP */ | ||
469 | |||
470 | int of_bus_type_init(struct bus_type *bus, const char *name) | ||
471 | { | ||
472 | bus->name = name; | ||
473 | bus->match = of_platform_bus_match; | ||
474 | bus->probe = of_platform_device_probe; | ||
475 | bus->remove = of_platform_device_remove; | ||
476 | bus->shutdown = of_platform_device_shutdown; | ||
477 | bus->dev_attrs = of_platform_device_attrs; | ||
478 | bus->pm = OF_PLATFORM_PM_OPS_PTR; | ||
479 | return bus_register(bus); | ||
480 | } | ||
481 | |||
482 | int of_register_driver(struct of_platform_driver *drv, struct bus_type *bus) | ||
483 | { | ||
484 | /* | ||
485 | * Temporary: of_platform_bus used to be distinct from the platform | ||
486 | * bus. It isn't anymore, and so drivers on the platform bus need | ||
487 | * to be registered in a special way. | ||
488 | * | ||
489 | * After all of_platform_bus_type drivers are converted to | ||
490 | * platform_drivers, this exception can be removed. | ||
491 | */ | ||
492 | if (bus == &platform_bus_type) | ||
493 | return of_register_platform_driver(drv); | ||
494 | |||
495 | /* register with core */ | ||
496 | drv->driver.bus = bus; | ||
497 | return driver_register(&drv->driver); | ||
498 | } | ||
499 | EXPORT_SYMBOL(of_register_driver); | ||
500 | |||
501 | void of_unregister_driver(struct of_platform_driver *drv) | ||
502 | { | ||
503 | if (drv->driver.bus == &platform_bus_type) | ||
504 | of_unregister_platform_driver(drv); | ||
505 | else | ||
506 | driver_unregister(&drv->driver); | ||
507 | } | ||
508 | EXPORT_SYMBOL(of_unregister_driver); | ||
509 | |||
510 | #if !defined(CONFIG_SPARC) | 49 | #if !defined(CONFIG_SPARC) |
511 | /* | 50 | /* |
512 | * The following routines scan a subtree and registers a device for | 51 | * The following routines scan a subtree and registers a device for |
@@ -584,34 +123,33 @@ struct platform_device *of_device_alloc(struct device_node *np, | |||
584 | struct device *parent) | 123 | struct device *parent) |
585 | { | 124 | { |
586 | struct platform_device *dev; | 125 | struct platform_device *dev; |
587 | int rc, i, num_reg = 0, num_irq = 0; | 126 | int rc, i, num_reg = 0, num_irq; |
588 | struct resource *res, temp_res; | 127 | struct resource *res, temp_res; |
589 | 128 | ||
590 | /* First count how many resources are needed */ | 129 | dev = platform_device_alloc("", -1); |
591 | while (of_address_to_resource(np, num_reg, &temp_res) == 0) | ||
592 | num_reg++; | ||
593 | while (of_irq_to_resource(np, num_irq, &temp_res) != NO_IRQ) | ||
594 | num_irq++; | ||
595 | |||
596 | /* Allocate memory for both the struct device and the resource table */ | ||
597 | dev = kzalloc(sizeof(*dev) + (sizeof(*res) * (num_reg + num_irq)), | ||
598 | GFP_KERNEL); | ||
599 | if (!dev) | 130 | if (!dev) |
600 | return NULL; | 131 | return NULL; |
601 | res = (struct resource *) &dev[1]; | 132 | |
133 | /* count the io and irq resources */ | ||
134 | while (of_address_to_resource(np, num_reg, &temp_res) == 0) | ||
135 | num_reg++; | ||
136 | num_irq = of_irq_count(np); | ||
602 | 137 | ||
603 | /* Populate the resource table */ | 138 | /* Populate the resource table */ |
604 | if (num_irq || num_reg) { | 139 | if (num_irq || num_reg) { |
140 | res = kzalloc(sizeof(*res) * (num_irq + num_reg), GFP_KERNEL); | ||
141 | if (!res) { | ||
142 | platform_device_put(dev); | ||
143 | return NULL; | ||
144 | } | ||
145 | |||
605 | dev->num_resources = num_reg + num_irq; | 146 | dev->num_resources = num_reg + num_irq; |
606 | dev->resource = res; | 147 | dev->resource = res; |
607 | for (i = 0; i < num_reg; i++, res++) { | 148 | for (i = 0; i < num_reg; i++, res++) { |
608 | rc = of_address_to_resource(np, i, res); | 149 | rc = of_address_to_resource(np, i, res); |
609 | WARN_ON(rc); | 150 | WARN_ON(rc); |
610 | } | 151 | } |
611 | for (i = 0; i < num_irq; i++, res++) { | 152 | WARN_ON(of_irq_to_resource_table(np, res, num_irq) != num_irq); |
612 | rc = of_irq_to_resource(np, i, res); | ||
613 | WARN_ON(rc == NO_IRQ); | ||
614 | } | ||
615 | } | 153 | } |
616 | 154 | ||
617 | dev->dev.of_node = of_node_get(np); | 155 | dev->dev.of_node = of_node_get(np); |
@@ -619,7 +157,6 @@ struct platform_device *of_device_alloc(struct device_node *np, | |||
619 | dev->dev.dma_mask = &dev->archdata.dma_mask; | 157 | dev->dev.dma_mask = &dev->archdata.dma_mask; |
620 | #endif | 158 | #endif |
621 | dev->dev.parent = parent; | 159 | dev->dev.parent = parent; |
622 | dev->dev.release = of_release_dev; | ||
623 | 160 | ||
624 | if (bus_id) | 161 | if (bus_id) |
625 | dev_set_name(&dev->dev, "%s", bus_id); | 162 | dev_set_name(&dev->dev, "%s", bus_id); |
@@ -635,6 +172,9 @@ EXPORT_SYMBOL(of_device_alloc); | |||
635 | * @np: pointer to node to create device for | 172 | * @np: pointer to node to create device for |
636 | * @bus_id: name to assign device | 173 | * @bus_id: name to assign device |
637 | * @parent: Linux device model parent device. | 174 | * @parent: Linux device model parent device. |
175 | * | ||
176 | * Returns pointer to created platform device, or NULL if a device was not | ||
177 | * registered. Unavailable devices will not get registered. | ||
638 | */ | 178 | */ |
639 | struct platform_device *of_platform_device_create(struct device_node *np, | 179 | struct platform_device *of_platform_device_create(struct device_node *np, |
640 | const char *bus_id, | 180 | const char *bus_id, |
@@ -642,6 +182,9 @@ struct platform_device *of_platform_device_create(struct device_node *np, | |||
642 | { | 182 | { |
643 | struct platform_device *dev; | 183 | struct platform_device *dev; |
644 | 184 | ||
185 | if (!of_device_is_available(np)) | ||
186 | return NULL; | ||
187 | |||
645 | dev = of_device_alloc(np, bus_id, parent); | 188 | dev = of_device_alloc(np, bus_id, parent); |
646 | if (!dev) | 189 | if (!dev) |
647 | return NULL; | 190 | return NULL; |
@@ -657,8 +200,8 @@ struct platform_device *of_platform_device_create(struct device_node *np, | |||
657 | * to do such, possibly using a device notifier | 200 | * to do such, possibly using a device notifier |
658 | */ | 201 | */ |
659 | 202 | ||
660 | if (of_device_register(dev) != 0) { | 203 | if (of_device_add(dev) != 0) { |
661 | of_device_free(dev); | 204 | platform_device_put(dev); |
662 | return NULL; | 205 | return NULL; |
663 | } | 206 | } |
664 | 207 | ||
@@ -667,13 +210,16 @@ struct platform_device *of_platform_device_create(struct device_node *np, | |||
667 | EXPORT_SYMBOL(of_platform_device_create); | 210 | EXPORT_SYMBOL(of_platform_device_create); |
668 | 211 | ||
669 | /** | 212 | /** |
670 | * of_platform_bus_create - Create an OF device for a bus node and all its | 213 | * of_platform_bus_create() - Create a device for a node and its children. |
671 | * children. Optionally recursively instantiate matching busses. | ||
672 | * @bus: device node of the bus to instantiate | 214 | * @bus: device node of the bus to instantiate |
673 | * @matches: match table, NULL to use the default, OF_NO_DEEP_PROBE to | 215 | * @matches: match table for bus nodes |
674 | * disallow recursive creation of child busses | 216 | * disallow recursive creation of child buses |
217 | * @parent: parent for new device, or NULL for top level. | ||
218 | * | ||
219 | * Creates a platform_device for the provided device_node, and optionally | ||
220 | * recursively create devices for all the child nodes. | ||
675 | */ | 221 | */ |
676 | static int of_platform_bus_create(const struct device_node *bus, | 222 | static int of_platform_bus_create(struct device_node *bus, |
677 | const struct of_device_id *matches, | 223 | const struct of_device_id *matches, |
678 | struct device *parent) | 224 | struct device *parent) |
679 | { | 225 | { |
@@ -681,17 +227,13 @@ static int of_platform_bus_create(const struct device_node *bus, | |||
681 | struct platform_device *dev; | 227 | struct platform_device *dev; |
682 | int rc = 0; | 228 | int rc = 0; |
683 | 229 | ||
230 | dev = of_platform_device_create(bus, NULL, parent); | ||
231 | if (!dev || !of_match_node(matches, bus)) | ||
232 | return 0; | ||
233 | |||
684 | for_each_child_of_node(bus, child) { | 234 | for_each_child_of_node(bus, child) { |
685 | pr_debug(" create child: %s\n", child->full_name); | 235 | pr_debug(" create child: %s\n", child->full_name); |
686 | dev = of_platform_device_create(child, NULL, parent); | 236 | rc = of_platform_bus_create(child, matches, &dev->dev); |
687 | if (dev == NULL) | ||
688 | rc = -ENOMEM; | ||
689 | else if (!of_match_node(matches, child)) | ||
690 | continue; | ||
691 | if (rc == 0) { | ||
692 | pr_debug(" and sub busses\n"); | ||
693 | rc = of_platform_bus_create(child, matches, &dev->dev); | ||
694 | } | ||
695 | if (rc) { | 237 | if (rc) { |
696 | of_node_put(child); | 238 | of_node_put(child); |
697 | break; | 239 | break; |
@@ -701,9 +243,9 @@ static int of_platform_bus_create(const struct device_node *bus, | |||
701 | } | 243 | } |
702 | 244 | ||
703 | /** | 245 | /** |
704 | * of_platform_bus_probe - Probe the device-tree for platform busses | 246 | * of_platform_bus_probe() - Probe the device-tree for platform buses |
705 | * @root: parent of the first level to probe or NULL for the root of the tree | 247 | * @root: parent of the first level to probe or NULL for the root of the tree |
706 | * @matches: match table, NULL to use the default | 248 | * @matches: match table for bus nodes |
707 | * @parent: parent to hook devices from, NULL for toplevel | 249 | * @parent: parent to hook devices from, NULL for toplevel |
708 | * | 250 | * |
709 | * Note that children of the provided root are not instantiated as devices | 251 | * Note that children of the provided root are not instantiated as devices |
@@ -714,51 +256,26 @@ int of_platform_bus_probe(struct device_node *root, | |||
714 | struct device *parent) | 256 | struct device *parent) |
715 | { | 257 | { |
716 | struct device_node *child; | 258 | struct device_node *child; |
717 | struct platform_device *dev; | ||
718 | int rc = 0; | 259 | int rc = 0; |
719 | 260 | ||
720 | if (WARN_ON(!matches || matches == OF_NO_DEEP_PROBE)) | 261 | root = root ? of_node_get(root) : of_find_node_by_path("/"); |
721 | return -EINVAL; | 262 | if (!root) |
722 | if (root == NULL) | ||
723 | root = of_find_node_by_path("/"); | ||
724 | else | ||
725 | of_node_get(root); | ||
726 | if (root == NULL) | ||
727 | return -EINVAL; | 263 | return -EINVAL; |
728 | 264 | ||
729 | pr_debug("of_platform_bus_probe()\n"); | 265 | pr_debug("of_platform_bus_probe()\n"); |
730 | pr_debug(" starting at: %s\n", root->full_name); | 266 | pr_debug(" starting at: %s\n", root->full_name); |
731 | 267 | ||
732 | /* Do a self check of bus type, if there's a match, create | 268 | /* Do a self check of bus type, if there's a match, create children */ |
733 | * children | ||
734 | */ | ||
735 | if (of_match_node(matches, root)) { | 269 | if (of_match_node(matches, root)) { |
736 | pr_debug(" root match, create all sub devices\n"); | 270 | rc = of_platform_bus_create(root, matches, parent); |
737 | dev = of_platform_device_create(root, NULL, parent); | 271 | } else for_each_child_of_node(root, child) { |
738 | if (dev == NULL) { | ||
739 | rc = -ENOMEM; | ||
740 | goto bail; | ||
741 | } | ||
742 | pr_debug(" create all sub busses\n"); | ||
743 | rc = of_platform_bus_create(root, matches, &dev->dev); | ||
744 | goto bail; | ||
745 | } | ||
746 | for_each_child_of_node(root, child) { | ||
747 | if (!of_match_node(matches, child)) | 272 | if (!of_match_node(matches, child)) |
748 | continue; | 273 | continue; |
749 | 274 | rc = of_platform_bus_create(child, matches, parent); | |
750 | pr_debug(" match: %s\n", child->full_name); | 275 | if (rc) |
751 | dev = of_platform_device_create(child, NULL, parent); | ||
752 | if (dev == NULL) | ||
753 | rc = -ENOMEM; | ||
754 | else | ||
755 | rc = of_platform_bus_create(child, matches, &dev->dev); | ||
756 | if (rc) { | ||
757 | of_node_put(child); | ||
758 | break; | 276 | break; |
759 | } | ||
760 | } | 277 | } |
761 | bail: | 278 | |
762 | of_node_put(root); | 279 | of_node_put(root); |
763 | return rc; | 280 | return rc; |
764 | } | 281 | } |