diff options
Diffstat (limited to 'drivers/of/platform.c')
-rw-r--r-- | drivers/of/platform.c | 384 |
1 files changed, 376 insertions, 8 deletions
diff --git a/drivers/of/platform.c b/drivers/of/platform.c index 7dacc1ebe91e..bb72223c22ae 100644 --- a/drivers/of/platform.c +++ b/drivers/of/platform.c | |||
@@ -14,8 +14,105 @@ | |||
14 | #include <linux/errno.h> | 14 | #include <linux/errno.h> |
15 | #include <linux/module.h> | 15 | #include <linux/module.h> |
16 | #include <linux/device.h> | 16 | #include <linux/device.h> |
17 | #include <linux/dma-mapping.h> | ||
18 | #include <linux/slab.h> | ||
19 | #include <linux/of_address.h> | ||
17 | #include <linux/of_device.h> | 20 | #include <linux/of_device.h> |
21 | #include <linux/of_irq.h> | ||
18 | #include <linux/of_platform.h> | 22 | #include <linux/of_platform.h> |
23 | #include <linux/platform_device.h> | ||
24 | |||
25 | static int of_dev_node_match(struct device *dev, void *data) | ||
26 | { | ||
27 | return dev->of_node == data; | ||
28 | } | ||
29 | |||
30 | /** | ||
31 | * of_find_device_by_node - Find the platform_device associated with a node | ||
32 | * @np: Pointer to device tree node | ||
33 | * | ||
34 | * Returns platform_device pointer, or NULL if not found | ||
35 | */ | ||
36 | struct platform_device *of_find_device_by_node(struct device_node *np) | ||
37 | { | ||
38 | struct device *dev; | ||
39 | |||
40 | dev = bus_find_device(&platform_bus_type, NULL, np, of_dev_node_match); | ||
41 | return dev ? to_platform_device(dev) : NULL; | ||
42 | } | ||
43 | EXPORT_SYMBOL(of_find_device_by_node); | ||
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) | ||
114 | #include <asm/dcr.h> | ||
115 | #endif | ||
19 | 116 | ||
20 | extern struct device_attribute of_platform_device_attrs[]; | 117 | extern struct device_attribute of_platform_device_attrs[]; |
21 | 118 | ||
@@ -33,11 +130,11 @@ static int of_platform_device_probe(struct device *dev) | |||
33 | { | 130 | { |
34 | int error = -ENODEV; | 131 | int error = -ENODEV; |
35 | struct of_platform_driver *drv; | 132 | struct of_platform_driver *drv; |
36 | struct of_device *of_dev; | 133 | struct platform_device *of_dev; |
37 | const struct of_device_id *match; | 134 | const struct of_device_id *match; |
38 | 135 | ||
39 | drv = to_of_platform_driver(dev->driver); | 136 | drv = to_of_platform_driver(dev->driver); |
40 | of_dev = to_of_device(dev); | 137 | of_dev = to_platform_device(dev); |
41 | 138 | ||
42 | if (!drv->probe) | 139 | if (!drv->probe) |
43 | return error; | 140 | return error; |
@@ -55,7 +152,7 @@ static int of_platform_device_probe(struct device *dev) | |||
55 | 152 | ||
56 | static int of_platform_device_remove(struct device *dev) | 153 | static int of_platform_device_remove(struct device *dev) |
57 | { | 154 | { |
58 | struct of_device *of_dev = to_of_device(dev); | 155 | struct platform_device *of_dev = to_platform_device(dev); |
59 | struct of_platform_driver *drv = to_of_platform_driver(dev->driver); | 156 | struct of_platform_driver *drv = to_of_platform_driver(dev->driver); |
60 | 157 | ||
61 | if (dev->driver && drv->remove) | 158 | if (dev->driver && drv->remove) |
@@ -65,7 +162,7 @@ static int of_platform_device_remove(struct device *dev) | |||
65 | 162 | ||
66 | static void of_platform_device_shutdown(struct device *dev) | 163 | static void of_platform_device_shutdown(struct device *dev) |
67 | { | 164 | { |
68 | struct of_device *of_dev = to_of_device(dev); | 165 | struct platform_device *of_dev = to_platform_device(dev); |
69 | struct of_platform_driver *drv = to_of_platform_driver(dev->driver); | 166 | struct of_platform_driver *drv = to_of_platform_driver(dev->driver); |
70 | 167 | ||
71 | if (dev->driver && drv->shutdown) | 168 | if (dev->driver && drv->shutdown) |
@@ -76,7 +173,7 @@ static void of_platform_device_shutdown(struct device *dev) | |||
76 | 173 | ||
77 | static int of_platform_legacy_suspend(struct device *dev, pm_message_t mesg) | 174 | static int of_platform_legacy_suspend(struct device *dev, pm_message_t mesg) |
78 | { | 175 | { |
79 | struct of_device *of_dev = to_of_device(dev); | 176 | struct platform_device *of_dev = to_platform_device(dev); |
80 | struct of_platform_driver *drv = to_of_platform_driver(dev->driver); | 177 | struct of_platform_driver *drv = to_of_platform_driver(dev->driver); |
81 | int ret = 0; | 178 | int ret = 0; |
82 | 179 | ||
@@ -87,7 +184,7 @@ static int of_platform_legacy_suspend(struct device *dev, pm_message_t mesg) | |||
87 | 184 | ||
88 | static int of_platform_legacy_resume(struct device *dev) | 185 | static int of_platform_legacy_resume(struct device *dev) |
89 | { | 186 | { |
90 | struct of_device *of_dev = to_of_device(dev); | 187 | struct platform_device *of_dev = to_platform_device(dev); |
91 | struct of_platform_driver *drv = to_of_platform_driver(dev->driver); | 188 | struct of_platform_driver *drv = to_of_platform_driver(dev->driver); |
92 | int ret = 0; | 189 | int ret = 0; |
93 | 190 | ||
@@ -384,15 +481,286 @@ int of_bus_type_init(struct bus_type *bus, const char *name) | |||
384 | 481 | ||
385 | int of_register_driver(struct of_platform_driver *drv, struct bus_type *bus) | 482 | int of_register_driver(struct of_platform_driver *drv, struct bus_type *bus) |
386 | { | 483 | { |
387 | drv->driver.bus = bus; | 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); | ||
388 | 494 | ||
389 | /* register with core */ | 495 | /* register with core */ |
496 | drv->driver.bus = bus; | ||
390 | return driver_register(&drv->driver); | 497 | return driver_register(&drv->driver); |
391 | } | 498 | } |
392 | EXPORT_SYMBOL(of_register_driver); | 499 | EXPORT_SYMBOL(of_register_driver); |
393 | 500 | ||
394 | void of_unregister_driver(struct of_platform_driver *drv) | 501 | void of_unregister_driver(struct of_platform_driver *drv) |
395 | { | 502 | { |
396 | driver_unregister(&drv->driver); | 503 | if (drv->driver.bus == &platform_bus_type) |
504 | of_unregister_platform_driver(drv); | ||
505 | else | ||
506 | driver_unregister(&drv->driver); | ||
397 | } | 507 | } |
398 | EXPORT_SYMBOL(of_unregister_driver); | 508 | EXPORT_SYMBOL(of_unregister_driver); |
509 | |||
510 | #if !defined(CONFIG_SPARC) | ||
511 | /* | ||
512 | * The following routines scan a subtree and registers a device for | ||
513 | * each applicable node. | ||
514 | * | ||
515 | * Note: sparc doesn't use these routines because it has a different | ||
516 | * mechanism for creating devices from device tree nodes. | ||
517 | */ | ||
518 | |||
519 | /** | ||
520 | * of_device_make_bus_id - Use the device node data to assign a unique name | ||
521 | * @dev: pointer to device structure that is linked to a device tree node | ||
522 | * | ||
523 | * This routine will first try using either the dcr-reg or the reg property | ||
524 | * value to derive a unique name. As a last resort it will use the node | ||
525 | * name followed by a unique number. | ||
526 | */ | ||
527 | void of_device_make_bus_id(struct device *dev) | ||
528 | { | ||
529 | static atomic_t bus_no_reg_magic; | ||
530 | struct device_node *node = dev->of_node; | ||
531 | const u32 *reg; | ||
532 | u64 addr; | ||
533 | int magic; | ||
534 | |||
535 | #ifdef CONFIG_PPC_DCR | ||
536 | /* | ||
537 | * If it's a DCR based device, use 'd' for native DCRs | ||
538 | * and 'D' for MMIO DCRs. | ||
539 | */ | ||
540 | reg = of_get_property(node, "dcr-reg", NULL); | ||
541 | if (reg) { | ||
542 | #ifdef CONFIG_PPC_DCR_NATIVE | ||
543 | dev_set_name(dev, "d%x.%s", *reg, node->name); | ||
544 | #else /* CONFIG_PPC_DCR_NATIVE */ | ||
545 | u64 addr = of_translate_dcr_address(node, *reg, NULL); | ||
546 | if (addr != OF_BAD_ADDR) { | ||
547 | dev_set_name(dev, "D%llx.%s", | ||
548 | (unsigned long long)addr, node->name); | ||
549 | return; | ||
550 | } | ||
551 | #endif /* !CONFIG_PPC_DCR_NATIVE */ | ||
552 | } | ||
553 | #endif /* CONFIG_PPC_DCR */ | ||
554 | |||
555 | /* | ||
556 | * For MMIO, get the physical address | ||
557 | */ | ||
558 | reg = of_get_property(node, "reg", NULL); | ||
559 | if (reg) { | ||
560 | addr = of_translate_address(node, reg); | ||
561 | if (addr != OF_BAD_ADDR) { | ||
562 | dev_set_name(dev, "%llx.%s", | ||
563 | (unsigned long long)addr, node->name); | ||
564 | return; | ||
565 | } | ||
566 | } | ||
567 | |||
568 | /* | ||
569 | * No BusID, use the node name and add a globally incremented | ||
570 | * counter (and pray...) | ||
571 | */ | ||
572 | magic = atomic_add_return(1, &bus_no_reg_magic); | ||
573 | dev_set_name(dev, "%s.%d", node->name, magic - 1); | ||
574 | } | ||
575 | |||
576 | /** | ||
577 | * of_device_alloc - Allocate and initialize an of_device | ||
578 | * @np: device node to assign to device | ||
579 | * @bus_id: Name to assign to the device. May be null to use default name. | ||
580 | * @parent: Parent device. | ||
581 | */ | ||
582 | struct platform_device *of_device_alloc(struct device_node *np, | ||
583 | const char *bus_id, | ||
584 | struct device *parent) | ||
585 | { | ||
586 | struct platform_device *dev; | ||
587 | int rc, i, num_reg = 0, num_irq = 0; | ||
588 | struct resource *res, temp_res; | ||
589 | |||
590 | /* First count how many resources are needed */ | ||
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) | ||
600 | return NULL; | ||
601 | res = (struct resource *) &dev[1]; | ||
602 | |||
603 | /* Populate the resource table */ | ||
604 | if (num_irq || num_reg) { | ||
605 | dev->num_resources = num_reg + num_irq; | ||
606 | dev->resource = res; | ||
607 | for (i = 0; i < num_reg; i++, res++) { | ||
608 | rc = of_address_to_resource(np, i, res); | ||
609 | WARN_ON(rc); | ||
610 | } | ||
611 | for (i = 0; i < num_irq; i++, res++) { | ||
612 | rc = of_irq_to_resource(np, i, res); | ||
613 | WARN_ON(rc == NO_IRQ); | ||
614 | } | ||
615 | } | ||
616 | |||
617 | dev->dev.of_node = of_node_get(np); | ||
618 | #if defined(CONFIG_PPC) || defined(CONFIG_MICROBLAZE) | ||
619 | dev->dev.dma_mask = &dev->archdata.dma_mask; | ||
620 | #endif | ||
621 | dev->dev.parent = parent; | ||
622 | dev->dev.release = of_release_dev; | ||
623 | |||
624 | if (bus_id) | ||
625 | dev_set_name(&dev->dev, "%s", bus_id); | ||
626 | else | ||
627 | of_device_make_bus_id(&dev->dev); | ||
628 | |||
629 | return dev; | ||
630 | } | ||
631 | EXPORT_SYMBOL(of_device_alloc); | ||
632 | |||
633 | /** | ||
634 | * of_platform_device_create - Alloc, initialize and register an of_device | ||
635 | * @np: pointer to node to create device for | ||
636 | * @bus_id: name to assign device | ||
637 | * @parent: Linux device model parent device. | ||
638 | */ | ||
639 | struct platform_device *of_platform_device_create(struct device_node *np, | ||
640 | const char *bus_id, | ||
641 | struct device *parent) | ||
642 | { | ||
643 | struct platform_device *dev; | ||
644 | |||
645 | dev = of_device_alloc(np, bus_id, parent); | ||
646 | if (!dev) | ||
647 | return NULL; | ||
648 | |||
649 | #if defined(CONFIG_PPC) || defined(CONFIG_MICROBLAZE) | ||
650 | dev->archdata.dma_mask = 0xffffffffUL; | ||
651 | #endif | ||
652 | dev->dev.coherent_dma_mask = DMA_BIT_MASK(32); | ||
653 | dev->dev.bus = &platform_bus_type; | ||
654 | |||
655 | /* We do not fill the DMA ops for platform devices by default. | ||
656 | * This is currently the responsibility of the platform code | ||
657 | * to do such, possibly using a device notifier | ||
658 | */ | ||
659 | |||
660 | if (of_device_register(dev) != 0) { | ||
661 | of_device_free(dev); | ||
662 | return NULL; | ||
663 | } | ||
664 | |||
665 | return dev; | ||
666 | } | ||
667 | EXPORT_SYMBOL(of_platform_device_create); | ||
668 | |||
669 | /** | ||
670 | * of_platform_bus_create - Create an OF device for a bus node and all its | ||
671 | * children. Optionally recursively instantiate matching busses. | ||
672 | * @bus: device node of the bus to instantiate | ||
673 | * @matches: match table, NULL to use the default, OF_NO_DEEP_PROBE to | ||
674 | * disallow recursive creation of child busses | ||
675 | */ | ||
676 | static int of_platform_bus_create(const struct device_node *bus, | ||
677 | const struct of_device_id *matches, | ||
678 | struct device *parent) | ||
679 | { | ||
680 | struct device_node *child; | ||
681 | struct platform_device *dev; | ||
682 | int rc = 0; | ||
683 | |||
684 | for_each_child_of_node(bus, child) { | ||
685 | pr_debug(" create child: %s\n", child->full_name); | ||
686 | dev = of_platform_device_create(child, NULL, parent); | ||
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) { | ||
696 | of_node_put(child); | ||
697 | break; | ||
698 | } | ||
699 | } | ||
700 | return rc; | ||
701 | } | ||
702 | |||
703 | /** | ||
704 | * of_platform_bus_probe - Probe the device-tree for platform busses | ||
705 | * @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 | ||
707 | * @parent: parent to hook devices from, NULL for toplevel | ||
708 | * | ||
709 | * Note that children of the provided root are not instantiated as devices | ||
710 | * unless the specified root itself matches the bus list and is not NULL. | ||
711 | */ | ||
712 | int of_platform_bus_probe(struct device_node *root, | ||
713 | const struct of_device_id *matches, | ||
714 | struct device *parent) | ||
715 | { | ||
716 | struct device_node *child; | ||
717 | struct platform_device *dev; | ||
718 | int rc = 0; | ||
719 | |||
720 | if (WARN_ON(!matches || matches == OF_NO_DEEP_PROBE)) | ||
721 | return -EINVAL; | ||
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; | ||
728 | |||
729 | pr_debug("of_platform_bus_probe()\n"); | ||
730 | pr_debug(" starting at: %s\n", root->full_name); | ||
731 | |||
732 | /* Do a self check of bus type, if there's a match, create | ||
733 | * children | ||
734 | */ | ||
735 | if (of_match_node(matches, root)) { | ||
736 | pr_debug(" root match, create all sub devices\n"); | ||
737 | dev = of_platform_device_create(root, NULL, parent); | ||
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)) | ||
748 | continue; | ||
749 | |||
750 | pr_debug(" match: %s\n", child->full_name); | ||
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; | ||
759 | } | ||
760 | } | ||
761 | bail: | ||
762 | of_node_put(root); | ||
763 | return rc; | ||
764 | } | ||
765 | EXPORT_SYMBOL(of_platform_bus_probe); | ||
766 | #endif /* !CONFIG_SPARC */ | ||