11da177e4SLinus Torvalds /* 21da177e4SLinus Torvalds * platform.c - platform 'pseudo' bus for legacy devices 31da177e4SLinus Torvalds * 41da177e4SLinus Torvalds * Copyright (c) 2002-3 Patrick Mochel 51da177e4SLinus Torvalds * Copyright (c) 2002-3 Open Source Development Labs 61da177e4SLinus Torvalds * 71da177e4SLinus Torvalds * This file is released under the GPLv2 81da177e4SLinus Torvalds * 91da177e4SLinus Torvalds * Please see Documentation/driver-model/platform.txt for more 101da177e4SLinus Torvalds * information. 111da177e4SLinus Torvalds */ 121da177e4SLinus Torvalds 13daa41226SAndrew Morton #include <linux/string.h> 14d052d1beSRussell King #include <linux/platform_device.h> 1505212157SGrant Likely #include <linux/of_device.h> 161da177e4SLinus Torvalds #include <linux/module.h> 171da177e4SLinus Torvalds #include <linux/init.h> 181da177e4SLinus Torvalds #include <linux/dma-mapping.h> 191da177e4SLinus Torvalds #include <linux/bootmem.h> 201da177e4SLinus Torvalds #include <linux/err.h> 214e57b681STim Schmielau #include <linux/slab.h> 229d730229SMagnus Damm #include <linux/pm_runtime.h> 231da177e4SLinus Torvalds 24a1bdc7aaSBen Dooks #include "base.h" 25a1bdc7aaSBen Dooks 264a3ad20cSGreg Kroah-Hartman #define to_platform_driver(drv) (container_of((drv), struct platform_driver, \ 274a3ad20cSGreg Kroah-Hartman driver)) 2800d3dcddSRussell King 291da177e4SLinus Torvalds struct device platform_bus = { 301e0b2cf9SKay Sievers .init_name = "platform", 311da177e4SLinus Torvalds }; 32a96b2042SDmitry Torokhov EXPORT_SYMBOL_GPL(platform_bus); 331da177e4SLinus Torvalds 341da177e4SLinus Torvalds /** 35a77ce816SKumar Gala * arch_setup_pdev_archdata - Allow manipulation of archdata before its used 367de636faSRandy Dunlap * @pdev: platform device 37a77ce816SKumar Gala * 38a77ce816SKumar Gala * This is called before platform_device_add() such that any pdev_archdata may 39a77ce816SKumar Gala * be setup before the platform_notifier is called. So if a user needs to 40a77ce816SKumar Gala * manipulate any relevant information in the pdev_archdata they can do: 41a77ce816SKumar Gala * 42a77ce816SKumar Gala * platform_devic_alloc() 43a77ce816SKumar Gala * ... manipulate ... 44a77ce816SKumar Gala * platform_device_add() 45a77ce816SKumar Gala * 46a77ce816SKumar Gala * And if they don't care they can just call platform_device_register() and 47a77ce816SKumar Gala * everything will just work out. 48a77ce816SKumar Gala */ 49a77ce816SKumar Gala void __weak arch_setup_pdev_archdata(struct platform_device *pdev) 50a77ce816SKumar Gala { 51a77ce816SKumar Gala } 52a77ce816SKumar Gala 53a77ce816SKumar Gala /** 541da177e4SLinus Torvalds * platform_get_resource - get a resource for a device 551da177e4SLinus Torvalds * @dev: platform device 561da177e4SLinus Torvalds * @type: resource type 571da177e4SLinus Torvalds * @num: resource index 581da177e4SLinus Torvalds */ 594a3ad20cSGreg Kroah-Hartman struct resource *platform_get_resource(struct platform_device *dev, 604a3ad20cSGreg Kroah-Hartman unsigned int type, unsigned int num) 611da177e4SLinus Torvalds { 621da177e4SLinus Torvalds int i; 631da177e4SLinus Torvalds 641da177e4SLinus Torvalds for (i = 0; i < dev->num_resources; i++) { 651da177e4SLinus Torvalds struct resource *r = &dev->resource[i]; 661da177e4SLinus Torvalds 67c9f66169SMagnus Damm if (type == resource_type(r) && num-- == 0) 681da177e4SLinus Torvalds return r; 691da177e4SLinus Torvalds } 701da177e4SLinus Torvalds return NULL; 711da177e4SLinus Torvalds } 72a96b2042SDmitry Torokhov EXPORT_SYMBOL_GPL(platform_get_resource); 731da177e4SLinus Torvalds 741da177e4SLinus Torvalds /** 751da177e4SLinus Torvalds * platform_get_irq - get an IRQ for a device 761da177e4SLinus Torvalds * @dev: platform device 771da177e4SLinus Torvalds * @num: IRQ number index 781da177e4SLinus Torvalds */ 791da177e4SLinus Torvalds int platform_get_irq(struct platform_device *dev, unsigned int num) 801da177e4SLinus Torvalds { 811da177e4SLinus Torvalds struct resource *r = platform_get_resource(dev, IORESOURCE_IRQ, num); 821da177e4SLinus Torvalds 83305b3228SDavid Vrabel return r ? r->start : -ENXIO; 841da177e4SLinus Torvalds } 85a96b2042SDmitry Torokhov EXPORT_SYMBOL_GPL(platform_get_irq); 861da177e4SLinus Torvalds 871da177e4SLinus Torvalds /** 881da177e4SLinus Torvalds * platform_get_resource_byname - get a resource for a device by name 891da177e4SLinus Torvalds * @dev: platform device 901da177e4SLinus Torvalds * @type: resource type 911da177e4SLinus Torvalds * @name: resource name 921da177e4SLinus Torvalds */ 934a3ad20cSGreg Kroah-Hartman struct resource *platform_get_resource_byname(struct platform_device *dev, 94c0afe7baSLinus Walleij unsigned int type, 95c0afe7baSLinus Walleij const char *name) 961da177e4SLinus Torvalds { 971da177e4SLinus Torvalds int i; 981da177e4SLinus Torvalds 991da177e4SLinus Torvalds for (i = 0; i < dev->num_resources; i++) { 1001da177e4SLinus Torvalds struct resource *r = &dev->resource[i]; 1011da177e4SLinus Torvalds 102c9f66169SMagnus Damm if (type == resource_type(r) && !strcmp(r->name, name)) 1031da177e4SLinus Torvalds return r; 1041da177e4SLinus Torvalds } 1051da177e4SLinus Torvalds return NULL; 1061da177e4SLinus Torvalds } 107a96b2042SDmitry Torokhov EXPORT_SYMBOL_GPL(platform_get_resource_byname); 1081da177e4SLinus Torvalds 1091da177e4SLinus Torvalds /** 1101da177e4SLinus Torvalds * platform_get_irq - get an IRQ for a device 1111da177e4SLinus Torvalds * @dev: platform device 1121da177e4SLinus Torvalds * @name: IRQ name 1131da177e4SLinus Torvalds */ 114c0afe7baSLinus Walleij int platform_get_irq_byname(struct platform_device *dev, const char *name) 1151da177e4SLinus Torvalds { 1164a3ad20cSGreg Kroah-Hartman struct resource *r = platform_get_resource_byname(dev, IORESOURCE_IRQ, 1174a3ad20cSGreg Kroah-Hartman name); 1181da177e4SLinus Torvalds 119305b3228SDavid Vrabel return r ? r->start : -ENXIO; 1201da177e4SLinus Torvalds } 121a96b2042SDmitry Torokhov EXPORT_SYMBOL_GPL(platform_get_irq_byname); 1221da177e4SLinus Torvalds 1231da177e4SLinus Torvalds /** 1241da177e4SLinus Torvalds * platform_add_devices - add a numbers of platform devices 1251da177e4SLinus Torvalds * @devs: array of platform devices to add 1261da177e4SLinus Torvalds * @num: number of platform devices in array 1271da177e4SLinus Torvalds */ 1281da177e4SLinus Torvalds int platform_add_devices(struct platform_device **devs, int num) 1291da177e4SLinus Torvalds { 1301da177e4SLinus Torvalds int i, ret = 0; 1311da177e4SLinus Torvalds 1321da177e4SLinus Torvalds for (i = 0; i < num; i++) { 1331da177e4SLinus Torvalds ret = platform_device_register(devs[i]); 1341da177e4SLinus Torvalds if (ret) { 1351da177e4SLinus Torvalds while (--i >= 0) 1361da177e4SLinus Torvalds platform_device_unregister(devs[i]); 1371da177e4SLinus Torvalds break; 1381da177e4SLinus Torvalds } 1391da177e4SLinus Torvalds } 1401da177e4SLinus Torvalds 1411da177e4SLinus Torvalds return ret; 1421da177e4SLinus Torvalds } 143a96b2042SDmitry Torokhov EXPORT_SYMBOL_GPL(platform_add_devices); 1441da177e4SLinus Torvalds 14537c12e74SRussell King struct platform_object { 14637c12e74SRussell King struct platform_device pdev; 14737c12e74SRussell King char name[1]; 14837c12e74SRussell King }; 14937c12e74SRussell King 1501da177e4SLinus Torvalds /** 1513c31f07aSBen Hutchings * platform_device_put - destroy a platform device 15237c12e74SRussell King * @pdev: platform device to free 15337c12e74SRussell King * 1544a3ad20cSGreg Kroah-Hartman * Free all memory associated with a platform device. This function must 1554a3ad20cSGreg Kroah-Hartman * _only_ be externally called in error cases. All other usage is a bug. 15637c12e74SRussell King */ 15737c12e74SRussell King void platform_device_put(struct platform_device *pdev) 15837c12e74SRussell King { 15937c12e74SRussell King if (pdev) 16037c12e74SRussell King put_device(&pdev->dev); 16137c12e74SRussell King } 16237c12e74SRussell King EXPORT_SYMBOL_GPL(platform_device_put); 16337c12e74SRussell King 16437c12e74SRussell King static void platform_device_release(struct device *dev) 16537c12e74SRussell King { 1664a3ad20cSGreg Kroah-Hartman struct platform_object *pa = container_of(dev, struct platform_object, 1674a3ad20cSGreg Kroah-Hartman pdev.dev); 16837c12e74SRussell King 1697096d042SGrant Likely of_device_node_put(&pa->pdev.dev); 17037c12e74SRussell King kfree(pa->pdev.dev.platform_data); 171e710d7d5SSamuel Ortiz kfree(pa->pdev.mfd_cell); 17237c12e74SRussell King kfree(pa->pdev.resource); 17337c12e74SRussell King kfree(pa); 17437c12e74SRussell King } 17537c12e74SRussell King 17637c12e74SRussell King /** 1773c31f07aSBen Hutchings * platform_device_alloc - create a platform device 17837c12e74SRussell King * @name: base name of the device we're adding 17937c12e74SRussell King * @id: instance id 18037c12e74SRussell King * 18137c12e74SRussell King * Create a platform device object which can have other objects attached 18237c12e74SRussell King * to it, and which will have attached objects freed when it is released. 18337c12e74SRussell King */ 1841359555eSJean Delvare struct platform_device *platform_device_alloc(const char *name, int id) 18537c12e74SRussell King { 18637c12e74SRussell King struct platform_object *pa; 18737c12e74SRussell King 18837c12e74SRussell King pa = kzalloc(sizeof(struct platform_object) + strlen(name), GFP_KERNEL); 18937c12e74SRussell King if (pa) { 19037c12e74SRussell King strcpy(pa->name, name); 19137c12e74SRussell King pa->pdev.name = pa->name; 19237c12e74SRussell King pa->pdev.id = id; 19337c12e74SRussell King device_initialize(&pa->pdev.dev); 19437c12e74SRussell King pa->pdev.dev.release = platform_device_release; 195a77ce816SKumar Gala arch_setup_pdev_archdata(&pa->pdev); 19637c12e74SRussell King } 19737c12e74SRussell King 19837c12e74SRussell King return pa ? &pa->pdev : NULL; 19937c12e74SRussell King } 20037c12e74SRussell King EXPORT_SYMBOL_GPL(platform_device_alloc); 20137c12e74SRussell King 20237c12e74SRussell King /** 2033c31f07aSBen Hutchings * platform_device_add_resources - add resources to a platform device 20437c12e74SRussell King * @pdev: platform device allocated by platform_device_alloc to add resources to 20537c12e74SRussell King * @res: set of resources that needs to be allocated for the device 20637c12e74SRussell King * @num: number of resources 20737c12e74SRussell King * 20837c12e74SRussell King * Add a copy of the resources to the platform device. The memory 2094a3ad20cSGreg Kroah-Hartman * associated with the resources will be freed when the platform device is 2104a3ad20cSGreg Kroah-Hartman * released. 21137c12e74SRussell King */ 2124a3ad20cSGreg Kroah-Hartman int platform_device_add_resources(struct platform_device *pdev, 2130b7f1a7eSGeert Uytterhoeven const struct resource *res, unsigned int num) 21437c12e74SRussell King { 215cea89623SUwe Kleine-König struct resource *r = NULL; 21637c12e74SRussell King 217cea89623SUwe Kleine-König if (res) { 2183e61dfd8SUwe Kleine-König r = kmemdup(res, sizeof(struct resource) * num, GFP_KERNEL); 219cea89623SUwe Kleine-König if (!r) 220cea89623SUwe Kleine-König return -ENOMEM; 221cea89623SUwe Kleine-König } 222cea89623SUwe Kleine-König 2234a03d6f7SUwe Kleine-König kfree(pdev->resource); 22437c12e74SRussell King pdev->resource = r; 22537c12e74SRussell King pdev->num_resources = num; 2263e61dfd8SUwe Kleine-König return 0; 22737c12e74SRussell King } 22837c12e74SRussell King EXPORT_SYMBOL_GPL(platform_device_add_resources); 22937c12e74SRussell King 23037c12e74SRussell King /** 2313c31f07aSBen Hutchings * platform_device_add_data - add platform-specific data to a platform device 23237c12e74SRussell King * @pdev: platform device allocated by platform_device_alloc to add resources to 23337c12e74SRussell King * @data: platform specific data for this platform device 23437c12e74SRussell King * @size: size of platform specific data 23537c12e74SRussell King * 2364a3ad20cSGreg Kroah-Hartman * Add a copy of platform specific data to the platform device's 2374a3ad20cSGreg Kroah-Hartman * platform_data pointer. The memory associated with the platform data 2384a3ad20cSGreg Kroah-Hartman * will be freed when the platform device is released. 23937c12e74SRussell King */ 2404a3ad20cSGreg Kroah-Hartman int platform_device_add_data(struct platform_device *pdev, const void *data, 2414a3ad20cSGreg Kroah-Hartman size_t size) 24237c12e74SRussell King { 24327a33f9eSUwe Kleine-König void *d = NULL; 24437c12e74SRussell King 24527a33f9eSUwe Kleine-König if (data) { 2465cfc64ceSAnton Vorontsov d = kmemdup(data, size, GFP_KERNEL); 24727a33f9eSUwe Kleine-König if (!d) 24827a33f9eSUwe Kleine-König return -ENOMEM; 24927a33f9eSUwe Kleine-König } 25027a33f9eSUwe Kleine-König 251251e031dSUwe Kleine-König kfree(pdev->dev.platform_data); 25237c12e74SRussell King pdev->dev.platform_data = d; 253daa41226SAndrew Morton return 0; 25437c12e74SRussell King } 25537c12e74SRussell King EXPORT_SYMBOL_GPL(platform_device_add_data); 25637c12e74SRussell King 25737c12e74SRussell King /** 25837c12e74SRussell King * platform_device_add - add a platform device to device hierarchy 25967be2dd1SMartin Waitz * @pdev: platform device we're adding 2601da177e4SLinus Torvalds * 26137c12e74SRussell King * This is part 2 of platform_device_register(), though may be called 26237c12e74SRussell King * separately _iff_ pdev was allocated by platform_device_alloc(). 2631da177e4SLinus Torvalds */ 26437c12e74SRussell King int platform_device_add(struct platform_device *pdev) 2651da177e4SLinus Torvalds { 2661da177e4SLinus Torvalds int i, ret = 0; 2671da177e4SLinus Torvalds 2681da177e4SLinus Torvalds if (!pdev) 2691da177e4SLinus Torvalds return -EINVAL; 2701da177e4SLinus Torvalds 2711da177e4SLinus Torvalds if (!pdev->dev.parent) 2721da177e4SLinus Torvalds pdev->dev.parent = &platform_bus; 2731da177e4SLinus Torvalds 2741da177e4SLinus Torvalds pdev->dev.bus = &platform_bus_type; 2751da177e4SLinus Torvalds 2761da177e4SLinus Torvalds if (pdev->id != -1) 2771e0b2cf9SKay Sievers dev_set_name(&pdev->dev, "%s.%d", pdev->name, pdev->id); 2781da177e4SLinus Torvalds else 279acc0e90fSGreg Kroah-Hartman dev_set_name(&pdev->dev, "%s", pdev->name); 2801da177e4SLinus Torvalds 2811da177e4SLinus Torvalds for (i = 0; i < pdev->num_resources; i++) { 2821da177e4SLinus Torvalds struct resource *p, *r = &pdev->resource[i]; 2831da177e4SLinus Torvalds 2841da177e4SLinus Torvalds if (r->name == NULL) 2851e0b2cf9SKay Sievers r->name = dev_name(&pdev->dev); 2861da177e4SLinus Torvalds 2871da177e4SLinus Torvalds p = r->parent; 2881da177e4SLinus Torvalds if (!p) { 289c9f66169SMagnus Damm if (resource_type(r) == IORESOURCE_MEM) 2901da177e4SLinus Torvalds p = &iomem_resource; 291c9f66169SMagnus Damm else if (resource_type(r) == IORESOURCE_IO) 2921da177e4SLinus Torvalds p = &ioport_resource; 2931da177e4SLinus Torvalds } 2941da177e4SLinus Torvalds 295d960bb4dSKumar Gala if (p && insert_resource(p, r)) { 2961da177e4SLinus Torvalds printk(KERN_ERR 2971da177e4SLinus Torvalds "%s: failed to claim resource %d\n", 2981e0b2cf9SKay Sievers dev_name(&pdev->dev), i); 2991da177e4SLinus Torvalds ret = -EBUSY; 3001da177e4SLinus Torvalds goto failed; 3011da177e4SLinus Torvalds } 3021da177e4SLinus Torvalds } 3031da177e4SLinus Torvalds 3041da177e4SLinus Torvalds pr_debug("Registering platform device '%s'. Parent at %s\n", 3051e0b2cf9SKay Sievers dev_name(&pdev->dev), dev_name(pdev->dev.parent)); 3061da177e4SLinus Torvalds 307e3915532SRussell King ret = device_add(&pdev->dev); 3081da177e4SLinus Torvalds if (ret == 0) 3091da177e4SLinus Torvalds return ret; 3101da177e4SLinus Torvalds 3111da177e4SLinus Torvalds failed: 312c9f66169SMagnus Damm while (--i >= 0) { 313c9f66169SMagnus Damm struct resource *r = &pdev->resource[i]; 314c9f66169SMagnus Damm unsigned long type = resource_type(r); 315c9f66169SMagnus Damm 316c9f66169SMagnus Damm if (type == IORESOURCE_MEM || type == IORESOURCE_IO) 317c9f66169SMagnus Damm release_resource(r); 318c9f66169SMagnus Damm } 319c9f66169SMagnus Damm 3201da177e4SLinus Torvalds return ret; 3211da177e4SLinus Torvalds } 32237c12e74SRussell King EXPORT_SYMBOL_GPL(platform_device_add); 32337c12e74SRussell King 32437c12e74SRussell King /** 32593ce3061SDmitry Torokhov * platform_device_del - remove a platform-level device 32693ce3061SDmitry Torokhov * @pdev: platform device we're removing 32793ce3061SDmitry Torokhov * 32893ce3061SDmitry Torokhov * Note that this function will also release all memory- and port-based 3294a3ad20cSGreg Kroah-Hartman * resources owned by the device (@dev->resource). This function must 3304a3ad20cSGreg Kroah-Hartman * _only_ be externally called in error cases. All other usage is a bug. 33193ce3061SDmitry Torokhov */ 33293ce3061SDmitry Torokhov void platform_device_del(struct platform_device *pdev) 33393ce3061SDmitry Torokhov { 33493ce3061SDmitry Torokhov int i; 33593ce3061SDmitry Torokhov 33693ce3061SDmitry Torokhov if (pdev) { 337dc4c15d4SJean Delvare device_del(&pdev->dev); 338dc4c15d4SJean Delvare 33993ce3061SDmitry Torokhov for (i = 0; i < pdev->num_resources; i++) { 34093ce3061SDmitry Torokhov struct resource *r = &pdev->resource[i]; 341c9f66169SMagnus Damm unsigned long type = resource_type(r); 342c9f66169SMagnus Damm 343c9f66169SMagnus Damm if (type == IORESOURCE_MEM || type == IORESOURCE_IO) 34493ce3061SDmitry Torokhov release_resource(r); 34593ce3061SDmitry Torokhov } 34693ce3061SDmitry Torokhov } 34793ce3061SDmitry Torokhov } 34893ce3061SDmitry Torokhov EXPORT_SYMBOL_GPL(platform_device_del); 34993ce3061SDmitry Torokhov 35093ce3061SDmitry Torokhov /** 35137c12e74SRussell King * platform_device_register - add a platform-level device 35237c12e74SRussell King * @pdev: platform device we're adding 35337c12e74SRussell King */ 35437c12e74SRussell King int platform_device_register(struct platform_device *pdev) 35537c12e74SRussell King { 35637c12e74SRussell King device_initialize(&pdev->dev); 357a77ce816SKumar Gala arch_setup_pdev_archdata(pdev); 35837c12e74SRussell King return platform_device_add(pdev); 35937c12e74SRussell King } 360a96b2042SDmitry Torokhov EXPORT_SYMBOL_GPL(platform_device_register); 3611da177e4SLinus Torvalds 3621da177e4SLinus Torvalds /** 36393ce3061SDmitry Torokhov * platform_device_unregister - unregister a platform-level device 36493ce3061SDmitry Torokhov * @pdev: platform device we're unregistering 3651da177e4SLinus Torvalds * 36680682fa9SUwe Zeisberger * Unregistration is done in 2 steps. First we release all resources 3672d7b5a70SJean Delvare * and remove it from the subsystem, then we drop reference count by 36893ce3061SDmitry Torokhov * calling platform_device_put(). 3691da177e4SLinus Torvalds */ 3701da177e4SLinus Torvalds void platform_device_unregister(struct platform_device *pdev) 3711da177e4SLinus Torvalds { 37293ce3061SDmitry Torokhov platform_device_del(pdev); 37393ce3061SDmitry Torokhov platform_device_put(pdev); 3741da177e4SLinus Torvalds } 375a96b2042SDmitry Torokhov EXPORT_SYMBOL_GPL(platform_device_unregister); 3761da177e4SLinus Torvalds 3771da177e4SLinus Torvalds /** 37844f28bdeSUwe Kleine-König * platform_device_register_resndata - add a platform-level device with 37944f28bdeSUwe Kleine-König * resources and platform-specific data 38044f28bdeSUwe Kleine-König * 38144f28bdeSUwe Kleine-König * @parent: parent device for the device we're adding 3821da177e4SLinus Torvalds * @name: base name of the device we're adding 3831da177e4SLinus Torvalds * @id: instance id 3841da177e4SLinus Torvalds * @res: set of resources that needs to be allocated for the device 3851da177e4SLinus Torvalds * @num: number of resources 386d8bf2540SDmitry Baryshkov * @data: platform specific data for this platform device 387d8bf2540SDmitry Baryshkov * @size: size of platform specific data 388d8bf2540SDmitry Baryshkov * 389f0eae0edSJani Nikula * Returns &struct platform_device pointer on success, or ERR_PTR() on error. 390d8bf2540SDmitry Baryshkov */ 391bb2b43feSAndrew Morton struct platform_device *platform_device_register_resndata( 392d8bf2540SDmitry Baryshkov struct device *parent, 393d8bf2540SDmitry Baryshkov const char *name, int id, 39444f28bdeSUwe Kleine-König const struct resource *res, unsigned int num, 395d8bf2540SDmitry Baryshkov const void *data, size_t size) 396d8bf2540SDmitry Baryshkov { 39744f28bdeSUwe Kleine-König int ret = -ENOMEM; 398d8bf2540SDmitry Baryshkov struct platform_device *pdev; 399d8bf2540SDmitry Baryshkov 400d8bf2540SDmitry Baryshkov pdev = platform_device_alloc(name, id); 40144f28bdeSUwe Kleine-König if (!pdev) 40244f28bdeSUwe Kleine-König goto err; 403d8bf2540SDmitry Baryshkov 404d8bf2540SDmitry Baryshkov pdev->dev.parent = parent; 405d8bf2540SDmitry Baryshkov 40644f28bdeSUwe Kleine-König ret = platform_device_add_resources(pdev, res, num); 40744f28bdeSUwe Kleine-König if (ret) 40844f28bdeSUwe Kleine-König goto err; 409d8bf2540SDmitry Baryshkov 41044f28bdeSUwe Kleine-König ret = platform_device_add_data(pdev, data, size); 41144f28bdeSUwe Kleine-König if (ret) 41244f28bdeSUwe Kleine-König goto err; 41344f28bdeSUwe Kleine-König 41444f28bdeSUwe Kleine-König ret = platform_device_add(pdev); 41544f28bdeSUwe Kleine-König if (ret) { 41644f28bdeSUwe Kleine-König err: 41744f28bdeSUwe Kleine-König platform_device_put(pdev); 41844f28bdeSUwe Kleine-König return ERR_PTR(ret); 41944f28bdeSUwe Kleine-König } 420d8bf2540SDmitry Baryshkov 421d8bf2540SDmitry Baryshkov return pdev; 422d8bf2540SDmitry Baryshkov } 42344f28bdeSUwe Kleine-König EXPORT_SYMBOL_GPL(platform_device_register_resndata); 424d8bf2540SDmitry Baryshkov 42500d3dcddSRussell King static int platform_drv_probe(struct device *_dev) 42600d3dcddSRussell King { 42700d3dcddSRussell King struct platform_driver *drv = to_platform_driver(_dev->driver); 42800d3dcddSRussell King struct platform_device *dev = to_platform_device(_dev); 42900d3dcddSRussell King 43000d3dcddSRussell King return drv->probe(dev); 43100d3dcddSRussell King } 43200d3dcddSRussell King 433c67334fbSDavid Brownell static int platform_drv_probe_fail(struct device *_dev) 434c67334fbSDavid Brownell { 435c67334fbSDavid Brownell return -ENXIO; 436c67334fbSDavid Brownell } 437c67334fbSDavid Brownell 43800d3dcddSRussell King static int platform_drv_remove(struct device *_dev) 43900d3dcddSRussell King { 44000d3dcddSRussell King struct platform_driver *drv = to_platform_driver(_dev->driver); 44100d3dcddSRussell King struct platform_device *dev = to_platform_device(_dev); 44200d3dcddSRussell King 44300d3dcddSRussell King return drv->remove(dev); 44400d3dcddSRussell King } 44500d3dcddSRussell King 44600d3dcddSRussell King static void platform_drv_shutdown(struct device *_dev) 44700d3dcddSRussell King { 44800d3dcddSRussell King struct platform_driver *drv = to_platform_driver(_dev->driver); 44900d3dcddSRussell King struct platform_device *dev = to_platform_device(_dev); 45000d3dcddSRussell King 45100d3dcddSRussell King drv->shutdown(dev); 45200d3dcddSRussell King } 45300d3dcddSRussell King 45400d3dcddSRussell King /** 4553c31f07aSBen Hutchings * platform_driver_register - register a driver for platform-level devices 45600d3dcddSRussell King * @drv: platform driver structure 45700d3dcddSRussell King */ 45800d3dcddSRussell King int platform_driver_register(struct platform_driver *drv) 45900d3dcddSRussell King { 46000d3dcddSRussell King drv->driver.bus = &platform_bus_type; 46100d3dcddSRussell King if (drv->probe) 46200d3dcddSRussell King drv->driver.probe = platform_drv_probe; 46300d3dcddSRussell King if (drv->remove) 46400d3dcddSRussell King drv->driver.remove = platform_drv_remove; 46500d3dcddSRussell King if (drv->shutdown) 46600d3dcddSRussell King drv->driver.shutdown = platform_drv_shutdown; 467783ea7d4SMagnus Damm 46800d3dcddSRussell King return driver_register(&drv->driver); 46900d3dcddSRussell King } 47000d3dcddSRussell King EXPORT_SYMBOL_GPL(platform_driver_register); 47100d3dcddSRussell King 47200d3dcddSRussell King /** 4733c31f07aSBen Hutchings * platform_driver_unregister - unregister a driver for platform-level devices 47400d3dcddSRussell King * @drv: platform driver structure 47500d3dcddSRussell King */ 47600d3dcddSRussell King void platform_driver_unregister(struct platform_driver *drv) 47700d3dcddSRussell King { 47800d3dcddSRussell King driver_unregister(&drv->driver); 47900d3dcddSRussell King } 48000d3dcddSRussell King EXPORT_SYMBOL_GPL(platform_driver_unregister); 48100d3dcddSRussell King 482c67334fbSDavid Brownell /** 483c67334fbSDavid Brownell * platform_driver_probe - register driver for non-hotpluggable device 484c67334fbSDavid Brownell * @drv: platform driver structure 485c67334fbSDavid Brownell * @probe: the driver probe routine, probably from an __init section 486c67334fbSDavid Brownell * 487c67334fbSDavid Brownell * Use this instead of platform_driver_register() when you know the device 488c67334fbSDavid Brownell * is not hotpluggable and has already been registered, and you want to 489c67334fbSDavid Brownell * remove its run-once probe() infrastructure from memory after the driver 490c67334fbSDavid Brownell * has bound to the device. 491c67334fbSDavid Brownell * 492c67334fbSDavid Brownell * One typical use for this would be with drivers for controllers integrated 493c67334fbSDavid Brownell * into system-on-chip processors, where the controller devices have been 494c67334fbSDavid Brownell * configured as part of board setup. 495c67334fbSDavid Brownell * 496c67334fbSDavid Brownell * Returns zero if the driver registered and bound to a device, else returns 497c67334fbSDavid Brownell * a negative error code and with the driver not registered. 498c67334fbSDavid Brownell */ 499c63e0783SAndrew Morton int __init_or_module platform_driver_probe(struct platform_driver *drv, 500c67334fbSDavid Brownell int (*probe)(struct platform_device *)) 501c67334fbSDavid Brownell { 502c67334fbSDavid Brownell int retval, code; 503c67334fbSDavid Brownell 5041a6f2a75SDmitry Torokhov /* make sure driver won't have bind/unbind attributes */ 5051a6f2a75SDmitry Torokhov drv->driver.suppress_bind_attrs = true; 5061a6f2a75SDmitry Torokhov 507c67334fbSDavid Brownell /* temporary section violation during probe() */ 508c67334fbSDavid Brownell drv->probe = probe; 509c67334fbSDavid Brownell retval = code = platform_driver_register(drv); 510c67334fbSDavid Brownell 5111a6f2a75SDmitry Torokhov /* 5121a6f2a75SDmitry Torokhov * Fixup that section violation, being paranoid about code scanning 513c67334fbSDavid Brownell * the list of drivers in order to probe new devices. Check to see 514c67334fbSDavid Brownell * if the probe was successful, and make sure any forced probes of 515c67334fbSDavid Brownell * new devices fail. 516c67334fbSDavid Brownell */ 517d79d3244SPatrick Pannuto spin_lock(&drv->driver.bus->p->klist_drivers.k_lock); 518c67334fbSDavid Brownell drv->probe = NULL; 519e5dd1278SGreg Kroah-Hartman if (code == 0 && list_empty(&drv->driver.p->klist_devices.k_list)) 520c67334fbSDavid Brownell retval = -ENODEV; 521c67334fbSDavid Brownell drv->driver.probe = platform_drv_probe_fail; 522d79d3244SPatrick Pannuto spin_unlock(&drv->driver.bus->p->klist_drivers.k_lock); 523c67334fbSDavid Brownell 524c67334fbSDavid Brownell if (code != retval) 525c67334fbSDavid Brownell platform_driver_unregister(drv); 526c67334fbSDavid Brownell return retval; 527c67334fbSDavid Brownell } 528c67334fbSDavid Brownell EXPORT_SYMBOL_GPL(platform_driver_probe); 5291da177e4SLinus Torvalds 530ecdf6cebSDmitry Torokhov /** 531ecdf6cebSDmitry Torokhov * platform_create_bundle - register driver and create corresponding device 532ecdf6cebSDmitry Torokhov * @driver: platform driver structure 533ecdf6cebSDmitry Torokhov * @probe: the driver probe routine, probably from an __init section 534ecdf6cebSDmitry Torokhov * @res: set of resources that needs to be allocated for the device 535ecdf6cebSDmitry Torokhov * @n_res: number of resources 536ecdf6cebSDmitry Torokhov * @data: platform specific data for this platform device 537ecdf6cebSDmitry Torokhov * @size: size of platform specific data 538ecdf6cebSDmitry Torokhov * 539ecdf6cebSDmitry Torokhov * Use this in legacy-style modules that probe hardware directly and 540ecdf6cebSDmitry Torokhov * register a single platform device and corresponding platform driver. 541f0eae0edSJani Nikula * 542f0eae0edSJani Nikula * Returns &struct platform_device pointer on success, or ERR_PTR() on error. 543ecdf6cebSDmitry Torokhov */ 544ecdf6cebSDmitry Torokhov struct platform_device * __init_or_module platform_create_bundle( 545ecdf6cebSDmitry Torokhov struct platform_driver *driver, 546ecdf6cebSDmitry Torokhov int (*probe)(struct platform_device *), 547ecdf6cebSDmitry Torokhov struct resource *res, unsigned int n_res, 548ecdf6cebSDmitry Torokhov const void *data, size_t size) 549ecdf6cebSDmitry Torokhov { 550ecdf6cebSDmitry Torokhov struct platform_device *pdev; 551ecdf6cebSDmitry Torokhov int error; 552ecdf6cebSDmitry Torokhov 553ecdf6cebSDmitry Torokhov pdev = platform_device_alloc(driver->driver.name, -1); 554ecdf6cebSDmitry Torokhov if (!pdev) { 555ecdf6cebSDmitry Torokhov error = -ENOMEM; 556ecdf6cebSDmitry Torokhov goto err_out; 557ecdf6cebSDmitry Torokhov } 558ecdf6cebSDmitry Torokhov 559ecdf6cebSDmitry Torokhov error = platform_device_add_resources(pdev, res, n_res); 560ecdf6cebSDmitry Torokhov if (error) 561ecdf6cebSDmitry Torokhov goto err_pdev_put; 562ecdf6cebSDmitry Torokhov 563ecdf6cebSDmitry Torokhov error = platform_device_add_data(pdev, data, size); 564ecdf6cebSDmitry Torokhov if (error) 565ecdf6cebSDmitry Torokhov goto err_pdev_put; 566ecdf6cebSDmitry Torokhov 567ecdf6cebSDmitry Torokhov error = platform_device_add(pdev); 568ecdf6cebSDmitry Torokhov if (error) 569ecdf6cebSDmitry Torokhov goto err_pdev_put; 570ecdf6cebSDmitry Torokhov 571ecdf6cebSDmitry Torokhov error = platform_driver_probe(driver, probe); 572ecdf6cebSDmitry Torokhov if (error) 573ecdf6cebSDmitry Torokhov goto err_pdev_del; 574ecdf6cebSDmitry Torokhov 575ecdf6cebSDmitry Torokhov return pdev; 576ecdf6cebSDmitry Torokhov 577ecdf6cebSDmitry Torokhov err_pdev_del: 578ecdf6cebSDmitry Torokhov platform_device_del(pdev); 579ecdf6cebSDmitry Torokhov err_pdev_put: 580ecdf6cebSDmitry Torokhov platform_device_put(pdev); 581ecdf6cebSDmitry Torokhov err_out: 582ecdf6cebSDmitry Torokhov return ERR_PTR(error); 583ecdf6cebSDmitry Torokhov } 584ecdf6cebSDmitry Torokhov EXPORT_SYMBOL_GPL(platform_create_bundle); 585ecdf6cebSDmitry Torokhov 586a0245f7aSDavid Brownell /* modalias support enables more hands-off userspace setup: 587a0245f7aSDavid Brownell * (a) environment variable lets new-style hotplug events work once system is 588a0245f7aSDavid Brownell * fully running: "modprobe $MODALIAS" 589a0245f7aSDavid Brownell * (b) sysfs attribute lets new-style coldplug recover from hotplug events 590a0245f7aSDavid Brownell * mishandled before system is fully running: "modprobe $(cat modalias)" 591a0245f7aSDavid Brownell */ 5924a3ad20cSGreg Kroah-Hartman static ssize_t modalias_show(struct device *dev, struct device_attribute *a, 5934a3ad20cSGreg Kroah-Hartman char *buf) 594a0245f7aSDavid Brownell { 595a0245f7aSDavid Brownell struct platform_device *pdev = to_platform_device(dev); 59643cc71eeSKay Sievers int len = snprintf(buf, PAGE_SIZE, "platform:%s\n", pdev->name); 597a0245f7aSDavid Brownell 598a0245f7aSDavid Brownell return (len >= PAGE_SIZE) ? (PAGE_SIZE - 1) : len; 599a0245f7aSDavid Brownell } 600a0245f7aSDavid Brownell 601a0245f7aSDavid Brownell static struct device_attribute platform_dev_attrs[] = { 602a0245f7aSDavid Brownell __ATTR_RO(modalias), 603a0245f7aSDavid Brownell __ATTR_NULL, 604a0245f7aSDavid Brownell }; 605a0245f7aSDavid Brownell 6067eff2e7aSKay Sievers static int platform_uevent(struct device *dev, struct kobj_uevent_env *env) 607a0245f7aSDavid Brownell { 608a0245f7aSDavid Brownell struct platform_device *pdev = to_platform_device(dev); 609eca39301SGrant Likely int rc; 610eca39301SGrant Likely 611eca39301SGrant Likely /* Some devices have extra OF data and an OF-style MODALIAS */ 612eca39301SGrant Likely rc = of_device_uevent(dev,env); 613eca39301SGrant Likely if (rc != -ENODEV) 614eca39301SGrant Likely return rc; 615a0245f7aSDavid Brownell 61657fee4a5SEric Miao add_uevent_var(env, "MODALIAS=%s%s", PLATFORM_MODULE_PREFIX, 61757fee4a5SEric Miao (pdev->id_entry) ? pdev->id_entry->name : pdev->name); 618a0245f7aSDavid Brownell return 0; 619a0245f7aSDavid Brownell } 620a0245f7aSDavid Brownell 62157fee4a5SEric Miao static const struct platform_device_id *platform_match_id( 622831fad2fSUwe Kleine-König const struct platform_device_id *id, 62357fee4a5SEric Miao struct platform_device *pdev) 62457fee4a5SEric Miao { 62557fee4a5SEric Miao while (id->name[0]) { 62657fee4a5SEric Miao if (strcmp(pdev->name, id->name) == 0) { 62757fee4a5SEric Miao pdev->id_entry = id; 62857fee4a5SEric Miao return id; 62957fee4a5SEric Miao } 63057fee4a5SEric Miao id++; 63157fee4a5SEric Miao } 63257fee4a5SEric Miao return NULL; 63357fee4a5SEric Miao } 63457fee4a5SEric Miao 6351da177e4SLinus Torvalds /** 6361da177e4SLinus Torvalds * platform_match - bind platform device to platform driver. 6371da177e4SLinus Torvalds * @dev: device. 6381da177e4SLinus Torvalds * @drv: driver. 6391da177e4SLinus Torvalds * 6401da177e4SLinus Torvalds * Platform device IDs are assumed to be encoded like this: 6414a3ad20cSGreg Kroah-Hartman * "<name><instance>", where <name> is a short description of the type of 6424a3ad20cSGreg Kroah-Hartman * device, like "pci" or "floppy", and <instance> is the enumerated 6434a3ad20cSGreg Kroah-Hartman * instance of the device, like '0' or '42'. Driver IDs are simply 6444a3ad20cSGreg Kroah-Hartman * "<name>". So, extract the <name> from the platform_device structure, 6454a3ad20cSGreg Kroah-Hartman * and compare it against the name of the driver. Return whether they match 6464a3ad20cSGreg Kroah-Hartman * or not. 6471da177e4SLinus Torvalds */ 6481da177e4SLinus Torvalds static int platform_match(struct device *dev, struct device_driver *drv) 6491da177e4SLinus Torvalds { 65071b3e0c1SEric Miao struct platform_device *pdev = to_platform_device(dev); 65157fee4a5SEric Miao struct platform_driver *pdrv = to_platform_driver(drv); 6521da177e4SLinus Torvalds 65305212157SGrant Likely /* Attempt an OF style match first */ 65405212157SGrant Likely if (of_driver_match_device(dev, drv)) 65505212157SGrant Likely return 1; 65605212157SGrant Likely 65705212157SGrant Likely /* Then try to match against the id table */ 65857fee4a5SEric Miao if (pdrv->id_table) 65957fee4a5SEric Miao return platform_match_id(pdrv->id_table, pdev) != NULL; 66057fee4a5SEric Miao 66157fee4a5SEric Miao /* fall-back to driver name match */ 6621e0b2cf9SKay Sievers return (strcmp(pdev->name, drv->name) == 0); 6631da177e4SLinus Torvalds } 6641da177e4SLinus Torvalds 66525e18499SRafael J. Wysocki #ifdef CONFIG_PM_SLEEP 66625e18499SRafael J. Wysocki 66725e18499SRafael J. Wysocki static int platform_legacy_suspend(struct device *dev, pm_message_t mesg) 6681da177e4SLinus Torvalds { 669783ea7d4SMagnus Damm struct platform_driver *pdrv = to_platform_driver(dev->driver); 670783ea7d4SMagnus Damm struct platform_device *pdev = to_platform_device(dev); 6711da177e4SLinus Torvalds int ret = 0; 6721da177e4SLinus Torvalds 673783ea7d4SMagnus Damm if (dev->driver && pdrv->suspend) 674783ea7d4SMagnus Damm ret = pdrv->suspend(pdev, mesg); 675386415d8SDavid Brownell 676386415d8SDavid Brownell return ret; 677386415d8SDavid Brownell } 678386415d8SDavid Brownell 67925e18499SRafael J. Wysocki static int platform_legacy_resume(struct device *dev) 6801da177e4SLinus Torvalds { 681783ea7d4SMagnus Damm struct platform_driver *pdrv = to_platform_driver(dev->driver); 682783ea7d4SMagnus Damm struct platform_device *pdev = to_platform_device(dev); 6831da177e4SLinus Torvalds int ret = 0; 6841da177e4SLinus Torvalds 685783ea7d4SMagnus Damm if (dev->driver && pdrv->resume) 686783ea7d4SMagnus Damm ret = pdrv->resume(pdev); 6879480e307SRussell King 6881da177e4SLinus Torvalds return ret; 6891da177e4SLinus Torvalds } 6901da177e4SLinus Torvalds 69169c9dd1eSRafael J. Wysocki int platform_pm_prepare(struct device *dev) 69225e18499SRafael J. Wysocki { 69325e18499SRafael J. Wysocki struct device_driver *drv = dev->driver; 69425e18499SRafael J. Wysocki int ret = 0; 69525e18499SRafael J. Wysocki 69625e18499SRafael J. Wysocki if (drv && drv->pm && drv->pm->prepare) 69725e18499SRafael J. Wysocki ret = drv->pm->prepare(dev); 69825e18499SRafael J. Wysocki 69925e18499SRafael J. Wysocki return ret; 70025e18499SRafael J. Wysocki } 70125e18499SRafael J. Wysocki 70269c9dd1eSRafael J. Wysocki void platform_pm_complete(struct device *dev) 70325e18499SRafael J. Wysocki { 70425e18499SRafael J. Wysocki struct device_driver *drv = dev->driver; 70525e18499SRafael J. Wysocki 70625e18499SRafael J. Wysocki if (drv && drv->pm && drv->pm->complete) 70725e18499SRafael J. Wysocki drv->pm->complete(dev); 70825e18499SRafael J. Wysocki } 70925e18499SRafael J. Wysocki 71069c9dd1eSRafael J. Wysocki #endif /* CONFIG_PM_SLEEP */ 7119d730229SMagnus Damm 71225e18499SRafael J. Wysocki #ifdef CONFIG_SUSPEND 71325e18499SRafael J. Wysocki 71469c9dd1eSRafael J. Wysocki int platform_pm_suspend(struct device *dev) 71525e18499SRafael J. Wysocki { 71625e18499SRafael J. Wysocki struct device_driver *drv = dev->driver; 71725e18499SRafael J. Wysocki int ret = 0; 71825e18499SRafael J. Wysocki 719adf09493SRafael J. Wysocki if (!drv) 720adf09493SRafael J. Wysocki return 0; 721adf09493SRafael J. Wysocki 722adf09493SRafael J. Wysocki if (drv->pm) { 72325e18499SRafael J. Wysocki if (drv->pm->suspend) 72425e18499SRafael J. Wysocki ret = drv->pm->suspend(dev); 72525e18499SRafael J. Wysocki } else { 72625e18499SRafael J. Wysocki ret = platform_legacy_suspend(dev, PMSG_SUSPEND); 72725e18499SRafael J. Wysocki } 72825e18499SRafael J. Wysocki 72925e18499SRafael J. Wysocki return ret; 73025e18499SRafael J. Wysocki } 73125e18499SRafael J. Wysocki 73269c9dd1eSRafael J. Wysocki int platform_pm_suspend_noirq(struct device *dev) 73325e18499SRafael J. Wysocki { 734adf09493SRafael J. Wysocki struct device_driver *drv = dev->driver; 73525e18499SRafael J. Wysocki int ret = 0; 73625e18499SRafael J. Wysocki 737adf09493SRafael J. Wysocki if (!drv) 73825e18499SRafael J. Wysocki return 0; 73925e18499SRafael J. Wysocki 740adf09493SRafael J. Wysocki if (drv->pm) { 741adf09493SRafael J. Wysocki if (drv->pm->suspend_noirq) 742adf09493SRafael J. Wysocki ret = drv->pm->suspend_noirq(dev); 74325e18499SRafael J. Wysocki } 74425e18499SRafael J. Wysocki 74525e18499SRafael J. Wysocki return ret; 74625e18499SRafael J. Wysocki } 74725e18499SRafael J. Wysocki 74869c9dd1eSRafael J. Wysocki int platform_pm_resume(struct device *dev) 74925e18499SRafael J. Wysocki { 75025e18499SRafael J. Wysocki struct device_driver *drv = dev->driver; 75125e18499SRafael J. Wysocki int ret = 0; 75225e18499SRafael J. Wysocki 753adf09493SRafael J. Wysocki if (!drv) 754adf09493SRafael J. Wysocki return 0; 755adf09493SRafael J. Wysocki 756adf09493SRafael J. Wysocki if (drv->pm) { 75725e18499SRafael J. Wysocki if (drv->pm->resume) 75825e18499SRafael J. Wysocki ret = drv->pm->resume(dev); 75925e18499SRafael J. Wysocki } else { 76025e18499SRafael J. Wysocki ret = platform_legacy_resume(dev); 76125e18499SRafael J. Wysocki } 76225e18499SRafael J. Wysocki 76325e18499SRafael J. Wysocki return ret; 76425e18499SRafael J. Wysocki } 76525e18499SRafael J. Wysocki 76669c9dd1eSRafael J. Wysocki int platform_pm_resume_noirq(struct device *dev) 76725e18499SRafael J. Wysocki { 768adf09493SRafael J. Wysocki struct device_driver *drv = dev->driver; 76925e18499SRafael J. Wysocki int ret = 0; 77025e18499SRafael J. Wysocki 771adf09493SRafael J. Wysocki if (!drv) 77225e18499SRafael J. Wysocki return 0; 77325e18499SRafael J. Wysocki 774adf09493SRafael J. Wysocki if (drv->pm) { 775adf09493SRafael J. Wysocki if (drv->pm->resume_noirq) 776adf09493SRafael J. Wysocki ret = drv->pm->resume_noirq(dev); 77725e18499SRafael J. Wysocki } 77825e18499SRafael J. Wysocki 77925e18499SRafael J. Wysocki return ret; 78025e18499SRafael J. Wysocki } 78125e18499SRafael J. Wysocki 78269c9dd1eSRafael J. Wysocki #endif /* CONFIG_SUSPEND */ 78325e18499SRafael J. Wysocki 7841f112ceeSRafael J. Wysocki #ifdef CONFIG_HIBERNATE_CALLBACKS 78525e18499SRafael J. Wysocki 78669c9dd1eSRafael J. Wysocki int platform_pm_freeze(struct device *dev) 78725e18499SRafael J. Wysocki { 78825e18499SRafael J. Wysocki struct device_driver *drv = dev->driver; 78925e18499SRafael J. Wysocki int ret = 0; 79025e18499SRafael J. Wysocki 79125e18499SRafael J. Wysocki if (!drv) 79225e18499SRafael J. Wysocki return 0; 79325e18499SRafael J. Wysocki 79425e18499SRafael J. Wysocki if (drv->pm) { 79525e18499SRafael J. Wysocki if (drv->pm->freeze) 79625e18499SRafael J. Wysocki ret = drv->pm->freeze(dev); 79725e18499SRafael J. Wysocki } else { 79825e18499SRafael J. Wysocki ret = platform_legacy_suspend(dev, PMSG_FREEZE); 79925e18499SRafael J. Wysocki } 80025e18499SRafael J. Wysocki 80125e18499SRafael J. Wysocki return ret; 80225e18499SRafael J. Wysocki } 80325e18499SRafael J. Wysocki 80469c9dd1eSRafael J. Wysocki int platform_pm_freeze_noirq(struct device *dev) 80525e18499SRafael J. Wysocki { 806adf09493SRafael J. Wysocki struct device_driver *drv = dev->driver; 80725e18499SRafael J. Wysocki int ret = 0; 80825e18499SRafael J. Wysocki 809adf09493SRafael J. Wysocki if (!drv) 81025e18499SRafael J. Wysocki return 0; 81125e18499SRafael J. Wysocki 812adf09493SRafael J. Wysocki if (drv->pm) { 813adf09493SRafael J. Wysocki if (drv->pm->freeze_noirq) 814adf09493SRafael J. Wysocki ret = drv->pm->freeze_noirq(dev); 81525e18499SRafael J. Wysocki } 81625e18499SRafael J. Wysocki 81725e18499SRafael J. Wysocki return ret; 81825e18499SRafael J. Wysocki } 81925e18499SRafael J. Wysocki 82069c9dd1eSRafael J. Wysocki int platform_pm_thaw(struct device *dev) 82125e18499SRafael J. Wysocki { 82225e18499SRafael J. Wysocki struct device_driver *drv = dev->driver; 82325e18499SRafael J. Wysocki int ret = 0; 82425e18499SRafael J. Wysocki 825adf09493SRafael J. Wysocki if (!drv) 826adf09493SRafael J. Wysocki return 0; 827adf09493SRafael J. Wysocki 828adf09493SRafael J. Wysocki if (drv->pm) { 82925e18499SRafael J. Wysocki if (drv->pm->thaw) 83025e18499SRafael J. Wysocki ret = drv->pm->thaw(dev); 83125e18499SRafael J. Wysocki } else { 83225e18499SRafael J. Wysocki ret = platform_legacy_resume(dev); 83325e18499SRafael J. Wysocki } 83425e18499SRafael J. Wysocki 83525e18499SRafael J. Wysocki return ret; 83625e18499SRafael J. Wysocki } 83725e18499SRafael J. Wysocki 83869c9dd1eSRafael J. Wysocki int platform_pm_thaw_noirq(struct device *dev) 83925e18499SRafael J. Wysocki { 840adf09493SRafael J. Wysocki struct device_driver *drv = dev->driver; 84125e18499SRafael J. Wysocki int ret = 0; 84225e18499SRafael J. Wysocki 843adf09493SRafael J. Wysocki if (!drv) 84425e18499SRafael J. Wysocki return 0; 84525e18499SRafael J. Wysocki 846adf09493SRafael J. Wysocki if (drv->pm) { 847adf09493SRafael J. Wysocki if (drv->pm->thaw_noirq) 848adf09493SRafael J. Wysocki ret = drv->pm->thaw_noirq(dev); 84925e18499SRafael J. Wysocki } 85025e18499SRafael J. Wysocki 85125e18499SRafael J. Wysocki return ret; 85225e18499SRafael J. Wysocki } 85325e18499SRafael J. Wysocki 85469c9dd1eSRafael J. Wysocki int platform_pm_poweroff(struct device *dev) 85525e18499SRafael J. Wysocki { 85625e18499SRafael J. Wysocki struct device_driver *drv = dev->driver; 85725e18499SRafael J. Wysocki int ret = 0; 85825e18499SRafael J. Wysocki 859adf09493SRafael J. Wysocki if (!drv) 860adf09493SRafael J. Wysocki return 0; 861adf09493SRafael J. Wysocki 862adf09493SRafael J. Wysocki if (drv->pm) { 86325e18499SRafael J. Wysocki if (drv->pm->poweroff) 86425e18499SRafael J. Wysocki ret = drv->pm->poweroff(dev); 86525e18499SRafael J. Wysocki } else { 86625e18499SRafael J. Wysocki ret = platform_legacy_suspend(dev, PMSG_HIBERNATE); 86725e18499SRafael J. Wysocki } 86825e18499SRafael J. Wysocki 86925e18499SRafael J. Wysocki return ret; 87025e18499SRafael J. Wysocki } 87125e18499SRafael J. Wysocki 87269c9dd1eSRafael J. Wysocki int platform_pm_poweroff_noirq(struct device *dev) 87325e18499SRafael J. Wysocki { 874adf09493SRafael J. Wysocki struct device_driver *drv = dev->driver; 87525e18499SRafael J. Wysocki int ret = 0; 87625e18499SRafael J. Wysocki 877adf09493SRafael J. Wysocki if (!drv) 87825e18499SRafael J. Wysocki return 0; 87925e18499SRafael J. Wysocki 880adf09493SRafael J. Wysocki if (drv->pm) { 881adf09493SRafael J. Wysocki if (drv->pm->poweroff_noirq) 882adf09493SRafael J. Wysocki ret = drv->pm->poweroff_noirq(dev); 88325e18499SRafael J. Wysocki } 88425e18499SRafael J. Wysocki 88525e18499SRafael J. Wysocki return ret; 88625e18499SRafael J. Wysocki } 88725e18499SRafael J. Wysocki 88869c9dd1eSRafael J. Wysocki int platform_pm_restore(struct device *dev) 88925e18499SRafael J. Wysocki { 89025e18499SRafael J. Wysocki struct device_driver *drv = dev->driver; 89125e18499SRafael J. Wysocki int ret = 0; 89225e18499SRafael J. Wysocki 893adf09493SRafael J. Wysocki if (!drv) 894adf09493SRafael J. Wysocki return 0; 895adf09493SRafael J. Wysocki 896adf09493SRafael J. Wysocki if (drv->pm) { 89725e18499SRafael J. Wysocki if (drv->pm->restore) 89825e18499SRafael J. Wysocki ret = drv->pm->restore(dev); 89925e18499SRafael J. Wysocki } else { 90025e18499SRafael J. Wysocki ret = platform_legacy_resume(dev); 90125e18499SRafael J. Wysocki } 90225e18499SRafael J. Wysocki 90325e18499SRafael J. Wysocki return ret; 90425e18499SRafael J. Wysocki } 90525e18499SRafael J. Wysocki 90669c9dd1eSRafael J. Wysocki int platform_pm_restore_noirq(struct device *dev) 90725e18499SRafael J. Wysocki { 908adf09493SRafael J. Wysocki struct device_driver *drv = dev->driver; 90925e18499SRafael J. Wysocki int ret = 0; 91025e18499SRafael J. Wysocki 911adf09493SRafael J. Wysocki if (!drv) 91225e18499SRafael J. Wysocki return 0; 91325e18499SRafael J. Wysocki 914adf09493SRafael J. Wysocki if (drv->pm) { 915adf09493SRafael J. Wysocki if (drv->pm->restore_noirq) 916adf09493SRafael J. Wysocki ret = drv->pm->restore_noirq(dev); 91725e18499SRafael J. Wysocki } 91825e18499SRafael J. Wysocki 91925e18499SRafael J. Wysocki return ret; 92025e18499SRafael J. Wysocki } 92125e18499SRafael J. Wysocki 92269c9dd1eSRafael J. Wysocki #endif /* CONFIG_HIBERNATE_CALLBACKS */ 92325e18499SRafael J. Wysocki 924d9ab7716SDmitry Torokhov static const struct dev_pm_ops platform_dev_pm_ops = { 9258b313a38SRafael J. Wysocki .runtime_suspend = pm_generic_runtime_suspend, 9268b313a38SRafael J. Wysocki .runtime_resume = pm_generic_runtime_resume, 9278b313a38SRafael J. Wysocki .runtime_idle = pm_generic_runtime_idle, 92869c9dd1eSRafael J. Wysocki USE_PLATFORM_PM_SLEEP_OPS 92925e18499SRafael J. Wysocki }; 93025e18499SRafael J. Wysocki 9311da177e4SLinus Torvalds struct bus_type platform_bus_type = { 9321da177e4SLinus Torvalds .name = "platform", 933a0245f7aSDavid Brownell .dev_attrs = platform_dev_attrs, 9341da177e4SLinus Torvalds .match = platform_match, 935a0245f7aSDavid Brownell .uevent = platform_uevent, 9369d730229SMagnus Damm .pm = &platform_dev_pm_ops, 9371da177e4SLinus Torvalds }; 938a96b2042SDmitry Torokhov EXPORT_SYMBOL_GPL(platform_bus_type); 9391da177e4SLinus Torvalds 9401da177e4SLinus Torvalds int __init platform_bus_init(void) 9411da177e4SLinus Torvalds { 942fbfb1445SCornelia Huck int error; 943fbfb1445SCornelia Huck 94413977091SMagnus Damm early_platform_cleanup(); 94513977091SMagnus Damm 946fbfb1445SCornelia Huck error = device_register(&platform_bus); 947fbfb1445SCornelia Huck if (error) 948fbfb1445SCornelia Huck return error; 949fbfb1445SCornelia Huck error = bus_register(&platform_bus_type); 950fbfb1445SCornelia Huck if (error) 951fbfb1445SCornelia Huck device_unregister(&platform_bus); 952fbfb1445SCornelia Huck return error; 9531da177e4SLinus Torvalds } 9541da177e4SLinus Torvalds 9551da177e4SLinus Torvalds #ifndef ARCH_HAS_DMA_GET_REQUIRED_MASK 9561da177e4SLinus Torvalds u64 dma_get_required_mask(struct device *dev) 9571da177e4SLinus Torvalds { 9581da177e4SLinus Torvalds u32 low_totalram = ((max_pfn - 1) << PAGE_SHIFT); 9591da177e4SLinus Torvalds u32 high_totalram = ((max_pfn - 1) >> (32 - PAGE_SHIFT)); 9601da177e4SLinus Torvalds u64 mask; 9611da177e4SLinus Torvalds 9621da177e4SLinus Torvalds if (!high_totalram) { 9631da177e4SLinus Torvalds /* convert to mask just covering totalram */ 9641da177e4SLinus Torvalds low_totalram = (1 << (fls(low_totalram) - 1)); 9651da177e4SLinus Torvalds low_totalram += low_totalram - 1; 9661da177e4SLinus Torvalds mask = low_totalram; 9671da177e4SLinus Torvalds } else { 9681da177e4SLinus Torvalds high_totalram = (1 << (fls(high_totalram) - 1)); 9691da177e4SLinus Torvalds high_totalram += high_totalram - 1; 9701da177e4SLinus Torvalds mask = (((u64)high_totalram) << 32) + 0xffffffff; 9711da177e4SLinus Torvalds } 972e88a0c2cSJames Bottomley return mask; 9731da177e4SLinus Torvalds } 9741da177e4SLinus Torvalds EXPORT_SYMBOL_GPL(dma_get_required_mask); 9751da177e4SLinus Torvalds #endif 97613977091SMagnus Damm 97713977091SMagnus Damm static __initdata LIST_HEAD(early_platform_driver_list); 97813977091SMagnus Damm static __initdata LIST_HEAD(early_platform_device_list); 97913977091SMagnus Damm 98013977091SMagnus Damm /** 9814d26e139SMagnus Damm * early_platform_driver_register - register early platform driver 982d86c1302SRandy Dunlap * @epdrv: early_platform driver structure 98313977091SMagnus Damm * @buf: string passed from early_param() 9844d26e139SMagnus Damm * 9854d26e139SMagnus Damm * Helper function for early_platform_init() / early_platform_init_buffer() 98613977091SMagnus Damm */ 98713977091SMagnus Damm int __init early_platform_driver_register(struct early_platform_driver *epdrv, 98813977091SMagnus Damm char *buf) 98913977091SMagnus Damm { 990c60e0504SMagnus Damm char *tmp; 99113977091SMagnus Damm int n; 99213977091SMagnus Damm 99313977091SMagnus Damm /* Simply add the driver to the end of the global list. 99413977091SMagnus Damm * Drivers will by default be put on the list in compiled-in order. 99513977091SMagnus Damm */ 99613977091SMagnus Damm if (!epdrv->list.next) { 99713977091SMagnus Damm INIT_LIST_HEAD(&epdrv->list); 99813977091SMagnus Damm list_add_tail(&epdrv->list, &early_platform_driver_list); 99913977091SMagnus Damm } 100013977091SMagnus Damm 100113977091SMagnus Damm /* If the user has specified device then make sure the driver 100213977091SMagnus Damm * gets prioritized. The driver of the last device specified on 100313977091SMagnus Damm * command line will be put first on the list. 100413977091SMagnus Damm */ 100513977091SMagnus Damm n = strlen(epdrv->pdrv->driver.name); 100613977091SMagnus Damm if (buf && !strncmp(buf, epdrv->pdrv->driver.name, n)) { 100713977091SMagnus Damm list_move(&epdrv->list, &early_platform_driver_list); 100813977091SMagnus Damm 1009c60e0504SMagnus Damm /* Allow passing parameters after device name */ 1010c60e0504SMagnus Damm if (buf[n] == '\0' || buf[n] == ',') 101113977091SMagnus Damm epdrv->requested_id = -1; 1012c60e0504SMagnus Damm else { 1013c60e0504SMagnus Damm epdrv->requested_id = simple_strtoul(&buf[n + 1], 1014c60e0504SMagnus Damm &tmp, 10); 1015c60e0504SMagnus Damm 1016c60e0504SMagnus Damm if (buf[n] != '.' || (tmp == &buf[n + 1])) { 101713977091SMagnus Damm epdrv->requested_id = EARLY_PLATFORM_ID_ERROR; 1018c60e0504SMagnus Damm n = 0; 1019c60e0504SMagnus Damm } else 1020c60e0504SMagnus Damm n += strcspn(&buf[n + 1], ",") + 1; 1021c60e0504SMagnus Damm } 1022c60e0504SMagnus Damm 1023c60e0504SMagnus Damm if (buf[n] == ',') 1024c60e0504SMagnus Damm n++; 1025c60e0504SMagnus Damm 1026c60e0504SMagnus Damm if (epdrv->bufsize) { 1027c60e0504SMagnus Damm memcpy(epdrv->buffer, &buf[n], 1028c60e0504SMagnus Damm min_t(int, epdrv->bufsize, strlen(&buf[n]) + 1)); 1029c60e0504SMagnus Damm epdrv->buffer[epdrv->bufsize - 1] = '\0'; 1030c60e0504SMagnus Damm } 103113977091SMagnus Damm } 103213977091SMagnus Damm 103313977091SMagnus Damm return 0; 103413977091SMagnus Damm } 103513977091SMagnus Damm 103613977091SMagnus Damm /** 10374d26e139SMagnus Damm * early_platform_add_devices - adds a number of early platform devices 103813977091SMagnus Damm * @devs: array of early platform devices to add 103913977091SMagnus Damm * @num: number of early platform devices in array 10404d26e139SMagnus Damm * 10414d26e139SMagnus Damm * Used by early architecture code to register early platform devices and 10424d26e139SMagnus Damm * their platform data. 104313977091SMagnus Damm */ 104413977091SMagnus Damm void __init early_platform_add_devices(struct platform_device **devs, int num) 104513977091SMagnus Damm { 104613977091SMagnus Damm struct device *dev; 104713977091SMagnus Damm int i; 104813977091SMagnus Damm 104913977091SMagnus Damm /* simply add the devices to list */ 105013977091SMagnus Damm for (i = 0; i < num; i++) { 105113977091SMagnus Damm dev = &devs[i]->dev; 105213977091SMagnus Damm 105313977091SMagnus Damm if (!dev->devres_head.next) { 105413977091SMagnus Damm INIT_LIST_HEAD(&dev->devres_head); 105513977091SMagnus Damm list_add_tail(&dev->devres_head, 105613977091SMagnus Damm &early_platform_device_list); 105713977091SMagnus Damm } 105813977091SMagnus Damm } 105913977091SMagnus Damm } 106013977091SMagnus Damm 106113977091SMagnus Damm /** 10624d26e139SMagnus Damm * early_platform_driver_register_all - register early platform drivers 106313977091SMagnus Damm * @class_str: string to identify early platform driver class 10644d26e139SMagnus Damm * 10654d26e139SMagnus Damm * Used by architecture code to register all early platform drivers 10664d26e139SMagnus Damm * for a certain class. If omitted then only early platform drivers 10674d26e139SMagnus Damm * with matching kernel command line class parameters will be registered. 106813977091SMagnus Damm */ 106913977091SMagnus Damm void __init early_platform_driver_register_all(char *class_str) 107013977091SMagnus Damm { 107113977091SMagnus Damm /* The "class_str" parameter may or may not be present on the kernel 107213977091SMagnus Damm * command line. If it is present then there may be more than one 107313977091SMagnus Damm * matching parameter. 107413977091SMagnus Damm * 107513977091SMagnus Damm * Since we register our early platform drivers using early_param() 107613977091SMagnus Damm * we need to make sure that they also get registered in the case 107713977091SMagnus Damm * when the parameter is missing from the kernel command line. 107813977091SMagnus Damm * 107913977091SMagnus Damm * We use parse_early_options() to make sure the early_param() gets 108013977091SMagnus Damm * called at least once. The early_param() may be called more than 108113977091SMagnus Damm * once since the name of the preferred device may be specified on 108213977091SMagnus Damm * the kernel command line. early_platform_driver_register() handles 108313977091SMagnus Damm * this case for us. 108413977091SMagnus Damm */ 108513977091SMagnus Damm parse_early_options(class_str); 108613977091SMagnus Damm } 108713977091SMagnus Damm 108813977091SMagnus Damm /** 10894d26e139SMagnus Damm * early_platform_match - find early platform device matching driver 1090d86c1302SRandy Dunlap * @epdrv: early platform driver structure 109113977091SMagnus Damm * @id: id to match against 109213977091SMagnus Damm */ 109313977091SMagnus Damm static __init struct platform_device * 109413977091SMagnus Damm early_platform_match(struct early_platform_driver *epdrv, int id) 109513977091SMagnus Damm { 109613977091SMagnus Damm struct platform_device *pd; 109713977091SMagnus Damm 109813977091SMagnus Damm list_for_each_entry(pd, &early_platform_device_list, dev.devres_head) 109913977091SMagnus Damm if (platform_match(&pd->dev, &epdrv->pdrv->driver)) 110013977091SMagnus Damm if (pd->id == id) 110113977091SMagnus Damm return pd; 110213977091SMagnus Damm 110313977091SMagnus Damm return NULL; 110413977091SMagnus Damm } 110513977091SMagnus Damm 110613977091SMagnus Damm /** 11074d26e139SMagnus Damm * early_platform_left - check if early platform driver has matching devices 1108d86c1302SRandy Dunlap * @epdrv: early platform driver structure 110913977091SMagnus Damm * @id: return true if id or above exists 111013977091SMagnus Damm */ 111113977091SMagnus Damm static __init int early_platform_left(struct early_platform_driver *epdrv, 111213977091SMagnus Damm int id) 111313977091SMagnus Damm { 111413977091SMagnus Damm struct platform_device *pd; 111513977091SMagnus Damm 111613977091SMagnus Damm list_for_each_entry(pd, &early_platform_device_list, dev.devres_head) 111713977091SMagnus Damm if (platform_match(&pd->dev, &epdrv->pdrv->driver)) 111813977091SMagnus Damm if (pd->id >= id) 111913977091SMagnus Damm return 1; 112013977091SMagnus Damm 112113977091SMagnus Damm return 0; 112213977091SMagnus Damm } 112313977091SMagnus Damm 112413977091SMagnus Damm /** 11254d26e139SMagnus Damm * early_platform_driver_probe_id - probe drivers matching class_str and id 112613977091SMagnus Damm * @class_str: string to identify early platform driver class 112713977091SMagnus Damm * @id: id to match against 112813977091SMagnus Damm * @nr_probe: number of platform devices to successfully probe before exiting 112913977091SMagnus Damm */ 113013977091SMagnus Damm static int __init early_platform_driver_probe_id(char *class_str, 113113977091SMagnus Damm int id, 113213977091SMagnus Damm int nr_probe) 113313977091SMagnus Damm { 113413977091SMagnus Damm struct early_platform_driver *epdrv; 113513977091SMagnus Damm struct platform_device *match; 113613977091SMagnus Damm int match_id; 113713977091SMagnus Damm int n = 0; 113813977091SMagnus Damm int left = 0; 113913977091SMagnus Damm 114013977091SMagnus Damm list_for_each_entry(epdrv, &early_platform_driver_list, list) { 114113977091SMagnus Damm /* only use drivers matching our class_str */ 114213977091SMagnus Damm if (strcmp(class_str, epdrv->class_str)) 114313977091SMagnus Damm continue; 114413977091SMagnus Damm 114513977091SMagnus Damm if (id == -2) { 114613977091SMagnus Damm match_id = epdrv->requested_id; 114713977091SMagnus Damm left = 1; 114813977091SMagnus Damm 114913977091SMagnus Damm } else { 115013977091SMagnus Damm match_id = id; 115113977091SMagnus Damm left += early_platform_left(epdrv, id); 115213977091SMagnus Damm 115313977091SMagnus Damm /* skip requested id */ 115413977091SMagnus Damm switch (epdrv->requested_id) { 115513977091SMagnus Damm case EARLY_PLATFORM_ID_ERROR: 115613977091SMagnus Damm case EARLY_PLATFORM_ID_UNSET: 115713977091SMagnus Damm break; 115813977091SMagnus Damm default: 115913977091SMagnus Damm if (epdrv->requested_id == id) 116013977091SMagnus Damm match_id = EARLY_PLATFORM_ID_UNSET; 116113977091SMagnus Damm } 116213977091SMagnus Damm } 116313977091SMagnus Damm 116413977091SMagnus Damm switch (match_id) { 116513977091SMagnus Damm case EARLY_PLATFORM_ID_ERROR: 116613977091SMagnus Damm pr_warning("%s: unable to parse %s parameter\n", 116713977091SMagnus Damm class_str, epdrv->pdrv->driver.name); 116813977091SMagnus Damm /* fall-through */ 116913977091SMagnus Damm case EARLY_PLATFORM_ID_UNSET: 117013977091SMagnus Damm match = NULL; 117113977091SMagnus Damm break; 117213977091SMagnus Damm default: 117313977091SMagnus Damm match = early_platform_match(epdrv, match_id); 117413977091SMagnus Damm } 117513977091SMagnus Damm 117613977091SMagnus Damm if (match) { 1177a636ee7fSPaul Mundt /* 1178a636ee7fSPaul Mundt * Set up a sensible init_name to enable 1179a636ee7fSPaul Mundt * dev_name() and others to be used before the 1180a636ee7fSPaul Mundt * rest of the driver core is initialized. 1181a636ee7fSPaul Mundt */ 118206fe53beSPaul Mundt if (!match->dev.init_name && slab_is_available()) { 1183a636ee7fSPaul Mundt if (match->id != -1) 1184bd05086bSPaul Mundt match->dev.init_name = 1185bd05086bSPaul Mundt kasprintf(GFP_KERNEL, "%s.%d", 1186bd05086bSPaul Mundt match->name, 1187bd05086bSPaul Mundt match->id); 1188a636ee7fSPaul Mundt else 1189bd05086bSPaul Mundt match->dev.init_name = 1190bd05086bSPaul Mundt kasprintf(GFP_KERNEL, "%s", 1191a636ee7fSPaul Mundt match->name); 1192a636ee7fSPaul Mundt 1193a636ee7fSPaul Mundt if (!match->dev.init_name) 1194a636ee7fSPaul Mundt return -ENOMEM; 1195a636ee7fSPaul Mundt } 1196bd05086bSPaul Mundt 119713977091SMagnus Damm if (epdrv->pdrv->probe(match)) 119813977091SMagnus Damm pr_warning("%s: unable to probe %s early.\n", 119913977091SMagnus Damm class_str, match->name); 120013977091SMagnus Damm else 120113977091SMagnus Damm n++; 120213977091SMagnus Damm } 120313977091SMagnus Damm 120413977091SMagnus Damm if (n >= nr_probe) 120513977091SMagnus Damm break; 120613977091SMagnus Damm } 120713977091SMagnus Damm 120813977091SMagnus Damm if (left) 120913977091SMagnus Damm return n; 121013977091SMagnus Damm else 121113977091SMagnus Damm return -ENODEV; 121213977091SMagnus Damm } 121313977091SMagnus Damm 121413977091SMagnus Damm /** 12154d26e139SMagnus Damm * early_platform_driver_probe - probe a class of registered drivers 121613977091SMagnus Damm * @class_str: string to identify early platform driver class 121713977091SMagnus Damm * @nr_probe: number of platform devices to successfully probe before exiting 121813977091SMagnus Damm * @user_only: only probe user specified early platform devices 12194d26e139SMagnus Damm * 12204d26e139SMagnus Damm * Used by architecture code to probe registered early platform drivers 12214d26e139SMagnus Damm * within a certain class. For probe to happen a registered early platform 12224d26e139SMagnus Damm * device matching a registered early platform driver is needed. 122313977091SMagnus Damm */ 122413977091SMagnus Damm int __init early_platform_driver_probe(char *class_str, 122513977091SMagnus Damm int nr_probe, 122613977091SMagnus Damm int user_only) 122713977091SMagnus Damm { 122813977091SMagnus Damm int k, n, i; 122913977091SMagnus Damm 123013977091SMagnus Damm n = 0; 123113977091SMagnus Damm for (i = -2; n < nr_probe; i++) { 123213977091SMagnus Damm k = early_platform_driver_probe_id(class_str, i, nr_probe - n); 123313977091SMagnus Damm 123413977091SMagnus Damm if (k < 0) 123513977091SMagnus Damm break; 123613977091SMagnus Damm 123713977091SMagnus Damm n += k; 123813977091SMagnus Damm 123913977091SMagnus Damm if (user_only) 124013977091SMagnus Damm break; 124113977091SMagnus Damm } 124213977091SMagnus Damm 124313977091SMagnus Damm return n; 124413977091SMagnus Damm } 124513977091SMagnus Damm 124613977091SMagnus Damm /** 124713977091SMagnus Damm * early_platform_cleanup - clean up early platform code 124813977091SMagnus Damm */ 124913977091SMagnus Damm void __init early_platform_cleanup(void) 125013977091SMagnus Damm { 125113977091SMagnus Damm struct platform_device *pd, *pd2; 125213977091SMagnus Damm 125313977091SMagnus Damm /* clean up the devres list used to chain devices */ 125413977091SMagnus Damm list_for_each_entry_safe(pd, pd2, &early_platform_device_list, 125513977091SMagnus Damm dev.devres_head) { 125613977091SMagnus Damm list_del(&pd->dev.devres_head); 125713977091SMagnus Damm memset(&pd->dev.devres_head, 0, sizeof(pd->dev.devres_head)); 125813977091SMagnus Damm } 125913977091SMagnus Damm } 126013977091SMagnus Damm 1261