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> 151da177e4SLinus Torvalds #include <linux/module.h> 161da177e4SLinus Torvalds #include <linux/init.h> 171da177e4SLinus Torvalds #include <linux/dma-mapping.h> 181da177e4SLinus Torvalds #include <linux/bootmem.h> 191da177e4SLinus Torvalds #include <linux/err.h> 204e57b681STim Schmielau #include <linux/slab.h> 219d730229SMagnus Damm #include <linux/pm_runtime.h> 221da177e4SLinus Torvalds 23a1bdc7aaSBen Dooks #include "base.h" 24a1bdc7aaSBen Dooks 254a3ad20cSGreg Kroah-Hartman #define to_platform_driver(drv) (container_of((drv), struct platform_driver, \ 264a3ad20cSGreg Kroah-Hartman driver)) 2700d3dcddSRussell King 281da177e4SLinus Torvalds struct device platform_bus = { 291e0b2cf9SKay Sievers .init_name = "platform", 301da177e4SLinus Torvalds }; 31a96b2042SDmitry Torokhov EXPORT_SYMBOL_GPL(platform_bus); 321da177e4SLinus Torvalds 331da177e4SLinus Torvalds /** 341da177e4SLinus Torvalds * platform_get_resource - get a resource for a device 351da177e4SLinus Torvalds * @dev: platform device 361da177e4SLinus Torvalds * @type: resource type 371da177e4SLinus Torvalds * @num: resource index 381da177e4SLinus Torvalds */ 394a3ad20cSGreg Kroah-Hartman struct resource *platform_get_resource(struct platform_device *dev, 404a3ad20cSGreg Kroah-Hartman unsigned int type, unsigned int num) 411da177e4SLinus Torvalds { 421da177e4SLinus Torvalds int i; 431da177e4SLinus Torvalds 441da177e4SLinus Torvalds for (i = 0; i < dev->num_resources; i++) { 451da177e4SLinus Torvalds struct resource *r = &dev->resource[i]; 461da177e4SLinus Torvalds 47c9f66169SMagnus Damm if (type == resource_type(r) && num-- == 0) 481da177e4SLinus Torvalds return r; 491da177e4SLinus Torvalds } 501da177e4SLinus Torvalds return NULL; 511da177e4SLinus Torvalds } 52a96b2042SDmitry Torokhov EXPORT_SYMBOL_GPL(platform_get_resource); 531da177e4SLinus Torvalds 541da177e4SLinus Torvalds /** 551da177e4SLinus Torvalds * platform_get_irq - get an IRQ for a device 561da177e4SLinus Torvalds * @dev: platform device 571da177e4SLinus Torvalds * @num: IRQ number index 581da177e4SLinus Torvalds */ 591da177e4SLinus Torvalds int platform_get_irq(struct platform_device *dev, unsigned int num) 601da177e4SLinus Torvalds { 611da177e4SLinus Torvalds struct resource *r = platform_get_resource(dev, IORESOURCE_IRQ, num); 621da177e4SLinus Torvalds 63305b3228SDavid Vrabel return r ? r->start : -ENXIO; 641da177e4SLinus Torvalds } 65a96b2042SDmitry Torokhov EXPORT_SYMBOL_GPL(platform_get_irq); 661da177e4SLinus Torvalds 671da177e4SLinus Torvalds /** 681da177e4SLinus Torvalds * platform_get_resource_byname - get a resource for a device by name 691da177e4SLinus Torvalds * @dev: platform device 701da177e4SLinus Torvalds * @type: resource type 711da177e4SLinus Torvalds * @name: resource name 721da177e4SLinus Torvalds */ 734a3ad20cSGreg Kroah-Hartman struct resource *platform_get_resource_byname(struct platform_device *dev, 74c0afe7baSLinus Walleij unsigned int type, 75c0afe7baSLinus Walleij const char *name) 761da177e4SLinus Torvalds { 771da177e4SLinus Torvalds int i; 781da177e4SLinus Torvalds 791da177e4SLinus Torvalds for (i = 0; i < dev->num_resources; i++) { 801da177e4SLinus Torvalds struct resource *r = &dev->resource[i]; 811da177e4SLinus Torvalds 82c9f66169SMagnus Damm if (type == resource_type(r) && !strcmp(r->name, name)) 831da177e4SLinus Torvalds return r; 841da177e4SLinus Torvalds } 851da177e4SLinus Torvalds return NULL; 861da177e4SLinus Torvalds } 87a96b2042SDmitry Torokhov EXPORT_SYMBOL_GPL(platform_get_resource_byname); 881da177e4SLinus Torvalds 891da177e4SLinus Torvalds /** 901da177e4SLinus Torvalds * platform_get_irq - get an IRQ for a device 911da177e4SLinus Torvalds * @dev: platform device 921da177e4SLinus Torvalds * @name: IRQ name 931da177e4SLinus Torvalds */ 94c0afe7baSLinus Walleij int platform_get_irq_byname(struct platform_device *dev, const char *name) 951da177e4SLinus Torvalds { 964a3ad20cSGreg Kroah-Hartman struct resource *r = platform_get_resource_byname(dev, IORESOURCE_IRQ, 974a3ad20cSGreg Kroah-Hartman name); 981da177e4SLinus Torvalds 99305b3228SDavid Vrabel return r ? r->start : -ENXIO; 1001da177e4SLinus Torvalds } 101a96b2042SDmitry Torokhov EXPORT_SYMBOL_GPL(platform_get_irq_byname); 1021da177e4SLinus Torvalds 1031da177e4SLinus Torvalds /** 1041da177e4SLinus Torvalds * platform_add_devices - add a numbers of platform devices 1051da177e4SLinus Torvalds * @devs: array of platform devices to add 1061da177e4SLinus Torvalds * @num: number of platform devices in array 1071da177e4SLinus Torvalds */ 1081da177e4SLinus Torvalds int platform_add_devices(struct platform_device **devs, int num) 1091da177e4SLinus Torvalds { 1101da177e4SLinus Torvalds int i, ret = 0; 1111da177e4SLinus Torvalds 1121da177e4SLinus Torvalds for (i = 0; i < num; i++) { 1131da177e4SLinus Torvalds ret = platform_device_register(devs[i]); 1141da177e4SLinus Torvalds if (ret) { 1151da177e4SLinus Torvalds while (--i >= 0) 1161da177e4SLinus Torvalds platform_device_unregister(devs[i]); 1171da177e4SLinus Torvalds break; 1181da177e4SLinus Torvalds } 1191da177e4SLinus Torvalds } 1201da177e4SLinus Torvalds 1211da177e4SLinus Torvalds return ret; 1221da177e4SLinus Torvalds } 123a96b2042SDmitry Torokhov EXPORT_SYMBOL_GPL(platform_add_devices); 1241da177e4SLinus Torvalds 12537c12e74SRussell King struct platform_object { 12637c12e74SRussell King struct platform_device pdev; 12737c12e74SRussell King char name[1]; 12837c12e74SRussell King }; 12937c12e74SRussell King 1301da177e4SLinus Torvalds /** 1313c31f07aSBen Hutchings * platform_device_put - destroy a platform device 13237c12e74SRussell King * @pdev: platform device to free 13337c12e74SRussell King * 1344a3ad20cSGreg Kroah-Hartman * Free all memory associated with a platform device. This function must 1354a3ad20cSGreg Kroah-Hartman * _only_ be externally called in error cases. All other usage is a bug. 13637c12e74SRussell King */ 13737c12e74SRussell King void platform_device_put(struct platform_device *pdev) 13837c12e74SRussell King { 13937c12e74SRussell King if (pdev) 14037c12e74SRussell King put_device(&pdev->dev); 14137c12e74SRussell King } 14237c12e74SRussell King EXPORT_SYMBOL_GPL(platform_device_put); 14337c12e74SRussell King 14437c12e74SRussell King static void platform_device_release(struct device *dev) 14537c12e74SRussell King { 1464a3ad20cSGreg Kroah-Hartman struct platform_object *pa = container_of(dev, struct platform_object, 1474a3ad20cSGreg Kroah-Hartman pdev.dev); 14837c12e74SRussell King 14937c12e74SRussell King kfree(pa->pdev.dev.platform_data); 15037c12e74SRussell King kfree(pa->pdev.resource); 15137c12e74SRussell King kfree(pa); 15237c12e74SRussell King } 15337c12e74SRussell King 15437c12e74SRussell King /** 1553c31f07aSBen Hutchings * platform_device_alloc - create a platform device 15637c12e74SRussell King * @name: base name of the device we're adding 15737c12e74SRussell King * @id: instance id 15837c12e74SRussell King * 15937c12e74SRussell King * Create a platform device object which can have other objects attached 16037c12e74SRussell King * to it, and which will have attached objects freed when it is released. 16137c12e74SRussell King */ 1621359555eSJean Delvare struct platform_device *platform_device_alloc(const char *name, int id) 16337c12e74SRussell King { 16437c12e74SRussell King struct platform_object *pa; 16537c12e74SRussell King 16637c12e74SRussell King pa = kzalloc(sizeof(struct platform_object) + strlen(name), GFP_KERNEL); 16737c12e74SRussell King if (pa) { 16837c12e74SRussell King strcpy(pa->name, name); 16937c12e74SRussell King pa->pdev.name = pa->name; 17037c12e74SRussell King pa->pdev.id = id; 17137c12e74SRussell King device_initialize(&pa->pdev.dev); 17237c12e74SRussell King pa->pdev.dev.release = platform_device_release; 17337c12e74SRussell King } 17437c12e74SRussell King 17537c12e74SRussell King return pa ? &pa->pdev : NULL; 17637c12e74SRussell King } 17737c12e74SRussell King EXPORT_SYMBOL_GPL(platform_device_alloc); 17837c12e74SRussell King 17937c12e74SRussell King /** 1803c31f07aSBen Hutchings * platform_device_add_resources - add resources to a platform device 18137c12e74SRussell King * @pdev: platform device allocated by platform_device_alloc to add resources to 18237c12e74SRussell King * @res: set of resources that needs to be allocated for the device 18337c12e74SRussell King * @num: number of resources 18437c12e74SRussell King * 18537c12e74SRussell King * Add a copy of the resources to the platform device. The memory 1864a3ad20cSGreg Kroah-Hartman * associated with the resources will be freed when the platform device is 1874a3ad20cSGreg Kroah-Hartman * released. 18837c12e74SRussell King */ 1894a3ad20cSGreg Kroah-Hartman int platform_device_add_resources(struct platform_device *pdev, 1904a3ad20cSGreg Kroah-Hartman struct resource *res, unsigned int num) 19137c12e74SRussell King { 19237c12e74SRussell King struct resource *r; 19337c12e74SRussell King 19437c12e74SRussell King r = kmalloc(sizeof(struct resource) * num, GFP_KERNEL); 19537c12e74SRussell King if (r) { 19637c12e74SRussell King memcpy(r, res, sizeof(struct resource) * num); 19737c12e74SRussell King pdev->resource = r; 19837c12e74SRussell King pdev->num_resources = num; 19937c12e74SRussell King } 20037c12e74SRussell King return r ? 0 : -ENOMEM; 20137c12e74SRussell King } 20237c12e74SRussell King EXPORT_SYMBOL_GPL(platform_device_add_resources); 20337c12e74SRussell King 20437c12e74SRussell King /** 2053c31f07aSBen Hutchings * platform_device_add_data - add platform-specific data to a platform device 20637c12e74SRussell King * @pdev: platform device allocated by platform_device_alloc to add resources to 20737c12e74SRussell King * @data: platform specific data for this platform device 20837c12e74SRussell King * @size: size of platform specific data 20937c12e74SRussell King * 2104a3ad20cSGreg Kroah-Hartman * Add a copy of platform specific data to the platform device's 2114a3ad20cSGreg Kroah-Hartman * platform_data pointer. The memory associated with the platform data 2124a3ad20cSGreg Kroah-Hartman * will be freed when the platform device is released. 21337c12e74SRussell King */ 2144a3ad20cSGreg Kroah-Hartman int platform_device_add_data(struct platform_device *pdev, const void *data, 2154a3ad20cSGreg Kroah-Hartman size_t size) 21637c12e74SRussell King { 217daa41226SAndrew Morton void *d = kmemdup(data, size, GFP_KERNEL); 21837c12e74SRussell King 21937c12e74SRussell King if (d) { 22037c12e74SRussell King pdev->dev.platform_data = d; 221daa41226SAndrew Morton return 0; 22237c12e74SRussell King } 223daa41226SAndrew Morton return -ENOMEM; 22437c12e74SRussell King } 22537c12e74SRussell King EXPORT_SYMBOL_GPL(platform_device_add_data); 22637c12e74SRussell King 22737c12e74SRussell King /** 22837c12e74SRussell King * platform_device_add - add a platform device to device hierarchy 22967be2dd1SMartin Waitz * @pdev: platform device we're adding 2301da177e4SLinus Torvalds * 23137c12e74SRussell King * This is part 2 of platform_device_register(), though may be called 23237c12e74SRussell King * separately _iff_ pdev was allocated by platform_device_alloc(). 2331da177e4SLinus Torvalds */ 23437c12e74SRussell King int platform_device_add(struct platform_device *pdev) 2351da177e4SLinus Torvalds { 2361da177e4SLinus Torvalds int i, ret = 0; 2371da177e4SLinus Torvalds 2381da177e4SLinus Torvalds if (!pdev) 2391da177e4SLinus Torvalds return -EINVAL; 2401da177e4SLinus Torvalds 2411da177e4SLinus Torvalds if (!pdev->dev.parent) 2421da177e4SLinus Torvalds pdev->dev.parent = &platform_bus; 2431da177e4SLinus Torvalds 2441da177e4SLinus Torvalds pdev->dev.bus = &platform_bus_type; 2451da177e4SLinus Torvalds 2461da177e4SLinus Torvalds if (pdev->id != -1) 2471e0b2cf9SKay Sievers dev_set_name(&pdev->dev, "%s.%d", pdev->name, pdev->id); 2481da177e4SLinus Torvalds else 249acc0e90fSGreg Kroah-Hartman dev_set_name(&pdev->dev, "%s", pdev->name); 2501da177e4SLinus Torvalds 2511da177e4SLinus Torvalds for (i = 0; i < pdev->num_resources; i++) { 2521da177e4SLinus Torvalds struct resource *p, *r = &pdev->resource[i]; 2531da177e4SLinus Torvalds 2541da177e4SLinus Torvalds if (r->name == NULL) 2551e0b2cf9SKay Sievers r->name = dev_name(&pdev->dev); 2561da177e4SLinus Torvalds 2571da177e4SLinus Torvalds p = r->parent; 2581da177e4SLinus Torvalds if (!p) { 259c9f66169SMagnus Damm if (resource_type(r) == IORESOURCE_MEM) 2601da177e4SLinus Torvalds p = &iomem_resource; 261c9f66169SMagnus Damm else if (resource_type(r) == IORESOURCE_IO) 2621da177e4SLinus Torvalds p = &ioport_resource; 2631da177e4SLinus Torvalds } 2641da177e4SLinus Torvalds 265d960bb4dSKumar Gala if (p && insert_resource(p, r)) { 2661da177e4SLinus Torvalds printk(KERN_ERR 2671da177e4SLinus Torvalds "%s: failed to claim resource %d\n", 2681e0b2cf9SKay Sievers dev_name(&pdev->dev), i); 2691da177e4SLinus Torvalds ret = -EBUSY; 2701da177e4SLinus Torvalds goto failed; 2711da177e4SLinus Torvalds } 2721da177e4SLinus Torvalds } 2731da177e4SLinus Torvalds 2741da177e4SLinus Torvalds pr_debug("Registering platform device '%s'. Parent at %s\n", 2751e0b2cf9SKay Sievers dev_name(&pdev->dev), dev_name(pdev->dev.parent)); 2761da177e4SLinus Torvalds 277e3915532SRussell King ret = device_add(&pdev->dev); 2781da177e4SLinus Torvalds if (ret == 0) 2791da177e4SLinus Torvalds return ret; 2801da177e4SLinus Torvalds 2811da177e4SLinus Torvalds failed: 282c9f66169SMagnus Damm while (--i >= 0) { 283c9f66169SMagnus Damm struct resource *r = &pdev->resource[i]; 284c9f66169SMagnus Damm unsigned long type = resource_type(r); 285c9f66169SMagnus Damm 286c9f66169SMagnus Damm if (type == IORESOURCE_MEM || type == IORESOURCE_IO) 287c9f66169SMagnus Damm release_resource(r); 288c9f66169SMagnus Damm } 289c9f66169SMagnus Damm 2901da177e4SLinus Torvalds return ret; 2911da177e4SLinus Torvalds } 29237c12e74SRussell King EXPORT_SYMBOL_GPL(platform_device_add); 29337c12e74SRussell King 29437c12e74SRussell King /** 29593ce3061SDmitry Torokhov * platform_device_del - remove a platform-level device 29693ce3061SDmitry Torokhov * @pdev: platform device we're removing 29793ce3061SDmitry Torokhov * 29893ce3061SDmitry Torokhov * Note that this function will also release all memory- and port-based 2994a3ad20cSGreg Kroah-Hartman * resources owned by the device (@dev->resource). This function must 3004a3ad20cSGreg Kroah-Hartman * _only_ be externally called in error cases. All other usage is a bug. 30193ce3061SDmitry Torokhov */ 30293ce3061SDmitry Torokhov void platform_device_del(struct platform_device *pdev) 30393ce3061SDmitry Torokhov { 30493ce3061SDmitry Torokhov int i; 30593ce3061SDmitry Torokhov 30693ce3061SDmitry Torokhov if (pdev) { 307dc4c15d4SJean Delvare device_del(&pdev->dev); 308dc4c15d4SJean Delvare 30993ce3061SDmitry Torokhov for (i = 0; i < pdev->num_resources; i++) { 31093ce3061SDmitry Torokhov struct resource *r = &pdev->resource[i]; 311c9f66169SMagnus Damm unsigned long type = resource_type(r); 312c9f66169SMagnus Damm 313c9f66169SMagnus Damm if (type == IORESOURCE_MEM || type == IORESOURCE_IO) 31493ce3061SDmitry Torokhov release_resource(r); 31593ce3061SDmitry Torokhov } 31693ce3061SDmitry Torokhov } 31793ce3061SDmitry Torokhov } 31893ce3061SDmitry Torokhov EXPORT_SYMBOL_GPL(platform_device_del); 31993ce3061SDmitry Torokhov 32093ce3061SDmitry Torokhov /** 32137c12e74SRussell King * platform_device_register - add a platform-level device 32237c12e74SRussell King * @pdev: platform device we're adding 32337c12e74SRussell King */ 32437c12e74SRussell King int platform_device_register(struct platform_device *pdev) 32537c12e74SRussell King { 32637c12e74SRussell King device_initialize(&pdev->dev); 32737c12e74SRussell King return platform_device_add(pdev); 32837c12e74SRussell King } 329a96b2042SDmitry Torokhov EXPORT_SYMBOL_GPL(platform_device_register); 3301da177e4SLinus Torvalds 3311da177e4SLinus Torvalds /** 33293ce3061SDmitry Torokhov * platform_device_unregister - unregister a platform-level device 33393ce3061SDmitry Torokhov * @pdev: platform device we're unregistering 3341da177e4SLinus Torvalds * 33580682fa9SUwe Zeisberger * Unregistration is done in 2 steps. First we release all resources 3362d7b5a70SJean Delvare * and remove it from the subsystem, then we drop reference count by 33793ce3061SDmitry Torokhov * calling platform_device_put(). 3381da177e4SLinus Torvalds */ 3391da177e4SLinus Torvalds void platform_device_unregister(struct platform_device *pdev) 3401da177e4SLinus Torvalds { 34193ce3061SDmitry Torokhov platform_device_del(pdev); 34293ce3061SDmitry Torokhov platform_device_put(pdev); 3431da177e4SLinus Torvalds } 344a96b2042SDmitry Torokhov EXPORT_SYMBOL_GPL(platform_device_unregister); 3451da177e4SLinus Torvalds 3461da177e4SLinus Torvalds /** 3473c31f07aSBen Hutchings * platform_device_register_simple - add a platform-level device and its resources 3481da177e4SLinus Torvalds * @name: base name of the device we're adding 3491da177e4SLinus Torvalds * @id: instance id 3501da177e4SLinus Torvalds * @res: set of resources that needs to be allocated for the device 3511da177e4SLinus Torvalds * @num: number of resources 3521da177e4SLinus Torvalds * 3531da177e4SLinus Torvalds * This function creates a simple platform device that requires minimal 3544a3ad20cSGreg Kroah-Hartman * resource and memory management. Canned release function freeing memory 3554a3ad20cSGreg Kroah-Hartman * allocated for the device allows drivers using such devices to be 3564a3ad20cSGreg Kroah-Hartman * unloaded without waiting for the last reference to the device to be 3574a3ad20cSGreg Kroah-Hartman * dropped. 35849a4ec18SDavid Brownell * 3594a3ad20cSGreg Kroah-Hartman * This interface is primarily intended for use with legacy drivers which 3604a3ad20cSGreg Kroah-Hartman * probe hardware directly. Because such drivers create sysfs device nodes 3614a3ad20cSGreg Kroah-Hartman * themselves, rather than letting system infrastructure handle such device 3624a3ad20cSGreg Kroah-Hartman * enumeration tasks, they don't fully conform to the Linux driver model. 3634a3ad20cSGreg Kroah-Hartman * In particular, when such drivers are built as modules, they can't be 3644a3ad20cSGreg Kroah-Hartman * "hotplugged". 3651da177e4SLinus Torvalds */ 3664a3ad20cSGreg Kroah-Hartman struct platform_device *platform_device_register_simple(const char *name, 3674a3ad20cSGreg Kroah-Hartman int id, 3684a3ad20cSGreg Kroah-Hartman struct resource *res, 3694a3ad20cSGreg Kroah-Hartman unsigned int num) 3701da177e4SLinus Torvalds { 37137c12e74SRussell King struct platform_device *pdev; 3721da177e4SLinus Torvalds int retval; 3731da177e4SLinus Torvalds 37437c12e74SRussell King pdev = platform_device_alloc(name, id); 37537c12e74SRussell King if (!pdev) { 3761da177e4SLinus Torvalds retval = -ENOMEM; 3771da177e4SLinus Torvalds goto error; 3781da177e4SLinus Torvalds } 3791da177e4SLinus Torvalds 3801da177e4SLinus Torvalds if (num) { 38137c12e74SRussell King retval = platform_device_add_resources(pdev, res, num); 38237c12e74SRussell King if (retval) 38337c12e74SRussell King goto error; 3841da177e4SLinus Torvalds } 3851da177e4SLinus Torvalds 38637c12e74SRussell King retval = platform_device_add(pdev); 3871da177e4SLinus Torvalds if (retval) 3881da177e4SLinus Torvalds goto error; 3891da177e4SLinus Torvalds 39037c12e74SRussell King return pdev; 3911da177e4SLinus Torvalds 3921da177e4SLinus Torvalds error: 39337c12e74SRussell King platform_device_put(pdev); 3941da177e4SLinus Torvalds return ERR_PTR(retval); 3951da177e4SLinus Torvalds } 396a96b2042SDmitry Torokhov EXPORT_SYMBOL_GPL(platform_device_register_simple); 3971da177e4SLinus Torvalds 398d8bf2540SDmitry Baryshkov /** 3993c31f07aSBen Hutchings * platform_device_register_data - add a platform-level device with platform-specific data 400d8bf2540SDmitry Baryshkov * @parent: parent device for the device we're adding 401d8bf2540SDmitry Baryshkov * @name: base name of the device we're adding 402d8bf2540SDmitry Baryshkov * @id: instance id 403d8bf2540SDmitry Baryshkov * @data: platform specific data for this platform device 404d8bf2540SDmitry Baryshkov * @size: size of platform specific data 405d8bf2540SDmitry Baryshkov * 406d8bf2540SDmitry Baryshkov * This function creates a simple platform device that requires minimal 407d8bf2540SDmitry Baryshkov * resource and memory management. Canned release function freeing memory 408d8bf2540SDmitry Baryshkov * allocated for the device allows drivers using such devices to be 409d8bf2540SDmitry Baryshkov * unloaded without waiting for the last reference to the device to be 410d8bf2540SDmitry Baryshkov * dropped. 411d8bf2540SDmitry Baryshkov */ 412d8bf2540SDmitry Baryshkov struct platform_device *platform_device_register_data( 413d8bf2540SDmitry Baryshkov struct device *parent, 414d8bf2540SDmitry Baryshkov const char *name, int id, 415d8bf2540SDmitry Baryshkov const void *data, size_t size) 416d8bf2540SDmitry Baryshkov { 417d8bf2540SDmitry Baryshkov struct platform_device *pdev; 418d8bf2540SDmitry Baryshkov int retval; 419d8bf2540SDmitry Baryshkov 420d8bf2540SDmitry Baryshkov pdev = platform_device_alloc(name, id); 421d8bf2540SDmitry Baryshkov if (!pdev) { 422d8bf2540SDmitry Baryshkov retval = -ENOMEM; 423d8bf2540SDmitry Baryshkov goto error; 424d8bf2540SDmitry Baryshkov } 425d8bf2540SDmitry Baryshkov 426d8bf2540SDmitry Baryshkov pdev->dev.parent = parent; 427d8bf2540SDmitry Baryshkov 428d8bf2540SDmitry Baryshkov if (size) { 429d8bf2540SDmitry Baryshkov retval = platform_device_add_data(pdev, data, size); 430d8bf2540SDmitry Baryshkov if (retval) 431d8bf2540SDmitry Baryshkov goto error; 432d8bf2540SDmitry Baryshkov } 433d8bf2540SDmitry Baryshkov 434d8bf2540SDmitry Baryshkov retval = platform_device_add(pdev); 435d8bf2540SDmitry Baryshkov if (retval) 436d8bf2540SDmitry Baryshkov goto error; 437d8bf2540SDmitry Baryshkov 438d8bf2540SDmitry Baryshkov return pdev; 439d8bf2540SDmitry Baryshkov 440d8bf2540SDmitry Baryshkov error: 441d8bf2540SDmitry Baryshkov platform_device_put(pdev); 442d8bf2540SDmitry Baryshkov return ERR_PTR(retval); 443d8bf2540SDmitry Baryshkov } 4440787fdf7SMichael Hennerich EXPORT_SYMBOL_GPL(platform_device_register_data); 445d8bf2540SDmitry Baryshkov 44600d3dcddSRussell King static int platform_drv_probe(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 return drv->probe(dev); 45200d3dcddSRussell King } 45300d3dcddSRussell King 454c67334fbSDavid Brownell static int platform_drv_probe_fail(struct device *_dev) 455c67334fbSDavid Brownell { 456c67334fbSDavid Brownell return -ENXIO; 457c67334fbSDavid Brownell } 458c67334fbSDavid Brownell 45900d3dcddSRussell King static int platform_drv_remove(struct device *_dev) 46000d3dcddSRussell King { 46100d3dcddSRussell King struct platform_driver *drv = to_platform_driver(_dev->driver); 46200d3dcddSRussell King struct platform_device *dev = to_platform_device(_dev); 46300d3dcddSRussell King 46400d3dcddSRussell King return drv->remove(dev); 46500d3dcddSRussell King } 46600d3dcddSRussell King 46700d3dcddSRussell King static void platform_drv_shutdown(struct device *_dev) 46800d3dcddSRussell King { 46900d3dcddSRussell King struct platform_driver *drv = to_platform_driver(_dev->driver); 47000d3dcddSRussell King struct platform_device *dev = to_platform_device(_dev); 47100d3dcddSRussell King 47200d3dcddSRussell King drv->shutdown(dev); 47300d3dcddSRussell King } 47400d3dcddSRussell King 47500d3dcddSRussell King /** 4763c31f07aSBen Hutchings * platform_driver_register - register a driver for platform-level devices 47700d3dcddSRussell King * @drv: platform driver structure 47800d3dcddSRussell King */ 47900d3dcddSRussell King int platform_driver_register(struct platform_driver *drv) 48000d3dcddSRussell King { 48100d3dcddSRussell King drv->driver.bus = &platform_bus_type; 48200d3dcddSRussell King if (drv->probe) 48300d3dcddSRussell King drv->driver.probe = platform_drv_probe; 48400d3dcddSRussell King if (drv->remove) 48500d3dcddSRussell King drv->driver.remove = platform_drv_remove; 48600d3dcddSRussell King if (drv->shutdown) 48700d3dcddSRussell King drv->driver.shutdown = platform_drv_shutdown; 488783ea7d4SMagnus Damm 48900d3dcddSRussell King return driver_register(&drv->driver); 49000d3dcddSRussell King } 49100d3dcddSRussell King EXPORT_SYMBOL_GPL(platform_driver_register); 49200d3dcddSRussell King 49300d3dcddSRussell King /** 4943c31f07aSBen Hutchings * platform_driver_unregister - unregister a driver for platform-level devices 49500d3dcddSRussell King * @drv: platform driver structure 49600d3dcddSRussell King */ 49700d3dcddSRussell King void platform_driver_unregister(struct platform_driver *drv) 49800d3dcddSRussell King { 49900d3dcddSRussell King driver_unregister(&drv->driver); 50000d3dcddSRussell King } 50100d3dcddSRussell King EXPORT_SYMBOL_GPL(platform_driver_unregister); 50200d3dcddSRussell King 503c67334fbSDavid Brownell /** 504c67334fbSDavid Brownell * platform_driver_probe - register driver for non-hotpluggable device 505c67334fbSDavid Brownell * @drv: platform driver structure 506c67334fbSDavid Brownell * @probe: the driver probe routine, probably from an __init section 507c67334fbSDavid Brownell * 508c67334fbSDavid Brownell * Use this instead of platform_driver_register() when you know the device 509c67334fbSDavid Brownell * is not hotpluggable and has already been registered, and you want to 510c67334fbSDavid Brownell * remove its run-once probe() infrastructure from memory after the driver 511c67334fbSDavid Brownell * has bound to the device. 512c67334fbSDavid Brownell * 513c67334fbSDavid Brownell * One typical use for this would be with drivers for controllers integrated 514c67334fbSDavid Brownell * into system-on-chip processors, where the controller devices have been 515c67334fbSDavid Brownell * configured as part of board setup. 516c67334fbSDavid Brownell * 517c67334fbSDavid Brownell * Returns zero if the driver registered and bound to a device, else returns 518c67334fbSDavid Brownell * a negative error code and with the driver not registered. 519c67334fbSDavid Brownell */ 520c63e0783SAndrew Morton int __init_or_module platform_driver_probe(struct platform_driver *drv, 521c67334fbSDavid Brownell int (*probe)(struct platform_device *)) 522c67334fbSDavid Brownell { 523c67334fbSDavid Brownell int retval, code; 524c67334fbSDavid Brownell 5251a6f2a75SDmitry Torokhov /* make sure driver won't have bind/unbind attributes */ 5261a6f2a75SDmitry Torokhov drv->driver.suppress_bind_attrs = true; 5271a6f2a75SDmitry Torokhov 528c67334fbSDavid Brownell /* temporary section violation during probe() */ 529c67334fbSDavid Brownell drv->probe = probe; 530c67334fbSDavid Brownell retval = code = platform_driver_register(drv); 531c67334fbSDavid Brownell 5321a6f2a75SDmitry Torokhov /* 5331a6f2a75SDmitry Torokhov * Fixup that section violation, being paranoid about code scanning 534c67334fbSDavid Brownell * the list of drivers in order to probe new devices. Check to see 535c67334fbSDavid Brownell * if the probe was successful, and make sure any forced probes of 536c67334fbSDavid Brownell * new devices fail. 537c67334fbSDavid Brownell */ 538c6f7e72aSGreg Kroah-Hartman spin_lock(&platform_bus_type.p->klist_drivers.k_lock); 539c67334fbSDavid Brownell drv->probe = NULL; 540e5dd1278SGreg Kroah-Hartman if (code == 0 && list_empty(&drv->driver.p->klist_devices.k_list)) 541c67334fbSDavid Brownell retval = -ENODEV; 542c67334fbSDavid Brownell drv->driver.probe = platform_drv_probe_fail; 543c6f7e72aSGreg Kroah-Hartman spin_unlock(&platform_bus_type.p->klist_drivers.k_lock); 544c67334fbSDavid Brownell 545c67334fbSDavid Brownell if (code != retval) 546c67334fbSDavid Brownell platform_driver_unregister(drv); 547c67334fbSDavid Brownell return retval; 548c67334fbSDavid Brownell } 549c67334fbSDavid Brownell EXPORT_SYMBOL_GPL(platform_driver_probe); 5501da177e4SLinus Torvalds 551ecdf6cebSDmitry Torokhov /** 552ecdf6cebSDmitry Torokhov * platform_create_bundle - register driver and create corresponding device 553ecdf6cebSDmitry Torokhov * @driver: platform driver structure 554ecdf6cebSDmitry Torokhov * @probe: the driver probe routine, probably from an __init section 555ecdf6cebSDmitry Torokhov * @res: set of resources that needs to be allocated for the device 556ecdf6cebSDmitry Torokhov * @n_res: number of resources 557ecdf6cebSDmitry Torokhov * @data: platform specific data for this platform device 558ecdf6cebSDmitry Torokhov * @size: size of platform specific data 559ecdf6cebSDmitry Torokhov * 560ecdf6cebSDmitry Torokhov * Use this in legacy-style modules that probe hardware directly and 561ecdf6cebSDmitry Torokhov * register a single platform device and corresponding platform driver. 562ecdf6cebSDmitry Torokhov */ 563ecdf6cebSDmitry Torokhov struct platform_device * __init_or_module platform_create_bundle( 564ecdf6cebSDmitry Torokhov struct platform_driver *driver, 565ecdf6cebSDmitry Torokhov int (*probe)(struct platform_device *), 566ecdf6cebSDmitry Torokhov struct resource *res, unsigned int n_res, 567ecdf6cebSDmitry Torokhov const void *data, size_t size) 568ecdf6cebSDmitry Torokhov { 569ecdf6cebSDmitry Torokhov struct platform_device *pdev; 570ecdf6cebSDmitry Torokhov int error; 571ecdf6cebSDmitry Torokhov 572ecdf6cebSDmitry Torokhov pdev = platform_device_alloc(driver->driver.name, -1); 573ecdf6cebSDmitry Torokhov if (!pdev) { 574ecdf6cebSDmitry Torokhov error = -ENOMEM; 575ecdf6cebSDmitry Torokhov goto err_out; 576ecdf6cebSDmitry Torokhov } 577ecdf6cebSDmitry Torokhov 578ecdf6cebSDmitry Torokhov if (res) { 579ecdf6cebSDmitry Torokhov error = platform_device_add_resources(pdev, res, n_res); 580ecdf6cebSDmitry Torokhov if (error) 581ecdf6cebSDmitry Torokhov goto err_pdev_put; 582ecdf6cebSDmitry Torokhov } 583ecdf6cebSDmitry Torokhov 584ecdf6cebSDmitry Torokhov if (data) { 585ecdf6cebSDmitry Torokhov error = platform_device_add_data(pdev, data, size); 586ecdf6cebSDmitry Torokhov if (error) 587ecdf6cebSDmitry Torokhov goto err_pdev_put; 588ecdf6cebSDmitry Torokhov } 589ecdf6cebSDmitry Torokhov 590ecdf6cebSDmitry Torokhov error = platform_device_add(pdev); 591ecdf6cebSDmitry Torokhov if (error) 592ecdf6cebSDmitry Torokhov goto err_pdev_put; 593ecdf6cebSDmitry Torokhov 594ecdf6cebSDmitry Torokhov error = platform_driver_probe(driver, probe); 595ecdf6cebSDmitry Torokhov if (error) 596ecdf6cebSDmitry Torokhov goto err_pdev_del; 597ecdf6cebSDmitry Torokhov 598ecdf6cebSDmitry Torokhov return pdev; 599ecdf6cebSDmitry Torokhov 600ecdf6cebSDmitry Torokhov err_pdev_del: 601ecdf6cebSDmitry Torokhov platform_device_del(pdev); 602ecdf6cebSDmitry Torokhov err_pdev_put: 603ecdf6cebSDmitry Torokhov platform_device_put(pdev); 604ecdf6cebSDmitry Torokhov err_out: 605ecdf6cebSDmitry Torokhov return ERR_PTR(error); 606ecdf6cebSDmitry Torokhov } 607ecdf6cebSDmitry Torokhov EXPORT_SYMBOL_GPL(platform_create_bundle); 608ecdf6cebSDmitry Torokhov 609a0245f7aSDavid Brownell /* modalias support enables more hands-off userspace setup: 610a0245f7aSDavid Brownell * (a) environment variable lets new-style hotplug events work once system is 611a0245f7aSDavid Brownell * fully running: "modprobe $MODALIAS" 612a0245f7aSDavid Brownell * (b) sysfs attribute lets new-style coldplug recover from hotplug events 613a0245f7aSDavid Brownell * mishandled before system is fully running: "modprobe $(cat modalias)" 614a0245f7aSDavid Brownell */ 6154a3ad20cSGreg Kroah-Hartman static ssize_t modalias_show(struct device *dev, struct device_attribute *a, 6164a3ad20cSGreg Kroah-Hartman char *buf) 617a0245f7aSDavid Brownell { 618a0245f7aSDavid Brownell struct platform_device *pdev = to_platform_device(dev); 61943cc71eeSKay Sievers int len = snprintf(buf, PAGE_SIZE, "platform:%s\n", pdev->name); 620a0245f7aSDavid Brownell 621a0245f7aSDavid Brownell return (len >= PAGE_SIZE) ? (PAGE_SIZE - 1) : len; 622a0245f7aSDavid Brownell } 623a0245f7aSDavid Brownell 624a0245f7aSDavid Brownell static struct device_attribute platform_dev_attrs[] = { 625a0245f7aSDavid Brownell __ATTR_RO(modalias), 626a0245f7aSDavid Brownell __ATTR_NULL, 627a0245f7aSDavid Brownell }; 628a0245f7aSDavid Brownell 6297eff2e7aSKay Sievers static int platform_uevent(struct device *dev, struct kobj_uevent_env *env) 630a0245f7aSDavid Brownell { 631a0245f7aSDavid Brownell struct platform_device *pdev = to_platform_device(dev); 632a0245f7aSDavid Brownell 63357fee4a5SEric Miao add_uevent_var(env, "MODALIAS=%s%s", PLATFORM_MODULE_PREFIX, 63457fee4a5SEric Miao (pdev->id_entry) ? pdev->id_entry->name : pdev->name); 635a0245f7aSDavid Brownell return 0; 636a0245f7aSDavid Brownell } 637a0245f7aSDavid Brownell 63857fee4a5SEric Miao static const struct platform_device_id *platform_match_id( 639831fad2fSUwe Kleine-König const struct platform_device_id *id, 64057fee4a5SEric Miao struct platform_device *pdev) 64157fee4a5SEric Miao { 64257fee4a5SEric Miao while (id->name[0]) { 64357fee4a5SEric Miao if (strcmp(pdev->name, id->name) == 0) { 64457fee4a5SEric Miao pdev->id_entry = id; 64557fee4a5SEric Miao return id; 64657fee4a5SEric Miao } 64757fee4a5SEric Miao id++; 64857fee4a5SEric Miao } 64957fee4a5SEric Miao return NULL; 65057fee4a5SEric Miao } 65157fee4a5SEric Miao 6521da177e4SLinus Torvalds /** 6531da177e4SLinus Torvalds * platform_match - bind platform device to platform driver. 6541da177e4SLinus Torvalds * @dev: device. 6551da177e4SLinus Torvalds * @drv: driver. 6561da177e4SLinus Torvalds * 6571da177e4SLinus Torvalds * Platform device IDs are assumed to be encoded like this: 6584a3ad20cSGreg Kroah-Hartman * "<name><instance>", where <name> is a short description of the type of 6594a3ad20cSGreg Kroah-Hartman * device, like "pci" or "floppy", and <instance> is the enumerated 6604a3ad20cSGreg Kroah-Hartman * instance of the device, like '0' or '42'. Driver IDs are simply 6614a3ad20cSGreg Kroah-Hartman * "<name>". So, extract the <name> from the platform_device structure, 6624a3ad20cSGreg Kroah-Hartman * and compare it against the name of the driver. Return whether they match 6634a3ad20cSGreg Kroah-Hartman * or not. 6641da177e4SLinus Torvalds */ 6651da177e4SLinus Torvalds static int platform_match(struct device *dev, struct device_driver *drv) 6661da177e4SLinus Torvalds { 66771b3e0c1SEric Miao struct platform_device *pdev = to_platform_device(dev); 66857fee4a5SEric Miao struct platform_driver *pdrv = to_platform_driver(drv); 6691da177e4SLinus Torvalds 67057fee4a5SEric Miao /* match against the id table first */ 67157fee4a5SEric Miao if (pdrv->id_table) 67257fee4a5SEric Miao return platform_match_id(pdrv->id_table, pdev) != NULL; 67357fee4a5SEric Miao 67457fee4a5SEric Miao /* fall-back to driver name match */ 6751e0b2cf9SKay Sievers return (strcmp(pdev->name, drv->name) == 0); 6761da177e4SLinus Torvalds } 6771da177e4SLinus Torvalds 67825e18499SRafael J. Wysocki #ifdef CONFIG_PM_SLEEP 67925e18499SRafael J. Wysocki 68025e18499SRafael J. Wysocki static int platform_legacy_suspend(struct device *dev, pm_message_t mesg) 6811da177e4SLinus Torvalds { 682783ea7d4SMagnus Damm struct platform_driver *pdrv = to_platform_driver(dev->driver); 683783ea7d4SMagnus Damm struct platform_device *pdev = to_platform_device(dev); 6841da177e4SLinus Torvalds int ret = 0; 6851da177e4SLinus Torvalds 686783ea7d4SMagnus Damm if (dev->driver && pdrv->suspend) 687783ea7d4SMagnus Damm ret = pdrv->suspend(pdev, mesg); 688386415d8SDavid Brownell 689386415d8SDavid Brownell return ret; 690386415d8SDavid Brownell } 691386415d8SDavid Brownell 69225e18499SRafael J. Wysocki static int platform_legacy_resume(struct device *dev) 6931da177e4SLinus Torvalds { 694783ea7d4SMagnus Damm struct platform_driver *pdrv = to_platform_driver(dev->driver); 695783ea7d4SMagnus Damm struct platform_device *pdev = to_platform_device(dev); 6961da177e4SLinus Torvalds int ret = 0; 6971da177e4SLinus Torvalds 698783ea7d4SMagnus Damm if (dev->driver && pdrv->resume) 699783ea7d4SMagnus Damm ret = pdrv->resume(pdev); 7009480e307SRussell King 7011da177e4SLinus Torvalds return ret; 7021da177e4SLinus Torvalds } 7031da177e4SLinus Torvalds 70425e18499SRafael J. Wysocki static int platform_pm_prepare(struct device *dev) 70525e18499SRafael J. Wysocki { 70625e18499SRafael J. Wysocki struct device_driver *drv = dev->driver; 70725e18499SRafael J. Wysocki int ret = 0; 70825e18499SRafael J. Wysocki 70925e18499SRafael J. Wysocki if (drv && drv->pm && drv->pm->prepare) 71025e18499SRafael J. Wysocki ret = drv->pm->prepare(dev); 71125e18499SRafael J. Wysocki 71225e18499SRafael J. Wysocki return ret; 71325e18499SRafael J. Wysocki } 71425e18499SRafael J. Wysocki 71525e18499SRafael J. Wysocki static void platform_pm_complete(struct device *dev) 71625e18499SRafael J. Wysocki { 71725e18499SRafael J. Wysocki struct device_driver *drv = dev->driver; 71825e18499SRafael J. Wysocki 71925e18499SRafael J. Wysocki if (drv && drv->pm && drv->pm->complete) 72025e18499SRafael J. Wysocki drv->pm->complete(dev); 72125e18499SRafael J. Wysocki } 72225e18499SRafael J. Wysocki 7239d730229SMagnus Damm #else /* !CONFIG_PM_SLEEP */ 7249d730229SMagnus Damm 7259d730229SMagnus Damm #define platform_pm_prepare NULL 7269d730229SMagnus Damm #define platform_pm_complete NULL 7279d730229SMagnus Damm 7289d730229SMagnus Damm #endif /* !CONFIG_PM_SLEEP */ 7299d730229SMagnus Damm 73025e18499SRafael J. Wysocki #ifdef CONFIG_SUSPEND 73125e18499SRafael J. Wysocki 73225e18499SRafael J. Wysocki static int platform_pm_suspend(struct device *dev) 73325e18499SRafael J. Wysocki { 73425e18499SRafael J. Wysocki struct device_driver *drv = dev->driver; 73525e18499SRafael J. Wysocki int ret = 0; 73625e18499SRafael J. Wysocki 737adf09493SRafael J. Wysocki if (!drv) 738adf09493SRafael J. Wysocki return 0; 739adf09493SRafael J. Wysocki 740adf09493SRafael J. Wysocki if (drv->pm) { 74125e18499SRafael J. Wysocki if (drv->pm->suspend) 74225e18499SRafael J. Wysocki ret = drv->pm->suspend(dev); 74325e18499SRafael J. Wysocki } else { 74425e18499SRafael J. Wysocki ret = platform_legacy_suspend(dev, PMSG_SUSPEND); 74525e18499SRafael J. Wysocki } 74625e18499SRafael J. Wysocki 74725e18499SRafael J. Wysocki return ret; 74825e18499SRafael J. Wysocki } 74925e18499SRafael J. Wysocki 75025e18499SRafael J. Wysocki static int platform_pm_suspend_noirq(struct device *dev) 75125e18499SRafael J. Wysocki { 752adf09493SRafael J. Wysocki struct device_driver *drv = dev->driver; 75325e18499SRafael J. Wysocki int ret = 0; 75425e18499SRafael J. Wysocki 755adf09493SRafael J. Wysocki if (!drv) 75625e18499SRafael J. Wysocki return 0; 75725e18499SRafael J. Wysocki 758adf09493SRafael J. Wysocki if (drv->pm) { 759adf09493SRafael J. Wysocki if (drv->pm->suspend_noirq) 760adf09493SRafael J. Wysocki ret = drv->pm->suspend_noirq(dev); 76125e18499SRafael J. Wysocki } 76225e18499SRafael J. Wysocki 76325e18499SRafael J. Wysocki return ret; 76425e18499SRafael J. Wysocki } 76525e18499SRafael J. Wysocki 76625e18499SRafael J. Wysocki static int platform_pm_resume(struct device *dev) 76725e18499SRafael J. Wysocki { 76825e18499SRafael J. Wysocki struct device_driver *drv = dev->driver; 76925e18499SRafael J. Wysocki int ret = 0; 77025e18499SRafael J. Wysocki 771adf09493SRafael J. Wysocki if (!drv) 772adf09493SRafael J. Wysocki return 0; 773adf09493SRafael J. Wysocki 774adf09493SRafael J. Wysocki if (drv->pm) { 77525e18499SRafael J. Wysocki if (drv->pm->resume) 77625e18499SRafael J. Wysocki ret = drv->pm->resume(dev); 77725e18499SRafael J. Wysocki } else { 77825e18499SRafael J. Wysocki ret = platform_legacy_resume(dev); 77925e18499SRafael J. Wysocki } 78025e18499SRafael J. Wysocki 78125e18499SRafael J. Wysocki return ret; 78225e18499SRafael J. Wysocki } 78325e18499SRafael J. Wysocki 78425e18499SRafael J. Wysocki static int platform_pm_resume_noirq(struct device *dev) 78525e18499SRafael J. Wysocki { 786adf09493SRafael J. Wysocki struct device_driver *drv = dev->driver; 78725e18499SRafael J. Wysocki int ret = 0; 78825e18499SRafael J. Wysocki 789adf09493SRafael J. Wysocki if (!drv) 79025e18499SRafael J. Wysocki return 0; 79125e18499SRafael J. Wysocki 792adf09493SRafael J. Wysocki if (drv->pm) { 793adf09493SRafael J. Wysocki if (drv->pm->resume_noirq) 794adf09493SRafael J. Wysocki ret = drv->pm->resume_noirq(dev); 79525e18499SRafael J. Wysocki } 79625e18499SRafael J. Wysocki 79725e18499SRafael J. Wysocki return ret; 79825e18499SRafael J. Wysocki } 79925e18499SRafael J. Wysocki 80025e18499SRafael J. Wysocki #else /* !CONFIG_SUSPEND */ 80125e18499SRafael J. Wysocki 80225e18499SRafael J. Wysocki #define platform_pm_suspend NULL 80325e18499SRafael J. Wysocki #define platform_pm_resume NULL 80425e18499SRafael J. Wysocki #define platform_pm_suspend_noirq NULL 80525e18499SRafael J. Wysocki #define platform_pm_resume_noirq NULL 80625e18499SRafael J. Wysocki 80725e18499SRafael J. Wysocki #endif /* !CONFIG_SUSPEND */ 80825e18499SRafael J. Wysocki 80925e18499SRafael J. Wysocki #ifdef CONFIG_HIBERNATION 81025e18499SRafael J. Wysocki 81125e18499SRafael J. Wysocki static int platform_pm_freeze(struct device *dev) 81225e18499SRafael J. Wysocki { 81325e18499SRafael J. Wysocki struct device_driver *drv = dev->driver; 81425e18499SRafael J. Wysocki int ret = 0; 81525e18499SRafael J. Wysocki 81625e18499SRafael J. Wysocki if (!drv) 81725e18499SRafael J. Wysocki return 0; 81825e18499SRafael J. Wysocki 81925e18499SRafael J. Wysocki if (drv->pm) { 82025e18499SRafael J. Wysocki if (drv->pm->freeze) 82125e18499SRafael J. Wysocki ret = drv->pm->freeze(dev); 82225e18499SRafael J. Wysocki } else { 82325e18499SRafael J. Wysocki ret = platform_legacy_suspend(dev, PMSG_FREEZE); 82425e18499SRafael J. Wysocki } 82525e18499SRafael J. Wysocki 82625e18499SRafael J. Wysocki return ret; 82725e18499SRafael J. Wysocki } 82825e18499SRafael J. Wysocki 82925e18499SRafael J. Wysocki static int platform_pm_freeze_noirq(struct device *dev) 83025e18499SRafael J. Wysocki { 831adf09493SRafael J. Wysocki struct device_driver *drv = dev->driver; 83225e18499SRafael J. Wysocki int ret = 0; 83325e18499SRafael J. Wysocki 834adf09493SRafael J. Wysocki if (!drv) 83525e18499SRafael J. Wysocki return 0; 83625e18499SRafael J. Wysocki 837adf09493SRafael J. Wysocki if (drv->pm) { 838adf09493SRafael J. Wysocki if (drv->pm->freeze_noirq) 839adf09493SRafael J. Wysocki ret = drv->pm->freeze_noirq(dev); 84025e18499SRafael J. Wysocki } 84125e18499SRafael J. Wysocki 84225e18499SRafael J. Wysocki return ret; 84325e18499SRafael J. Wysocki } 84425e18499SRafael J. Wysocki 84525e18499SRafael J. Wysocki static int platform_pm_thaw(struct device *dev) 84625e18499SRafael J. Wysocki { 84725e18499SRafael J. Wysocki struct device_driver *drv = dev->driver; 84825e18499SRafael J. Wysocki int ret = 0; 84925e18499SRafael J. Wysocki 850adf09493SRafael J. Wysocki if (!drv) 851adf09493SRafael J. Wysocki return 0; 852adf09493SRafael J. Wysocki 853adf09493SRafael J. Wysocki if (drv->pm) { 85425e18499SRafael J. Wysocki if (drv->pm->thaw) 85525e18499SRafael J. Wysocki ret = drv->pm->thaw(dev); 85625e18499SRafael J. Wysocki } else { 85725e18499SRafael J. Wysocki ret = platform_legacy_resume(dev); 85825e18499SRafael J. Wysocki } 85925e18499SRafael J. Wysocki 86025e18499SRafael J. Wysocki return ret; 86125e18499SRafael J. Wysocki } 86225e18499SRafael J. Wysocki 86325e18499SRafael J. Wysocki static int platform_pm_thaw_noirq(struct device *dev) 86425e18499SRafael J. Wysocki { 865adf09493SRafael J. Wysocki struct device_driver *drv = dev->driver; 86625e18499SRafael J. Wysocki int ret = 0; 86725e18499SRafael J. Wysocki 868adf09493SRafael J. Wysocki if (!drv) 86925e18499SRafael J. Wysocki return 0; 87025e18499SRafael J. Wysocki 871adf09493SRafael J. Wysocki if (drv->pm) { 872adf09493SRafael J. Wysocki if (drv->pm->thaw_noirq) 873adf09493SRafael J. Wysocki ret = drv->pm->thaw_noirq(dev); 87425e18499SRafael J. Wysocki } 87525e18499SRafael J. Wysocki 87625e18499SRafael J. Wysocki return ret; 87725e18499SRafael J. Wysocki } 87825e18499SRafael J. Wysocki 87925e18499SRafael J. Wysocki static int platform_pm_poweroff(struct device *dev) 88025e18499SRafael J. Wysocki { 88125e18499SRafael J. Wysocki struct device_driver *drv = dev->driver; 88225e18499SRafael J. Wysocki int ret = 0; 88325e18499SRafael J. Wysocki 884adf09493SRafael J. Wysocki if (!drv) 885adf09493SRafael J. Wysocki return 0; 886adf09493SRafael J. Wysocki 887adf09493SRafael J. Wysocki if (drv->pm) { 88825e18499SRafael J. Wysocki if (drv->pm->poweroff) 88925e18499SRafael J. Wysocki ret = drv->pm->poweroff(dev); 89025e18499SRafael J. Wysocki } else { 89125e18499SRafael J. Wysocki ret = platform_legacy_suspend(dev, PMSG_HIBERNATE); 89225e18499SRafael J. Wysocki } 89325e18499SRafael J. Wysocki 89425e18499SRafael J. Wysocki return ret; 89525e18499SRafael J. Wysocki } 89625e18499SRafael J. Wysocki 89725e18499SRafael J. Wysocki static int platform_pm_poweroff_noirq(struct device *dev) 89825e18499SRafael J. Wysocki { 899adf09493SRafael J. Wysocki struct device_driver *drv = dev->driver; 90025e18499SRafael J. Wysocki int ret = 0; 90125e18499SRafael J. Wysocki 902adf09493SRafael J. Wysocki if (!drv) 90325e18499SRafael J. Wysocki return 0; 90425e18499SRafael J. Wysocki 905adf09493SRafael J. Wysocki if (drv->pm) { 906adf09493SRafael J. Wysocki if (drv->pm->poweroff_noirq) 907adf09493SRafael J. Wysocki ret = drv->pm->poweroff_noirq(dev); 90825e18499SRafael J. Wysocki } 90925e18499SRafael J. Wysocki 91025e18499SRafael J. Wysocki return ret; 91125e18499SRafael J. Wysocki } 91225e18499SRafael J. Wysocki 91325e18499SRafael J. Wysocki static int platform_pm_restore(struct device *dev) 91425e18499SRafael J. Wysocki { 91525e18499SRafael J. Wysocki struct device_driver *drv = dev->driver; 91625e18499SRafael J. Wysocki int ret = 0; 91725e18499SRafael J. Wysocki 918adf09493SRafael J. Wysocki if (!drv) 919adf09493SRafael J. Wysocki return 0; 920adf09493SRafael J. Wysocki 921adf09493SRafael J. Wysocki if (drv->pm) { 92225e18499SRafael J. Wysocki if (drv->pm->restore) 92325e18499SRafael J. Wysocki ret = drv->pm->restore(dev); 92425e18499SRafael J. Wysocki } else { 92525e18499SRafael J. Wysocki ret = platform_legacy_resume(dev); 92625e18499SRafael J. Wysocki } 92725e18499SRafael J. Wysocki 92825e18499SRafael J. Wysocki return ret; 92925e18499SRafael J. Wysocki } 93025e18499SRafael J. Wysocki 93125e18499SRafael J. Wysocki static int platform_pm_restore_noirq(struct device *dev) 93225e18499SRafael J. Wysocki { 933adf09493SRafael J. Wysocki struct device_driver *drv = dev->driver; 93425e18499SRafael J. Wysocki int ret = 0; 93525e18499SRafael J. Wysocki 936adf09493SRafael J. Wysocki if (!drv) 93725e18499SRafael J. Wysocki return 0; 93825e18499SRafael J. Wysocki 939adf09493SRafael J. Wysocki if (drv->pm) { 940adf09493SRafael J. Wysocki if (drv->pm->restore_noirq) 941adf09493SRafael J. Wysocki ret = drv->pm->restore_noirq(dev); 94225e18499SRafael J. Wysocki } 94325e18499SRafael J. Wysocki 94425e18499SRafael J. Wysocki return ret; 94525e18499SRafael J. Wysocki } 94625e18499SRafael J. Wysocki 94725e18499SRafael J. Wysocki #else /* !CONFIG_HIBERNATION */ 94825e18499SRafael J. Wysocki 94925e18499SRafael J. Wysocki #define platform_pm_freeze NULL 95025e18499SRafael J. Wysocki #define platform_pm_thaw NULL 95125e18499SRafael J. Wysocki #define platform_pm_poweroff NULL 95225e18499SRafael J. Wysocki #define platform_pm_restore NULL 95325e18499SRafael J. Wysocki #define platform_pm_freeze_noirq NULL 95425e18499SRafael J. Wysocki #define platform_pm_thaw_noirq NULL 95525e18499SRafael J. Wysocki #define platform_pm_poweroff_noirq NULL 95625e18499SRafael J. Wysocki #define platform_pm_restore_noirq NULL 95725e18499SRafael J. Wysocki 95825e18499SRafael J. Wysocki #endif /* !CONFIG_HIBERNATION */ 95925e18499SRafael J. Wysocki 9609d730229SMagnus Damm #ifdef CONFIG_PM_RUNTIME 9619d730229SMagnus Damm 9629d730229SMagnus Damm int __weak platform_pm_runtime_suspend(struct device *dev) 9639d730229SMagnus Damm { 9649d730229SMagnus Damm return -ENOSYS; 9659d730229SMagnus Damm }; 9669d730229SMagnus Damm 9679d730229SMagnus Damm int __weak platform_pm_runtime_resume(struct device *dev) 9689d730229SMagnus Damm { 9699d730229SMagnus Damm return -ENOSYS; 9709d730229SMagnus Damm }; 9719d730229SMagnus Damm 9729d730229SMagnus Damm int __weak platform_pm_runtime_idle(struct device *dev) 9739d730229SMagnus Damm { 9749d730229SMagnus Damm return -ENOSYS; 9759d730229SMagnus Damm }; 9769d730229SMagnus Damm 9779d730229SMagnus Damm #else /* !CONFIG_PM_RUNTIME */ 9789d730229SMagnus Damm 9799d730229SMagnus Damm #define platform_pm_runtime_suspend NULL 9809d730229SMagnus Damm #define platform_pm_runtime_resume NULL 9819d730229SMagnus Damm #define platform_pm_runtime_idle NULL 9829d730229SMagnus Damm 9839d730229SMagnus Damm #endif /* !CONFIG_PM_RUNTIME */ 9849d730229SMagnus Damm 985d9ab7716SDmitry Torokhov static const struct dev_pm_ops platform_dev_pm_ops = { 98625e18499SRafael J. Wysocki .prepare = platform_pm_prepare, 98725e18499SRafael J. Wysocki .complete = platform_pm_complete, 98825e18499SRafael J. Wysocki .suspend = platform_pm_suspend, 98925e18499SRafael J. Wysocki .resume = platform_pm_resume, 99025e18499SRafael J. Wysocki .freeze = platform_pm_freeze, 99125e18499SRafael J. Wysocki .thaw = platform_pm_thaw, 99225e18499SRafael J. Wysocki .poweroff = platform_pm_poweroff, 99325e18499SRafael J. Wysocki .restore = platform_pm_restore, 99425e18499SRafael J. Wysocki .suspend_noirq = platform_pm_suspend_noirq, 99525e18499SRafael J. Wysocki .resume_noirq = platform_pm_resume_noirq, 99625e18499SRafael J. Wysocki .freeze_noirq = platform_pm_freeze_noirq, 99725e18499SRafael J. Wysocki .thaw_noirq = platform_pm_thaw_noirq, 99825e18499SRafael J. Wysocki .poweroff_noirq = platform_pm_poweroff_noirq, 99925e18499SRafael J. Wysocki .restore_noirq = platform_pm_restore_noirq, 10009d730229SMagnus Damm .runtime_suspend = platform_pm_runtime_suspend, 10019d730229SMagnus Damm .runtime_resume = platform_pm_runtime_resume, 10029d730229SMagnus Damm .runtime_idle = platform_pm_runtime_idle, 100325e18499SRafael J. Wysocki }; 100425e18499SRafael J. Wysocki 10051da177e4SLinus Torvalds struct bus_type platform_bus_type = { 10061da177e4SLinus Torvalds .name = "platform", 1007a0245f7aSDavid Brownell .dev_attrs = platform_dev_attrs, 10081da177e4SLinus Torvalds .match = platform_match, 1009a0245f7aSDavid Brownell .uevent = platform_uevent, 10109d730229SMagnus Damm .pm = &platform_dev_pm_ops, 10111da177e4SLinus Torvalds }; 1012a96b2042SDmitry Torokhov EXPORT_SYMBOL_GPL(platform_bus_type); 10131da177e4SLinus Torvalds 10141da177e4SLinus Torvalds int __init platform_bus_init(void) 10151da177e4SLinus Torvalds { 1016fbfb1445SCornelia Huck int error; 1017fbfb1445SCornelia Huck 101813977091SMagnus Damm early_platform_cleanup(); 101913977091SMagnus Damm 1020fbfb1445SCornelia Huck error = device_register(&platform_bus); 1021fbfb1445SCornelia Huck if (error) 1022fbfb1445SCornelia Huck return error; 1023fbfb1445SCornelia Huck error = bus_register(&platform_bus_type); 1024fbfb1445SCornelia Huck if (error) 1025fbfb1445SCornelia Huck device_unregister(&platform_bus); 1026fbfb1445SCornelia Huck return error; 10271da177e4SLinus Torvalds } 10281da177e4SLinus Torvalds 10291da177e4SLinus Torvalds #ifndef ARCH_HAS_DMA_GET_REQUIRED_MASK 10301da177e4SLinus Torvalds u64 dma_get_required_mask(struct device *dev) 10311da177e4SLinus Torvalds { 10321da177e4SLinus Torvalds u32 low_totalram = ((max_pfn - 1) << PAGE_SHIFT); 10331da177e4SLinus Torvalds u32 high_totalram = ((max_pfn - 1) >> (32 - PAGE_SHIFT)); 10341da177e4SLinus Torvalds u64 mask; 10351da177e4SLinus Torvalds 10361da177e4SLinus Torvalds if (!high_totalram) { 10371da177e4SLinus Torvalds /* convert to mask just covering totalram */ 10381da177e4SLinus Torvalds low_totalram = (1 << (fls(low_totalram) - 1)); 10391da177e4SLinus Torvalds low_totalram += low_totalram - 1; 10401da177e4SLinus Torvalds mask = low_totalram; 10411da177e4SLinus Torvalds } else { 10421da177e4SLinus Torvalds high_totalram = (1 << (fls(high_totalram) - 1)); 10431da177e4SLinus Torvalds high_totalram += high_totalram - 1; 10441da177e4SLinus Torvalds mask = (((u64)high_totalram) << 32) + 0xffffffff; 10451da177e4SLinus Torvalds } 1046e88a0c2cSJames Bottomley return mask; 10471da177e4SLinus Torvalds } 10481da177e4SLinus Torvalds EXPORT_SYMBOL_GPL(dma_get_required_mask); 10491da177e4SLinus Torvalds #endif 105013977091SMagnus Damm 105113977091SMagnus Damm static __initdata LIST_HEAD(early_platform_driver_list); 105213977091SMagnus Damm static __initdata LIST_HEAD(early_platform_device_list); 105313977091SMagnus Damm 105413977091SMagnus Damm /** 105513977091SMagnus Damm * early_platform_driver_register 1056d86c1302SRandy Dunlap * @epdrv: early_platform driver structure 105713977091SMagnus Damm * @buf: string passed from early_param() 105813977091SMagnus Damm */ 105913977091SMagnus Damm int __init early_platform_driver_register(struct early_platform_driver *epdrv, 106013977091SMagnus Damm char *buf) 106113977091SMagnus Damm { 1062c60e0504SMagnus Damm char *tmp; 106313977091SMagnus Damm int n; 106413977091SMagnus Damm 106513977091SMagnus Damm /* Simply add the driver to the end of the global list. 106613977091SMagnus Damm * Drivers will by default be put on the list in compiled-in order. 106713977091SMagnus Damm */ 106813977091SMagnus Damm if (!epdrv->list.next) { 106913977091SMagnus Damm INIT_LIST_HEAD(&epdrv->list); 107013977091SMagnus Damm list_add_tail(&epdrv->list, &early_platform_driver_list); 107113977091SMagnus Damm } 107213977091SMagnus Damm 107313977091SMagnus Damm /* If the user has specified device then make sure the driver 107413977091SMagnus Damm * gets prioritized. The driver of the last device specified on 107513977091SMagnus Damm * command line will be put first on the list. 107613977091SMagnus Damm */ 107713977091SMagnus Damm n = strlen(epdrv->pdrv->driver.name); 107813977091SMagnus Damm if (buf && !strncmp(buf, epdrv->pdrv->driver.name, n)) { 107913977091SMagnus Damm list_move(&epdrv->list, &early_platform_driver_list); 108013977091SMagnus Damm 1081c60e0504SMagnus Damm /* Allow passing parameters after device name */ 1082c60e0504SMagnus Damm if (buf[n] == '\0' || buf[n] == ',') 108313977091SMagnus Damm epdrv->requested_id = -1; 1084c60e0504SMagnus Damm else { 1085c60e0504SMagnus Damm epdrv->requested_id = simple_strtoul(&buf[n + 1], 1086c60e0504SMagnus Damm &tmp, 10); 1087c60e0504SMagnus Damm 1088c60e0504SMagnus Damm if (buf[n] != '.' || (tmp == &buf[n + 1])) { 108913977091SMagnus Damm epdrv->requested_id = EARLY_PLATFORM_ID_ERROR; 1090c60e0504SMagnus Damm n = 0; 1091c60e0504SMagnus Damm } else 1092c60e0504SMagnus Damm n += strcspn(&buf[n + 1], ",") + 1; 1093c60e0504SMagnus Damm } 1094c60e0504SMagnus Damm 1095c60e0504SMagnus Damm if (buf[n] == ',') 1096c60e0504SMagnus Damm n++; 1097c60e0504SMagnus Damm 1098c60e0504SMagnus Damm if (epdrv->bufsize) { 1099c60e0504SMagnus Damm memcpy(epdrv->buffer, &buf[n], 1100c60e0504SMagnus Damm min_t(int, epdrv->bufsize, strlen(&buf[n]) + 1)); 1101c60e0504SMagnus Damm epdrv->buffer[epdrv->bufsize - 1] = '\0'; 1102c60e0504SMagnus Damm } 110313977091SMagnus Damm } 110413977091SMagnus Damm 110513977091SMagnus Damm return 0; 110613977091SMagnus Damm } 110713977091SMagnus Damm 110813977091SMagnus Damm /** 110913977091SMagnus Damm * early_platform_add_devices - add a numbers of early platform devices 111013977091SMagnus Damm * @devs: array of early platform devices to add 111113977091SMagnus Damm * @num: number of early platform devices in array 111213977091SMagnus Damm */ 111313977091SMagnus Damm void __init early_platform_add_devices(struct platform_device **devs, int num) 111413977091SMagnus Damm { 111513977091SMagnus Damm struct device *dev; 111613977091SMagnus Damm int i; 111713977091SMagnus Damm 111813977091SMagnus Damm /* simply add the devices to list */ 111913977091SMagnus Damm for (i = 0; i < num; i++) { 112013977091SMagnus Damm dev = &devs[i]->dev; 112113977091SMagnus Damm 112213977091SMagnus Damm if (!dev->devres_head.next) { 112313977091SMagnus Damm INIT_LIST_HEAD(&dev->devres_head); 112413977091SMagnus Damm list_add_tail(&dev->devres_head, 112513977091SMagnus Damm &early_platform_device_list); 112613977091SMagnus Damm } 112713977091SMagnus Damm } 112813977091SMagnus Damm } 112913977091SMagnus Damm 113013977091SMagnus Damm /** 113113977091SMagnus Damm * early_platform_driver_register_all 113213977091SMagnus Damm * @class_str: string to identify early platform driver class 113313977091SMagnus Damm */ 113413977091SMagnus Damm void __init early_platform_driver_register_all(char *class_str) 113513977091SMagnus Damm { 113613977091SMagnus Damm /* The "class_str" parameter may or may not be present on the kernel 113713977091SMagnus Damm * command line. If it is present then there may be more than one 113813977091SMagnus Damm * matching parameter. 113913977091SMagnus Damm * 114013977091SMagnus Damm * Since we register our early platform drivers using early_param() 114113977091SMagnus Damm * we need to make sure that they also get registered in the case 114213977091SMagnus Damm * when the parameter is missing from the kernel command line. 114313977091SMagnus Damm * 114413977091SMagnus Damm * We use parse_early_options() to make sure the early_param() gets 114513977091SMagnus Damm * called at least once. The early_param() may be called more than 114613977091SMagnus Damm * once since the name of the preferred device may be specified on 114713977091SMagnus Damm * the kernel command line. early_platform_driver_register() handles 114813977091SMagnus Damm * this case for us. 114913977091SMagnus Damm */ 115013977091SMagnus Damm parse_early_options(class_str); 115113977091SMagnus Damm } 115213977091SMagnus Damm 115313977091SMagnus Damm /** 115413977091SMagnus Damm * early_platform_match 1155d86c1302SRandy Dunlap * @epdrv: early platform driver structure 115613977091SMagnus Damm * @id: id to match against 115713977091SMagnus Damm */ 115813977091SMagnus Damm static __init struct platform_device * 115913977091SMagnus Damm early_platform_match(struct early_platform_driver *epdrv, int id) 116013977091SMagnus Damm { 116113977091SMagnus Damm struct platform_device *pd; 116213977091SMagnus Damm 116313977091SMagnus Damm list_for_each_entry(pd, &early_platform_device_list, dev.devres_head) 116413977091SMagnus Damm if (platform_match(&pd->dev, &epdrv->pdrv->driver)) 116513977091SMagnus Damm if (pd->id == id) 116613977091SMagnus Damm return pd; 116713977091SMagnus Damm 116813977091SMagnus Damm return NULL; 116913977091SMagnus Damm } 117013977091SMagnus Damm 117113977091SMagnus Damm /** 117213977091SMagnus Damm * early_platform_left 1173d86c1302SRandy Dunlap * @epdrv: early platform driver structure 117413977091SMagnus Damm * @id: return true if id or above exists 117513977091SMagnus Damm */ 117613977091SMagnus Damm static __init int early_platform_left(struct early_platform_driver *epdrv, 117713977091SMagnus Damm int id) 117813977091SMagnus Damm { 117913977091SMagnus Damm struct platform_device *pd; 118013977091SMagnus Damm 118113977091SMagnus Damm list_for_each_entry(pd, &early_platform_device_list, dev.devres_head) 118213977091SMagnus Damm if (platform_match(&pd->dev, &epdrv->pdrv->driver)) 118313977091SMagnus Damm if (pd->id >= id) 118413977091SMagnus Damm return 1; 118513977091SMagnus Damm 118613977091SMagnus Damm return 0; 118713977091SMagnus Damm } 118813977091SMagnus Damm 118913977091SMagnus Damm /** 119013977091SMagnus Damm * early_platform_driver_probe_id 119113977091SMagnus Damm * @class_str: string to identify early platform driver class 119213977091SMagnus Damm * @id: id to match against 119313977091SMagnus Damm * @nr_probe: number of platform devices to successfully probe before exiting 119413977091SMagnus Damm */ 119513977091SMagnus Damm static int __init early_platform_driver_probe_id(char *class_str, 119613977091SMagnus Damm int id, 119713977091SMagnus Damm int nr_probe) 119813977091SMagnus Damm { 119913977091SMagnus Damm struct early_platform_driver *epdrv; 120013977091SMagnus Damm struct platform_device *match; 120113977091SMagnus Damm int match_id; 120213977091SMagnus Damm int n = 0; 120313977091SMagnus Damm int left = 0; 120413977091SMagnus Damm 120513977091SMagnus Damm list_for_each_entry(epdrv, &early_platform_driver_list, list) { 120613977091SMagnus Damm /* only use drivers matching our class_str */ 120713977091SMagnus Damm if (strcmp(class_str, epdrv->class_str)) 120813977091SMagnus Damm continue; 120913977091SMagnus Damm 121013977091SMagnus Damm if (id == -2) { 121113977091SMagnus Damm match_id = epdrv->requested_id; 121213977091SMagnus Damm left = 1; 121313977091SMagnus Damm 121413977091SMagnus Damm } else { 121513977091SMagnus Damm match_id = id; 121613977091SMagnus Damm left += early_platform_left(epdrv, id); 121713977091SMagnus Damm 121813977091SMagnus Damm /* skip requested id */ 121913977091SMagnus Damm switch (epdrv->requested_id) { 122013977091SMagnus Damm case EARLY_PLATFORM_ID_ERROR: 122113977091SMagnus Damm case EARLY_PLATFORM_ID_UNSET: 122213977091SMagnus Damm break; 122313977091SMagnus Damm default: 122413977091SMagnus Damm if (epdrv->requested_id == id) 122513977091SMagnus Damm match_id = EARLY_PLATFORM_ID_UNSET; 122613977091SMagnus Damm } 122713977091SMagnus Damm } 122813977091SMagnus Damm 122913977091SMagnus Damm switch (match_id) { 123013977091SMagnus Damm case EARLY_PLATFORM_ID_ERROR: 123113977091SMagnus Damm pr_warning("%s: unable to parse %s parameter\n", 123213977091SMagnus Damm class_str, epdrv->pdrv->driver.name); 123313977091SMagnus Damm /* fall-through */ 123413977091SMagnus Damm case EARLY_PLATFORM_ID_UNSET: 123513977091SMagnus Damm match = NULL; 123613977091SMagnus Damm break; 123713977091SMagnus Damm default: 123813977091SMagnus Damm match = early_platform_match(epdrv, match_id); 123913977091SMagnus Damm } 124013977091SMagnus Damm 124113977091SMagnus Damm if (match) { 1242a636ee7fSPaul Mundt /* 1243a636ee7fSPaul Mundt * Set up a sensible init_name to enable 1244a636ee7fSPaul Mundt * dev_name() and others to be used before the 1245a636ee7fSPaul Mundt * rest of the driver core is initialized. 1246a636ee7fSPaul Mundt */ 124706fe53beSPaul Mundt if (!match->dev.init_name && slab_is_available()) { 1248a636ee7fSPaul Mundt if (match->id != -1) 1249bd05086bSPaul Mundt match->dev.init_name = 1250bd05086bSPaul Mundt kasprintf(GFP_KERNEL, "%s.%d", 1251bd05086bSPaul Mundt match->name, 1252bd05086bSPaul Mundt match->id); 1253a636ee7fSPaul Mundt else 1254bd05086bSPaul Mundt match->dev.init_name = 1255bd05086bSPaul Mundt kasprintf(GFP_KERNEL, "%s", 1256a636ee7fSPaul Mundt match->name); 1257a636ee7fSPaul Mundt 1258a636ee7fSPaul Mundt if (!match->dev.init_name) 1259a636ee7fSPaul Mundt return -ENOMEM; 1260a636ee7fSPaul Mundt } 1261bd05086bSPaul Mundt 126213977091SMagnus Damm if (epdrv->pdrv->probe(match)) 126313977091SMagnus Damm pr_warning("%s: unable to probe %s early.\n", 126413977091SMagnus Damm class_str, match->name); 126513977091SMagnus Damm else 126613977091SMagnus Damm n++; 126713977091SMagnus Damm } 126813977091SMagnus Damm 126913977091SMagnus Damm if (n >= nr_probe) 127013977091SMagnus Damm break; 127113977091SMagnus Damm } 127213977091SMagnus Damm 127313977091SMagnus Damm if (left) 127413977091SMagnus Damm return n; 127513977091SMagnus Damm else 127613977091SMagnus Damm return -ENODEV; 127713977091SMagnus Damm } 127813977091SMagnus Damm 127913977091SMagnus Damm /** 128013977091SMagnus Damm * early_platform_driver_probe 128113977091SMagnus Damm * @class_str: string to identify early platform driver class 128213977091SMagnus Damm * @nr_probe: number of platform devices to successfully probe before exiting 128313977091SMagnus Damm * @user_only: only probe user specified early platform devices 128413977091SMagnus Damm */ 128513977091SMagnus Damm int __init early_platform_driver_probe(char *class_str, 128613977091SMagnus Damm int nr_probe, 128713977091SMagnus Damm int user_only) 128813977091SMagnus Damm { 128913977091SMagnus Damm int k, n, i; 129013977091SMagnus Damm 129113977091SMagnus Damm n = 0; 129213977091SMagnus Damm for (i = -2; n < nr_probe; i++) { 129313977091SMagnus Damm k = early_platform_driver_probe_id(class_str, i, nr_probe - n); 129413977091SMagnus Damm 129513977091SMagnus Damm if (k < 0) 129613977091SMagnus Damm break; 129713977091SMagnus Damm 129813977091SMagnus Damm n += k; 129913977091SMagnus Damm 130013977091SMagnus Damm if (user_only) 130113977091SMagnus Damm break; 130213977091SMagnus Damm } 130313977091SMagnus Damm 130413977091SMagnus Damm return n; 130513977091SMagnus Damm } 130613977091SMagnus Damm 130713977091SMagnus Damm /** 130813977091SMagnus Damm * early_platform_cleanup - clean up early platform code 130913977091SMagnus Damm */ 131013977091SMagnus Damm void __init early_platform_cleanup(void) 131113977091SMagnus Damm { 131213977091SMagnus Damm struct platform_device *pd, *pd2; 131313977091SMagnus Damm 131413977091SMagnus Damm /* clean up the devres list used to chain devices */ 131513977091SMagnus Damm list_for_each_entry_safe(pd, pd2, &early_platform_device_list, 131613977091SMagnus Damm dev.devres_head) { 131713977091SMagnus Damm list_del(&pd->dev.devres_head); 131813977091SMagnus Damm memset(&pd->dev.devres_head, 0, sizeof(pd->dev.devres_head)); 131913977091SMagnus Damm } 132013977091SMagnus Damm } 132113977091SMagnus Damm 1322