diff options
Diffstat (limited to 'drivers/base/platform.c')
-rw-r--r-- | drivers/base/platform.c | 147 |
1 files changed, 122 insertions, 25 deletions
diff --git a/drivers/base/platform.c b/drivers/base/platform.c index 58efaf2f1259..4d99c8bdfedc 100644 --- a/drivers/base/platform.c +++ b/drivers/base/platform.c | |||
@@ -128,7 +128,7 @@ struct platform_object { | |||
128 | }; | 128 | }; |
129 | 129 | ||
130 | /** | 130 | /** |
131 | * platform_device_put | 131 | * platform_device_put - destroy a platform device |
132 | * @pdev: platform device to free | 132 | * @pdev: platform device to free |
133 | * | 133 | * |
134 | * Free all memory associated with a platform device. This function must | 134 | * Free all memory associated with a platform device. This function must |
@@ -152,7 +152,7 @@ static void platform_device_release(struct device *dev) | |||
152 | } | 152 | } |
153 | 153 | ||
154 | /** | 154 | /** |
155 | * platform_device_alloc | 155 | * platform_device_alloc - create a platform device |
156 | * @name: base name of the device we're adding | 156 | * @name: base name of the device we're adding |
157 | * @id: instance id | 157 | * @id: instance id |
158 | * | 158 | * |
@@ -177,7 +177,7 @@ struct platform_device *platform_device_alloc(const char *name, int id) | |||
177 | EXPORT_SYMBOL_GPL(platform_device_alloc); | 177 | EXPORT_SYMBOL_GPL(platform_device_alloc); |
178 | 178 | ||
179 | /** | 179 | /** |
180 | * platform_device_add_resources | 180 | * platform_device_add_resources - add resources to a platform device |
181 | * @pdev: platform device allocated by platform_device_alloc to add resources to | 181 | * @pdev: platform device allocated by platform_device_alloc to add resources to |
182 | * @res: set of resources that needs to be allocated for the device | 182 | * @res: set of resources that needs to be allocated for the device |
183 | * @num: number of resources | 183 | * @num: number of resources |
@@ -187,7 +187,7 @@ EXPORT_SYMBOL_GPL(platform_device_alloc); | |||
187 | * released. | 187 | * released. |
188 | */ | 188 | */ |
189 | int platform_device_add_resources(struct platform_device *pdev, | 189 | int platform_device_add_resources(struct platform_device *pdev, |
190 | struct resource *res, unsigned int num) | 190 | const struct resource *res, unsigned int num) |
191 | { | 191 | { |
192 | struct resource *r; | 192 | struct resource *r; |
193 | 193 | ||
@@ -202,7 +202,7 @@ int platform_device_add_resources(struct platform_device *pdev, | |||
202 | EXPORT_SYMBOL_GPL(platform_device_add_resources); | 202 | EXPORT_SYMBOL_GPL(platform_device_add_resources); |
203 | 203 | ||
204 | /** | 204 | /** |
205 | * platform_device_add_data | 205 | * platform_device_add_data - add platform-specific data to a platform device |
206 | * @pdev: platform device allocated by platform_device_alloc to add resources to | 206 | * @pdev: platform device allocated by platform_device_alloc to add resources to |
207 | * @data: platform specific data for this platform device | 207 | * @data: platform specific data for this platform device |
208 | * @size: size of platform specific data | 208 | * @size: size of platform specific data |
@@ -344,7 +344,7 @@ void platform_device_unregister(struct platform_device *pdev) | |||
344 | EXPORT_SYMBOL_GPL(platform_device_unregister); | 344 | EXPORT_SYMBOL_GPL(platform_device_unregister); |
345 | 345 | ||
346 | /** | 346 | /** |
347 | * platform_device_register_simple | 347 | * platform_device_register_simple - add a platform-level device and its resources |
348 | * @name: base name of the device we're adding | 348 | * @name: base name of the device we're adding |
349 | * @id: instance id | 349 | * @id: instance id |
350 | * @res: set of resources that needs to be allocated for the device | 350 | * @res: set of resources that needs to be allocated for the device |
@@ -362,10 +362,12 @@ EXPORT_SYMBOL_GPL(platform_device_unregister); | |||
362 | * enumeration tasks, they don't fully conform to the Linux driver model. | 362 | * enumeration tasks, they don't fully conform to the Linux driver model. |
363 | * In particular, when such drivers are built as modules, they can't be | 363 | * In particular, when such drivers are built as modules, they can't be |
364 | * "hotplugged". | 364 | * "hotplugged". |
365 | * | ||
366 | * Returns &struct platform_device pointer on success, or ERR_PTR() on error. | ||
365 | */ | 367 | */ |
366 | struct platform_device *platform_device_register_simple(const char *name, | 368 | struct platform_device *platform_device_register_simple(const char *name, |
367 | int id, | 369 | int id, |
368 | struct resource *res, | 370 | const struct resource *res, |
369 | unsigned int num) | 371 | unsigned int num) |
370 | { | 372 | { |
371 | struct platform_device *pdev; | 373 | struct platform_device *pdev; |
@@ -396,7 +398,7 @@ error: | |||
396 | EXPORT_SYMBOL_GPL(platform_device_register_simple); | 398 | EXPORT_SYMBOL_GPL(platform_device_register_simple); |
397 | 399 | ||
398 | /** | 400 | /** |
399 | * platform_device_register_data | 401 | * platform_device_register_data - add a platform-level device with platform-specific data |
400 | * @parent: parent device for the device we're adding | 402 | * @parent: parent device for the device we're adding |
401 | * @name: base name of the device we're adding | 403 | * @name: base name of the device we're adding |
402 | * @id: instance id | 404 | * @id: instance id |
@@ -408,6 +410,8 @@ EXPORT_SYMBOL_GPL(platform_device_register_simple); | |||
408 | * allocated for the device allows drivers using such devices to be | 410 | * allocated for the device allows drivers using such devices to be |
409 | * unloaded without waiting for the last reference to the device to be | 411 | * unloaded without waiting for the last reference to the device to be |
410 | * dropped. | 412 | * dropped. |
413 | * | ||
414 | * Returns &struct platform_device pointer on success, or ERR_PTR() on error. | ||
411 | */ | 415 | */ |
412 | struct platform_device *platform_device_register_data( | 416 | struct platform_device *platform_device_register_data( |
413 | struct device *parent, | 417 | struct device *parent, |
@@ -473,7 +477,7 @@ static void platform_drv_shutdown(struct device *_dev) | |||
473 | } | 477 | } |
474 | 478 | ||
475 | /** | 479 | /** |
476 | * platform_driver_register | 480 | * platform_driver_register - register a driver for platform-level devices |
477 | * @drv: platform driver structure | 481 | * @drv: platform driver structure |
478 | */ | 482 | */ |
479 | int platform_driver_register(struct platform_driver *drv) | 483 | int platform_driver_register(struct platform_driver *drv) |
@@ -491,7 +495,7 @@ int platform_driver_register(struct platform_driver *drv) | |||
491 | EXPORT_SYMBOL_GPL(platform_driver_register); | 495 | EXPORT_SYMBOL_GPL(platform_driver_register); |
492 | 496 | ||
493 | /** | 497 | /** |
494 | * platform_driver_unregister | 498 | * platform_driver_unregister - unregister a driver for platform-level devices |
495 | * @drv: platform driver structure | 499 | * @drv: platform driver structure |
496 | */ | 500 | */ |
497 | void platform_driver_unregister(struct platform_driver *drv) | 501 | void platform_driver_unregister(struct platform_driver *drv) |
@@ -548,6 +552,66 @@ int __init_or_module platform_driver_probe(struct platform_driver *drv, | |||
548 | } | 552 | } |
549 | EXPORT_SYMBOL_GPL(platform_driver_probe); | 553 | EXPORT_SYMBOL_GPL(platform_driver_probe); |
550 | 554 | ||
555 | /** | ||
556 | * platform_create_bundle - register driver and create corresponding device | ||
557 | * @driver: platform driver structure | ||
558 | * @probe: the driver probe routine, probably from an __init section | ||
559 | * @res: set of resources that needs to be allocated for the device | ||
560 | * @n_res: number of resources | ||
561 | * @data: platform specific data for this platform device | ||
562 | * @size: size of platform specific data | ||
563 | * | ||
564 | * Use this in legacy-style modules that probe hardware directly and | ||
565 | * register a single platform device and corresponding platform driver. | ||
566 | * | ||
567 | * Returns &struct platform_device pointer on success, or ERR_PTR() on error. | ||
568 | */ | ||
569 | struct platform_device * __init_or_module platform_create_bundle( | ||
570 | struct platform_driver *driver, | ||
571 | int (*probe)(struct platform_device *), | ||
572 | struct resource *res, unsigned int n_res, | ||
573 | const void *data, size_t size) | ||
574 | { | ||
575 | struct platform_device *pdev; | ||
576 | int error; | ||
577 | |||
578 | pdev = platform_device_alloc(driver->driver.name, -1); | ||
579 | if (!pdev) { | ||
580 | error = -ENOMEM; | ||
581 | goto err_out; | ||
582 | } | ||
583 | |||
584 | if (res) { | ||
585 | error = platform_device_add_resources(pdev, res, n_res); | ||
586 | if (error) | ||
587 | goto err_pdev_put; | ||
588 | } | ||
589 | |||
590 | if (data) { | ||
591 | error = platform_device_add_data(pdev, data, size); | ||
592 | if (error) | ||
593 | goto err_pdev_put; | ||
594 | } | ||
595 | |||
596 | error = platform_device_add(pdev); | ||
597 | if (error) | ||
598 | goto err_pdev_put; | ||
599 | |||
600 | error = platform_driver_probe(driver, probe); | ||
601 | if (error) | ||
602 | goto err_pdev_del; | ||
603 | |||
604 | return pdev; | ||
605 | |||
606 | err_pdev_del: | ||
607 | platform_device_del(pdev); | ||
608 | err_pdev_put: | ||
609 | platform_device_put(pdev); | ||
610 | err_out: | ||
611 | return ERR_PTR(error); | ||
612 | } | ||
613 | EXPORT_SYMBOL_GPL(platform_create_bundle); | ||
614 | |||
551 | /* modalias support enables more hands-off userspace setup: | 615 | /* modalias support enables more hands-off userspace setup: |
552 | * (a) environment variable lets new-style hotplug events work once system is | 616 | * (a) environment variable lets new-style hotplug events work once system is |
553 | * fully running: "modprobe $MODALIAS" | 617 | * fully running: "modprobe $MODALIAS" |
@@ -578,7 +642,7 @@ static int platform_uevent(struct device *dev, struct kobj_uevent_env *env) | |||
578 | } | 642 | } |
579 | 643 | ||
580 | static const struct platform_device_id *platform_match_id( | 644 | static const struct platform_device_id *platform_match_id( |
581 | struct platform_device_id *id, | 645 | const struct platform_device_id *id, |
582 | struct platform_device *pdev) | 646 | struct platform_device *pdev) |
583 | { | 647 | { |
584 | while (id->name[0]) { | 648 | while (id->name[0]) { |
@@ -671,7 +735,7 @@ static void platform_pm_complete(struct device *dev) | |||
671 | 735 | ||
672 | #ifdef CONFIG_SUSPEND | 736 | #ifdef CONFIG_SUSPEND |
673 | 737 | ||
674 | static int platform_pm_suspend(struct device *dev) | 738 | int __weak platform_pm_suspend(struct device *dev) |
675 | { | 739 | { |
676 | struct device_driver *drv = dev->driver; | 740 | struct device_driver *drv = dev->driver; |
677 | int ret = 0; | 741 | int ret = 0; |
@@ -689,7 +753,7 @@ static int platform_pm_suspend(struct device *dev) | |||
689 | return ret; | 753 | return ret; |
690 | } | 754 | } |
691 | 755 | ||
692 | static int platform_pm_suspend_noirq(struct device *dev) | 756 | int __weak platform_pm_suspend_noirq(struct device *dev) |
693 | { | 757 | { |
694 | struct device_driver *drv = dev->driver; | 758 | struct device_driver *drv = dev->driver; |
695 | int ret = 0; | 759 | int ret = 0; |
@@ -705,7 +769,7 @@ static int platform_pm_suspend_noirq(struct device *dev) | |||
705 | return ret; | 769 | return ret; |
706 | } | 770 | } |
707 | 771 | ||
708 | static int platform_pm_resume(struct device *dev) | 772 | int __weak platform_pm_resume(struct device *dev) |
709 | { | 773 | { |
710 | struct device_driver *drv = dev->driver; | 774 | struct device_driver *drv = dev->driver; |
711 | int ret = 0; | 775 | int ret = 0; |
@@ -723,7 +787,7 @@ static int platform_pm_resume(struct device *dev) | |||
723 | return ret; | 787 | return ret; |
724 | } | 788 | } |
725 | 789 | ||
726 | static int platform_pm_resume_noirq(struct device *dev) | 790 | int __weak platform_pm_resume_noirq(struct device *dev) |
727 | { | 791 | { |
728 | struct device_driver *drv = dev->driver; | 792 | struct device_driver *drv = dev->driver; |
729 | int ret = 0; | 793 | int ret = 0; |
@@ -903,17 +967,17 @@ static int platform_pm_restore_noirq(struct device *dev) | |||
903 | 967 | ||
904 | int __weak platform_pm_runtime_suspend(struct device *dev) | 968 | int __weak platform_pm_runtime_suspend(struct device *dev) |
905 | { | 969 | { |
906 | return -ENOSYS; | 970 | return pm_generic_runtime_suspend(dev); |
907 | }; | 971 | }; |
908 | 972 | ||
909 | int __weak platform_pm_runtime_resume(struct device *dev) | 973 | int __weak platform_pm_runtime_resume(struct device *dev) |
910 | { | 974 | { |
911 | return -ENOSYS; | 975 | return pm_generic_runtime_resume(dev); |
912 | }; | 976 | }; |
913 | 977 | ||
914 | int __weak platform_pm_runtime_idle(struct device *dev) | 978 | int __weak platform_pm_runtime_idle(struct device *dev) |
915 | { | 979 | { |
916 | return -ENOSYS; | 980 | return pm_generic_runtime_idle(dev); |
917 | }; | 981 | }; |
918 | 982 | ||
919 | #else /* !CONFIG_PM_RUNTIME */ | 983 | #else /* !CONFIG_PM_RUNTIME */ |
@@ -994,9 +1058,11 @@ static __initdata LIST_HEAD(early_platform_driver_list); | |||
994 | static __initdata LIST_HEAD(early_platform_device_list); | 1058 | static __initdata LIST_HEAD(early_platform_device_list); |
995 | 1059 | ||
996 | /** | 1060 | /** |
997 | * early_platform_driver_register | 1061 | * early_platform_driver_register - register early platform driver |
998 | * @epdrv: early_platform driver structure | 1062 | * @epdrv: early_platform driver structure |
999 | * @buf: string passed from early_param() | 1063 | * @buf: string passed from early_param() |
1064 | * | ||
1065 | * Helper function for early_platform_init() / early_platform_init_buffer() | ||
1000 | */ | 1066 | */ |
1001 | int __init early_platform_driver_register(struct early_platform_driver *epdrv, | 1067 | int __init early_platform_driver_register(struct early_platform_driver *epdrv, |
1002 | char *buf) | 1068 | char *buf) |
@@ -1048,9 +1114,12 @@ int __init early_platform_driver_register(struct early_platform_driver *epdrv, | |||
1048 | } | 1114 | } |
1049 | 1115 | ||
1050 | /** | 1116 | /** |
1051 | * early_platform_add_devices - add a numbers of early platform devices | 1117 | * early_platform_add_devices - adds a number of early platform devices |
1052 | * @devs: array of early platform devices to add | 1118 | * @devs: array of early platform devices to add |
1053 | * @num: number of early platform devices in array | 1119 | * @num: number of early platform devices in array |
1120 | * | ||
1121 | * Used by early architecture code to register early platform devices and | ||
1122 | * their platform data. | ||
1054 | */ | 1123 | */ |
1055 | void __init early_platform_add_devices(struct platform_device **devs, int num) | 1124 | void __init early_platform_add_devices(struct platform_device **devs, int num) |
1056 | { | 1125 | { |
@@ -1070,8 +1139,12 @@ void __init early_platform_add_devices(struct platform_device **devs, int num) | |||
1070 | } | 1139 | } |
1071 | 1140 | ||
1072 | /** | 1141 | /** |
1073 | * early_platform_driver_register_all | 1142 | * early_platform_driver_register_all - register early platform drivers |
1074 | * @class_str: string to identify early platform driver class | 1143 | * @class_str: string to identify early platform driver class |
1144 | * | ||
1145 | * Used by architecture code to register all early platform drivers | ||
1146 | * for a certain class. If omitted then only early platform drivers | ||
1147 | * with matching kernel command line class parameters will be registered. | ||
1075 | */ | 1148 | */ |
1076 | void __init early_platform_driver_register_all(char *class_str) | 1149 | void __init early_platform_driver_register_all(char *class_str) |
1077 | { | 1150 | { |
@@ -1093,7 +1166,7 @@ void __init early_platform_driver_register_all(char *class_str) | |||
1093 | } | 1166 | } |
1094 | 1167 | ||
1095 | /** | 1168 | /** |
1096 | * early_platform_match | 1169 | * early_platform_match - find early platform device matching driver |
1097 | * @epdrv: early platform driver structure | 1170 | * @epdrv: early platform driver structure |
1098 | * @id: id to match against | 1171 | * @id: id to match against |
1099 | */ | 1172 | */ |
@@ -1111,7 +1184,7 @@ early_platform_match(struct early_platform_driver *epdrv, int id) | |||
1111 | } | 1184 | } |
1112 | 1185 | ||
1113 | /** | 1186 | /** |
1114 | * early_platform_left | 1187 | * early_platform_left - check if early platform driver has matching devices |
1115 | * @epdrv: early platform driver structure | 1188 | * @epdrv: early platform driver structure |
1116 | * @id: return true if id or above exists | 1189 | * @id: return true if id or above exists |
1117 | */ | 1190 | */ |
@@ -1129,7 +1202,7 @@ static __init int early_platform_left(struct early_platform_driver *epdrv, | |||
1129 | } | 1202 | } |
1130 | 1203 | ||
1131 | /** | 1204 | /** |
1132 | * early_platform_driver_probe_id | 1205 | * early_platform_driver_probe_id - probe drivers matching class_str and id |
1133 | * @class_str: string to identify early platform driver class | 1206 | * @class_str: string to identify early platform driver class |
1134 | * @id: id to match against | 1207 | * @id: id to match against |
1135 | * @nr_probe: number of platform devices to successfully probe before exiting | 1208 | * @nr_probe: number of platform devices to successfully probe before exiting |
@@ -1181,6 +1254,26 @@ static int __init early_platform_driver_probe_id(char *class_str, | |||
1181 | } | 1254 | } |
1182 | 1255 | ||
1183 | if (match) { | 1256 | if (match) { |
1257 | /* | ||
1258 | * Set up a sensible init_name to enable | ||
1259 | * dev_name() and others to be used before the | ||
1260 | * rest of the driver core is initialized. | ||
1261 | */ | ||
1262 | if (!match->dev.init_name && slab_is_available()) { | ||
1263 | if (match->id != -1) | ||
1264 | match->dev.init_name = | ||
1265 | kasprintf(GFP_KERNEL, "%s.%d", | ||
1266 | match->name, | ||
1267 | match->id); | ||
1268 | else | ||
1269 | match->dev.init_name = | ||
1270 | kasprintf(GFP_KERNEL, "%s", | ||
1271 | match->name); | ||
1272 | |||
1273 | if (!match->dev.init_name) | ||
1274 | return -ENOMEM; | ||
1275 | } | ||
1276 | |||
1184 | if (epdrv->pdrv->probe(match)) | 1277 | if (epdrv->pdrv->probe(match)) |
1185 | pr_warning("%s: unable to probe %s early.\n", | 1278 | pr_warning("%s: unable to probe %s early.\n", |
1186 | class_str, match->name); | 1279 | class_str, match->name); |
@@ -1199,10 +1292,14 @@ static int __init early_platform_driver_probe_id(char *class_str, | |||
1199 | } | 1292 | } |
1200 | 1293 | ||
1201 | /** | 1294 | /** |
1202 | * early_platform_driver_probe | 1295 | * early_platform_driver_probe - probe a class of registered drivers |
1203 | * @class_str: string to identify early platform driver class | 1296 | * @class_str: string to identify early platform driver class |
1204 | * @nr_probe: number of platform devices to successfully probe before exiting | 1297 | * @nr_probe: number of platform devices to successfully probe before exiting |
1205 | * @user_only: only probe user specified early platform devices | 1298 | * @user_only: only probe user specified early platform devices |
1299 | * | ||
1300 | * Used by architecture code to probe registered early platform drivers | ||
1301 | * within a certain class. For probe to happen a registered early platform | ||
1302 | * device matching a registered early platform driver is needed. | ||
1206 | */ | 1303 | */ |
1207 | int __init early_platform_driver_probe(char *class_str, | 1304 | int __init early_platform_driver_probe(char *class_str, |
1208 | int nr_probe, | 1305 | int nr_probe, |