xref: /openbmc/linux/drivers/base/platform.c (revision 06fe53be)
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