xref: /openbmc/linux/drivers/base/platform.c (revision f48c767c)
11da177e4SLinus Torvalds /*
21da177e4SLinus Torvalds  * platform.c - platform 'pseudo' bus for legacy devices
31da177e4SLinus Torvalds  *
41da177e4SLinus Torvalds  * Copyright (c) 2002-3 Patrick Mochel
51da177e4SLinus Torvalds  * Copyright (c) 2002-3 Open Source Development Labs
61da177e4SLinus Torvalds  *
71da177e4SLinus Torvalds  * This file is released under the GPLv2
81da177e4SLinus Torvalds  *
91da177e4SLinus Torvalds  * Please see Documentation/driver-model/platform.txt for more
101da177e4SLinus Torvalds  * information.
111da177e4SLinus Torvalds  */
121da177e4SLinus Torvalds 
13daa41226SAndrew Morton #include <linux/string.h>
14d052d1beSRussell King #include <linux/platform_device.h>
1505212157SGrant Likely #include <linux/of_device.h>
169ec36cafSRob Herring #include <linux/of_irq.h>
171da177e4SLinus Torvalds #include <linux/module.h>
181da177e4SLinus Torvalds #include <linux/init.h>
191da177e4SLinus Torvalds #include <linux/dma-mapping.h>
201da177e4SLinus Torvalds #include <linux/bootmem.h>
211da177e4SLinus Torvalds #include <linux/err.h>
224e57b681STim Schmielau #include <linux/slab.h>
239d730229SMagnus Damm #include <linux/pm_runtime.h>
24f48c767cSUlf Hansson #include <linux/pm_domain.h>
25689ae231SJean Delvare #include <linux/idr.h>
2691e56878SMika Westerberg #include <linux/acpi.h>
2786be408bSSylwester Nawrocki #include <linux/clk/clk-conf.h>
283d713e0eSKim Phillips #include <linux/limits.h>
291da177e4SLinus Torvalds 
30a1bdc7aaSBen Dooks #include "base.h"
31bed2b42dSRafael J. Wysocki #include "power/power.h"
32a1bdc7aaSBen Dooks 
33689ae231SJean Delvare /* For automatically allocated device IDs */
34689ae231SJean Delvare static DEFINE_IDA(platform_devid_ida);
35689ae231SJean Delvare 
361da177e4SLinus Torvalds struct device platform_bus = {
371e0b2cf9SKay Sievers 	.init_name	= "platform",
381da177e4SLinus Torvalds };
39a96b2042SDmitry Torokhov EXPORT_SYMBOL_GPL(platform_bus);
401da177e4SLinus Torvalds 
411da177e4SLinus Torvalds /**
42a77ce816SKumar Gala  * arch_setup_pdev_archdata - Allow manipulation of archdata before its used
437de636faSRandy Dunlap  * @pdev: platform device
44a77ce816SKumar Gala  *
45a77ce816SKumar Gala  * This is called before platform_device_add() such that any pdev_archdata may
46a77ce816SKumar Gala  * be setup before the platform_notifier is called.  So if a user needs to
47a77ce816SKumar Gala  * manipulate any relevant information in the pdev_archdata they can do:
48a77ce816SKumar Gala  *
49b1d6d822SSebastian Andrzej Siewior  *	platform_device_alloc()
50a77ce816SKumar Gala  *	... manipulate ...
51a77ce816SKumar Gala  *	platform_device_add()
52a77ce816SKumar Gala  *
53a77ce816SKumar Gala  * And if they don't care they can just call platform_device_register() and
54a77ce816SKumar Gala  * everything will just work out.
55a77ce816SKumar Gala  */
56a77ce816SKumar Gala void __weak arch_setup_pdev_archdata(struct platform_device *pdev)
57a77ce816SKumar Gala {
58a77ce816SKumar Gala }
59a77ce816SKumar Gala 
60a77ce816SKumar Gala /**
611da177e4SLinus Torvalds  * platform_get_resource - get a resource for a device
621da177e4SLinus Torvalds  * @dev: platform device
631da177e4SLinus Torvalds  * @type: resource type
641da177e4SLinus Torvalds  * @num: resource index
651da177e4SLinus Torvalds  */
664a3ad20cSGreg Kroah-Hartman struct resource *platform_get_resource(struct platform_device *dev,
674a3ad20cSGreg Kroah-Hartman 				       unsigned int type, unsigned int num)
681da177e4SLinus Torvalds {
691da177e4SLinus Torvalds 	int i;
701da177e4SLinus Torvalds 
711da177e4SLinus Torvalds 	for (i = 0; i < dev->num_resources; i++) {
721da177e4SLinus Torvalds 		struct resource *r = &dev->resource[i];
731da177e4SLinus Torvalds 
74c9f66169SMagnus Damm 		if (type == resource_type(r) && num-- == 0)
751da177e4SLinus Torvalds 			return r;
761da177e4SLinus Torvalds 	}
771da177e4SLinus Torvalds 	return NULL;
781da177e4SLinus Torvalds }
79a96b2042SDmitry Torokhov EXPORT_SYMBOL_GPL(platform_get_resource);
801da177e4SLinus Torvalds 
811da177e4SLinus Torvalds /**
821da177e4SLinus Torvalds  * platform_get_irq - get an IRQ for a device
831da177e4SLinus Torvalds  * @dev: platform device
841da177e4SLinus Torvalds  * @num: IRQ number index
851da177e4SLinus Torvalds  */
861da177e4SLinus Torvalds int platform_get_irq(struct platform_device *dev, unsigned int num)
871da177e4SLinus Torvalds {
885cf8f7dbSAndreas Larsson #ifdef CONFIG_SPARC
895cf8f7dbSAndreas Larsson 	/* sparc does not have irqs represented as IORESOURCE_IRQ resources */
905cf8f7dbSAndreas Larsson 	if (!dev || num >= dev->archdata.num_irqs)
915cf8f7dbSAndreas Larsson 		return -ENXIO;
925cf8f7dbSAndreas Larsson 	return dev->archdata.irqs[num];
935cf8f7dbSAndreas Larsson #else
949ec36cafSRob Herring 	struct resource *r;
95aff008adSGuenter Roeck 	if (IS_ENABLED(CONFIG_OF_IRQ) && dev->dev.of_node) {
96aff008adSGuenter Roeck 		int ret;
97aff008adSGuenter Roeck 
98aff008adSGuenter Roeck 		ret = of_irq_get(dev->dev.of_node, num);
99aff008adSGuenter Roeck 		if (ret >= 0 || ret == -EPROBE_DEFER)
100aff008adSGuenter Roeck 			return ret;
101aff008adSGuenter Roeck 	}
1029ec36cafSRob Herring 
1039ec36cafSRob Herring 	r = platform_get_resource(dev, IORESOURCE_IRQ, num);
1041da177e4SLinus Torvalds 
105305b3228SDavid Vrabel 	return r ? r->start : -ENXIO;
1065cf8f7dbSAndreas Larsson #endif
1071da177e4SLinus Torvalds }
108a96b2042SDmitry Torokhov EXPORT_SYMBOL_GPL(platform_get_irq);
1091da177e4SLinus Torvalds 
1101da177e4SLinus Torvalds /**
1111da177e4SLinus Torvalds  * platform_get_resource_byname - get a resource for a device by name
1121da177e4SLinus Torvalds  * @dev: platform device
1131da177e4SLinus Torvalds  * @type: resource type
1141da177e4SLinus Torvalds  * @name: resource name
1151da177e4SLinus Torvalds  */
1164a3ad20cSGreg Kroah-Hartman struct resource *platform_get_resource_byname(struct platform_device *dev,
117c0afe7baSLinus Walleij 					      unsigned int type,
118c0afe7baSLinus Walleij 					      const char *name)
1191da177e4SLinus Torvalds {
1201da177e4SLinus Torvalds 	int i;
1211da177e4SLinus Torvalds 
1221da177e4SLinus Torvalds 	for (i = 0; i < dev->num_resources; i++) {
1231da177e4SLinus Torvalds 		struct resource *r = &dev->resource[i];
1241da177e4SLinus Torvalds 
1251b8cb929SPeter Ujfalusi 		if (unlikely(!r->name))
1261b8cb929SPeter Ujfalusi 			continue;
1271b8cb929SPeter Ujfalusi 
128c9f66169SMagnus Damm 		if (type == resource_type(r) && !strcmp(r->name, name))
1291da177e4SLinus Torvalds 			return r;
1301da177e4SLinus Torvalds 	}
1311da177e4SLinus Torvalds 	return NULL;
1321da177e4SLinus Torvalds }
133a96b2042SDmitry Torokhov EXPORT_SYMBOL_GPL(platform_get_resource_byname);
1341da177e4SLinus Torvalds 
1351da177e4SLinus Torvalds /**
136d6ff8551SWolfram Sang  * platform_get_irq_byname - get an IRQ for a device by name
1371da177e4SLinus Torvalds  * @dev: platform device
1381da177e4SLinus Torvalds  * @name: IRQ name
1391da177e4SLinus Torvalds  */
140c0afe7baSLinus Walleij int platform_get_irq_byname(struct platform_device *dev, const char *name)
1411da177e4SLinus Torvalds {
142ad69674eSGrygorii Strashko 	struct resource *r;
1431da177e4SLinus Torvalds 
144aff008adSGuenter Roeck 	if (IS_ENABLED(CONFIG_OF_IRQ) && dev->dev.of_node) {
145aff008adSGuenter Roeck 		int ret;
146aff008adSGuenter Roeck 
147aff008adSGuenter Roeck 		ret = of_irq_get_byname(dev->dev.of_node, name);
148aff008adSGuenter Roeck 		if (ret >= 0 || ret == -EPROBE_DEFER)
149aff008adSGuenter Roeck 			return ret;
150aff008adSGuenter Roeck 	}
151ad69674eSGrygorii Strashko 
152ad69674eSGrygorii Strashko 	r = platform_get_resource_byname(dev, IORESOURCE_IRQ, name);
153305b3228SDavid Vrabel 	return r ? r->start : -ENXIO;
1541da177e4SLinus Torvalds }
155a96b2042SDmitry Torokhov EXPORT_SYMBOL_GPL(platform_get_irq_byname);
1561da177e4SLinus Torvalds 
1571da177e4SLinus Torvalds /**
1581da177e4SLinus Torvalds  * platform_add_devices - add a numbers of platform devices
1591da177e4SLinus Torvalds  * @devs: array of platform devices to add
1601da177e4SLinus Torvalds  * @num: number of platform devices in array
1611da177e4SLinus Torvalds  */
1621da177e4SLinus Torvalds int platform_add_devices(struct platform_device **devs, int num)
1631da177e4SLinus Torvalds {
1641da177e4SLinus Torvalds 	int i, ret = 0;
1651da177e4SLinus Torvalds 
1661da177e4SLinus Torvalds 	for (i = 0; i < num; i++) {
1671da177e4SLinus Torvalds 		ret = platform_device_register(devs[i]);
1681da177e4SLinus Torvalds 		if (ret) {
1691da177e4SLinus Torvalds 			while (--i >= 0)
1701da177e4SLinus Torvalds 				platform_device_unregister(devs[i]);
1711da177e4SLinus Torvalds 			break;
1721da177e4SLinus Torvalds 		}
1731da177e4SLinus Torvalds 	}
1741da177e4SLinus Torvalds 
1751da177e4SLinus Torvalds 	return ret;
1761da177e4SLinus Torvalds }
177a96b2042SDmitry Torokhov EXPORT_SYMBOL_GPL(platform_add_devices);
1781da177e4SLinus Torvalds 
17937c12e74SRussell King struct platform_object {
18037c12e74SRussell King 	struct platform_device pdev;
1811cec24c5SYann Droneaud 	char name[];
18237c12e74SRussell King };
18337c12e74SRussell King 
1841da177e4SLinus Torvalds /**
1853c31f07aSBen Hutchings  * platform_device_put - destroy a platform device
18637c12e74SRussell King  * @pdev: platform device to free
18737c12e74SRussell King  *
1884a3ad20cSGreg Kroah-Hartman  * Free all memory associated with a platform device.  This function must
1894a3ad20cSGreg Kroah-Hartman  * _only_ be externally called in error cases.  All other usage is a bug.
19037c12e74SRussell King  */
19137c12e74SRussell King void platform_device_put(struct platform_device *pdev)
19237c12e74SRussell King {
19337c12e74SRussell King 	if (pdev)
19437c12e74SRussell King 		put_device(&pdev->dev);
19537c12e74SRussell King }
19637c12e74SRussell King EXPORT_SYMBOL_GPL(platform_device_put);
19737c12e74SRussell King 
19837c12e74SRussell King static void platform_device_release(struct device *dev)
19937c12e74SRussell King {
2004a3ad20cSGreg Kroah-Hartman 	struct platform_object *pa = container_of(dev, struct platform_object,
2014a3ad20cSGreg Kroah-Hartman 						  pdev.dev);
20237c12e74SRussell King 
2037096d042SGrant Likely 	of_device_node_put(&pa->pdev.dev);
20437c12e74SRussell King 	kfree(pa->pdev.dev.platform_data);
205e710d7d5SSamuel Ortiz 	kfree(pa->pdev.mfd_cell);
20637c12e74SRussell King 	kfree(pa->pdev.resource);
2073d713e0eSKim Phillips 	kfree(pa->pdev.driver_override);
20837c12e74SRussell King 	kfree(pa);
20937c12e74SRussell King }
21037c12e74SRussell King 
21137c12e74SRussell King /**
2123c31f07aSBen Hutchings  * platform_device_alloc - create a platform device
21337c12e74SRussell King  * @name: base name of the device we're adding
21437c12e74SRussell King  * @id: instance id
21537c12e74SRussell King  *
21637c12e74SRussell King  * Create a platform device object which can have other objects attached
21737c12e74SRussell King  * to it, and which will have attached objects freed when it is released.
21837c12e74SRussell King  */
2191359555eSJean Delvare struct platform_device *platform_device_alloc(const char *name, int id)
22037c12e74SRussell King {
22137c12e74SRussell King 	struct platform_object *pa;
22237c12e74SRussell King 
2231cec24c5SYann Droneaud 	pa = kzalloc(sizeof(*pa) + strlen(name) + 1, GFP_KERNEL);
22437c12e74SRussell King 	if (pa) {
22537c12e74SRussell King 		strcpy(pa->name, name);
22637c12e74SRussell King 		pa->pdev.name = pa->name;
22737c12e74SRussell King 		pa->pdev.id = id;
22837c12e74SRussell King 		device_initialize(&pa->pdev.dev);
22937c12e74SRussell King 		pa->pdev.dev.release = platform_device_release;
230a77ce816SKumar Gala 		arch_setup_pdev_archdata(&pa->pdev);
23137c12e74SRussell King 	}
23237c12e74SRussell King 
23337c12e74SRussell King 	return pa ? &pa->pdev : NULL;
23437c12e74SRussell King }
23537c12e74SRussell King EXPORT_SYMBOL_GPL(platform_device_alloc);
23637c12e74SRussell King 
23737c12e74SRussell King /**
2383c31f07aSBen Hutchings  * platform_device_add_resources - add resources to a platform device
23937c12e74SRussell King  * @pdev: platform device allocated by platform_device_alloc to add resources to
24037c12e74SRussell King  * @res: set of resources that needs to be allocated for the device
24137c12e74SRussell King  * @num: number of resources
24237c12e74SRussell King  *
24337c12e74SRussell King  * Add a copy of the resources to the platform device.  The memory
2444a3ad20cSGreg Kroah-Hartman  * associated with the resources will be freed when the platform device is
2454a3ad20cSGreg Kroah-Hartman  * released.
24637c12e74SRussell King  */
2474a3ad20cSGreg Kroah-Hartman int platform_device_add_resources(struct platform_device *pdev,
2480b7f1a7eSGeert Uytterhoeven 				  const struct resource *res, unsigned int num)
24937c12e74SRussell King {
250cea89623SUwe Kleine-König 	struct resource *r = NULL;
25137c12e74SRussell King 
252cea89623SUwe Kleine-König 	if (res) {
2533e61dfd8SUwe Kleine-König 		r = kmemdup(res, sizeof(struct resource) * num, GFP_KERNEL);
254cea89623SUwe Kleine-König 		if (!r)
255cea89623SUwe Kleine-König 			return -ENOMEM;
256cea89623SUwe Kleine-König 	}
257cea89623SUwe Kleine-König 
2584a03d6f7SUwe Kleine-König 	kfree(pdev->resource);
25937c12e74SRussell King 	pdev->resource = r;
26037c12e74SRussell King 	pdev->num_resources = num;
2613e61dfd8SUwe Kleine-König 	return 0;
26237c12e74SRussell King }
26337c12e74SRussell King EXPORT_SYMBOL_GPL(platform_device_add_resources);
26437c12e74SRussell King 
26537c12e74SRussell King /**
2663c31f07aSBen Hutchings  * platform_device_add_data - add platform-specific data to a platform device
26737c12e74SRussell King  * @pdev: platform device allocated by platform_device_alloc to add resources to
26837c12e74SRussell King  * @data: platform specific data for this platform device
26937c12e74SRussell King  * @size: size of platform specific data
27037c12e74SRussell King  *
2714a3ad20cSGreg Kroah-Hartman  * Add a copy of platform specific data to the platform device's
2724a3ad20cSGreg Kroah-Hartman  * platform_data pointer.  The memory associated with the platform data
2734a3ad20cSGreg Kroah-Hartman  * will be freed when the platform device is released.
27437c12e74SRussell King  */
2754a3ad20cSGreg Kroah-Hartman int platform_device_add_data(struct platform_device *pdev, const void *data,
2764a3ad20cSGreg Kroah-Hartman 			     size_t size)
27737c12e74SRussell King {
27827a33f9eSUwe Kleine-König 	void *d = NULL;
27937c12e74SRussell King 
28027a33f9eSUwe Kleine-König 	if (data) {
2815cfc64ceSAnton Vorontsov 		d = kmemdup(data, size, GFP_KERNEL);
28227a33f9eSUwe Kleine-König 		if (!d)
28327a33f9eSUwe Kleine-König 			return -ENOMEM;
28427a33f9eSUwe Kleine-König 	}
28527a33f9eSUwe Kleine-König 
286251e031dSUwe Kleine-König 	kfree(pdev->dev.platform_data);
28737c12e74SRussell King 	pdev->dev.platform_data = d;
288daa41226SAndrew Morton 	return 0;
28937c12e74SRussell King }
29037c12e74SRussell King EXPORT_SYMBOL_GPL(platform_device_add_data);
29137c12e74SRussell King 
29237c12e74SRussell King /**
29337c12e74SRussell King  * platform_device_add - add a platform device to device hierarchy
29467be2dd1SMartin Waitz  * @pdev: platform device we're adding
2951da177e4SLinus Torvalds  *
29637c12e74SRussell King  * This is part 2 of platform_device_register(), though may be called
29737c12e74SRussell King  * separately _iff_ pdev was allocated by platform_device_alloc().
2981da177e4SLinus Torvalds  */
29937c12e74SRussell King int platform_device_add(struct platform_device *pdev)
3001da177e4SLinus Torvalds {
301689ae231SJean Delvare 	int i, ret;
3021da177e4SLinus Torvalds 
3031da177e4SLinus Torvalds 	if (!pdev)
3041da177e4SLinus Torvalds 		return -EINVAL;
3051da177e4SLinus Torvalds 
3061da177e4SLinus Torvalds 	if (!pdev->dev.parent)
3071da177e4SLinus Torvalds 		pdev->dev.parent = &platform_bus;
3081da177e4SLinus Torvalds 
3091da177e4SLinus Torvalds 	pdev->dev.bus = &platform_bus_type;
3101da177e4SLinus Torvalds 
311689ae231SJean Delvare 	switch (pdev->id) {
312689ae231SJean Delvare 	default:
3131e0b2cf9SKay Sievers 		dev_set_name(&pdev->dev, "%s.%d", pdev->name,  pdev->id);
314689ae231SJean Delvare 		break;
315689ae231SJean Delvare 	case PLATFORM_DEVID_NONE:
316acc0e90fSGreg Kroah-Hartman 		dev_set_name(&pdev->dev, "%s", pdev->name);
317689ae231SJean Delvare 		break;
318689ae231SJean Delvare 	case PLATFORM_DEVID_AUTO:
319689ae231SJean Delvare 		/*
320689ae231SJean Delvare 		 * Automatically allocated device ID. We mark it as such so
321689ae231SJean Delvare 		 * that we remember it must be freed, and we append a suffix
322689ae231SJean Delvare 		 * to avoid namespace collision with explicit IDs.
323689ae231SJean Delvare 		 */
324689ae231SJean Delvare 		ret = ida_simple_get(&platform_devid_ida, 0, 0, GFP_KERNEL);
325689ae231SJean Delvare 		if (ret < 0)
326689ae231SJean Delvare 			goto err_out;
327689ae231SJean Delvare 		pdev->id = ret;
328689ae231SJean Delvare 		pdev->id_auto = true;
329689ae231SJean Delvare 		dev_set_name(&pdev->dev, "%s.%d.auto", pdev->name, pdev->id);
330689ae231SJean Delvare 		break;
331689ae231SJean Delvare 	}
3321da177e4SLinus Torvalds 
3331da177e4SLinus Torvalds 	for (i = 0; i < pdev->num_resources; i++) {
3341da177e4SLinus Torvalds 		struct resource *p, *r = &pdev->resource[i];
3351da177e4SLinus Torvalds 
3361da177e4SLinus Torvalds 		if (r->name == NULL)
3371e0b2cf9SKay Sievers 			r->name = dev_name(&pdev->dev);
3381da177e4SLinus Torvalds 
3391da177e4SLinus Torvalds 		p = r->parent;
3401da177e4SLinus Torvalds 		if (!p) {
341c9f66169SMagnus Damm 			if (resource_type(r) == IORESOURCE_MEM)
3421da177e4SLinus Torvalds 				p = &iomem_resource;
343c9f66169SMagnus Damm 			else if (resource_type(r) == IORESOURCE_IO)
3441da177e4SLinus Torvalds 				p = &ioport_resource;
3451da177e4SLinus Torvalds 		}
3461da177e4SLinus Torvalds 
347d960bb4dSKumar Gala 		if (p && insert_resource(p, r)) {
3480258e182SFabio Porcedda 			dev_err(&pdev->dev, "failed to claim resource %d\n", i);
3491da177e4SLinus Torvalds 			ret = -EBUSY;
3501da177e4SLinus Torvalds 			goto failed;
3511da177e4SLinus Torvalds 		}
3521da177e4SLinus Torvalds 	}
3531da177e4SLinus Torvalds 
3541da177e4SLinus Torvalds 	pr_debug("Registering platform device '%s'. Parent at %s\n",
3551e0b2cf9SKay Sievers 		 dev_name(&pdev->dev), dev_name(pdev->dev.parent));
3561da177e4SLinus Torvalds 
357e3915532SRussell King 	ret = device_add(&pdev->dev);
3581da177e4SLinus Torvalds 	if (ret == 0)
3591da177e4SLinus Torvalds 		return ret;
3601da177e4SLinus Torvalds 
3611da177e4SLinus Torvalds  failed:
362689ae231SJean Delvare 	if (pdev->id_auto) {
363689ae231SJean Delvare 		ida_simple_remove(&platform_devid_ida, pdev->id);
364689ae231SJean Delvare 		pdev->id = PLATFORM_DEVID_AUTO;
365689ae231SJean Delvare 	}
366689ae231SJean Delvare 
367c9f66169SMagnus Damm 	while (--i >= 0) {
368c9f66169SMagnus Damm 		struct resource *r = &pdev->resource[i];
369c9f66169SMagnus Damm 		unsigned long type = resource_type(r);
370c9f66169SMagnus Damm 
371c9f66169SMagnus Damm 		if (type == IORESOURCE_MEM || type == IORESOURCE_IO)
372c9f66169SMagnus Damm 			release_resource(r);
373c9f66169SMagnus Damm 	}
374c9f66169SMagnus Damm 
375689ae231SJean Delvare  err_out:
3761da177e4SLinus Torvalds 	return ret;
3771da177e4SLinus Torvalds }
37837c12e74SRussell King EXPORT_SYMBOL_GPL(platform_device_add);
37937c12e74SRussell King 
38037c12e74SRussell King /**
38193ce3061SDmitry Torokhov  * platform_device_del - remove a platform-level device
38293ce3061SDmitry Torokhov  * @pdev: platform device we're removing
38393ce3061SDmitry Torokhov  *
38493ce3061SDmitry Torokhov  * Note that this function will also release all memory- and port-based
3854a3ad20cSGreg Kroah-Hartman  * resources owned by the device (@dev->resource).  This function must
3864a3ad20cSGreg Kroah-Hartman  * _only_ be externally called in error cases.  All other usage is a bug.
38793ce3061SDmitry Torokhov  */
38893ce3061SDmitry Torokhov void platform_device_del(struct platform_device *pdev)
38993ce3061SDmitry Torokhov {
39093ce3061SDmitry Torokhov 	int i;
39193ce3061SDmitry Torokhov 
39293ce3061SDmitry Torokhov 	if (pdev) {
393dc4c15d4SJean Delvare 		device_del(&pdev->dev);
394dc4c15d4SJean Delvare 
395689ae231SJean Delvare 		if (pdev->id_auto) {
396689ae231SJean Delvare 			ida_simple_remove(&platform_devid_ida, pdev->id);
397689ae231SJean Delvare 			pdev->id = PLATFORM_DEVID_AUTO;
398689ae231SJean Delvare 		}
399689ae231SJean Delvare 
40093ce3061SDmitry Torokhov 		for (i = 0; i < pdev->num_resources; i++) {
40193ce3061SDmitry Torokhov 			struct resource *r = &pdev->resource[i];
402c9f66169SMagnus Damm 			unsigned long type = resource_type(r);
403c9f66169SMagnus Damm 
404c9f66169SMagnus Damm 			if (type == IORESOURCE_MEM || type == IORESOURCE_IO)
40593ce3061SDmitry Torokhov 				release_resource(r);
40693ce3061SDmitry Torokhov 		}
40793ce3061SDmitry Torokhov 	}
40893ce3061SDmitry Torokhov }
40993ce3061SDmitry Torokhov EXPORT_SYMBOL_GPL(platform_device_del);
41093ce3061SDmitry Torokhov 
41193ce3061SDmitry Torokhov /**
41237c12e74SRussell King  * platform_device_register - add a platform-level device
41337c12e74SRussell King  * @pdev: platform device we're adding
41437c12e74SRussell King  */
41537c12e74SRussell King int platform_device_register(struct platform_device *pdev)
41637c12e74SRussell King {
41737c12e74SRussell King 	device_initialize(&pdev->dev);
418a77ce816SKumar Gala 	arch_setup_pdev_archdata(pdev);
41937c12e74SRussell King 	return platform_device_add(pdev);
42037c12e74SRussell King }
421a96b2042SDmitry Torokhov EXPORT_SYMBOL_GPL(platform_device_register);
4221da177e4SLinus Torvalds 
4231da177e4SLinus Torvalds /**
42493ce3061SDmitry Torokhov  * platform_device_unregister - unregister a platform-level device
42593ce3061SDmitry Torokhov  * @pdev: platform device we're unregistering
4261da177e4SLinus Torvalds  *
42780682fa9SUwe Zeisberger  * Unregistration is done in 2 steps. First we release all resources
4282d7b5a70SJean Delvare  * and remove it from the subsystem, then we drop reference count by
42993ce3061SDmitry Torokhov  * calling platform_device_put().
4301da177e4SLinus Torvalds  */
4311da177e4SLinus Torvalds void platform_device_unregister(struct platform_device *pdev)
4321da177e4SLinus Torvalds {
43393ce3061SDmitry Torokhov 	platform_device_del(pdev);
43493ce3061SDmitry Torokhov 	platform_device_put(pdev);
4351da177e4SLinus Torvalds }
436a96b2042SDmitry Torokhov EXPORT_SYMBOL_GPL(platform_device_unregister);
4371da177e4SLinus Torvalds 
4381da177e4SLinus Torvalds /**
43901dcc60aSUwe Kleine-König  * platform_device_register_full - add a platform-level device with
44044f28bdeSUwe Kleine-König  * resources and platform-specific data
44144f28bdeSUwe Kleine-König  *
44201dcc60aSUwe Kleine-König  * @pdevinfo: data used to create device
443d8bf2540SDmitry Baryshkov  *
444f0eae0edSJani Nikula  * Returns &struct platform_device pointer on success, or ERR_PTR() on error.
445d8bf2540SDmitry Baryshkov  */
44601dcc60aSUwe Kleine-König struct platform_device *platform_device_register_full(
4475a3072beSUwe Kleine-König 		const struct platform_device_info *pdevinfo)
448d8bf2540SDmitry Baryshkov {
44944f28bdeSUwe Kleine-König 	int ret = -ENOMEM;
450d8bf2540SDmitry Baryshkov 	struct platform_device *pdev;
451d8bf2540SDmitry Baryshkov 
45201dcc60aSUwe Kleine-König 	pdev = platform_device_alloc(pdevinfo->name, pdevinfo->id);
45344f28bdeSUwe Kleine-König 	if (!pdev)
45401dcc60aSUwe Kleine-König 		goto err_alloc;
45501dcc60aSUwe Kleine-König 
45601dcc60aSUwe Kleine-König 	pdev->dev.parent = pdevinfo->parent;
4577b199811SRafael J. Wysocki 	ACPI_COMPANION_SET(&pdev->dev, pdevinfo->acpi_node.companion);
45801dcc60aSUwe Kleine-König 
45901dcc60aSUwe Kleine-König 	if (pdevinfo->dma_mask) {
46001dcc60aSUwe Kleine-König 		/*
46101dcc60aSUwe Kleine-König 		 * This memory isn't freed when the device is put,
46201dcc60aSUwe Kleine-König 		 * I don't have a nice idea for that though.  Conceptually
46301dcc60aSUwe Kleine-König 		 * dma_mask in struct device should not be a pointer.
46401dcc60aSUwe Kleine-König 		 * See http://thread.gmane.org/gmane.linux.kernel.pci/9081
46501dcc60aSUwe Kleine-König 		 */
46601dcc60aSUwe Kleine-König 		pdev->dev.dma_mask =
46701dcc60aSUwe Kleine-König 			kmalloc(sizeof(*pdev->dev.dma_mask), GFP_KERNEL);
46801dcc60aSUwe Kleine-König 		if (!pdev->dev.dma_mask)
46944f28bdeSUwe Kleine-König 			goto err;
470d8bf2540SDmitry Baryshkov 
47101dcc60aSUwe Kleine-König 		*pdev->dev.dma_mask = pdevinfo->dma_mask;
47201dcc60aSUwe Kleine-König 		pdev->dev.coherent_dma_mask = pdevinfo->dma_mask;
47301dcc60aSUwe Kleine-König 	}
474d8bf2540SDmitry Baryshkov 
47501dcc60aSUwe Kleine-König 	ret = platform_device_add_resources(pdev,
47601dcc60aSUwe Kleine-König 			pdevinfo->res, pdevinfo->num_res);
47744f28bdeSUwe Kleine-König 	if (ret)
47844f28bdeSUwe Kleine-König 		goto err;
479d8bf2540SDmitry Baryshkov 
48001dcc60aSUwe Kleine-König 	ret = platform_device_add_data(pdev,
48101dcc60aSUwe Kleine-König 			pdevinfo->data, pdevinfo->size_data);
48244f28bdeSUwe Kleine-König 	if (ret)
48344f28bdeSUwe Kleine-König 		goto err;
48444f28bdeSUwe Kleine-König 
48544f28bdeSUwe Kleine-König 	ret = platform_device_add(pdev);
48644f28bdeSUwe Kleine-König 	if (ret) {
48744f28bdeSUwe Kleine-König err:
4887b199811SRafael J. Wysocki 		ACPI_COMPANION_SET(&pdev->dev, NULL);
48901dcc60aSUwe Kleine-König 		kfree(pdev->dev.dma_mask);
49001dcc60aSUwe Kleine-König 
49101dcc60aSUwe Kleine-König err_alloc:
49244f28bdeSUwe Kleine-König 		platform_device_put(pdev);
49344f28bdeSUwe Kleine-König 		return ERR_PTR(ret);
49444f28bdeSUwe Kleine-König 	}
495d8bf2540SDmitry Baryshkov 
496d8bf2540SDmitry Baryshkov 	return pdev;
497d8bf2540SDmitry Baryshkov }
49801dcc60aSUwe Kleine-König EXPORT_SYMBOL_GPL(platform_device_register_full);
499d8bf2540SDmitry Baryshkov 
50000d3dcddSRussell King static int platform_drv_probe(struct device *_dev)
50100d3dcddSRussell King {
50200d3dcddSRussell King 	struct platform_driver *drv = to_platform_driver(_dev->driver);
50300d3dcddSRussell King 	struct platform_device *dev = to_platform_device(_dev);
50494d76d5dSRafael J. Wysocki 	int ret;
50500d3dcddSRussell King 
50686be408bSSylwester Nawrocki 	ret = of_clk_set_defaults(_dev->of_node, false);
50786be408bSSylwester Nawrocki 	if (ret < 0)
50886be408bSSylwester Nawrocki 		return ret;
50986be408bSSylwester Nawrocki 
510cb518413SUlf Hansson 	ret = dev_pm_domain_attach(_dev, true);
511cb518413SUlf Hansson 	if (ret != -EPROBE_DEFER) {
51294d76d5dSRafael J. Wysocki 		ret = drv->probe(dev);
5139383f4c6SJosh Cartwright 		if (ret)
514cb518413SUlf Hansson 			dev_pm_domain_detach(_dev, true);
515cb518413SUlf Hansson 	}
51694d76d5dSRafael J. Wysocki 
5173f9120b0SJohan Hovold 	if (drv->prevent_deferred_probe && ret == -EPROBE_DEFER) {
5183f9120b0SJohan Hovold 		dev_warn(_dev, "probe deferral not supported\n");
5193f9120b0SJohan Hovold 		ret = -ENXIO;
5203f9120b0SJohan Hovold 	}
5213f9120b0SJohan Hovold 
52294d76d5dSRafael J. Wysocki 	return ret;
52300d3dcddSRussell King }
52400d3dcddSRussell King 
525c67334fbSDavid Brownell static int platform_drv_probe_fail(struct device *_dev)
526c67334fbSDavid Brownell {
527c67334fbSDavid Brownell 	return -ENXIO;
528c67334fbSDavid Brownell }
529c67334fbSDavid Brownell 
53000d3dcddSRussell King static int platform_drv_remove(struct device *_dev)
53100d3dcddSRussell King {
53200d3dcddSRussell King 	struct platform_driver *drv = to_platform_driver(_dev->driver);
53300d3dcddSRussell King 	struct platform_device *dev = to_platform_device(_dev);
53494d76d5dSRafael J. Wysocki 	int ret;
53500d3dcddSRussell King 
53694d76d5dSRafael J. Wysocki 	ret = drv->remove(dev);
537cb518413SUlf Hansson 	dev_pm_domain_detach(_dev, true);
53894d76d5dSRafael J. Wysocki 
53994d76d5dSRafael J. Wysocki 	return ret;
54000d3dcddSRussell King }
54100d3dcddSRussell King 
54200d3dcddSRussell King static void platform_drv_shutdown(struct device *_dev)
54300d3dcddSRussell King {
54400d3dcddSRussell King 	struct platform_driver *drv = to_platform_driver(_dev->driver);
54500d3dcddSRussell King 	struct platform_device *dev = to_platform_device(_dev);
54600d3dcddSRussell King 
54700d3dcddSRussell King 	drv->shutdown(dev);
548cb518413SUlf Hansson 	dev_pm_domain_detach(_dev, true);
54900d3dcddSRussell King }
55000d3dcddSRussell King 
55100d3dcddSRussell King /**
5529447057eSLibo Chen  * __platform_driver_register - register a driver for platform-level devices
55300d3dcddSRussell King  * @drv: platform driver structure
55408801f96SRandy Dunlap  * @owner: owning module/driver
55500d3dcddSRussell King  */
5569447057eSLibo Chen int __platform_driver_register(struct platform_driver *drv,
5579447057eSLibo Chen 				struct module *owner)
55800d3dcddSRussell King {
5599447057eSLibo Chen 	drv->driver.owner = owner;
56000d3dcddSRussell King 	drv->driver.bus = &platform_bus_type;
56100d3dcddSRussell King 	if (drv->probe)
56200d3dcddSRussell King 		drv->driver.probe = platform_drv_probe;
56300d3dcddSRussell King 	if (drv->remove)
56400d3dcddSRussell King 		drv->driver.remove = platform_drv_remove;
56500d3dcddSRussell King 	if (drv->shutdown)
56600d3dcddSRussell King 		drv->driver.shutdown = platform_drv_shutdown;
567783ea7d4SMagnus Damm 
56800d3dcddSRussell King 	return driver_register(&drv->driver);
56900d3dcddSRussell King }
5709447057eSLibo Chen EXPORT_SYMBOL_GPL(__platform_driver_register);
57100d3dcddSRussell King 
57200d3dcddSRussell King /**
5733c31f07aSBen Hutchings  * platform_driver_unregister - unregister a driver for platform-level devices
57400d3dcddSRussell King  * @drv: platform driver structure
57500d3dcddSRussell King  */
57600d3dcddSRussell King void platform_driver_unregister(struct platform_driver *drv)
57700d3dcddSRussell King {
57800d3dcddSRussell King 	driver_unregister(&drv->driver);
57900d3dcddSRussell King }
58000d3dcddSRussell King EXPORT_SYMBOL_GPL(platform_driver_unregister);
58100d3dcddSRussell King 
582c67334fbSDavid Brownell /**
583c67334fbSDavid Brownell  * platform_driver_probe - register driver for non-hotpluggable device
584c67334fbSDavid Brownell  * @drv: platform driver structure
5853f9120b0SJohan Hovold  * @probe: the driver probe routine, probably from an __init section
586c67334fbSDavid Brownell  *
587c67334fbSDavid Brownell  * Use this instead of platform_driver_register() when you know the device
588c67334fbSDavid Brownell  * is not hotpluggable and has already been registered, and you want to
589c67334fbSDavid Brownell  * remove its run-once probe() infrastructure from memory after the driver
590c67334fbSDavid Brownell  * has bound to the device.
591c67334fbSDavid Brownell  *
592c67334fbSDavid Brownell  * One typical use for this would be with drivers for controllers integrated
593c67334fbSDavid Brownell  * into system-on-chip processors, where the controller devices have been
594c67334fbSDavid Brownell  * configured as part of board setup.
595c67334fbSDavid Brownell  *
5963f9120b0SJohan Hovold  * Note that this is incompatible with deferred probing.
597647c86d0SFabio Porcedda  *
598c67334fbSDavid Brownell  * Returns zero if the driver registered and bound to a device, else returns
599c67334fbSDavid Brownell  * a negative error code and with the driver not registered.
600c67334fbSDavid Brownell  */
601c63e0783SAndrew Morton int __init_or_module platform_driver_probe(struct platform_driver *drv,
602c67334fbSDavid Brownell 		int (*probe)(struct platform_device *))
603c67334fbSDavid Brownell {
604c67334fbSDavid Brownell 	int retval, code;
605c67334fbSDavid Brownell 
6063f9120b0SJohan Hovold 	/*
6073f9120b0SJohan Hovold 	 * Prevent driver from requesting probe deferral to avoid further
6083f9120b0SJohan Hovold 	 * futile probe attempts.
6093f9120b0SJohan Hovold 	 */
6103f9120b0SJohan Hovold 	drv->prevent_deferred_probe = true;
6113f9120b0SJohan Hovold 
6121a6f2a75SDmitry Torokhov 	/* make sure driver won't have bind/unbind attributes */
6131a6f2a75SDmitry Torokhov 	drv->driver.suppress_bind_attrs = true;
6141a6f2a75SDmitry Torokhov 
615c67334fbSDavid Brownell 	/* temporary section violation during probe() */
616c67334fbSDavid Brownell 	drv->probe = probe;
617c67334fbSDavid Brownell 	retval = code = platform_driver_register(drv);
618c67334fbSDavid Brownell 
6191a6f2a75SDmitry Torokhov 	/*
6201a6f2a75SDmitry Torokhov 	 * Fixup that section violation, being paranoid about code scanning
621c67334fbSDavid Brownell 	 * the list of drivers in order to probe new devices.  Check to see
622c67334fbSDavid Brownell 	 * if the probe was successful, and make sure any forced probes of
623c67334fbSDavid Brownell 	 * new devices fail.
624c67334fbSDavid Brownell 	 */
625d79d3244SPatrick Pannuto 	spin_lock(&drv->driver.bus->p->klist_drivers.k_lock);
626c67334fbSDavid Brownell 	drv->probe = NULL;
627e5dd1278SGreg Kroah-Hartman 	if (code == 0 && list_empty(&drv->driver.p->klist_devices.k_list))
628c67334fbSDavid Brownell 		retval = -ENODEV;
629c67334fbSDavid Brownell 	drv->driver.probe = platform_drv_probe_fail;
630d79d3244SPatrick Pannuto 	spin_unlock(&drv->driver.bus->p->klist_drivers.k_lock);
631c67334fbSDavid Brownell 
632c67334fbSDavid Brownell 	if (code != retval)
633c67334fbSDavid Brownell 		platform_driver_unregister(drv);
634c67334fbSDavid Brownell 	return retval;
635c67334fbSDavid Brownell }
636c67334fbSDavid Brownell EXPORT_SYMBOL_GPL(platform_driver_probe);
6371da177e4SLinus Torvalds 
638ecdf6cebSDmitry Torokhov /**
639ecdf6cebSDmitry Torokhov  * platform_create_bundle - register driver and create corresponding device
640ecdf6cebSDmitry Torokhov  * @driver: platform driver structure
641ecdf6cebSDmitry Torokhov  * @probe: the driver probe routine, probably from an __init section
642ecdf6cebSDmitry Torokhov  * @res: set of resources that needs to be allocated for the device
643ecdf6cebSDmitry Torokhov  * @n_res: number of resources
644ecdf6cebSDmitry Torokhov  * @data: platform specific data for this platform device
645ecdf6cebSDmitry Torokhov  * @size: size of platform specific data
646ecdf6cebSDmitry Torokhov  *
647ecdf6cebSDmitry Torokhov  * Use this in legacy-style modules that probe hardware directly and
648ecdf6cebSDmitry Torokhov  * register a single platform device and corresponding platform driver.
649f0eae0edSJani Nikula  *
650f0eae0edSJani Nikula  * Returns &struct platform_device pointer on success, or ERR_PTR() on error.
651ecdf6cebSDmitry Torokhov  */
652ecdf6cebSDmitry Torokhov struct platform_device * __init_or_module platform_create_bundle(
653ecdf6cebSDmitry Torokhov 			struct platform_driver *driver,
654ecdf6cebSDmitry Torokhov 			int (*probe)(struct platform_device *),
655ecdf6cebSDmitry Torokhov 			struct resource *res, unsigned int n_res,
656ecdf6cebSDmitry Torokhov 			const void *data, size_t size)
657ecdf6cebSDmitry Torokhov {
658ecdf6cebSDmitry Torokhov 	struct platform_device *pdev;
659ecdf6cebSDmitry Torokhov 	int error;
660ecdf6cebSDmitry Torokhov 
661ecdf6cebSDmitry Torokhov 	pdev = platform_device_alloc(driver->driver.name, -1);
662ecdf6cebSDmitry Torokhov 	if (!pdev) {
663ecdf6cebSDmitry Torokhov 		error = -ENOMEM;
664ecdf6cebSDmitry Torokhov 		goto err_out;
665ecdf6cebSDmitry Torokhov 	}
666ecdf6cebSDmitry Torokhov 
667ecdf6cebSDmitry Torokhov 	error = platform_device_add_resources(pdev, res, n_res);
668ecdf6cebSDmitry Torokhov 	if (error)
669ecdf6cebSDmitry Torokhov 		goto err_pdev_put;
670ecdf6cebSDmitry Torokhov 
671ecdf6cebSDmitry Torokhov 	error = platform_device_add_data(pdev, data, size);
672ecdf6cebSDmitry Torokhov 	if (error)
673ecdf6cebSDmitry Torokhov 		goto err_pdev_put;
674ecdf6cebSDmitry Torokhov 
675ecdf6cebSDmitry Torokhov 	error = platform_device_add(pdev);
676ecdf6cebSDmitry Torokhov 	if (error)
677ecdf6cebSDmitry Torokhov 		goto err_pdev_put;
678ecdf6cebSDmitry Torokhov 
679ecdf6cebSDmitry Torokhov 	error = platform_driver_probe(driver, probe);
680ecdf6cebSDmitry Torokhov 	if (error)
681ecdf6cebSDmitry Torokhov 		goto err_pdev_del;
682ecdf6cebSDmitry Torokhov 
683ecdf6cebSDmitry Torokhov 	return pdev;
684ecdf6cebSDmitry Torokhov 
685ecdf6cebSDmitry Torokhov err_pdev_del:
686ecdf6cebSDmitry Torokhov 	platform_device_del(pdev);
687ecdf6cebSDmitry Torokhov err_pdev_put:
688ecdf6cebSDmitry Torokhov 	platform_device_put(pdev);
689ecdf6cebSDmitry Torokhov err_out:
690ecdf6cebSDmitry Torokhov 	return ERR_PTR(error);
691ecdf6cebSDmitry Torokhov }
692ecdf6cebSDmitry Torokhov EXPORT_SYMBOL_GPL(platform_create_bundle);
693ecdf6cebSDmitry Torokhov 
694a0245f7aSDavid Brownell /* modalias support enables more hands-off userspace setup:
695a0245f7aSDavid Brownell  * (a) environment variable lets new-style hotplug events work once system is
696a0245f7aSDavid Brownell  *     fully running:  "modprobe $MODALIAS"
697a0245f7aSDavid Brownell  * (b) sysfs attribute lets new-style coldplug recover from hotplug events
698a0245f7aSDavid Brownell  *     mishandled before system is fully running:  "modprobe $(cat modalias)"
699a0245f7aSDavid Brownell  */
7004a3ad20cSGreg Kroah-Hartman static ssize_t modalias_show(struct device *dev, struct device_attribute *a,
7014a3ad20cSGreg Kroah-Hartman 			     char *buf)
702a0245f7aSDavid Brownell {
703a0245f7aSDavid Brownell 	struct platform_device	*pdev = to_platform_device(dev);
7048c4ff6d0SZhang Rui 	int len;
7058c4ff6d0SZhang Rui 
706b9f73067SZhang Rui 	len = of_device_get_modalias(dev, buf, PAGE_SIZE -1);
707b9f73067SZhang Rui 	if (len != -ENODEV)
708b9f73067SZhang Rui 		return len;
709b9f73067SZhang Rui 
7108c4ff6d0SZhang Rui 	len = acpi_device_modalias(dev, buf, PAGE_SIZE -1);
7118c4ff6d0SZhang Rui 	if (len != -ENODEV)
7128c4ff6d0SZhang Rui 		return len;
7138c4ff6d0SZhang Rui 
7148c4ff6d0SZhang Rui 	len = snprintf(buf, PAGE_SIZE, "platform:%s\n", pdev->name);
715a0245f7aSDavid Brownell 
716a0245f7aSDavid Brownell 	return (len >= PAGE_SIZE) ? (PAGE_SIZE - 1) : len;
717a0245f7aSDavid Brownell }
718d06262e5SGreg Kroah-Hartman static DEVICE_ATTR_RO(modalias);
719a0245f7aSDavid Brownell 
7203d713e0eSKim Phillips static ssize_t driver_override_store(struct device *dev,
7213d713e0eSKim Phillips 				     struct device_attribute *attr,
7223d713e0eSKim Phillips 				     const char *buf, size_t count)
7233d713e0eSKim Phillips {
7243d713e0eSKim Phillips 	struct platform_device *pdev = to_platform_device(dev);
7253d713e0eSKim Phillips 	char *driver_override, *old = pdev->driver_override, *cp;
7263d713e0eSKim Phillips 
7273d713e0eSKim Phillips 	if (count > PATH_MAX)
7283d713e0eSKim Phillips 		return -EINVAL;
7293d713e0eSKim Phillips 
7303d713e0eSKim Phillips 	driver_override = kstrndup(buf, count, GFP_KERNEL);
7313d713e0eSKim Phillips 	if (!driver_override)
7323d713e0eSKim Phillips 		return -ENOMEM;
7333d713e0eSKim Phillips 
7343d713e0eSKim Phillips 	cp = strchr(driver_override, '\n');
7353d713e0eSKim Phillips 	if (cp)
7363d713e0eSKim Phillips 		*cp = '\0';
7373d713e0eSKim Phillips 
7383d713e0eSKim Phillips 	if (strlen(driver_override)) {
7393d713e0eSKim Phillips 		pdev->driver_override = driver_override;
7403d713e0eSKim Phillips 	} else {
7413d713e0eSKim Phillips 		kfree(driver_override);
7423d713e0eSKim Phillips 		pdev->driver_override = NULL;
7433d713e0eSKim Phillips 	}
7443d713e0eSKim Phillips 
7453d713e0eSKim Phillips 	kfree(old);
7463d713e0eSKim Phillips 
7473d713e0eSKim Phillips 	return count;
7483d713e0eSKim Phillips }
7493d713e0eSKim Phillips 
7503d713e0eSKim Phillips static ssize_t driver_override_show(struct device *dev,
7513d713e0eSKim Phillips 				    struct device_attribute *attr, char *buf)
7523d713e0eSKim Phillips {
7533d713e0eSKim Phillips 	struct platform_device *pdev = to_platform_device(dev);
7543d713e0eSKim Phillips 
7553d713e0eSKim Phillips 	return sprintf(buf, "%s\n", pdev->driver_override);
7563d713e0eSKim Phillips }
7573d713e0eSKim Phillips static DEVICE_ATTR_RW(driver_override);
7583d713e0eSKim Phillips 
7593d713e0eSKim Phillips 
760d06262e5SGreg Kroah-Hartman static struct attribute *platform_dev_attrs[] = {
761d06262e5SGreg Kroah-Hartman 	&dev_attr_modalias.attr,
7623d713e0eSKim Phillips 	&dev_attr_driver_override.attr,
763d06262e5SGreg Kroah-Hartman 	NULL,
764a0245f7aSDavid Brownell };
765d06262e5SGreg Kroah-Hartman ATTRIBUTE_GROUPS(platform_dev);
766a0245f7aSDavid Brownell 
7677eff2e7aSKay Sievers static int platform_uevent(struct device *dev, struct kobj_uevent_env *env)
768a0245f7aSDavid Brownell {
769a0245f7aSDavid Brownell 	struct platform_device	*pdev = to_platform_device(dev);
770eca39301SGrant Likely 	int rc;
771eca39301SGrant Likely 
772eca39301SGrant Likely 	/* Some devices have extra OF data and an OF-style MODALIAS */
77307d57a32SGrant Likely 	rc = of_device_uevent_modalias(dev, env);
774eca39301SGrant Likely 	if (rc != -ENODEV)
775eca39301SGrant Likely 		return rc;
776a0245f7aSDavid Brownell 
7778c4ff6d0SZhang Rui 	rc = acpi_device_uevent_modalias(dev, env);
7788c4ff6d0SZhang Rui 	if (rc != -ENODEV)
7798c4ff6d0SZhang Rui 		return rc;
7808c4ff6d0SZhang Rui 
78157fee4a5SEric Miao 	add_uevent_var(env, "MODALIAS=%s%s", PLATFORM_MODULE_PREFIX,
7820a26813cSSebastian Andrzej Siewior 			pdev->name);
783a0245f7aSDavid Brownell 	return 0;
784a0245f7aSDavid Brownell }
785a0245f7aSDavid Brownell 
78657fee4a5SEric Miao static const struct platform_device_id *platform_match_id(
787831fad2fSUwe Kleine-König 			const struct platform_device_id *id,
78857fee4a5SEric Miao 			struct platform_device *pdev)
78957fee4a5SEric Miao {
79057fee4a5SEric Miao 	while (id->name[0]) {
79157fee4a5SEric Miao 		if (strcmp(pdev->name, id->name) == 0) {
79257fee4a5SEric Miao 			pdev->id_entry = id;
79357fee4a5SEric Miao 			return id;
79457fee4a5SEric Miao 		}
79557fee4a5SEric Miao 		id++;
79657fee4a5SEric Miao 	}
79757fee4a5SEric Miao 	return NULL;
79857fee4a5SEric Miao }
79957fee4a5SEric Miao 
8001da177e4SLinus Torvalds /**
8011da177e4SLinus Torvalds  * platform_match - bind platform device to platform driver.
8021da177e4SLinus Torvalds  * @dev: device.
8031da177e4SLinus Torvalds  * @drv: driver.
8041da177e4SLinus Torvalds  *
8051da177e4SLinus Torvalds  * Platform device IDs are assumed to be encoded like this:
8064a3ad20cSGreg Kroah-Hartman  * "<name><instance>", where <name> is a short description of the type of
8074a3ad20cSGreg Kroah-Hartman  * device, like "pci" or "floppy", and <instance> is the enumerated
8084a3ad20cSGreg Kroah-Hartman  * instance of the device, like '0' or '42'.  Driver IDs are simply
8094a3ad20cSGreg Kroah-Hartman  * "<name>".  So, extract the <name> from the platform_device structure,
8104a3ad20cSGreg Kroah-Hartman  * and compare it against the name of the driver. Return whether they match
8114a3ad20cSGreg Kroah-Hartman  * or not.
8121da177e4SLinus Torvalds  */
8131da177e4SLinus Torvalds static int platform_match(struct device *dev, struct device_driver *drv)
8141da177e4SLinus Torvalds {
81571b3e0c1SEric Miao 	struct platform_device *pdev = to_platform_device(dev);
81657fee4a5SEric Miao 	struct platform_driver *pdrv = to_platform_driver(drv);
8171da177e4SLinus Torvalds 
8183d713e0eSKim Phillips 	/* When driver_override is set, only bind to the matching driver */
8193d713e0eSKim Phillips 	if (pdev->driver_override)
8203d713e0eSKim Phillips 		return !strcmp(pdev->driver_override, drv->name);
8213d713e0eSKim Phillips 
82205212157SGrant Likely 	/* Attempt an OF style match first */
82305212157SGrant Likely 	if (of_driver_match_device(dev, drv))
82405212157SGrant Likely 		return 1;
82505212157SGrant Likely 
82691e56878SMika Westerberg 	/* Then try ACPI style match */
82791e56878SMika Westerberg 	if (acpi_driver_match_device(dev, drv))
82891e56878SMika Westerberg 		return 1;
82991e56878SMika Westerberg 
83005212157SGrant Likely 	/* Then try to match against the id table */
83157fee4a5SEric Miao 	if (pdrv->id_table)
83257fee4a5SEric Miao 		return platform_match_id(pdrv->id_table, pdev) != NULL;
83357fee4a5SEric Miao 
83457fee4a5SEric Miao 	/* fall-back to driver name match */
8351e0b2cf9SKay Sievers 	return (strcmp(pdev->name, drv->name) == 0);
8361da177e4SLinus Torvalds }
8371da177e4SLinus Torvalds 
83825e18499SRafael J. Wysocki #ifdef CONFIG_PM_SLEEP
83925e18499SRafael J. Wysocki 
84025e18499SRafael J. Wysocki static int platform_legacy_suspend(struct device *dev, pm_message_t mesg)
8411da177e4SLinus Torvalds {
842783ea7d4SMagnus Damm 	struct platform_driver *pdrv = to_platform_driver(dev->driver);
843783ea7d4SMagnus Damm 	struct platform_device *pdev = to_platform_device(dev);
8441da177e4SLinus Torvalds 	int ret = 0;
8451da177e4SLinus Torvalds 
846783ea7d4SMagnus Damm 	if (dev->driver && pdrv->suspend)
847783ea7d4SMagnus Damm 		ret = pdrv->suspend(pdev, mesg);
848386415d8SDavid Brownell 
849386415d8SDavid Brownell 	return ret;
850386415d8SDavid Brownell }
851386415d8SDavid Brownell 
85225e18499SRafael J. Wysocki static int platform_legacy_resume(struct device *dev)
8531da177e4SLinus Torvalds {
854783ea7d4SMagnus Damm 	struct platform_driver *pdrv = to_platform_driver(dev->driver);
855783ea7d4SMagnus Damm 	struct platform_device *pdev = to_platform_device(dev);
8561da177e4SLinus Torvalds 	int ret = 0;
8571da177e4SLinus Torvalds 
858783ea7d4SMagnus Damm 	if (dev->driver && pdrv->resume)
859783ea7d4SMagnus Damm 		ret = pdrv->resume(pdev);
8609480e307SRussell King 
8611da177e4SLinus Torvalds 	return ret;
8621da177e4SLinus Torvalds }
8631da177e4SLinus Torvalds 
86469c9dd1eSRafael J. Wysocki #endif /* CONFIG_PM_SLEEP */
8659d730229SMagnus Damm 
86625e18499SRafael J. Wysocki #ifdef CONFIG_SUSPEND
86725e18499SRafael J. Wysocki 
86869c9dd1eSRafael J. Wysocki int platform_pm_suspend(struct device *dev)
86925e18499SRafael J. Wysocki {
87025e18499SRafael J. Wysocki 	struct device_driver *drv = dev->driver;
87125e18499SRafael J. Wysocki 	int ret = 0;
87225e18499SRafael J. Wysocki 
873adf09493SRafael J. Wysocki 	if (!drv)
874adf09493SRafael J. Wysocki 		return 0;
875adf09493SRafael J. Wysocki 
876adf09493SRafael J. Wysocki 	if (drv->pm) {
87725e18499SRafael J. Wysocki 		if (drv->pm->suspend)
87825e18499SRafael J. Wysocki 			ret = drv->pm->suspend(dev);
87925e18499SRafael J. Wysocki 	} else {
88025e18499SRafael J. Wysocki 		ret = platform_legacy_suspend(dev, PMSG_SUSPEND);
88125e18499SRafael J. Wysocki 	}
88225e18499SRafael J. Wysocki 
88325e18499SRafael J. Wysocki 	return ret;
88425e18499SRafael J. Wysocki }
88525e18499SRafael J. Wysocki 
88669c9dd1eSRafael J. Wysocki int platform_pm_resume(struct device *dev)
88725e18499SRafael J. Wysocki {
88825e18499SRafael J. Wysocki 	struct device_driver *drv = dev->driver;
88925e18499SRafael J. Wysocki 	int ret = 0;
89025e18499SRafael J. Wysocki 
891adf09493SRafael J. Wysocki 	if (!drv)
892adf09493SRafael J. Wysocki 		return 0;
893adf09493SRafael J. Wysocki 
894adf09493SRafael J. Wysocki 	if (drv->pm) {
89525e18499SRafael J. Wysocki 		if (drv->pm->resume)
89625e18499SRafael J. Wysocki 			ret = drv->pm->resume(dev);
89725e18499SRafael J. Wysocki 	} else {
89825e18499SRafael J. Wysocki 		ret = platform_legacy_resume(dev);
89925e18499SRafael J. Wysocki 	}
90025e18499SRafael J. Wysocki 
90125e18499SRafael J. Wysocki 	return ret;
90225e18499SRafael J. Wysocki }
90325e18499SRafael J. Wysocki 
90469c9dd1eSRafael J. Wysocki #endif /* CONFIG_SUSPEND */
90525e18499SRafael J. Wysocki 
9061f112ceeSRafael J. Wysocki #ifdef CONFIG_HIBERNATE_CALLBACKS
90725e18499SRafael J. Wysocki 
90869c9dd1eSRafael J. Wysocki int platform_pm_freeze(struct device *dev)
90925e18499SRafael J. Wysocki {
91025e18499SRafael J. Wysocki 	struct device_driver *drv = dev->driver;
91125e18499SRafael J. Wysocki 	int ret = 0;
91225e18499SRafael J. Wysocki 
91325e18499SRafael J. Wysocki 	if (!drv)
91425e18499SRafael J. Wysocki 		return 0;
91525e18499SRafael J. Wysocki 
91625e18499SRafael J. Wysocki 	if (drv->pm) {
91725e18499SRafael J. Wysocki 		if (drv->pm->freeze)
91825e18499SRafael J. Wysocki 			ret = drv->pm->freeze(dev);
91925e18499SRafael J. Wysocki 	} else {
92025e18499SRafael J. Wysocki 		ret = platform_legacy_suspend(dev, PMSG_FREEZE);
92125e18499SRafael J. Wysocki 	}
92225e18499SRafael J. Wysocki 
92325e18499SRafael J. Wysocki 	return ret;
92425e18499SRafael J. Wysocki }
92525e18499SRafael J. Wysocki 
92669c9dd1eSRafael J. Wysocki int platform_pm_thaw(struct device *dev)
92725e18499SRafael J. Wysocki {
92825e18499SRafael J. Wysocki 	struct device_driver *drv = dev->driver;
92925e18499SRafael J. Wysocki 	int ret = 0;
93025e18499SRafael J. Wysocki 
931adf09493SRafael J. Wysocki 	if (!drv)
932adf09493SRafael J. Wysocki 		return 0;
933adf09493SRafael J. Wysocki 
934adf09493SRafael J. Wysocki 	if (drv->pm) {
93525e18499SRafael J. Wysocki 		if (drv->pm->thaw)
93625e18499SRafael J. Wysocki 			ret = drv->pm->thaw(dev);
93725e18499SRafael J. Wysocki 	} else {
93825e18499SRafael J. Wysocki 		ret = platform_legacy_resume(dev);
93925e18499SRafael J. Wysocki 	}
94025e18499SRafael J. Wysocki 
94125e18499SRafael J. Wysocki 	return ret;
94225e18499SRafael J. Wysocki }
94325e18499SRafael J. Wysocki 
94469c9dd1eSRafael J. Wysocki int platform_pm_poweroff(struct device *dev)
94525e18499SRafael J. Wysocki {
94625e18499SRafael J. Wysocki 	struct device_driver *drv = dev->driver;
94725e18499SRafael J. Wysocki 	int ret = 0;
94825e18499SRafael J. Wysocki 
949adf09493SRafael J. Wysocki 	if (!drv)
950adf09493SRafael J. Wysocki 		return 0;
951adf09493SRafael J. Wysocki 
952adf09493SRafael J. Wysocki 	if (drv->pm) {
95325e18499SRafael J. Wysocki 		if (drv->pm->poweroff)
95425e18499SRafael J. Wysocki 			ret = drv->pm->poweroff(dev);
95525e18499SRafael J. Wysocki 	} else {
95625e18499SRafael J. Wysocki 		ret = platform_legacy_suspend(dev, PMSG_HIBERNATE);
95725e18499SRafael J. Wysocki 	}
95825e18499SRafael J. Wysocki 
95925e18499SRafael J. Wysocki 	return ret;
96025e18499SRafael J. Wysocki }
96125e18499SRafael J. Wysocki 
96269c9dd1eSRafael J. Wysocki int platform_pm_restore(struct device *dev)
96325e18499SRafael J. Wysocki {
96425e18499SRafael J. Wysocki 	struct device_driver *drv = dev->driver;
96525e18499SRafael J. Wysocki 	int ret = 0;
96625e18499SRafael J. Wysocki 
967adf09493SRafael J. Wysocki 	if (!drv)
968adf09493SRafael J. Wysocki 		return 0;
969adf09493SRafael J. Wysocki 
970adf09493SRafael J. Wysocki 	if (drv->pm) {
97125e18499SRafael J. Wysocki 		if (drv->pm->restore)
97225e18499SRafael J. Wysocki 			ret = drv->pm->restore(dev);
97325e18499SRafael J. Wysocki 	} else {
97425e18499SRafael J. Wysocki 		ret = platform_legacy_resume(dev);
97525e18499SRafael J. Wysocki 	}
97625e18499SRafael J. Wysocki 
97725e18499SRafael J. Wysocki 	return ret;
97825e18499SRafael J. Wysocki }
97925e18499SRafael J. Wysocki 
98069c9dd1eSRafael J. Wysocki #endif /* CONFIG_HIBERNATE_CALLBACKS */
98125e18499SRafael J. Wysocki 
982d9ab7716SDmitry Torokhov static const struct dev_pm_ops platform_dev_pm_ops = {
9838b313a38SRafael J. Wysocki 	.runtime_suspend = pm_generic_runtime_suspend,
9848b313a38SRafael J. Wysocki 	.runtime_resume = pm_generic_runtime_resume,
98569c9dd1eSRafael J. Wysocki 	USE_PLATFORM_PM_SLEEP_OPS
98625e18499SRafael J. Wysocki };
98725e18499SRafael J. Wysocki 
9881da177e4SLinus Torvalds struct bus_type platform_bus_type = {
9891da177e4SLinus Torvalds 	.name		= "platform",
990d06262e5SGreg Kroah-Hartman 	.dev_groups	= platform_dev_groups,
9911da177e4SLinus Torvalds 	.match		= platform_match,
992a0245f7aSDavid Brownell 	.uevent		= platform_uevent,
9939d730229SMagnus Damm 	.pm		= &platform_dev_pm_ops,
9941da177e4SLinus Torvalds };
995a96b2042SDmitry Torokhov EXPORT_SYMBOL_GPL(platform_bus_type);
9961da177e4SLinus Torvalds 
9971da177e4SLinus Torvalds int __init platform_bus_init(void)
9981da177e4SLinus Torvalds {
999fbfb1445SCornelia Huck 	int error;
1000fbfb1445SCornelia Huck 
100113977091SMagnus Damm 	early_platform_cleanup();
100213977091SMagnus Damm 
1003fbfb1445SCornelia Huck 	error = device_register(&platform_bus);
1004fbfb1445SCornelia Huck 	if (error)
1005fbfb1445SCornelia Huck 		return error;
1006fbfb1445SCornelia Huck 	error =  bus_register(&platform_bus_type);
1007fbfb1445SCornelia Huck 	if (error)
1008fbfb1445SCornelia Huck 		device_unregister(&platform_bus);
1009fbfb1445SCornelia Huck 	return error;
10101da177e4SLinus Torvalds }
10111da177e4SLinus Torvalds 
10121da177e4SLinus Torvalds #ifndef ARCH_HAS_DMA_GET_REQUIRED_MASK
10131da177e4SLinus Torvalds u64 dma_get_required_mask(struct device *dev)
10141da177e4SLinus Torvalds {
10151da177e4SLinus Torvalds 	u32 low_totalram = ((max_pfn - 1) << PAGE_SHIFT);
10161da177e4SLinus Torvalds 	u32 high_totalram = ((max_pfn - 1) >> (32 - PAGE_SHIFT));
10171da177e4SLinus Torvalds 	u64 mask;
10181da177e4SLinus Torvalds 
10191da177e4SLinus Torvalds 	if (!high_totalram) {
10201da177e4SLinus Torvalds 		/* convert to mask just covering totalram */
10211da177e4SLinus Torvalds 		low_totalram = (1 << (fls(low_totalram) - 1));
10221da177e4SLinus Torvalds 		low_totalram += low_totalram - 1;
10231da177e4SLinus Torvalds 		mask = low_totalram;
10241da177e4SLinus Torvalds 	} else {
10251da177e4SLinus Torvalds 		high_totalram = (1 << (fls(high_totalram) - 1));
10261da177e4SLinus Torvalds 		high_totalram += high_totalram - 1;
10271da177e4SLinus Torvalds 		mask = (((u64)high_totalram) << 32) + 0xffffffff;
10281da177e4SLinus Torvalds 	}
1029e88a0c2cSJames Bottomley 	return mask;
10301da177e4SLinus Torvalds }
10311da177e4SLinus Torvalds EXPORT_SYMBOL_GPL(dma_get_required_mask);
10321da177e4SLinus Torvalds #endif
103313977091SMagnus Damm 
103413977091SMagnus Damm static __initdata LIST_HEAD(early_platform_driver_list);
103513977091SMagnus Damm static __initdata LIST_HEAD(early_platform_device_list);
103613977091SMagnus Damm 
103713977091SMagnus Damm /**
10384d26e139SMagnus Damm  * early_platform_driver_register - register early platform driver
1039d86c1302SRandy Dunlap  * @epdrv: early_platform driver structure
104013977091SMagnus Damm  * @buf: string passed from early_param()
10414d26e139SMagnus Damm  *
10424d26e139SMagnus Damm  * Helper function for early_platform_init() / early_platform_init_buffer()
104313977091SMagnus Damm  */
104413977091SMagnus Damm int __init early_platform_driver_register(struct early_platform_driver *epdrv,
104513977091SMagnus Damm 					  char *buf)
104613977091SMagnus Damm {
1047c60e0504SMagnus Damm 	char *tmp;
104813977091SMagnus Damm 	int n;
104913977091SMagnus Damm 
105013977091SMagnus Damm 	/* Simply add the driver to the end of the global list.
105113977091SMagnus Damm 	 * Drivers will by default be put on the list in compiled-in order.
105213977091SMagnus Damm 	 */
105313977091SMagnus Damm 	if (!epdrv->list.next) {
105413977091SMagnus Damm 		INIT_LIST_HEAD(&epdrv->list);
105513977091SMagnus Damm 		list_add_tail(&epdrv->list, &early_platform_driver_list);
105613977091SMagnus Damm 	}
105713977091SMagnus Damm 
105813977091SMagnus Damm 	/* If the user has specified device then make sure the driver
105913977091SMagnus Damm 	 * gets prioritized. The driver of the last device specified on
106013977091SMagnus Damm 	 * command line will be put first on the list.
106113977091SMagnus Damm 	 */
106213977091SMagnus Damm 	n = strlen(epdrv->pdrv->driver.name);
106313977091SMagnus Damm 	if (buf && !strncmp(buf, epdrv->pdrv->driver.name, n)) {
106413977091SMagnus Damm 		list_move(&epdrv->list, &early_platform_driver_list);
106513977091SMagnus Damm 
1066c60e0504SMagnus Damm 		/* Allow passing parameters after device name */
1067c60e0504SMagnus Damm 		if (buf[n] == '\0' || buf[n] == ',')
106813977091SMagnus Damm 			epdrv->requested_id = -1;
1069c60e0504SMagnus Damm 		else {
1070c60e0504SMagnus Damm 			epdrv->requested_id = simple_strtoul(&buf[n + 1],
1071c60e0504SMagnus Damm 							     &tmp, 10);
1072c60e0504SMagnus Damm 
1073c60e0504SMagnus Damm 			if (buf[n] != '.' || (tmp == &buf[n + 1])) {
107413977091SMagnus Damm 				epdrv->requested_id = EARLY_PLATFORM_ID_ERROR;
1075c60e0504SMagnus Damm 				n = 0;
1076c60e0504SMagnus Damm 			} else
1077c60e0504SMagnus Damm 				n += strcspn(&buf[n + 1], ",") + 1;
1078c60e0504SMagnus Damm 		}
1079c60e0504SMagnus Damm 
1080c60e0504SMagnus Damm 		if (buf[n] == ',')
1081c60e0504SMagnus Damm 			n++;
1082c60e0504SMagnus Damm 
1083c60e0504SMagnus Damm 		if (epdrv->bufsize) {
1084c60e0504SMagnus Damm 			memcpy(epdrv->buffer, &buf[n],
1085c60e0504SMagnus Damm 			       min_t(int, epdrv->bufsize, strlen(&buf[n]) + 1));
1086c60e0504SMagnus Damm 			epdrv->buffer[epdrv->bufsize - 1] = '\0';
1087c60e0504SMagnus Damm 		}
108813977091SMagnus Damm 	}
108913977091SMagnus Damm 
109013977091SMagnus Damm 	return 0;
109113977091SMagnus Damm }
109213977091SMagnus Damm 
109313977091SMagnus Damm /**
10944d26e139SMagnus Damm  * early_platform_add_devices - adds a number of early platform devices
109513977091SMagnus Damm  * @devs: array of early platform devices to add
109613977091SMagnus Damm  * @num: number of early platform devices in array
10974d26e139SMagnus Damm  *
10984d26e139SMagnus Damm  * Used by early architecture code to register early platform devices and
10994d26e139SMagnus Damm  * their platform data.
110013977091SMagnus Damm  */
110113977091SMagnus Damm void __init early_platform_add_devices(struct platform_device **devs, int num)
110213977091SMagnus Damm {
110313977091SMagnus Damm 	struct device *dev;
110413977091SMagnus Damm 	int i;
110513977091SMagnus Damm 
110613977091SMagnus Damm 	/* simply add the devices to list */
110713977091SMagnus Damm 	for (i = 0; i < num; i++) {
110813977091SMagnus Damm 		dev = &devs[i]->dev;
110913977091SMagnus Damm 
111013977091SMagnus Damm 		if (!dev->devres_head.next) {
1111bed2b42dSRafael J. Wysocki 			pm_runtime_early_init(dev);
111213977091SMagnus Damm 			INIT_LIST_HEAD(&dev->devres_head);
111313977091SMagnus Damm 			list_add_tail(&dev->devres_head,
111413977091SMagnus Damm 				      &early_platform_device_list);
111513977091SMagnus Damm 		}
111613977091SMagnus Damm 	}
111713977091SMagnus Damm }
111813977091SMagnus Damm 
111913977091SMagnus Damm /**
11204d26e139SMagnus Damm  * early_platform_driver_register_all - register early platform drivers
112113977091SMagnus Damm  * @class_str: string to identify early platform driver class
11224d26e139SMagnus Damm  *
11234d26e139SMagnus Damm  * Used by architecture code to register all early platform drivers
11244d26e139SMagnus Damm  * for a certain class. If omitted then only early platform drivers
11254d26e139SMagnus Damm  * with matching kernel command line class parameters will be registered.
112613977091SMagnus Damm  */
112713977091SMagnus Damm void __init early_platform_driver_register_all(char *class_str)
112813977091SMagnus Damm {
112913977091SMagnus Damm 	/* The "class_str" parameter may or may not be present on the kernel
113013977091SMagnus Damm 	 * command line. If it is present then there may be more than one
113113977091SMagnus Damm 	 * matching parameter.
113213977091SMagnus Damm 	 *
113313977091SMagnus Damm 	 * Since we register our early platform drivers using early_param()
113413977091SMagnus Damm 	 * we need to make sure that they also get registered in the case
113513977091SMagnus Damm 	 * when the parameter is missing from the kernel command line.
113613977091SMagnus Damm 	 *
113713977091SMagnus Damm 	 * We use parse_early_options() to make sure the early_param() gets
113813977091SMagnus Damm 	 * called at least once. The early_param() may be called more than
113913977091SMagnus Damm 	 * once since the name of the preferred device may be specified on
114013977091SMagnus Damm 	 * the kernel command line. early_platform_driver_register() handles
114113977091SMagnus Damm 	 * this case for us.
114213977091SMagnus Damm 	 */
114313977091SMagnus Damm 	parse_early_options(class_str);
114413977091SMagnus Damm }
114513977091SMagnus Damm 
114613977091SMagnus Damm /**
11474d26e139SMagnus Damm  * early_platform_match - find early platform device matching driver
1148d86c1302SRandy Dunlap  * @epdrv: early platform driver structure
114913977091SMagnus Damm  * @id: id to match against
115013977091SMagnus Damm  */
1151a8257910SHanjun Guo static struct platform_device * __init
115213977091SMagnus Damm early_platform_match(struct early_platform_driver *epdrv, int id)
115313977091SMagnus Damm {
115413977091SMagnus Damm 	struct platform_device *pd;
115513977091SMagnus Damm 
115613977091SMagnus Damm 	list_for_each_entry(pd, &early_platform_device_list, dev.devres_head)
115713977091SMagnus Damm 		if (platform_match(&pd->dev, &epdrv->pdrv->driver))
115813977091SMagnus Damm 			if (pd->id == id)
115913977091SMagnus Damm 				return pd;
116013977091SMagnus Damm 
116113977091SMagnus Damm 	return NULL;
116213977091SMagnus Damm }
116313977091SMagnus Damm 
116413977091SMagnus Damm /**
11654d26e139SMagnus Damm  * early_platform_left - check if early platform driver has matching devices
1166d86c1302SRandy Dunlap  * @epdrv: early platform driver structure
116713977091SMagnus Damm  * @id: return true if id or above exists
116813977091SMagnus Damm  */
1169a8257910SHanjun Guo static int __init early_platform_left(struct early_platform_driver *epdrv,
117013977091SMagnus Damm 				       int id)
117113977091SMagnus Damm {
117213977091SMagnus Damm 	struct platform_device *pd;
117313977091SMagnus Damm 
117413977091SMagnus Damm 	list_for_each_entry(pd, &early_platform_device_list, dev.devres_head)
117513977091SMagnus Damm 		if (platform_match(&pd->dev, &epdrv->pdrv->driver))
117613977091SMagnus Damm 			if (pd->id >= id)
117713977091SMagnus Damm 				return 1;
117813977091SMagnus Damm 
117913977091SMagnus Damm 	return 0;
118013977091SMagnus Damm }
118113977091SMagnus Damm 
118213977091SMagnus Damm /**
11834d26e139SMagnus Damm  * early_platform_driver_probe_id - probe drivers matching class_str and id
118413977091SMagnus Damm  * @class_str: string to identify early platform driver class
118513977091SMagnus Damm  * @id: id to match against
118613977091SMagnus Damm  * @nr_probe: number of platform devices to successfully probe before exiting
118713977091SMagnus Damm  */
118813977091SMagnus Damm static int __init early_platform_driver_probe_id(char *class_str,
118913977091SMagnus Damm 						 int id,
119013977091SMagnus Damm 						 int nr_probe)
119113977091SMagnus Damm {
119213977091SMagnus Damm 	struct early_platform_driver *epdrv;
119313977091SMagnus Damm 	struct platform_device *match;
119413977091SMagnus Damm 	int match_id;
119513977091SMagnus Damm 	int n = 0;
119613977091SMagnus Damm 	int left = 0;
119713977091SMagnus Damm 
119813977091SMagnus Damm 	list_for_each_entry(epdrv, &early_platform_driver_list, list) {
119913977091SMagnus Damm 		/* only use drivers matching our class_str */
120013977091SMagnus Damm 		if (strcmp(class_str, epdrv->class_str))
120113977091SMagnus Damm 			continue;
120213977091SMagnus Damm 
120313977091SMagnus Damm 		if (id == -2) {
120413977091SMagnus Damm 			match_id = epdrv->requested_id;
120513977091SMagnus Damm 			left = 1;
120613977091SMagnus Damm 
120713977091SMagnus Damm 		} else {
120813977091SMagnus Damm 			match_id = id;
120913977091SMagnus Damm 			left += early_platform_left(epdrv, id);
121013977091SMagnus Damm 
121113977091SMagnus Damm 			/* skip requested id */
121213977091SMagnus Damm 			switch (epdrv->requested_id) {
121313977091SMagnus Damm 			case EARLY_PLATFORM_ID_ERROR:
121413977091SMagnus Damm 			case EARLY_PLATFORM_ID_UNSET:
121513977091SMagnus Damm 				break;
121613977091SMagnus Damm 			default:
121713977091SMagnus Damm 				if (epdrv->requested_id == id)
121813977091SMagnus Damm 					match_id = EARLY_PLATFORM_ID_UNSET;
121913977091SMagnus Damm 			}
122013977091SMagnus Damm 		}
122113977091SMagnus Damm 
122213977091SMagnus Damm 		switch (match_id) {
122313977091SMagnus Damm 		case EARLY_PLATFORM_ID_ERROR:
12240258e182SFabio Porcedda 			pr_warn("%s: unable to parse %s parameter\n",
122513977091SMagnus Damm 				class_str, epdrv->pdrv->driver.name);
122613977091SMagnus Damm 			/* fall-through */
122713977091SMagnus Damm 		case EARLY_PLATFORM_ID_UNSET:
122813977091SMagnus Damm 			match = NULL;
122913977091SMagnus Damm 			break;
123013977091SMagnus Damm 		default:
123113977091SMagnus Damm 			match = early_platform_match(epdrv, match_id);
123213977091SMagnus Damm 		}
123313977091SMagnus Damm 
123413977091SMagnus Damm 		if (match) {
1235a636ee7fSPaul Mundt 			/*
1236a636ee7fSPaul Mundt 			 * Set up a sensible init_name to enable
1237a636ee7fSPaul Mundt 			 * dev_name() and others to be used before the
1238a636ee7fSPaul Mundt 			 * rest of the driver core is initialized.
1239a636ee7fSPaul Mundt 			 */
124006fe53beSPaul Mundt 			if (!match->dev.init_name && slab_is_available()) {
1241a636ee7fSPaul Mundt 				if (match->id != -1)
1242bd05086bSPaul Mundt 					match->dev.init_name =
1243bd05086bSPaul Mundt 						kasprintf(GFP_KERNEL, "%s.%d",
1244bd05086bSPaul Mundt 							  match->name,
1245bd05086bSPaul Mundt 							  match->id);
1246a636ee7fSPaul Mundt 				else
1247bd05086bSPaul Mundt 					match->dev.init_name =
1248bd05086bSPaul Mundt 						kasprintf(GFP_KERNEL, "%s",
1249a636ee7fSPaul Mundt 							  match->name);
1250a636ee7fSPaul Mundt 
1251a636ee7fSPaul Mundt 				if (!match->dev.init_name)
1252a636ee7fSPaul Mundt 					return -ENOMEM;
1253a636ee7fSPaul Mundt 			}
1254bd05086bSPaul Mundt 
125513977091SMagnus Damm 			if (epdrv->pdrv->probe(match))
12560258e182SFabio Porcedda 				pr_warn("%s: unable to probe %s early.\n",
125713977091SMagnus Damm 					class_str, match->name);
125813977091SMagnus Damm 			else
125913977091SMagnus Damm 				n++;
126013977091SMagnus Damm 		}
126113977091SMagnus Damm 
126213977091SMagnus Damm 		if (n >= nr_probe)
126313977091SMagnus Damm 			break;
126413977091SMagnus Damm 	}
126513977091SMagnus Damm 
126613977091SMagnus Damm 	if (left)
126713977091SMagnus Damm 		return n;
126813977091SMagnus Damm 	else
126913977091SMagnus Damm 		return -ENODEV;
127013977091SMagnus Damm }
127113977091SMagnus Damm 
127213977091SMagnus Damm /**
12734d26e139SMagnus Damm  * early_platform_driver_probe - probe a class of registered drivers
127413977091SMagnus Damm  * @class_str: string to identify early platform driver class
127513977091SMagnus Damm  * @nr_probe: number of platform devices to successfully probe before exiting
127613977091SMagnus Damm  * @user_only: only probe user specified early platform devices
12774d26e139SMagnus Damm  *
12784d26e139SMagnus Damm  * Used by architecture code to probe registered early platform drivers
12794d26e139SMagnus Damm  * within a certain class. For probe to happen a registered early platform
12804d26e139SMagnus Damm  * device matching a registered early platform driver is needed.
128113977091SMagnus Damm  */
128213977091SMagnus Damm int __init early_platform_driver_probe(char *class_str,
128313977091SMagnus Damm 				       int nr_probe,
128413977091SMagnus Damm 				       int user_only)
128513977091SMagnus Damm {
128613977091SMagnus Damm 	int k, n, i;
128713977091SMagnus Damm 
128813977091SMagnus Damm 	n = 0;
128913977091SMagnus Damm 	for (i = -2; n < nr_probe; i++) {
129013977091SMagnus Damm 		k = early_platform_driver_probe_id(class_str, i, nr_probe - n);
129113977091SMagnus Damm 
129213977091SMagnus Damm 		if (k < 0)
129313977091SMagnus Damm 			break;
129413977091SMagnus Damm 
129513977091SMagnus Damm 		n += k;
129613977091SMagnus Damm 
129713977091SMagnus Damm 		if (user_only)
129813977091SMagnus Damm 			break;
129913977091SMagnus Damm 	}
130013977091SMagnus Damm 
130113977091SMagnus Damm 	return n;
130213977091SMagnus Damm }
130313977091SMagnus Damm 
130413977091SMagnus Damm /**
130513977091SMagnus Damm  * early_platform_cleanup - clean up early platform code
130613977091SMagnus Damm  */
130713977091SMagnus Damm void __init early_platform_cleanup(void)
130813977091SMagnus Damm {
130913977091SMagnus Damm 	struct platform_device *pd, *pd2;
131013977091SMagnus Damm 
131113977091SMagnus Damm 	/* clean up the devres list used to chain devices */
131213977091SMagnus Damm 	list_for_each_entry_safe(pd, pd2, &early_platform_device_list,
131313977091SMagnus Damm 				 dev.devres_head) {
131413977091SMagnus Damm 		list_del(&pd->dev.devres_head);
131513977091SMagnus Damm 		memset(&pd->dev.devres_head, 0, sizeof(pd->dev.devres_head));
131613977091SMagnus Damm 	}
131713977091SMagnus Damm }
131813977091SMagnus Damm 
1319