Commit | Line | Data |
---|---|---|
fd531431 DM |
1 | #include <linux/string.h> |
2 | #include <linux/kernel.h> | |
f85ff305 | 3 | #include <linux/of.h> |
fd531431 DM |
4 | #include <linux/init.h> |
5 | #include <linux/module.h> | |
6 | #include <linux/mod_devicetable.h> | |
7 | #include <linux/slab.h> | |
8 | ||
9 | #include <asm/errno.h> | |
10 | #include <asm/of_device.h> | |
11 | ||
fd531431 DM |
12 | static int of_platform_bus_match(struct device *dev, struct device_driver *drv) |
13 | { | |
14 | struct of_device * of_dev = to_of_device(dev); | |
15 | struct of_platform_driver * of_drv = to_of_platform_driver(drv); | |
16 | const struct of_device_id * matches = of_drv->match_table; | |
17 | ||
18 | if (!matches) | |
19 | return 0; | |
20 | ||
21 | return of_match_device(matches, of_dev) != NULL; | |
22 | } | |
23 | ||
fd531431 DM |
24 | static int of_device_probe(struct device *dev) |
25 | { | |
26 | int error = -ENODEV; | |
27 | struct of_platform_driver *drv; | |
28 | struct of_device *of_dev; | |
29 | const struct of_device_id *match; | |
30 | ||
31 | drv = to_of_platform_driver(dev->driver); | |
32 | of_dev = to_of_device(dev); | |
33 | ||
34 | if (!drv->probe) | |
35 | return error; | |
36 | ||
37 | of_dev_get(of_dev); | |
38 | ||
39 | match = of_match_device(drv->match_table, of_dev); | |
40 | if (match) | |
41 | error = drv->probe(of_dev, match); | |
42 | if (error) | |
43 | of_dev_put(of_dev); | |
44 | ||
45 | return error; | |
46 | } | |
47 | ||
48 | static int of_device_remove(struct device *dev) | |
49 | { | |
50 | struct of_device * of_dev = to_of_device(dev); | |
51 | struct of_platform_driver * drv = to_of_platform_driver(dev->driver); | |
52 | ||
53 | if (dev->driver && drv->remove) | |
54 | drv->remove(of_dev); | |
55 | return 0; | |
56 | } | |
57 | ||
58 | static int of_device_suspend(struct device *dev, pm_message_t state) | |
59 | { | |
60 | struct of_device * of_dev = to_of_device(dev); | |
61 | struct of_platform_driver * drv = to_of_platform_driver(dev->driver); | |
62 | int error = 0; | |
63 | ||
64 | if (dev->driver && drv->suspend) | |
65 | error = drv->suspend(of_dev, state); | |
66 | return error; | |
67 | } | |
68 | ||
69 | static int of_device_resume(struct device * dev) | |
70 | { | |
71 | struct of_device * of_dev = to_of_device(dev); | |
72 | struct of_platform_driver * drv = to_of_platform_driver(dev->driver); | |
73 | int error = 0; | |
74 | ||
75 | if (dev->driver && drv->resume) | |
76 | error = drv->resume(of_dev); | |
77 | return error; | |
78 | } | |
79 | ||
8f96cd1a DM |
80 | static int node_match(struct device *dev, void *data) |
81 | { | |
82 | struct of_device *op = to_of_device(dev); | |
83 | struct device_node *dp = data; | |
84 | ||
85 | return (op->node == dp); | |
86 | } | |
87 | ||
88 | struct of_device *of_find_device_by_node(struct device_node *dp) | |
89 | { | |
90 | struct device *dev = bus_find_device(&of_bus_type, NULL, | |
91 | dp, node_match); | |
92 | ||
93 | if (dev) | |
94 | return to_of_device(dev); | |
95 | ||
96 | return NULL; | |
97 | } | |
98 | EXPORT_SYMBOL(of_find_device_by_node); | |
99 | ||
fd531431 DM |
100 | #ifdef CONFIG_PCI |
101 | struct bus_type ebus_bus_type = { | |
102 | .name = "ebus", | |
103 | .match = of_platform_bus_match, | |
104 | .probe = of_device_probe, | |
105 | .remove = of_device_remove, | |
106 | .suspend = of_device_suspend, | |
107 | .resume = of_device_resume, | |
108 | }; | |
69853918 | 109 | EXPORT_SYMBOL(ebus_bus_type); |
fd531431 DM |
110 | #endif |
111 | ||
112 | #ifdef CONFIG_SBUS | |
113 | struct bus_type sbus_bus_type = { | |
114 | .name = "sbus", | |
115 | .match = of_platform_bus_match, | |
116 | .probe = of_device_probe, | |
117 | .remove = of_device_remove, | |
118 | .suspend = of_device_suspend, | |
119 | .resume = of_device_resume, | |
120 | }; | |
69853918 | 121 | EXPORT_SYMBOL(sbus_bus_type); |
fd531431 DM |
122 | #endif |
123 | ||
cf44bbc2 DM |
124 | struct bus_type of_bus_type = { |
125 | .name = "of", | |
126 | .match = of_platform_bus_match, | |
127 | .probe = of_device_probe, | |
128 | .remove = of_device_remove, | |
129 | .suspend = of_device_suspend, | |
130 | .resume = of_device_resume, | |
131 | }; | |
132 | EXPORT_SYMBOL(of_bus_type); | |
133 | ||
a83f9823 | 134 | static inline u64 of_read_addr(const u32 *cell, int size) |
cf44bbc2 DM |
135 | { |
136 | u64 r = 0; | |
137 | while (size--) | |
138 | r = (r << 32) | *(cell++); | |
139 | return r; | |
140 | } | |
141 | ||
142 | static void __init get_cells(struct device_node *dp, | |
143 | int *addrc, int *sizec) | |
144 | { | |
145 | if (addrc) | |
146 | *addrc = of_n_addr_cells(dp); | |
147 | if (sizec) | |
148 | *sizec = of_n_size_cells(dp); | |
149 | } | |
150 | ||
151 | /* Max address size we deal with */ | |
152 | #define OF_MAX_ADDR_CELLS 4 | |
153 | ||
154 | struct of_bus { | |
155 | const char *name; | |
156 | const char *addr_prop_name; | |
157 | int (*match)(struct device_node *parent); | |
158 | void (*count_cells)(struct device_node *child, | |
159 | int *addrc, int *sizec); | |
a83f9823 DM |
160 | int (*map)(u32 *addr, const u32 *range, |
161 | int na, int ns, int pna); | |
8271f042 | 162 | unsigned int (*get_flags)(const u32 *addr); |
cf44bbc2 DM |
163 | }; |
164 | ||
165 | /* | |
166 | * Default translator (generic bus) | |
167 | */ | |
168 | ||
169 | static void of_bus_default_count_cells(struct device_node *dev, | |
170 | int *addrc, int *sizec) | |
171 | { | |
172 | get_cells(dev, addrc, sizec); | |
173 | } | |
174 | ||
a83f9823 DM |
175 | /* Make sure the least significant 64-bits are in-range. Even |
176 | * for 3 or 4 cell values it is a good enough approximation. | |
177 | */ | |
178 | static int of_out_of_range(const u32 *addr, const u32 *base, | |
179 | const u32 *size, int na, int ns) | |
cf44bbc2 | 180 | { |
a83f9823 DM |
181 | u64 a = of_read_addr(addr, na); |
182 | u64 b = of_read_addr(base, na); | |
183 | ||
184 | if (a < b) | |
185 | return 1; | |
cf44bbc2 | 186 | |
a83f9823 DM |
187 | b += of_read_addr(size, ns); |
188 | if (a >= b) | |
189 | return 1; | |
cf44bbc2 | 190 | |
a83f9823 | 191 | return 0; |
cf44bbc2 DM |
192 | } |
193 | ||
a83f9823 DM |
194 | static int of_bus_default_map(u32 *addr, const u32 *range, |
195 | int na, int ns, int pna) | |
cf44bbc2 | 196 | { |
a83f9823 DM |
197 | u32 result[OF_MAX_ADDR_CELLS]; |
198 | int i; | |
199 | ||
200 | if (ns > 2) { | |
201 | printk("of_device: Cannot handle size cells (%d) > 2.", ns); | |
202 | return -EINVAL; | |
203 | } | |
204 | ||
205 | if (of_out_of_range(addr, range, range + na + pna, na, ns)) | |
206 | return -EINVAL; | |
207 | ||
208 | /* Start with the parent range base. */ | |
209 | memcpy(result, range + na, pna * 4); | |
210 | ||
211 | /* Add in the child address offset. */ | |
212 | for (i = 0; i < na; i++) | |
213 | result[pna - 1 - i] += | |
214 | (addr[na - 1 - i] - | |
215 | range[na - 1 - i]); | |
216 | ||
217 | memcpy(addr, result, pna * 4); | |
cf44bbc2 DM |
218 | |
219 | return 0; | |
220 | } | |
221 | ||
8271f042 | 222 | static unsigned int of_bus_default_get_flags(const u32 *addr) |
cf44bbc2 DM |
223 | { |
224 | return IORESOURCE_MEM; | |
225 | } | |
226 | ||
cf44bbc2 DM |
227 | /* |
228 | * PCI bus specific translator | |
229 | */ | |
230 | ||
231 | static int of_bus_pci_match(struct device_node *np) | |
232 | { | |
a83f9823 DM |
233 | if (!strcmp(np->type, "pci") || !strcmp(np->type, "pciex")) { |
234 | /* Do not do PCI specific frobbing if the | |
235 | * PCI bridge lacks a ranges property. We | |
236 | * want to pass it through up to the next | |
237 | * parent as-is, not with the PCI translate | |
238 | * method which chops off the top address cell. | |
239 | */ | |
240 | if (!of_find_property(np, "ranges", NULL)) | |
241 | return 0; | |
242 | ||
243 | return 1; | |
244 | } | |
245 | ||
246 | return 0; | |
cf44bbc2 DM |
247 | } |
248 | ||
249 | static void of_bus_pci_count_cells(struct device_node *np, | |
250 | int *addrc, int *sizec) | |
251 | { | |
252 | if (addrc) | |
253 | *addrc = 3; | |
254 | if (sizec) | |
255 | *sizec = 2; | |
256 | } | |
257 | ||
a83f9823 DM |
258 | static int of_bus_pci_map(u32 *addr, const u32 *range, |
259 | int na, int ns, int pna) | |
cf44bbc2 | 260 | { |
a83f9823 DM |
261 | u32 result[OF_MAX_ADDR_CELLS]; |
262 | int i; | |
cf44bbc2 DM |
263 | |
264 | /* Check address type match */ | |
265 | if ((addr[0] ^ range[0]) & 0x03000000) | |
a83f9823 | 266 | return -EINVAL; |
cf44bbc2 | 267 | |
a83f9823 DM |
268 | if (of_out_of_range(addr + 1, range + 1, range + na + pna, |
269 | na - 1, ns)) | |
270 | return -EINVAL; | |
cf44bbc2 | 271 | |
a83f9823 DM |
272 | /* Start with the parent range base. */ |
273 | memcpy(result, range + na, pna * 4); | |
cf44bbc2 | 274 | |
a83f9823 DM |
275 | /* Add in the child address offset, skipping high cell. */ |
276 | for (i = 0; i < na - 1; i++) | |
277 | result[pna - 1 - i] += | |
278 | (addr[na - 1 - i] - | |
279 | range[na - 1 - i]); | |
280 | ||
281 | memcpy(addr, result, pna * 4); | |
282 | ||
283 | return 0; | |
cf44bbc2 DM |
284 | } |
285 | ||
8271f042 | 286 | static unsigned int of_bus_pci_get_flags(const u32 *addr) |
cf44bbc2 DM |
287 | { |
288 | unsigned int flags = 0; | |
289 | u32 w = addr[0]; | |
290 | ||
291 | switch((w >> 24) & 0x03) { | |
292 | case 0x01: | |
293 | flags |= IORESOURCE_IO; | |
294 | case 0x02: /* 32 bits */ | |
295 | case 0x03: /* 64 bits */ | |
296 | flags |= IORESOURCE_MEM; | |
297 | } | |
298 | if (w & 0x40000000) | |
299 | flags |= IORESOURCE_PREFETCH; | |
300 | return flags; | |
301 | } | |
302 | ||
303 | /* | |
304 | * SBUS bus specific translator | |
305 | */ | |
306 | ||
307 | static int of_bus_sbus_match(struct device_node *np) | |
308 | { | |
309 | return !strcmp(np->name, "sbus") || | |
310 | !strcmp(np->name, "sbi"); | |
311 | } | |
312 | ||
313 | static void of_bus_sbus_count_cells(struct device_node *child, | |
314 | int *addrc, int *sizec) | |
315 | { | |
316 | if (addrc) | |
317 | *addrc = 2; | |
318 | if (sizec) | |
319 | *sizec = 1; | |
320 | } | |
321 | ||
a83f9823 | 322 | static int of_bus_sbus_map(u32 *addr, const u32 *range, int na, int ns, int pna) |
cf44bbc2 DM |
323 | { |
324 | return of_bus_default_map(addr, range, na, ns, pna); | |
325 | } | |
326 | ||
8271f042 | 327 | static unsigned int of_bus_sbus_get_flags(const u32 *addr) |
cf44bbc2 DM |
328 | { |
329 | return IORESOURCE_MEM; | |
330 | } | |
331 | ||
332 | ||
333 | /* | |
334 | * Array of bus specific translators | |
335 | */ | |
336 | ||
337 | static struct of_bus of_busses[] = { | |
338 | /* PCI */ | |
339 | { | |
340 | .name = "pci", | |
341 | .addr_prop_name = "assigned-addresses", | |
342 | .match = of_bus_pci_match, | |
343 | .count_cells = of_bus_pci_count_cells, | |
344 | .map = of_bus_pci_map, | |
cf44bbc2 DM |
345 | .get_flags = of_bus_pci_get_flags, |
346 | }, | |
347 | /* SBUS */ | |
348 | { | |
349 | .name = "sbus", | |
350 | .addr_prop_name = "reg", | |
351 | .match = of_bus_sbus_match, | |
352 | .count_cells = of_bus_sbus_count_cells, | |
353 | .map = of_bus_sbus_map, | |
cf44bbc2 DM |
354 | .get_flags = of_bus_sbus_get_flags, |
355 | }, | |
356 | /* Default */ | |
357 | { | |
358 | .name = "default", | |
359 | .addr_prop_name = "reg", | |
360 | .match = NULL, | |
361 | .count_cells = of_bus_default_count_cells, | |
362 | .map = of_bus_default_map, | |
cf44bbc2 DM |
363 | .get_flags = of_bus_default_get_flags, |
364 | }, | |
365 | }; | |
366 | ||
367 | static struct of_bus *of_match_bus(struct device_node *np) | |
368 | { | |
369 | int i; | |
370 | ||
371 | for (i = 0; i < ARRAY_SIZE(of_busses); i ++) | |
372 | if (!of_busses[i].match || of_busses[i].match(np)) | |
373 | return &of_busses[i]; | |
374 | BUG(); | |
375 | return NULL; | |
376 | } | |
377 | ||
378 | static int __init build_one_resource(struct device_node *parent, | |
379 | struct of_bus *bus, | |
380 | struct of_bus *pbus, | |
381 | u32 *addr, | |
382 | int na, int ns, int pna) | |
383 | { | |
8271f042 | 384 | const u32 *ranges; |
cf44bbc2 DM |
385 | unsigned int rlen; |
386 | int rone; | |
cf44bbc2 DM |
387 | |
388 | ranges = of_get_property(parent, "ranges", &rlen); | |
389 | if (ranges == NULL || rlen == 0) { | |
a83f9823 DM |
390 | u32 result[OF_MAX_ADDR_CELLS]; |
391 | int i; | |
392 | ||
393 | memset(result, 0, pna * 4); | |
394 | for (i = 0; i < na; i++) | |
395 | result[pna - 1 - i] = | |
396 | addr[na - 1 - i]; | |
397 | ||
398 | memcpy(addr, result, pna * 4); | |
399 | return 0; | |
cf44bbc2 DM |
400 | } |
401 | ||
402 | /* Now walk through the ranges */ | |
403 | rlen /= 4; | |
404 | rone = na + pna + ns; | |
405 | for (; rlen >= rone; rlen -= rone, ranges += rone) { | |
a83f9823 DM |
406 | if (!bus->map(addr, ranges, na, ns, pna)) |
407 | return 0; | |
cf44bbc2 | 408 | } |
cf44bbc2 | 409 | |
a83f9823 | 410 | return 1; |
cf44bbc2 DM |
411 | } |
412 | ||
a83f9823 DM |
413 | static int of_resource_verbose; |
414 | ||
cf44bbc2 DM |
415 | static void __init build_device_resources(struct of_device *op, |
416 | struct device *parent) | |
417 | { | |
418 | struct of_device *p_op; | |
419 | struct of_bus *bus; | |
420 | int na, ns; | |
421 | int index, num_reg; | |
8271f042 | 422 | const void *preg; |
cf44bbc2 DM |
423 | |
424 | if (!parent) | |
425 | return; | |
426 | ||
427 | p_op = to_of_device(parent); | |
428 | bus = of_match_bus(p_op->node); | |
429 | bus->count_cells(op->node, &na, &ns); | |
430 | ||
431 | preg = of_get_property(op->node, bus->addr_prop_name, &num_reg); | |
432 | if (!preg || num_reg == 0) | |
433 | return; | |
434 | ||
435 | /* Convert to num-cells. */ | |
436 | num_reg /= 4; | |
437 | ||
438 | /* Conver to num-entries. */ | |
439 | num_reg /= na + ns; | |
440 | ||
441 | for (index = 0; index < num_reg; index++) { | |
442 | struct resource *r = &op->resource[index]; | |
443 | u32 addr[OF_MAX_ADDR_CELLS]; | |
8271f042 | 444 | const u32 *reg = (preg + (index * ((na + ns) * 4))); |
cf44bbc2 DM |
445 | struct device_node *dp = op->node; |
446 | struct device_node *pp = p_op->node; | |
b85cdd49 | 447 | struct of_bus *pbus, *dbus; |
cf44bbc2 DM |
448 | u64 size, result = OF_BAD_ADDR; |
449 | unsigned long flags; | |
450 | int dna, dns; | |
451 | int pna, pns; | |
452 | ||
453 | size = of_read_addr(reg + na, ns); | |
454 | flags = bus->get_flags(reg); | |
455 | ||
456 | memcpy(addr, reg, na * 4); | |
457 | ||
458 | /* If the immediate parent has no ranges property to apply, | |
459 | * just use a 1<->1 mapping. | |
460 | */ | |
461 | if (of_find_property(pp, "ranges", NULL) == NULL) { | |
462 | result = of_read_addr(addr, na); | |
463 | goto build_res; | |
464 | } | |
465 | ||
466 | dna = na; | |
467 | dns = ns; | |
b85cdd49 | 468 | dbus = bus; |
cf44bbc2 DM |
469 | |
470 | while (1) { | |
471 | dp = pp; | |
472 | pp = dp->parent; | |
473 | if (!pp) { | |
474 | result = of_read_addr(addr, dna); | |
475 | break; | |
476 | } | |
477 | ||
478 | pbus = of_match_bus(pp); | |
479 | pbus->count_cells(dp, &pna, &pns); | |
480 | ||
b85cdd49 | 481 | if (build_one_resource(dp, dbus, pbus, addr, |
a83f9823 | 482 | dna, dns, pna)) |
cf44bbc2 DM |
483 | break; |
484 | ||
485 | dna = pna; | |
486 | dns = pns; | |
b85cdd49 | 487 | dbus = pbus; |
cf44bbc2 DM |
488 | } |
489 | ||
490 | build_res: | |
491 | memset(r, 0, sizeof(*r)); | |
a83f9823 DM |
492 | |
493 | if (of_resource_verbose) | |
494 | printk("%s reg[%d] -> %llx\n", | |
495 | op->node->full_name, index, | |
496 | result); | |
497 | ||
cf44bbc2 | 498 | if (result != OF_BAD_ADDR) { |
95714e12 | 499 | r->start = result & 0xffffffff; |
cf44bbc2 | 500 | r->end = result + size - 1; |
95714e12 | 501 | r->flags = flags | ((result >> 32ULL) & 0xffUL); |
cf44bbc2 DM |
502 | } |
503 | r->name = op->node->name; | |
504 | } | |
505 | } | |
506 | ||
507 | static struct of_device * __init scan_one_device(struct device_node *dp, | |
508 | struct device *parent) | |
509 | { | |
510 | struct of_device *op = kzalloc(sizeof(*op), GFP_KERNEL); | |
8271f042 | 511 | const struct linux_prom_irqs *intr; |
8f96cd1a | 512 | int len, i; |
cf44bbc2 DM |
513 | |
514 | if (!op) | |
515 | return NULL; | |
516 | ||
517 | op->node = dp; | |
518 | ||
519 | op->clock_freq = of_getintprop_default(dp, "clock-frequency", | |
520 | (25*1000*1000)); | |
521 | op->portid = of_getintprop_default(dp, "upa-portid", -1); | |
522 | if (op->portid == -1) | |
523 | op->portid = of_getintprop_default(dp, "portid", -1); | |
524 | ||
8f96cd1a DM |
525 | intr = of_get_property(dp, "intr", &len); |
526 | if (intr) { | |
527 | op->num_irqs = len / sizeof(struct linux_prom_irqs); | |
528 | for (i = 0; i < op->num_irqs; i++) | |
529 | op->irqs[i] = intr[i].pri; | |
530 | } else { | |
8271f042 SR |
531 | const unsigned int *irq = |
532 | of_get_property(dp, "interrupts", &len); | |
8f96cd1a DM |
533 | |
534 | if (irq) { | |
535 | op->num_irqs = len / sizeof(unsigned int); | |
536 | for (i = 0; i < op->num_irqs; i++) | |
537 | op->irqs[i] = irq[i]; | |
538 | } else { | |
539 | op->num_irqs = 0; | |
540 | } | |
541 | } | |
542 | if (sparc_cpu_model == sun4d) { | |
543 | static int pil_to_sbus[] = { | |
544 | 0, 0, 1, 2, 0, 3, 0, 4, 0, 5, 0, 6, 0, 7, 0, 0, | |
545 | }; | |
9d7ab1f4 | 546 | struct device_node *io_unit, *sbi = dp->parent; |
8271f042 | 547 | const struct linux_prom_registers *regs; |
9d7ab1f4 DM |
548 | int board, slot; |
549 | ||
550 | while (sbi) { | |
551 | if (!strcmp(sbi->name, "sbi")) | |
552 | break; | |
553 | ||
554 | sbi = sbi->parent; | |
555 | } | |
556 | if (!sbi) | |
557 | goto build_resources; | |
8f96cd1a DM |
558 | |
559 | regs = of_get_property(dp, "reg", NULL); | |
9d7ab1f4 DM |
560 | if (!regs) |
561 | goto build_resources; | |
562 | ||
8f96cd1a DM |
563 | slot = regs->which_io; |
564 | ||
9d7ab1f4 DM |
565 | /* If SBI's parent is not io-unit or the io-unit lacks |
566 | * a "board#" property, something is very wrong. | |
567 | */ | |
568 | if (!sbi->parent || strcmp(sbi->parent->name, "io-unit")) { | |
569 | printk("%s: Error, parent is not io-unit.\n", | |
570 | sbi->full_name); | |
571 | goto build_resources; | |
572 | } | |
573 | io_unit = sbi->parent; | |
574 | board = of_getintprop_default(io_unit, "board#", -1); | |
575 | if (board == -1) { | |
576 | printk("%s: Error, lacks board# property.\n", | |
577 | io_unit->full_name); | |
578 | goto build_resources; | |
579 | } | |
580 | ||
8f96cd1a DM |
581 | for (i = 0; i < op->num_irqs; i++) { |
582 | int this_irq = op->irqs[i]; | |
583 | int sbusl = pil_to_sbus[this_irq]; | |
584 | ||
585 | if (sbusl) | |
586 | this_irq = (((board + 1) << 5) + | |
587 | (sbusl << 2) + | |
588 | slot); | |
589 | ||
590 | op->irqs[i] = this_irq; | |
591 | } | |
592 | } | |
cf44bbc2 | 593 | |
9d7ab1f4 | 594 | build_resources: |
cf44bbc2 DM |
595 | build_device_resources(op, parent); |
596 | ||
597 | op->dev.parent = parent; | |
598 | op->dev.bus = &of_bus_type; | |
599 | if (!parent) | |
600 | strcpy(op->dev.bus_id, "root"); | |
601 | else | |
f5ef9d11 | 602 | sprintf(op->dev.bus_id, "%08x", dp->node); |
cf44bbc2 DM |
603 | |
604 | if (of_device_register(op)) { | |
605 | printk("%s: Could not register of device.\n", | |
606 | dp->full_name); | |
607 | kfree(op); | |
608 | op = NULL; | |
609 | } | |
610 | ||
611 | return op; | |
612 | } | |
613 | ||
614 | static void __init scan_tree(struct device_node *dp, struct device *parent) | |
615 | { | |
616 | while (dp) { | |
617 | struct of_device *op = scan_one_device(dp, parent); | |
618 | ||
619 | if (op) | |
620 | scan_tree(dp->child, &op->dev); | |
621 | ||
622 | dp = dp->sibling; | |
623 | } | |
624 | } | |
625 | ||
626 | static void __init scan_of_devices(void) | |
627 | { | |
628 | struct device_node *root = of_find_node_by_path("/"); | |
629 | struct of_device *parent; | |
630 | ||
631 | parent = scan_one_device(root, NULL); | |
632 | if (!parent) | |
633 | return; | |
634 | ||
635 | scan_tree(root->child, &parent->dev); | |
636 | } | |
637 | ||
fd531431 DM |
638 | static int __init of_bus_driver_init(void) |
639 | { | |
cf44bbc2 | 640 | int err; |
fd531431 | 641 | |
cf44bbc2 | 642 | err = bus_register(&of_bus_type); |
fd531431 DM |
643 | #ifdef CONFIG_PCI |
644 | if (!err) | |
645 | err = bus_register(&ebus_bus_type); | |
646 | #endif | |
647 | #ifdef CONFIG_SBUS | |
648 | if (!err) | |
649 | err = bus_register(&sbus_bus_type); | |
650 | #endif | |
cf44bbc2 DM |
651 | |
652 | if (!err) | |
653 | scan_of_devices(); | |
654 | ||
655 | return err; | |
fd531431 DM |
656 | } |
657 | ||
658 | postcore_initcall(of_bus_driver_init); | |
659 | ||
a83f9823 DM |
660 | static int __init of_debug(char *str) |
661 | { | |
662 | int val = 0; | |
663 | ||
664 | get_option(&str, &val); | |
665 | if (val & 1) | |
666 | of_resource_verbose = 1; | |
667 | return 1; | |
668 | } | |
669 | ||
670 | __setup("of_debug=", of_debug); | |
671 | ||
fd531431 DM |
672 | int of_register_driver(struct of_platform_driver *drv, struct bus_type *bus) |
673 | { | |
674 | /* initialize common driver fields */ | |
675 | drv->driver.name = drv->name; | |
676 | drv->driver.bus = bus; | |
677 | ||
678 | /* register with core */ | |
679 | return driver_register(&drv->driver); | |
680 | } | |
681 | ||
682 | void of_unregister_driver(struct of_platform_driver *drv) | |
683 | { | |
684 | driver_unregister(&drv->driver); | |
685 | } | |
686 | ||
fd531431 DM |
687 | struct of_device* of_platform_device_create(struct device_node *np, |
688 | const char *bus_id, | |
689 | struct device *parent, | |
690 | struct bus_type *bus) | |
691 | { | |
692 | struct of_device *dev; | |
693 | ||
c80892d1 | 694 | dev = kzalloc(sizeof(*dev), GFP_KERNEL); |
fd531431 DM |
695 | if (!dev) |
696 | return NULL; | |
fd531431 DM |
697 | |
698 | dev->dev.parent = parent; | |
699 | dev->dev.bus = bus; | |
700 | dev->dev.release = of_release_dev; | |
701 | ||
702 | strlcpy(dev->dev.bus_id, bus_id, BUS_ID_SIZE); | |
703 | ||
704 | if (of_device_register(dev) != 0) { | |
705 | kfree(dev); | |
706 | return NULL; | |
707 | } | |
708 | ||
709 | return dev; | |
710 | } | |
711 | ||
fd531431 DM |
712 | EXPORT_SYMBOL(of_register_driver); |
713 | EXPORT_SYMBOL(of_unregister_driver); | |
fd531431 | 714 | EXPORT_SYMBOL(of_platform_device_create); |