xref: /openbmc/linux/drivers/base/platform.c (revision 0707cfa5)
1989d42e8SGreg Kroah-Hartman // SPDX-License-Identifier: GPL-2.0
21da177e4SLinus Torvalds /*
31da177e4SLinus Torvalds  * platform.c - platform 'pseudo' bus for legacy devices
41da177e4SLinus Torvalds  *
51da177e4SLinus Torvalds  * Copyright (c) 2002-3 Patrick Mochel
61da177e4SLinus Torvalds  * Copyright (c) 2002-3 Open Source Development Labs
71da177e4SLinus Torvalds  *
8fe34c89dSMauro Carvalho Chehab  * Please see Documentation/driver-api/driver-model/platform.rst for more
91da177e4SLinus Torvalds  * information.
101da177e4SLinus Torvalds  */
111da177e4SLinus Torvalds 
12daa41226SAndrew Morton #include <linux/string.h>
13d052d1beSRussell King #include <linux/platform_device.h>
1405212157SGrant Likely #include <linux/of_device.h>
159ec36cafSRob Herring #include <linux/of_irq.h>
161da177e4SLinus Torvalds #include <linux/module.h>
171da177e4SLinus Torvalds #include <linux/init.h>
181da177e4SLinus Torvalds #include <linux/dma-mapping.h>
1957c8a661SMike Rapoport #include <linux/memblock.h>
201da177e4SLinus Torvalds #include <linux/err.h>
214e57b681STim Schmielau #include <linux/slab.h>
229d730229SMagnus Damm #include <linux/pm_runtime.h>
23f48c767cSUlf Hansson #include <linux/pm_domain.h>
24689ae231SJean Delvare #include <linux/idr.h>
2591e56878SMika Westerberg #include <linux/acpi.h>
2686be408bSSylwester Nawrocki #include <linux/clk/clk-conf.h>
273d713e0eSKim Phillips #include <linux/limits.h>
2800bbc1d8SMika Westerberg #include <linux/property.h>
29967d3010SQian Cai #include <linux/kmemleak.h>
3039cc539fSSimon Schwartz #include <linux/types.h>
311da177e4SLinus Torvalds 
32a1bdc7aaSBen Dooks #include "base.h"
33bed2b42dSRafael J. Wysocki #include "power/power.h"
34a1bdc7aaSBen Dooks 
35689ae231SJean Delvare /* For automatically allocated device IDs */
36689ae231SJean Delvare static DEFINE_IDA(platform_devid_ida);
37689ae231SJean Delvare 
381da177e4SLinus Torvalds struct device platform_bus = {
391e0b2cf9SKay Sievers 	.init_name	= "platform",
401da177e4SLinus Torvalds };
41a96b2042SDmitry Torokhov EXPORT_SYMBOL_GPL(platform_bus);
421da177e4SLinus Torvalds 
431da177e4SLinus Torvalds /**
441da177e4SLinus Torvalds  * platform_get_resource - get a resource for a device
451da177e4SLinus Torvalds  * @dev: platform device
461da177e4SLinus Torvalds  * @type: resource type
471da177e4SLinus Torvalds  * @num: resource index
481da177e4SLinus Torvalds  */
494a3ad20cSGreg Kroah-Hartman struct resource *platform_get_resource(struct platform_device *dev,
504a3ad20cSGreg Kroah-Hartman 				       unsigned int type, unsigned int num)
511da177e4SLinus Torvalds {
5239cc539fSSimon Schwartz 	u32 i;
531da177e4SLinus Torvalds 
541da177e4SLinus Torvalds 	for (i = 0; i < dev->num_resources; i++) {
551da177e4SLinus Torvalds 		struct resource *r = &dev->resource[i];
561da177e4SLinus Torvalds 
57c9f66169SMagnus Damm 		if (type == resource_type(r) && num-- == 0)
581da177e4SLinus Torvalds 			return r;
591da177e4SLinus Torvalds 	}
601da177e4SLinus Torvalds 	return NULL;
611da177e4SLinus Torvalds }
62a96b2042SDmitry Torokhov EXPORT_SYMBOL_GPL(platform_get_resource);
631da177e4SLinus Torvalds 
64bb6243b4SBartosz Golaszewski #ifdef CONFIG_HAS_IOMEM
651da177e4SLinus Torvalds /**
667945f929SBartosz Golaszewski  * devm_platform_ioremap_resource - call devm_ioremap_resource() for a platform
677945f929SBartosz Golaszewski  *				    device
687945f929SBartosz Golaszewski  *
697945f929SBartosz Golaszewski  * @pdev: platform device to use both for memory resource lookup as well as
707067c96eSBartosz Golaszewski  *        resource management
717945f929SBartosz Golaszewski  * @index: resource index
727945f929SBartosz Golaszewski  */
737945f929SBartosz Golaszewski void __iomem *devm_platform_ioremap_resource(struct platform_device *pdev,
747945f929SBartosz Golaszewski 					     unsigned int index)
757945f929SBartosz Golaszewski {
767945f929SBartosz Golaszewski 	struct resource *res;
777945f929SBartosz Golaszewski 
787945f929SBartosz Golaszewski 	res = platform_get_resource(pdev, IORESOURCE_MEM, index);
797945f929SBartosz Golaszewski 	return devm_ioremap_resource(&pdev->dev, res);
807945f929SBartosz Golaszewski }
817945f929SBartosz Golaszewski EXPORT_SYMBOL_GPL(devm_platform_ioremap_resource);
82bb6243b4SBartosz Golaszewski 
83bb6243b4SBartosz Golaszewski /**
84bb6243b4SBartosz Golaszewski  * devm_platform_ioremap_resource_wc - write-combined variant of
85bb6243b4SBartosz Golaszewski  *                                     devm_platform_ioremap_resource()
86bb6243b4SBartosz Golaszewski  *
87bb6243b4SBartosz Golaszewski  * @pdev: platform device to use both for memory resource lookup as well as
88bb6243b4SBartosz Golaszewski  *        resource management
89bb6243b4SBartosz Golaszewski  * @index: resource index
90bb6243b4SBartosz Golaszewski  */
91bb6243b4SBartosz Golaszewski void __iomem *devm_platform_ioremap_resource_wc(struct platform_device *pdev,
92bb6243b4SBartosz Golaszewski 						unsigned int index)
93bb6243b4SBartosz Golaszewski {
94bb6243b4SBartosz Golaszewski 	struct resource *res;
95bb6243b4SBartosz Golaszewski 
96bb6243b4SBartosz Golaszewski 	res = platform_get_resource(pdev, IORESOURCE_MEM, index);
97bb6243b4SBartosz Golaszewski 	return devm_ioremap_resource_wc(&pdev->dev, res);
98bb6243b4SBartosz Golaszewski }
99c9c8641dSBartosz Golaszewski 
100c9c8641dSBartosz Golaszewski /**
101c9c8641dSBartosz Golaszewski  * devm_platform_ioremap_resource_byname - call devm_ioremap_resource for
102c9c8641dSBartosz Golaszewski  *					   a platform device, retrieve the
103c9c8641dSBartosz Golaszewski  *					   resource by name
104c9c8641dSBartosz Golaszewski  *
105c9c8641dSBartosz Golaszewski  * @pdev: platform device to use both for memory resource lookup as well as
106c9c8641dSBartosz Golaszewski  *	  resource management
107c9c8641dSBartosz Golaszewski  * @name: name of the resource
108c9c8641dSBartosz Golaszewski  */
109c9c8641dSBartosz Golaszewski void __iomem *
110c9c8641dSBartosz Golaszewski devm_platform_ioremap_resource_byname(struct platform_device *pdev,
111c9c8641dSBartosz Golaszewski 				      const char *name)
112c9c8641dSBartosz Golaszewski {
113c9c8641dSBartosz Golaszewski 	struct resource *res;
114c9c8641dSBartosz Golaszewski 
115c9c8641dSBartosz Golaszewski 	res = platform_get_resource_byname(pdev, IORESOURCE_MEM, name);
116c9c8641dSBartosz Golaszewski 	return devm_ioremap_resource(&pdev->dev, res);
117c9c8641dSBartosz Golaszewski }
118c9c8641dSBartosz Golaszewski EXPORT_SYMBOL_GPL(devm_platform_ioremap_resource_byname);
119837ccda3SBartosz Golaszewski #endif /* CONFIG_HAS_IOMEM */
1207945f929SBartosz Golaszewski 
121ec4e2906SUwe Kleine-König /**
122ec4e2906SUwe Kleine-König  * platform_get_irq_optional - get an optional IRQ for a device
123ec4e2906SUwe Kleine-König  * @dev: platform device
124ec4e2906SUwe Kleine-König  * @num: IRQ number index
125ec4e2906SUwe Kleine-König  *
126ec4e2906SUwe Kleine-König  * Gets an IRQ for a platform device. Device drivers should check the return
127ec4e2906SUwe Kleine-König  * value for errors so as to not pass a negative integer value to the
128ec4e2906SUwe Kleine-König  * request_irq() APIs. This is the same as platform_get_irq(), except that it
129ec4e2906SUwe Kleine-König  * does not print an error message if an IRQ can not be obtained.
130ec4e2906SUwe Kleine-König  *
131ec4e2906SUwe Kleine-König  * Example:
132ec4e2906SUwe Kleine-König  *		int irq = platform_get_irq_optional(pdev, 0);
133ec4e2906SUwe Kleine-König  *		if (irq < 0)
134ec4e2906SUwe Kleine-König  *			return irq;
135ec4e2906SUwe Kleine-König  *
136ec4e2906SUwe Kleine-König  * Return: IRQ number on success, negative error number on failure.
137ec4e2906SUwe Kleine-König  */
138ec4e2906SUwe Kleine-König int platform_get_irq_optional(struct platform_device *dev, unsigned int num)
1391da177e4SLinus Torvalds {
1405cf8f7dbSAndreas Larsson #ifdef CONFIG_SPARC
1415cf8f7dbSAndreas Larsson 	/* sparc does not have irqs represented as IORESOURCE_IRQ resources */
1425cf8f7dbSAndreas Larsson 	if (!dev || num >= dev->archdata.num_irqs)
1435cf8f7dbSAndreas Larsson 		return -ENXIO;
1445cf8f7dbSAndreas Larsson 	return dev->archdata.irqs[num];
1455cf8f7dbSAndreas Larsson #else
1469ec36cafSRob Herring 	struct resource *r;
147aff008adSGuenter Roeck 	int ret;
148aff008adSGuenter Roeck 
14971564a26SAndy Shevchenko 	if (IS_ENABLED(CONFIG_OF_IRQ) && dev->dev.of_node) {
150aff008adSGuenter Roeck 		ret = of_irq_get(dev->dev.of_node, num);
151e330b9a6SSergei Shtylyov 		if (ret > 0 || ret == -EPROBE_DEFER)
152aff008adSGuenter Roeck 			return ret;
153aff008adSGuenter Roeck 	}
1549ec36cafSRob Herring 
1559ec36cafSRob Herring 	r = platform_get_resource(dev, IORESOURCE_IRQ, num);
156d44fa3d4SAgustin Vega-Frias 	if (has_acpi_companion(&dev->dev)) {
157d44fa3d4SAgustin Vega-Frias 		if (r && r->flags & IORESOURCE_DISABLED) {
158d44fa3d4SAgustin Vega-Frias 			ret = acpi_irq_get(ACPI_HANDLE(&dev->dev), num, r);
159d44fa3d4SAgustin Vega-Frias 			if (ret)
160d44fa3d4SAgustin Vega-Frias 				return ret;
161d44fa3d4SAgustin Vega-Frias 		}
162d44fa3d4SAgustin Vega-Frias 	}
163d44fa3d4SAgustin Vega-Frias 
1647085a740SLinus Walleij 	/*
1657085a740SLinus Walleij 	 * The resources may pass trigger flags to the irqs that need
1667085a740SLinus Walleij 	 * to be set up. It so happens that the trigger flags for
1677085a740SLinus Walleij 	 * IORESOURCE_BITS correspond 1-to-1 to the IRQF_TRIGGER*
1687085a740SLinus Walleij 	 * settings.
1697085a740SLinus Walleij 	 */
17060ca5e0dSGuenter Roeck 	if (r && r->flags & IORESOURCE_BITS) {
17160ca5e0dSGuenter Roeck 		struct irq_data *irqd;
17260ca5e0dSGuenter Roeck 
17360ca5e0dSGuenter Roeck 		irqd = irq_get_irq_data(r->start);
17460ca5e0dSGuenter Roeck 		if (!irqd)
17560ca5e0dSGuenter Roeck 			return -ENXIO;
17660ca5e0dSGuenter Roeck 		irqd_set_trigger_type(irqd, r->flags & IORESOURCE_BITS);
17760ca5e0dSGuenter Roeck 	}
1781da177e4SLinus Torvalds 
179daaef255SEnrico Granata 	if (r)
180daaef255SEnrico Granata 		return r->start;
181daaef255SEnrico Granata 
182daaef255SEnrico Granata 	/*
183daaef255SEnrico Granata 	 * For the index 0 interrupt, allow falling back to GpioInt
184daaef255SEnrico Granata 	 * resources. While a device could have both Interrupt and GpioInt
185daaef255SEnrico Granata 	 * resources, making this fallback ambiguous, in many common cases
186daaef255SEnrico Granata 	 * the device will only expose one IRQ, and this fallback
187daaef255SEnrico Granata 	 * allows a common code path across either kind of resource.
188daaef255SEnrico Granata 	 */
18946c42d84SBrian Norris 	if (num == 0 && has_acpi_companion(&dev->dev)) {
19071564a26SAndy Shevchenko 		ret = acpi_dev_gpio_irq_get(ACPI_COMPANION(&dev->dev), num);
19146c42d84SBrian Norris 		/* Our callers expect -ENXIO for missing IRQs. */
19246c42d84SBrian Norris 		if (ret >= 0 || ret == -EPROBE_DEFER)
19346c42d84SBrian Norris 			return ret;
19446c42d84SBrian Norris 	}
195daaef255SEnrico Granata 
196daaef255SEnrico Granata 	return -ENXIO;
1975cf8f7dbSAndreas Larsson #endif
1981da177e4SLinus Torvalds }
199ec4e2906SUwe Kleine-König EXPORT_SYMBOL_GPL(platform_get_irq_optional);
2007723f4c5SStephen Boyd 
2017723f4c5SStephen Boyd /**
2027723f4c5SStephen Boyd  * platform_get_irq - get an IRQ for a device
2037723f4c5SStephen Boyd  * @dev: platform device
2047723f4c5SStephen Boyd  * @num: IRQ number index
2057723f4c5SStephen Boyd  *
2067723f4c5SStephen Boyd  * Gets an IRQ for a platform device and prints an error message if finding the
2077723f4c5SStephen Boyd  * IRQ fails. Device drivers should check the return value for errors so as to
2087723f4c5SStephen Boyd  * not pass a negative integer value to the request_irq() APIs.
2097723f4c5SStephen Boyd  *
2107723f4c5SStephen Boyd  * Example:
2117723f4c5SStephen Boyd  *		int irq = platform_get_irq(pdev, 0);
2127723f4c5SStephen Boyd  *		if (irq < 0)
2137723f4c5SStephen Boyd  *			return irq;
2147723f4c5SStephen Boyd  *
2157723f4c5SStephen Boyd  * Return: IRQ number on success, negative error number on failure.
2167723f4c5SStephen Boyd  */
2177723f4c5SStephen Boyd int platform_get_irq(struct platform_device *dev, unsigned int num)
2187723f4c5SStephen Boyd {
2197723f4c5SStephen Boyd 	int ret;
2207723f4c5SStephen Boyd 
221ec4e2906SUwe Kleine-König 	ret = platform_get_irq_optional(dev, num);
2227723f4c5SStephen Boyd 	if (ret < 0 && ret != -EPROBE_DEFER)
2237723f4c5SStephen Boyd 		dev_err(&dev->dev, "IRQ index %u not found\n", num);
2247723f4c5SStephen Boyd 
2257723f4c5SStephen Boyd 	return ret;
2267723f4c5SStephen Boyd }
227a96b2042SDmitry Torokhov EXPORT_SYMBOL_GPL(platform_get_irq);
2281da177e4SLinus Torvalds 
2291da177e4SLinus Torvalds /**
2304b83555dSStephen Boyd  * platform_irq_count - Count the number of IRQs a platform device uses
2314b83555dSStephen Boyd  * @dev: platform device
2324b83555dSStephen Boyd  *
2334b83555dSStephen Boyd  * Return: Number of IRQs a platform device uses or EPROBE_DEFER
2344b83555dSStephen Boyd  */
2354b83555dSStephen Boyd int platform_irq_count(struct platform_device *dev)
2364b83555dSStephen Boyd {
2374b83555dSStephen Boyd 	int ret, nr = 0;
2384b83555dSStephen Boyd 
239ec4e2906SUwe Kleine-König 	while ((ret = platform_get_irq_optional(dev, nr)) >= 0)
2404b83555dSStephen Boyd 		nr++;
2414b83555dSStephen Boyd 
2424b83555dSStephen Boyd 	if (ret == -EPROBE_DEFER)
2434b83555dSStephen Boyd 		return ret;
2444b83555dSStephen Boyd 
2454b83555dSStephen Boyd 	return nr;
2464b83555dSStephen Boyd }
2474b83555dSStephen Boyd EXPORT_SYMBOL_GPL(platform_irq_count);
2484b83555dSStephen Boyd 
2494b83555dSStephen Boyd /**
2501da177e4SLinus Torvalds  * platform_get_resource_byname - get a resource for a device by name
2511da177e4SLinus Torvalds  * @dev: platform device
2521da177e4SLinus Torvalds  * @type: resource type
2531da177e4SLinus Torvalds  * @name: resource name
2541da177e4SLinus Torvalds  */
2554a3ad20cSGreg Kroah-Hartman struct resource *platform_get_resource_byname(struct platform_device *dev,
256c0afe7baSLinus Walleij 					      unsigned int type,
257c0afe7baSLinus Walleij 					      const char *name)
2581da177e4SLinus Torvalds {
25939cc539fSSimon Schwartz 	u32 i;
2601da177e4SLinus Torvalds 
2611da177e4SLinus Torvalds 	for (i = 0; i < dev->num_resources; i++) {
2621da177e4SLinus Torvalds 		struct resource *r = &dev->resource[i];
2631da177e4SLinus Torvalds 
2641b8cb929SPeter Ujfalusi 		if (unlikely(!r->name))
2651b8cb929SPeter Ujfalusi 			continue;
2661b8cb929SPeter Ujfalusi 
267c9f66169SMagnus Damm 		if (type == resource_type(r) && !strcmp(r->name, name))
2681da177e4SLinus Torvalds 			return r;
2691da177e4SLinus Torvalds 	}
2701da177e4SLinus Torvalds 	return NULL;
2711da177e4SLinus Torvalds }
272a96b2042SDmitry Torokhov EXPORT_SYMBOL_GPL(platform_get_resource_byname);
2731da177e4SLinus Torvalds 
274f1da567fSHans de Goede static int __platform_get_irq_byname(struct platform_device *dev,
275f1da567fSHans de Goede 				     const char *name)
2761da177e4SLinus Torvalds {
277ad69674eSGrygorii Strashko 	struct resource *r;
278aff008adSGuenter Roeck 	int ret;
279aff008adSGuenter Roeck 
28071564a26SAndy Shevchenko 	if (IS_ENABLED(CONFIG_OF_IRQ) && dev->dev.of_node) {
281aff008adSGuenter Roeck 		ret = of_irq_get_byname(dev->dev.of_node, name);
282e330b9a6SSergei Shtylyov 		if (ret > 0 || ret == -EPROBE_DEFER)
283aff008adSGuenter Roeck 			return ret;
284aff008adSGuenter Roeck 	}
285ad69674eSGrygorii Strashko 
286ad69674eSGrygorii Strashko 	r = platform_get_resource_byname(dev, IORESOURCE_IRQ, name);
2877723f4c5SStephen Boyd 	if (r)
2887723f4c5SStephen Boyd 		return r->start;
2897723f4c5SStephen Boyd 
2907723f4c5SStephen Boyd 	return -ENXIO;
2911da177e4SLinus Torvalds }
292f1da567fSHans de Goede 
293f1da567fSHans de Goede /**
294f1da567fSHans de Goede  * platform_get_irq_byname - get an IRQ for a device by name
295f1da567fSHans de Goede  * @dev: platform device
296f1da567fSHans de Goede  * @name: IRQ name
297f1da567fSHans de Goede  *
298f1da567fSHans de Goede  * Get an IRQ like platform_get_irq(), but then by name rather then by index.
299f1da567fSHans de Goede  *
300f1da567fSHans de Goede  * Return: IRQ number on success, negative error number on failure.
301f1da567fSHans de Goede  */
302f1da567fSHans de Goede int platform_get_irq_byname(struct platform_device *dev, const char *name)
303f1da567fSHans de Goede {
304f1da567fSHans de Goede 	int ret;
305f1da567fSHans de Goede 
306f1da567fSHans de Goede 	ret = __platform_get_irq_byname(dev, name);
307f1da567fSHans de Goede 	if (ret < 0 && ret != -EPROBE_DEFER)
308f1da567fSHans de Goede 		dev_err(&dev->dev, "IRQ %s not found\n", name);
309f1da567fSHans de Goede 
310f1da567fSHans de Goede 	return ret;
311f1da567fSHans de Goede }
312a96b2042SDmitry Torokhov EXPORT_SYMBOL_GPL(platform_get_irq_byname);
3131da177e4SLinus Torvalds 
3141da177e4SLinus Torvalds /**
315f1da567fSHans de Goede  * platform_get_irq_byname_optional - get an optional IRQ for a device by name
316f1da567fSHans de Goede  * @dev: platform device
317f1da567fSHans de Goede  * @name: IRQ name
318f1da567fSHans de Goede  *
319f1da567fSHans de Goede  * Get an optional IRQ by name like platform_get_irq_byname(). Except that it
320f1da567fSHans de Goede  * does not print an error message if an IRQ can not be obtained.
321f1da567fSHans de Goede  *
322f1da567fSHans de Goede  * Return: IRQ number on success, negative error number on failure.
323f1da567fSHans de Goede  */
324f1da567fSHans de Goede int platform_get_irq_byname_optional(struct platform_device *dev,
325f1da567fSHans de Goede 				     const char *name)
326f1da567fSHans de Goede {
327f1da567fSHans de Goede 	return __platform_get_irq_byname(dev, name);
328f1da567fSHans de Goede }
329f1da567fSHans de Goede EXPORT_SYMBOL_GPL(platform_get_irq_byname_optional);
330f1da567fSHans de Goede 
331f1da567fSHans de Goede /**
3321da177e4SLinus Torvalds  * platform_add_devices - add a numbers of platform devices
3331da177e4SLinus Torvalds  * @devs: array of platform devices to add
3341da177e4SLinus Torvalds  * @num: number of platform devices in array
3351da177e4SLinus Torvalds  */
3361da177e4SLinus Torvalds int platform_add_devices(struct platform_device **devs, int num)
3371da177e4SLinus Torvalds {
3381da177e4SLinus Torvalds 	int i, ret = 0;
3391da177e4SLinus Torvalds 
3401da177e4SLinus Torvalds 	for (i = 0; i < num; i++) {
3411da177e4SLinus Torvalds 		ret = platform_device_register(devs[i]);
3421da177e4SLinus Torvalds 		if (ret) {
3431da177e4SLinus Torvalds 			while (--i >= 0)
3441da177e4SLinus Torvalds 				platform_device_unregister(devs[i]);
3451da177e4SLinus Torvalds 			break;
3461da177e4SLinus Torvalds 		}
3471da177e4SLinus Torvalds 	}
3481da177e4SLinus Torvalds 
3491da177e4SLinus Torvalds 	return ret;
3501da177e4SLinus Torvalds }
351a96b2042SDmitry Torokhov EXPORT_SYMBOL_GPL(platform_add_devices);
3521da177e4SLinus Torvalds 
35337c12e74SRussell King struct platform_object {
35437c12e74SRussell King 	struct platform_device pdev;
3551cec24c5SYann Droneaud 	char name[];
35637c12e74SRussell King };
35737c12e74SRussell King 
358cdfee562SChristoph Hellwig /*
359cdfee562SChristoph Hellwig  * Set up default DMA mask for platform devices if the they weren't
360cdfee562SChristoph Hellwig  * previously set by the architecture / DT.
361cdfee562SChristoph Hellwig  */
362cdfee562SChristoph Hellwig static void setup_pdev_dma_masks(struct platform_device *pdev)
363cdfee562SChristoph Hellwig {
364cdfee562SChristoph Hellwig 	if (!pdev->dev.coherent_dma_mask)
365cdfee562SChristoph Hellwig 		pdev->dev.coherent_dma_mask = DMA_BIT_MASK(32);
366cdfee562SChristoph Hellwig 	if (!pdev->dma_mask)
367cdfee562SChristoph Hellwig 		pdev->dma_mask = DMA_BIT_MASK(32);
368cdfee562SChristoph Hellwig 	if (!pdev->dev.dma_mask)
369cdfee562SChristoph Hellwig 		pdev->dev.dma_mask = &pdev->dma_mask;
370cdfee562SChristoph Hellwig };
371cdfee562SChristoph Hellwig 
3721da177e4SLinus Torvalds /**
3733c31f07aSBen Hutchings  * platform_device_put - destroy a platform device
37437c12e74SRussell King  * @pdev: platform device to free
37537c12e74SRussell King  *
3764a3ad20cSGreg Kroah-Hartman  * Free all memory associated with a platform device.  This function must
3774a3ad20cSGreg Kroah-Hartman  * _only_ be externally called in error cases.  All other usage is a bug.
37837c12e74SRussell King  */
37937c12e74SRussell King void platform_device_put(struct platform_device *pdev)
38037c12e74SRussell King {
38199fef587SAndy Shevchenko 	if (!IS_ERR_OR_NULL(pdev))
38237c12e74SRussell King 		put_device(&pdev->dev);
38337c12e74SRussell King }
38437c12e74SRussell King EXPORT_SYMBOL_GPL(platform_device_put);
38537c12e74SRussell King 
38637c12e74SRussell King static void platform_device_release(struct device *dev)
38737c12e74SRussell King {
3884a3ad20cSGreg Kroah-Hartman 	struct platform_object *pa = container_of(dev, struct platform_object,
3894a3ad20cSGreg Kroah-Hartman 						  pdev.dev);
39037c12e74SRussell King 
3917096d042SGrant Likely 	of_device_node_put(&pa->pdev.dev);
39237c12e74SRussell King 	kfree(pa->pdev.dev.platform_data);
393e710d7d5SSamuel Ortiz 	kfree(pa->pdev.mfd_cell);
39437c12e74SRussell King 	kfree(pa->pdev.resource);
3953d713e0eSKim Phillips 	kfree(pa->pdev.driver_override);
39637c12e74SRussell King 	kfree(pa);
39737c12e74SRussell King }
39837c12e74SRussell King 
39937c12e74SRussell King /**
4003c31f07aSBen Hutchings  * platform_device_alloc - create a platform device
40137c12e74SRussell King  * @name: base name of the device we're adding
40237c12e74SRussell King  * @id: instance id
40337c12e74SRussell King  *
40437c12e74SRussell King  * Create a platform device object which can have other objects attached
40537c12e74SRussell King  * to it, and which will have attached objects freed when it is released.
40637c12e74SRussell King  */
4071359555eSJean Delvare struct platform_device *platform_device_alloc(const char *name, int id)
40837c12e74SRussell King {
40937c12e74SRussell King 	struct platform_object *pa;
41037c12e74SRussell King 
4111cec24c5SYann Droneaud 	pa = kzalloc(sizeof(*pa) + strlen(name) + 1, GFP_KERNEL);
41237c12e74SRussell King 	if (pa) {
41337c12e74SRussell King 		strcpy(pa->name, name);
41437c12e74SRussell King 		pa->pdev.name = pa->name;
41537c12e74SRussell King 		pa->pdev.id = id;
41637c12e74SRussell King 		device_initialize(&pa->pdev.dev);
41737c12e74SRussell King 		pa->pdev.dev.release = platform_device_release;
418cdfee562SChristoph Hellwig 		setup_pdev_dma_masks(&pa->pdev);
41937c12e74SRussell King 	}
42037c12e74SRussell King 
42137c12e74SRussell King 	return pa ? &pa->pdev : NULL;
42237c12e74SRussell King }
42337c12e74SRussell King EXPORT_SYMBOL_GPL(platform_device_alloc);
42437c12e74SRussell King 
42537c12e74SRussell King /**
4263c31f07aSBen Hutchings  * platform_device_add_resources - add resources to a platform device
42737c12e74SRussell King  * @pdev: platform device allocated by platform_device_alloc to add resources to
42837c12e74SRussell King  * @res: set of resources that needs to be allocated for the device
42937c12e74SRussell King  * @num: number of resources
43037c12e74SRussell King  *
43137c12e74SRussell King  * Add a copy of the resources to the platform device.  The memory
4324a3ad20cSGreg Kroah-Hartman  * associated with the resources will be freed when the platform device is
4334a3ad20cSGreg Kroah-Hartman  * released.
43437c12e74SRussell King  */
4354a3ad20cSGreg Kroah-Hartman int platform_device_add_resources(struct platform_device *pdev,
4360b7f1a7eSGeert Uytterhoeven 				  const struct resource *res, unsigned int num)
43737c12e74SRussell King {
438cea89623SUwe Kleine-König 	struct resource *r = NULL;
43937c12e74SRussell King 
440cea89623SUwe Kleine-König 	if (res) {
4413e61dfd8SUwe Kleine-König 		r = kmemdup(res, sizeof(struct resource) * num, GFP_KERNEL);
442cea89623SUwe Kleine-König 		if (!r)
443cea89623SUwe Kleine-König 			return -ENOMEM;
444cea89623SUwe Kleine-König 	}
445cea89623SUwe Kleine-König 
4464a03d6f7SUwe Kleine-König 	kfree(pdev->resource);
44737c12e74SRussell King 	pdev->resource = r;
44837c12e74SRussell King 	pdev->num_resources = num;
4493e61dfd8SUwe Kleine-König 	return 0;
45037c12e74SRussell King }
45137c12e74SRussell King EXPORT_SYMBOL_GPL(platform_device_add_resources);
45237c12e74SRussell King 
45337c12e74SRussell King /**
4543c31f07aSBen Hutchings  * platform_device_add_data - add platform-specific data to a platform device
45537c12e74SRussell King  * @pdev: platform device allocated by platform_device_alloc to add resources to
45637c12e74SRussell King  * @data: platform specific data for this platform device
45737c12e74SRussell King  * @size: size of platform specific data
45837c12e74SRussell King  *
4594a3ad20cSGreg Kroah-Hartman  * Add a copy of platform specific data to the platform device's
4604a3ad20cSGreg Kroah-Hartman  * platform_data pointer.  The memory associated with the platform data
4614a3ad20cSGreg Kroah-Hartman  * will be freed when the platform device is released.
46237c12e74SRussell King  */
4634a3ad20cSGreg Kroah-Hartman int platform_device_add_data(struct platform_device *pdev, const void *data,
4644a3ad20cSGreg Kroah-Hartman 			     size_t size)
46537c12e74SRussell King {
46627a33f9eSUwe Kleine-König 	void *d = NULL;
46737c12e74SRussell King 
46827a33f9eSUwe Kleine-König 	if (data) {
4695cfc64ceSAnton Vorontsov 		d = kmemdup(data, size, GFP_KERNEL);
47027a33f9eSUwe Kleine-König 		if (!d)
47127a33f9eSUwe Kleine-König 			return -ENOMEM;
47227a33f9eSUwe Kleine-König 	}
47327a33f9eSUwe Kleine-König 
474251e031dSUwe Kleine-König 	kfree(pdev->dev.platform_data);
47537c12e74SRussell King 	pdev->dev.platform_data = d;
476daa41226SAndrew Morton 	return 0;
47737c12e74SRussell King }
47837c12e74SRussell King EXPORT_SYMBOL_GPL(platform_device_add_data);
47937c12e74SRussell King 
48037c12e74SRussell King /**
48100bbc1d8SMika Westerberg  * platform_device_add_properties - add built-in properties to a platform device
48200bbc1d8SMika Westerberg  * @pdev: platform device to add properties to
483f4d05266SHeikki Krogerus  * @properties: null terminated array of properties to add
48400bbc1d8SMika Westerberg  *
485f4d05266SHeikki Krogerus  * The function will take deep copy of @properties and attach the copy to the
486f4d05266SHeikki Krogerus  * platform device. The memory associated with properties will be freed when the
487f4d05266SHeikki Krogerus  * platform device is released.
48800bbc1d8SMika Westerberg  */
48900bbc1d8SMika Westerberg int platform_device_add_properties(struct platform_device *pdev,
490277036f0SJan Kiszka 				   const struct property_entry *properties)
49100bbc1d8SMika Westerberg {
492f4d05266SHeikki Krogerus 	return device_add_properties(&pdev->dev, properties);
49300bbc1d8SMika Westerberg }
49400bbc1d8SMika Westerberg EXPORT_SYMBOL_GPL(platform_device_add_properties);
49500bbc1d8SMika Westerberg 
49600bbc1d8SMika Westerberg /**
49737c12e74SRussell King  * platform_device_add - add a platform device to device hierarchy
49867be2dd1SMartin Waitz  * @pdev: platform device we're adding
4991da177e4SLinus Torvalds  *
50037c12e74SRussell King  * This is part 2 of platform_device_register(), though may be called
50137c12e74SRussell King  * separately _iff_ pdev was allocated by platform_device_alloc().
5021da177e4SLinus Torvalds  */
50337c12e74SRussell King int platform_device_add(struct platform_device *pdev)
5041da177e4SLinus Torvalds {
50539cc539fSSimon Schwartz 	u32 i;
50639cc539fSSimon Schwartz 	int ret;
5071da177e4SLinus Torvalds 
5081da177e4SLinus Torvalds 	if (!pdev)
5091da177e4SLinus Torvalds 		return -EINVAL;
5101da177e4SLinus Torvalds 
5111da177e4SLinus Torvalds 	if (!pdev->dev.parent)
5121da177e4SLinus Torvalds 		pdev->dev.parent = &platform_bus;
5131da177e4SLinus Torvalds 
5141da177e4SLinus Torvalds 	pdev->dev.bus = &platform_bus_type;
5151da177e4SLinus Torvalds 
516689ae231SJean Delvare 	switch (pdev->id) {
517689ae231SJean Delvare 	default:
5181e0b2cf9SKay Sievers 		dev_set_name(&pdev->dev, "%s.%d", pdev->name,  pdev->id);
519689ae231SJean Delvare 		break;
520689ae231SJean Delvare 	case PLATFORM_DEVID_NONE:
521acc0e90fSGreg Kroah-Hartman 		dev_set_name(&pdev->dev, "%s", pdev->name);
522689ae231SJean Delvare 		break;
523689ae231SJean Delvare 	case PLATFORM_DEVID_AUTO:
524689ae231SJean Delvare 		/*
525689ae231SJean Delvare 		 * Automatically allocated device ID. We mark it as such so
526689ae231SJean Delvare 		 * that we remember it must be freed, and we append a suffix
527689ae231SJean Delvare 		 * to avoid namespace collision with explicit IDs.
528689ae231SJean Delvare 		 */
529689ae231SJean Delvare 		ret = ida_simple_get(&platform_devid_ida, 0, 0, GFP_KERNEL);
530689ae231SJean Delvare 		if (ret < 0)
5315da7f709SGreg Kroah-Hartman 			goto err_out;
532689ae231SJean Delvare 		pdev->id = ret;
533689ae231SJean Delvare 		pdev->id_auto = true;
534689ae231SJean Delvare 		dev_set_name(&pdev->dev, "%s.%d.auto", pdev->name, pdev->id);
535689ae231SJean Delvare 		break;
536689ae231SJean Delvare 	}
5371da177e4SLinus Torvalds 
5381da177e4SLinus Torvalds 	for (i = 0; i < pdev->num_resources; i++) {
5395da7f709SGreg Kroah-Hartman 		struct resource *p, *r = &pdev->resource[i];
5401da177e4SLinus Torvalds 
5411da177e4SLinus Torvalds 		if (r->name == NULL)
5421e0b2cf9SKay Sievers 			r->name = dev_name(&pdev->dev);
5431da177e4SLinus Torvalds 
5441da177e4SLinus Torvalds 		p = r->parent;
5451da177e4SLinus Torvalds 		if (!p) {
5460e6c861fSGreg Kroah-Hartman 			if (resource_type(r) == IORESOURCE_MEM)
5471da177e4SLinus Torvalds 				p = &iomem_resource;
5480e6c861fSGreg Kroah-Hartman 			else if (resource_type(r) == IORESOURCE_IO)
5491da177e4SLinus Torvalds 				p = &ioport_resource;
5501da177e4SLinus Torvalds 		}
5511da177e4SLinus Torvalds 
55225ebcb7dSAndy Shevchenko 		if (p) {
55325ebcb7dSAndy Shevchenko 			ret = insert_resource(p, r);
55425ebcb7dSAndy Shevchenko 			if (ret) {
5558a18f428SChen Yu 				dev_err(&pdev->dev, "failed to claim resource %d: %pR\n", i, r);
5565da7f709SGreg Kroah-Hartman 				goto failed;
5575da7f709SGreg Kroah-Hartman 			}
5581da177e4SLinus Torvalds 		}
55925ebcb7dSAndy Shevchenko 	}
5601da177e4SLinus Torvalds 
5611da177e4SLinus Torvalds 	pr_debug("Registering platform device '%s'. Parent at %s\n",
5621e0b2cf9SKay Sievers 		 dev_name(&pdev->dev), dev_name(pdev->dev.parent));
5631da177e4SLinus Torvalds 
564e3915532SRussell King 	ret = device_add(&pdev->dev);
5658b2dcebaSGreg Kroah-Hartman 	if (ret == 0)
5668b2dcebaSGreg Kroah-Hartman 		return ret;
5678b2dcebaSGreg Kroah-Hartman 
5685da7f709SGreg Kroah-Hartman  failed:
5698b2dcebaSGreg Kroah-Hartman 	if (pdev->id_auto) {
5708b2dcebaSGreg Kroah-Hartman 		ida_simple_remove(&platform_devid_ida, pdev->id);
5718b2dcebaSGreg Kroah-Hartman 		pdev->id = PLATFORM_DEVID_AUTO;
5728b2dcebaSGreg Kroah-Hartman 	}
5738b2dcebaSGreg Kroah-Hartman 
5740707cfa5SColin Ian King 	while (i--) {
5758b2dcebaSGreg Kroah-Hartman 		struct resource *r = &pdev->resource[i];
5767f5dcaf1SGrant Likely 		if (r->parent)
5778b2dcebaSGreg Kroah-Hartman 			release_resource(r);
5788b2dcebaSGreg Kroah-Hartman 	}
579c9f66169SMagnus Damm 
5805da7f709SGreg Kroah-Hartman  err_out:
5811da177e4SLinus Torvalds 	return ret;
5821da177e4SLinus Torvalds }
58337c12e74SRussell King EXPORT_SYMBOL_GPL(platform_device_add);
58437c12e74SRussell King 
58537c12e74SRussell King /**
58693ce3061SDmitry Torokhov  * platform_device_del - remove a platform-level device
58793ce3061SDmitry Torokhov  * @pdev: platform device we're removing
58893ce3061SDmitry Torokhov  *
58993ce3061SDmitry Torokhov  * Note that this function will also release all memory- and port-based
5904a3ad20cSGreg Kroah-Hartman  * resources owned by the device (@dev->resource).  This function must
5914a3ad20cSGreg Kroah-Hartman  * _only_ be externally called in error cases.  All other usage is a bug.
59293ce3061SDmitry Torokhov  */
59393ce3061SDmitry Torokhov void platform_device_del(struct platform_device *pdev)
59493ce3061SDmitry Torokhov {
59539cc539fSSimon Schwartz 	u32 i;
59693ce3061SDmitry Torokhov 
59799fef587SAndy Shevchenko 	if (!IS_ERR_OR_NULL(pdev)) {
598dc4c15d4SJean Delvare 		device_del(&pdev->dev);
5998b2dcebaSGreg Kroah-Hartman 
6008b2dcebaSGreg Kroah-Hartman 		if (pdev->id_auto) {
6018b2dcebaSGreg Kroah-Hartman 			ida_simple_remove(&platform_devid_ida, pdev->id);
6028b2dcebaSGreg Kroah-Hartman 			pdev->id = PLATFORM_DEVID_AUTO;
6038b2dcebaSGreg Kroah-Hartman 		}
6048b2dcebaSGreg Kroah-Hartman 
6058b2dcebaSGreg Kroah-Hartman 		for (i = 0; i < pdev->num_resources; i++) {
6068b2dcebaSGreg Kroah-Hartman 			struct resource *r = &pdev->resource[i];
6077f5dcaf1SGrant Likely 			if (r->parent)
6088b2dcebaSGreg Kroah-Hartman 				release_resource(r);
6098b2dcebaSGreg Kroah-Hartman 		}
6108b2dcebaSGreg Kroah-Hartman 	}
61193ce3061SDmitry Torokhov }
61293ce3061SDmitry Torokhov EXPORT_SYMBOL_GPL(platform_device_del);
61393ce3061SDmitry Torokhov 
61493ce3061SDmitry Torokhov /**
61537c12e74SRussell King  * platform_device_register - add a platform-level device
61637c12e74SRussell King  * @pdev: platform device we're adding
61737c12e74SRussell King  */
61837c12e74SRussell King int platform_device_register(struct platform_device *pdev)
61937c12e74SRussell King {
62037c12e74SRussell King 	device_initialize(&pdev->dev);
621cdfee562SChristoph Hellwig 	setup_pdev_dma_masks(pdev);
62237c12e74SRussell King 	return platform_device_add(pdev);
62337c12e74SRussell King }
624a96b2042SDmitry Torokhov EXPORT_SYMBOL_GPL(platform_device_register);
6251da177e4SLinus Torvalds 
6261da177e4SLinus Torvalds /**
62793ce3061SDmitry Torokhov  * platform_device_unregister - unregister a platform-level device
62893ce3061SDmitry Torokhov  * @pdev: platform device we're unregistering
6291da177e4SLinus Torvalds  *
63080682fa9SUwe Zeisberger  * Unregistration is done in 2 steps. First we release all resources
6312d7b5a70SJean Delvare  * and remove it from the subsystem, then we drop reference count by
63293ce3061SDmitry Torokhov  * calling platform_device_put().
6331da177e4SLinus Torvalds  */
6341da177e4SLinus Torvalds void platform_device_unregister(struct platform_device *pdev)
6351da177e4SLinus Torvalds {
63693ce3061SDmitry Torokhov 	platform_device_del(pdev);
63793ce3061SDmitry Torokhov 	platform_device_put(pdev);
6381da177e4SLinus Torvalds }
639a96b2042SDmitry Torokhov EXPORT_SYMBOL_GPL(platform_device_unregister);
6401da177e4SLinus Torvalds 
6411da177e4SLinus Torvalds /**
64201dcc60aSUwe Kleine-König  * platform_device_register_full - add a platform-level device with
64344f28bdeSUwe Kleine-König  * resources and platform-specific data
64444f28bdeSUwe Kleine-König  *
64501dcc60aSUwe Kleine-König  * @pdevinfo: data used to create device
646d8bf2540SDmitry Baryshkov  *
647f0eae0edSJani Nikula  * Returns &struct platform_device pointer on success, or ERR_PTR() on error.
648d8bf2540SDmitry Baryshkov  */
64901dcc60aSUwe Kleine-König struct platform_device *platform_device_register_full(
6505a3072beSUwe Kleine-König 		const struct platform_device_info *pdevinfo)
651d8bf2540SDmitry Baryshkov {
65244f28bdeSUwe Kleine-König 	int ret = -ENOMEM;
653d8bf2540SDmitry Baryshkov 	struct platform_device *pdev;
654d8bf2540SDmitry Baryshkov 
65501dcc60aSUwe Kleine-König 	pdev = platform_device_alloc(pdevinfo->name, pdevinfo->id);
65644f28bdeSUwe Kleine-König 	if (!pdev)
65736cf3b13SJohannes Berg 		return ERR_PTR(-ENOMEM);
65801dcc60aSUwe Kleine-König 
65901dcc60aSUwe Kleine-König 	pdev->dev.parent = pdevinfo->parent;
660ce793486SRafael J. Wysocki 	pdev->dev.fwnode = pdevinfo->fwnode;
6612c1ea6abSMans Rullgard 	pdev->dev.of_node = of_node_get(to_of_node(pdev->dev.fwnode));
6622c1ea6abSMans Rullgard 	pdev->dev.of_node_reused = pdevinfo->of_node_reused;
66301dcc60aSUwe Kleine-König 
66401dcc60aSUwe Kleine-König 	if (pdevinfo->dma_mask) {
66501dcc60aSUwe Kleine-König 		/*
66601dcc60aSUwe Kleine-König 		 * This memory isn't freed when the device is put,
66701dcc60aSUwe Kleine-König 		 * I don't have a nice idea for that though.  Conceptually
66801dcc60aSUwe Kleine-König 		 * dma_mask in struct device should not be a pointer.
66901dcc60aSUwe Kleine-König 		 * See http://thread.gmane.org/gmane.linux.kernel.pci/9081
67001dcc60aSUwe Kleine-König 		 */
67101dcc60aSUwe Kleine-König 		pdev->dev.dma_mask =
67201dcc60aSUwe Kleine-König 			kmalloc(sizeof(*pdev->dev.dma_mask), GFP_KERNEL);
67301dcc60aSUwe Kleine-König 		if (!pdev->dev.dma_mask)
67444f28bdeSUwe Kleine-König 			goto err;
675d8bf2540SDmitry Baryshkov 
676967d3010SQian Cai 		kmemleak_ignore(pdev->dev.dma_mask);
677967d3010SQian Cai 
67801dcc60aSUwe Kleine-König 		*pdev->dev.dma_mask = pdevinfo->dma_mask;
67901dcc60aSUwe Kleine-König 		pdev->dev.coherent_dma_mask = pdevinfo->dma_mask;
68001dcc60aSUwe Kleine-König 	}
681d8bf2540SDmitry Baryshkov 
68201dcc60aSUwe Kleine-König 	ret = platform_device_add_resources(pdev,
68301dcc60aSUwe Kleine-König 			pdevinfo->res, pdevinfo->num_res);
68444f28bdeSUwe Kleine-König 	if (ret)
68544f28bdeSUwe Kleine-König 		goto err;
686d8bf2540SDmitry Baryshkov 
68701dcc60aSUwe Kleine-König 	ret = platform_device_add_data(pdev,
68801dcc60aSUwe Kleine-König 			pdevinfo->data, pdevinfo->size_data);
68944f28bdeSUwe Kleine-König 	if (ret)
69044f28bdeSUwe Kleine-König 		goto err;
69144f28bdeSUwe Kleine-König 
692f4d05266SHeikki Krogerus 	if (pdevinfo->properties) {
693f4d05266SHeikki Krogerus 		ret = platform_device_add_properties(pdev,
694f4d05266SHeikki Krogerus 						     pdevinfo->properties);
69500bbc1d8SMika Westerberg 		if (ret)
69600bbc1d8SMika Westerberg 			goto err;
69700bbc1d8SMika Westerberg 	}
69800bbc1d8SMika Westerberg 
69944f28bdeSUwe Kleine-König 	ret = platform_device_add(pdev);
70044f28bdeSUwe Kleine-König 	if (ret) {
70144f28bdeSUwe Kleine-König err:
7027b199811SRafael J. Wysocki 		ACPI_COMPANION_SET(&pdev->dev, NULL);
70301dcc60aSUwe Kleine-König 		kfree(pdev->dev.dma_mask);
70444f28bdeSUwe Kleine-König 		platform_device_put(pdev);
70544f28bdeSUwe Kleine-König 		return ERR_PTR(ret);
70644f28bdeSUwe Kleine-König 	}
707d8bf2540SDmitry Baryshkov 
708d8bf2540SDmitry Baryshkov 	return pdev;
709d8bf2540SDmitry Baryshkov }
71001dcc60aSUwe Kleine-König EXPORT_SYMBOL_GPL(platform_device_register_full);
711d8bf2540SDmitry Baryshkov 
71200d3dcddSRussell King static int platform_drv_probe(struct device *_dev)
71300d3dcddSRussell King {
71400d3dcddSRussell King 	struct platform_driver *drv = to_platform_driver(_dev->driver);
71500d3dcddSRussell King 	struct platform_device *dev = to_platform_device(_dev);
71694d76d5dSRafael J. Wysocki 	int ret;
71700d3dcddSRussell King 
71886be408bSSylwester Nawrocki 	ret = of_clk_set_defaults(_dev->of_node, false);
71986be408bSSylwester Nawrocki 	if (ret < 0)
72086be408bSSylwester Nawrocki 		return ret;
72186be408bSSylwester Nawrocki 
722cb518413SUlf Hansson 	ret = dev_pm_domain_attach(_dev, true);
72388a9769eSUlf Hansson 	if (ret)
72488a9769eSUlf Hansson 		goto out;
72588a9769eSUlf Hansson 
72625cad69fSMartin Wilck 	if (drv->probe) {
72794d76d5dSRafael J. Wysocki 		ret = drv->probe(dev);
7289383f4c6SJosh Cartwright 		if (ret)
729cb518413SUlf Hansson 			dev_pm_domain_detach(_dev, true);
730cb518413SUlf Hansson 	}
73194d76d5dSRafael J. Wysocki 
73288a9769eSUlf Hansson out:
7333f9120b0SJohan Hovold 	if (drv->prevent_deferred_probe && ret == -EPROBE_DEFER) {
7343f9120b0SJohan Hovold 		dev_warn(_dev, "probe deferral not supported\n");
7353f9120b0SJohan Hovold 		ret = -ENXIO;
7363f9120b0SJohan Hovold 	}
7373f9120b0SJohan Hovold 
73894d76d5dSRafael J. Wysocki 	return ret;
73900d3dcddSRussell King }
74000d3dcddSRussell King 
741c67334fbSDavid Brownell static int platform_drv_probe_fail(struct device *_dev)
742c67334fbSDavid Brownell {
743c67334fbSDavid Brownell 	return -ENXIO;
744c67334fbSDavid Brownell }
745c67334fbSDavid Brownell 
74600d3dcddSRussell King static int platform_drv_remove(struct device *_dev)
74700d3dcddSRussell King {
74800d3dcddSRussell King 	struct platform_driver *drv = to_platform_driver(_dev->driver);
74900d3dcddSRussell King 	struct platform_device *dev = to_platform_device(_dev);
750b8b2c7d8SUwe Kleine-König 	int ret = 0;
75100d3dcddSRussell King 
752b8b2c7d8SUwe Kleine-König 	if (drv->remove)
75394d76d5dSRafael J. Wysocki 		ret = drv->remove(dev);
754cb518413SUlf Hansson 	dev_pm_domain_detach(_dev, true);
75594d76d5dSRafael J. Wysocki 
75694d76d5dSRafael J. Wysocki 	return ret;
75700d3dcddSRussell King }
75800d3dcddSRussell King 
75900d3dcddSRussell King static void platform_drv_shutdown(struct device *_dev)
76000d3dcddSRussell King {
76100d3dcddSRussell King 	struct platform_driver *drv = to_platform_driver(_dev->driver);
76200d3dcddSRussell King 	struct platform_device *dev = to_platform_device(_dev);
76300d3dcddSRussell King 
764b8b2c7d8SUwe Kleine-König 	if (drv->shutdown)
76500d3dcddSRussell King 		drv->shutdown(dev);
76600d3dcddSRussell King }
76700d3dcddSRussell King 
76800d3dcddSRussell King /**
7699447057eSLibo Chen  * __platform_driver_register - register a driver for platform-level devices
77000d3dcddSRussell King  * @drv: platform driver structure
77108801f96SRandy Dunlap  * @owner: owning module/driver
77200d3dcddSRussell King  */
7739447057eSLibo Chen int __platform_driver_register(struct platform_driver *drv,
7749447057eSLibo Chen 				struct module *owner)
77500d3dcddSRussell King {
7769447057eSLibo Chen 	drv->driver.owner = owner;
77700d3dcddSRussell King 	drv->driver.bus = &platform_bus_type;
77800d3dcddSRussell King 	drv->driver.probe = platform_drv_probe;
77900d3dcddSRussell King 	drv->driver.remove = platform_drv_remove;
78000d3dcddSRussell King 	drv->driver.shutdown = platform_drv_shutdown;
781783ea7d4SMagnus Damm 
78200d3dcddSRussell King 	return driver_register(&drv->driver);
78300d3dcddSRussell King }
7849447057eSLibo Chen EXPORT_SYMBOL_GPL(__platform_driver_register);
78500d3dcddSRussell King 
78600d3dcddSRussell King /**
7873c31f07aSBen Hutchings  * platform_driver_unregister - unregister a driver for platform-level devices
78800d3dcddSRussell King  * @drv: platform driver structure
78900d3dcddSRussell King  */
79000d3dcddSRussell King void platform_driver_unregister(struct platform_driver *drv)
79100d3dcddSRussell King {
79200d3dcddSRussell King 	driver_unregister(&drv->driver);
79300d3dcddSRussell King }
79400d3dcddSRussell King EXPORT_SYMBOL_GPL(platform_driver_unregister);
79500d3dcddSRussell King 
796c67334fbSDavid Brownell /**
797c3b50dc2SWolfram Sang  * __platform_driver_probe - register driver for non-hotpluggable device
798c67334fbSDavid Brownell  * @drv: platform driver structure
7993f9120b0SJohan Hovold  * @probe: the driver probe routine, probably from an __init section
800c3b50dc2SWolfram Sang  * @module: module which will be the owner of the driver
801c67334fbSDavid Brownell  *
802c67334fbSDavid Brownell  * Use this instead of platform_driver_register() when you know the device
803c67334fbSDavid Brownell  * is not hotpluggable and has already been registered, and you want to
804c67334fbSDavid Brownell  * remove its run-once probe() infrastructure from memory after the driver
805c67334fbSDavid Brownell  * has bound to the device.
806c67334fbSDavid Brownell  *
807c67334fbSDavid Brownell  * One typical use for this would be with drivers for controllers integrated
808c67334fbSDavid Brownell  * into system-on-chip processors, where the controller devices have been
809c67334fbSDavid Brownell  * configured as part of board setup.
810c67334fbSDavid Brownell  *
8113f9120b0SJohan Hovold  * Note that this is incompatible with deferred probing.
812647c86d0SFabio Porcedda  *
813c67334fbSDavid Brownell  * Returns zero if the driver registered and bound to a device, else returns
814c67334fbSDavid Brownell  * a negative error code and with the driver not registered.
815c67334fbSDavid Brownell  */
816c3b50dc2SWolfram Sang int __init_or_module __platform_driver_probe(struct platform_driver *drv,
817c3b50dc2SWolfram Sang 		int (*probe)(struct platform_device *), struct module *module)
818c67334fbSDavid Brownell {
819c67334fbSDavid Brownell 	int retval, code;
820c67334fbSDavid Brownell 
8215c36eb2aSDmitry Torokhov 	if (drv->driver.probe_type == PROBE_PREFER_ASYNCHRONOUS) {
8225c36eb2aSDmitry Torokhov 		pr_err("%s: drivers registered with %s can not be probed asynchronously\n",
8235c36eb2aSDmitry Torokhov 			 drv->driver.name, __func__);
8245c36eb2aSDmitry Torokhov 		return -EINVAL;
8255c36eb2aSDmitry Torokhov 	}
8265c36eb2aSDmitry Torokhov 
8275c36eb2aSDmitry Torokhov 	/*
8285c36eb2aSDmitry Torokhov 	 * We have to run our probes synchronously because we check if
8295c36eb2aSDmitry Torokhov 	 * we find any devices to bind to and exit with error if there
8305c36eb2aSDmitry Torokhov 	 * are any.
8315c36eb2aSDmitry Torokhov 	 */
8325c36eb2aSDmitry Torokhov 	drv->driver.probe_type = PROBE_FORCE_SYNCHRONOUS;
8335c36eb2aSDmitry Torokhov 
8343f9120b0SJohan Hovold 	/*
8353f9120b0SJohan Hovold 	 * Prevent driver from requesting probe deferral to avoid further
8363f9120b0SJohan Hovold 	 * futile probe attempts.
8373f9120b0SJohan Hovold 	 */
8383f9120b0SJohan Hovold 	drv->prevent_deferred_probe = true;
8393f9120b0SJohan Hovold 
8401a6f2a75SDmitry Torokhov 	/* make sure driver won't have bind/unbind attributes */
8411a6f2a75SDmitry Torokhov 	drv->driver.suppress_bind_attrs = true;
8421a6f2a75SDmitry Torokhov 
843c67334fbSDavid Brownell 	/* temporary section violation during probe() */
844c67334fbSDavid Brownell 	drv->probe = probe;
845c3b50dc2SWolfram Sang 	retval = code = __platform_driver_register(drv, module);
846c67334fbSDavid Brownell 
8471a6f2a75SDmitry Torokhov 	/*
8481a6f2a75SDmitry Torokhov 	 * Fixup that section violation, being paranoid about code scanning
849c67334fbSDavid Brownell 	 * the list of drivers in order to probe new devices.  Check to see
850c67334fbSDavid Brownell 	 * if the probe was successful, and make sure any forced probes of
851c67334fbSDavid Brownell 	 * new devices fail.
852c67334fbSDavid Brownell 	 */
853d79d3244SPatrick Pannuto 	spin_lock(&drv->driver.bus->p->klist_drivers.k_lock);
854c67334fbSDavid Brownell 	drv->probe = NULL;
855e5dd1278SGreg Kroah-Hartman 	if (code == 0 && list_empty(&drv->driver.p->klist_devices.k_list))
856c67334fbSDavid Brownell 		retval = -ENODEV;
857c67334fbSDavid Brownell 	drv->driver.probe = platform_drv_probe_fail;
858d79d3244SPatrick Pannuto 	spin_unlock(&drv->driver.bus->p->klist_drivers.k_lock);
859c67334fbSDavid Brownell 
860c67334fbSDavid Brownell 	if (code != retval)
861c67334fbSDavid Brownell 		platform_driver_unregister(drv);
862c67334fbSDavid Brownell 	return retval;
863c67334fbSDavid Brownell }
864c3b50dc2SWolfram Sang EXPORT_SYMBOL_GPL(__platform_driver_probe);
8651da177e4SLinus Torvalds 
866ecdf6cebSDmitry Torokhov /**
867291f653aSWolfram Sang  * __platform_create_bundle - register driver and create corresponding device
868ecdf6cebSDmitry Torokhov  * @driver: platform driver structure
869ecdf6cebSDmitry Torokhov  * @probe: the driver probe routine, probably from an __init section
870ecdf6cebSDmitry Torokhov  * @res: set of resources that needs to be allocated for the device
871ecdf6cebSDmitry Torokhov  * @n_res: number of resources
872ecdf6cebSDmitry Torokhov  * @data: platform specific data for this platform device
873ecdf6cebSDmitry Torokhov  * @size: size of platform specific data
874291f653aSWolfram Sang  * @module: module which will be the owner of the driver
875ecdf6cebSDmitry Torokhov  *
876ecdf6cebSDmitry Torokhov  * Use this in legacy-style modules that probe hardware directly and
877ecdf6cebSDmitry Torokhov  * register a single platform device and corresponding platform driver.
878f0eae0edSJani Nikula  *
879f0eae0edSJani Nikula  * Returns &struct platform_device pointer on success, or ERR_PTR() on error.
880ecdf6cebSDmitry Torokhov  */
881291f653aSWolfram Sang struct platform_device * __init_or_module __platform_create_bundle(
882ecdf6cebSDmitry Torokhov 			struct platform_driver *driver,
883ecdf6cebSDmitry Torokhov 			int (*probe)(struct platform_device *),
884ecdf6cebSDmitry Torokhov 			struct resource *res, unsigned int n_res,
885291f653aSWolfram Sang 			const void *data, size_t size, struct module *module)
886ecdf6cebSDmitry Torokhov {
887ecdf6cebSDmitry Torokhov 	struct platform_device *pdev;
888ecdf6cebSDmitry Torokhov 	int error;
889ecdf6cebSDmitry Torokhov 
890ecdf6cebSDmitry Torokhov 	pdev = platform_device_alloc(driver->driver.name, -1);
891ecdf6cebSDmitry Torokhov 	if (!pdev) {
892ecdf6cebSDmitry Torokhov 		error = -ENOMEM;
893ecdf6cebSDmitry Torokhov 		goto err_out;
894ecdf6cebSDmitry Torokhov 	}
895ecdf6cebSDmitry Torokhov 
896ecdf6cebSDmitry Torokhov 	error = platform_device_add_resources(pdev, res, n_res);
897ecdf6cebSDmitry Torokhov 	if (error)
898ecdf6cebSDmitry Torokhov 		goto err_pdev_put;
899ecdf6cebSDmitry Torokhov 
900ecdf6cebSDmitry Torokhov 	error = platform_device_add_data(pdev, data, size);
901ecdf6cebSDmitry Torokhov 	if (error)
902ecdf6cebSDmitry Torokhov 		goto err_pdev_put;
903ecdf6cebSDmitry Torokhov 
904ecdf6cebSDmitry Torokhov 	error = platform_device_add(pdev);
905ecdf6cebSDmitry Torokhov 	if (error)
906ecdf6cebSDmitry Torokhov 		goto err_pdev_put;
907ecdf6cebSDmitry Torokhov 
908291f653aSWolfram Sang 	error = __platform_driver_probe(driver, probe, module);
909ecdf6cebSDmitry Torokhov 	if (error)
910ecdf6cebSDmitry Torokhov 		goto err_pdev_del;
911ecdf6cebSDmitry Torokhov 
912ecdf6cebSDmitry Torokhov 	return pdev;
913ecdf6cebSDmitry Torokhov 
914ecdf6cebSDmitry Torokhov err_pdev_del:
915ecdf6cebSDmitry Torokhov 	platform_device_del(pdev);
916ecdf6cebSDmitry Torokhov err_pdev_put:
917ecdf6cebSDmitry Torokhov 	platform_device_put(pdev);
918ecdf6cebSDmitry Torokhov err_out:
919ecdf6cebSDmitry Torokhov 	return ERR_PTR(error);
920ecdf6cebSDmitry Torokhov }
921291f653aSWolfram Sang EXPORT_SYMBOL_GPL(__platform_create_bundle);
922ecdf6cebSDmitry Torokhov 
923dbe2256dSThierry Reding /**
924dbe2256dSThierry Reding  * __platform_register_drivers - register an array of platform drivers
925dbe2256dSThierry Reding  * @drivers: an array of drivers to register
926dbe2256dSThierry Reding  * @count: the number of drivers to register
927dbe2256dSThierry Reding  * @owner: module owning the drivers
928dbe2256dSThierry Reding  *
929dbe2256dSThierry Reding  * Registers platform drivers specified by an array. On failure to register a
930dbe2256dSThierry Reding  * driver, all previously registered drivers will be unregistered. Callers of
931dbe2256dSThierry Reding  * this API should use platform_unregister_drivers() to unregister drivers in
932dbe2256dSThierry Reding  * the reverse order.
933dbe2256dSThierry Reding  *
934dbe2256dSThierry Reding  * Returns: 0 on success or a negative error code on failure.
935dbe2256dSThierry Reding  */
936dbe2256dSThierry Reding int __platform_register_drivers(struct platform_driver * const *drivers,
937dbe2256dSThierry Reding 				unsigned int count, struct module *owner)
938dbe2256dSThierry Reding {
939dbe2256dSThierry Reding 	unsigned int i;
940dbe2256dSThierry Reding 	int err;
941dbe2256dSThierry Reding 
942dbe2256dSThierry Reding 	for (i = 0; i < count; i++) {
943dbe2256dSThierry Reding 		pr_debug("registering platform driver %ps\n", drivers[i]);
944dbe2256dSThierry Reding 
945dbe2256dSThierry Reding 		err = __platform_driver_register(drivers[i], owner);
946dbe2256dSThierry Reding 		if (err < 0) {
947dbe2256dSThierry Reding 			pr_err("failed to register platform driver %ps: %d\n",
948dbe2256dSThierry Reding 			       drivers[i], err);
949dbe2256dSThierry Reding 			goto error;
950dbe2256dSThierry Reding 		}
951dbe2256dSThierry Reding 	}
952dbe2256dSThierry Reding 
953dbe2256dSThierry Reding 	return 0;
954dbe2256dSThierry Reding 
955dbe2256dSThierry Reding error:
956dbe2256dSThierry Reding 	while (i--) {
957dbe2256dSThierry Reding 		pr_debug("unregistering platform driver %ps\n", drivers[i]);
958dbe2256dSThierry Reding 		platform_driver_unregister(drivers[i]);
959dbe2256dSThierry Reding 	}
960dbe2256dSThierry Reding 
961dbe2256dSThierry Reding 	return err;
962dbe2256dSThierry Reding }
963dbe2256dSThierry Reding EXPORT_SYMBOL_GPL(__platform_register_drivers);
964dbe2256dSThierry Reding 
965dbe2256dSThierry Reding /**
966dbe2256dSThierry Reding  * platform_unregister_drivers - unregister an array of platform drivers
967dbe2256dSThierry Reding  * @drivers: an array of drivers to unregister
968dbe2256dSThierry Reding  * @count: the number of drivers to unregister
969dbe2256dSThierry Reding  *
970dbe2256dSThierry Reding  * Unegisters platform drivers specified by an array. This is typically used
971dbe2256dSThierry Reding  * to complement an earlier call to platform_register_drivers(). Drivers are
972dbe2256dSThierry Reding  * unregistered in the reverse order in which they were registered.
973dbe2256dSThierry Reding  */
974dbe2256dSThierry Reding void platform_unregister_drivers(struct platform_driver * const *drivers,
975dbe2256dSThierry Reding 				 unsigned int count)
976dbe2256dSThierry Reding {
977dbe2256dSThierry Reding 	while (count--) {
978dbe2256dSThierry Reding 		pr_debug("unregistering platform driver %ps\n", drivers[count]);
979dbe2256dSThierry Reding 		platform_driver_unregister(drivers[count]);
980dbe2256dSThierry Reding 	}
981dbe2256dSThierry Reding }
982dbe2256dSThierry Reding EXPORT_SYMBOL_GPL(platform_unregister_drivers);
983dbe2256dSThierry Reding 
984a0245f7aSDavid Brownell /* modalias support enables more hands-off userspace setup:
985a0245f7aSDavid Brownell  * (a) environment variable lets new-style hotplug events work once system is
986a0245f7aSDavid Brownell  *     fully running:  "modprobe $MODALIAS"
987a0245f7aSDavid Brownell  * (b) sysfs attribute lets new-style coldplug recover from hotplug events
988a0245f7aSDavid Brownell  *     mishandled before system is fully running:  "modprobe $(cat modalias)"
989a0245f7aSDavid Brownell  */
9904a3ad20cSGreg Kroah-Hartman static ssize_t modalias_show(struct device *dev, struct device_attribute *a,
9914a3ad20cSGreg Kroah-Hartman 			     char *buf)
992a0245f7aSDavid Brownell {
993a0245f7aSDavid Brownell 	struct platform_device	*pdev = to_platform_device(dev);
9948c4ff6d0SZhang Rui 	int len;
9958c4ff6d0SZhang Rui 
9960634c295SRob Herring 	len = of_device_modalias(dev, buf, PAGE_SIZE);
997b9f73067SZhang Rui 	if (len != -ENODEV)
998b9f73067SZhang Rui 		return len;
999b9f73067SZhang Rui 
10008c4ff6d0SZhang Rui 	len = acpi_device_modalias(dev, buf, PAGE_SIZE -1);
10018c4ff6d0SZhang Rui 	if (len != -ENODEV)
10028c4ff6d0SZhang Rui 		return len;
10038c4ff6d0SZhang Rui 
1004391c0325SGreg Kroah-Hartman 	len = snprintf(buf, PAGE_SIZE, "platform:%s\n", pdev->name);
1005a0245f7aSDavid Brownell 
1006a0245f7aSDavid Brownell 	return (len >= PAGE_SIZE) ? (PAGE_SIZE - 1) : len;
1007a0245f7aSDavid Brownell }
1008d06262e5SGreg Kroah-Hartman static DEVICE_ATTR_RO(modalias);
1009a0245f7aSDavid Brownell 
10103d713e0eSKim Phillips static ssize_t driver_override_store(struct device *dev,
10113d713e0eSKim Phillips 				     struct device_attribute *attr,
10123d713e0eSKim Phillips 				     const char *buf, size_t count)
10133d713e0eSKim Phillips {
10143d713e0eSKim Phillips 	struct platform_device *pdev = to_platform_device(dev);
101562655397SAdrian Salido 	char *driver_override, *old, *cp;
10163d713e0eSKim Phillips 
1017bf563b01SNicolai Stange 	/* We need to keep extra room for a newline */
1018bf563b01SNicolai Stange 	if (count >= (PAGE_SIZE - 1))
10193d713e0eSKim Phillips 		return -EINVAL;
10203d713e0eSKim Phillips 
10213d713e0eSKim Phillips 	driver_override = kstrndup(buf, count, GFP_KERNEL);
10223d713e0eSKim Phillips 	if (!driver_override)
10233d713e0eSKim Phillips 		return -ENOMEM;
10243d713e0eSKim Phillips 
10253d713e0eSKim Phillips 	cp = strchr(driver_override, '\n');
10263d713e0eSKim Phillips 	if (cp)
10273d713e0eSKim Phillips 		*cp = '\0';
10283d713e0eSKim Phillips 
102962655397SAdrian Salido 	device_lock(dev);
103062655397SAdrian Salido 	old = pdev->driver_override;
10313d713e0eSKim Phillips 	if (strlen(driver_override)) {
10323d713e0eSKim Phillips 		pdev->driver_override = driver_override;
10333d713e0eSKim Phillips 	} else {
10343d713e0eSKim Phillips 		kfree(driver_override);
10353d713e0eSKim Phillips 		pdev->driver_override = NULL;
10363d713e0eSKim Phillips 	}
103762655397SAdrian Salido 	device_unlock(dev);
10383d713e0eSKim Phillips 
10393d713e0eSKim Phillips 	kfree(old);
10403d713e0eSKim Phillips 
10413d713e0eSKim Phillips 	return count;
10423d713e0eSKim Phillips }
10433d713e0eSKim Phillips 
10443d713e0eSKim Phillips static ssize_t driver_override_show(struct device *dev,
10453d713e0eSKim Phillips 				    struct device_attribute *attr, char *buf)
10463d713e0eSKim Phillips {
10473d713e0eSKim Phillips 	struct platform_device *pdev = to_platform_device(dev);
104862655397SAdrian Salido 	ssize_t len;
10493d713e0eSKim Phillips 
105062655397SAdrian Salido 	device_lock(dev);
105162655397SAdrian Salido 	len = sprintf(buf, "%s\n", pdev->driver_override);
105262655397SAdrian Salido 	device_unlock(dev);
105362655397SAdrian Salido 	return len;
10543d713e0eSKim Phillips }
10553d713e0eSKim Phillips static DEVICE_ATTR_RW(driver_override);
10563d713e0eSKim Phillips 
10573d713e0eSKim Phillips 
1058d06262e5SGreg Kroah-Hartman static struct attribute *platform_dev_attrs[] = {
1059d06262e5SGreg Kroah-Hartman 	&dev_attr_modalias.attr,
10603d713e0eSKim Phillips 	&dev_attr_driver_override.attr,
1061d06262e5SGreg Kroah-Hartman 	NULL,
1062a0245f7aSDavid Brownell };
1063d06262e5SGreg Kroah-Hartman ATTRIBUTE_GROUPS(platform_dev);
1064a0245f7aSDavid Brownell 
10657eff2e7aSKay Sievers static int platform_uevent(struct device *dev, struct kobj_uevent_env *env)
1066a0245f7aSDavid Brownell {
1067a0245f7aSDavid Brownell 	struct platform_device	*pdev = to_platform_device(dev);
1068eca39301SGrant Likely 	int rc;
1069eca39301SGrant Likely 
1070eca39301SGrant Likely 	/* Some devices have extra OF data and an OF-style MODALIAS */
107107d57a32SGrant Likely 	rc = of_device_uevent_modalias(dev, env);
1072eca39301SGrant Likely 	if (rc != -ENODEV)
1073eca39301SGrant Likely 		return rc;
1074a0245f7aSDavid Brownell 
10758c4ff6d0SZhang Rui 	rc = acpi_device_uevent_modalias(dev, env);
10768c4ff6d0SZhang Rui 	if (rc != -ENODEV)
10778c4ff6d0SZhang Rui 		return rc;
10788c4ff6d0SZhang Rui 
107957fee4a5SEric Miao 	add_uevent_var(env, "MODALIAS=%s%s", PLATFORM_MODULE_PREFIX,
1080391c0325SGreg Kroah-Hartman 			pdev->name);
1081a0245f7aSDavid Brownell 	return 0;
1082a0245f7aSDavid Brownell }
1083a0245f7aSDavid Brownell 
108457fee4a5SEric Miao static const struct platform_device_id *platform_match_id(
1085831fad2fSUwe Kleine-König 			const struct platform_device_id *id,
108657fee4a5SEric Miao 			struct platform_device *pdev)
108757fee4a5SEric Miao {
108857fee4a5SEric Miao 	while (id->name[0]) {
1089391c0325SGreg Kroah-Hartman 		if (strcmp(pdev->name, id->name) == 0) {
109057fee4a5SEric Miao 			pdev->id_entry = id;
109157fee4a5SEric Miao 			return id;
109257fee4a5SEric Miao 		}
109357fee4a5SEric Miao 		id++;
109457fee4a5SEric Miao 	}
109557fee4a5SEric Miao 	return NULL;
109657fee4a5SEric Miao }
109757fee4a5SEric Miao 
10981da177e4SLinus Torvalds /**
10991da177e4SLinus Torvalds  * platform_match - bind platform device to platform driver.
11001da177e4SLinus Torvalds  * @dev: device.
11011da177e4SLinus Torvalds  * @drv: driver.
11021da177e4SLinus Torvalds  *
11031da177e4SLinus Torvalds  * Platform device IDs are assumed to be encoded like this:
11044a3ad20cSGreg Kroah-Hartman  * "<name><instance>", where <name> is a short description of the type of
11054a3ad20cSGreg Kroah-Hartman  * device, like "pci" or "floppy", and <instance> is the enumerated
11064a3ad20cSGreg Kroah-Hartman  * instance of the device, like '0' or '42'.  Driver IDs are simply
11074a3ad20cSGreg Kroah-Hartman  * "<name>".  So, extract the <name> from the platform_device structure,
11084a3ad20cSGreg Kroah-Hartman  * and compare it against the name of the driver. Return whether they match
11094a3ad20cSGreg Kroah-Hartman  * or not.
11101da177e4SLinus Torvalds  */
11111da177e4SLinus Torvalds static int platform_match(struct device *dev, struct device_driver *drv)
11121da177e4SLinus Torvalds {
111371b3e0c1SEric Miao 	struct platform_device *pdev = to_platform_device(dev);
111457fee4a5SEric Miao 	struct platform_driver *pdrv = to_platform_driver(drv);
11151da177e4SLinus Torvalds 
11163d713e0eSKim Phillips 	/* When driver_override is set, only bind to the matching driver */
11173d713e0eSKim Phillips 	if (pdev->driver_override)
11183d713e0eSKim Phillips 		return !strcmp(pdev->driver_override, drv->name);
11193d713e0eSKim Phillips 
112005212157SGrant Likely 	/* Attempt an OF style match first */
112105212157SGrant Likely 	if (of_driver_match_device(dev, drv))
112205212157SGrant Likely 		return 1;
112305212157SGrant Likely 
112491e56878SMika Westerberg 	/* Then try ACPI style match */
112591e56878SMika Westerberg 	if (acpi_driver_match_device(dev, drv))
112691e56878SMika Westerberg 		return 1;
112791e56878SMika Westerberg 
112805212157SGrant Likely 	/* Then try to match against the id table */
112957fee4a5SEric Miao 	if (pdrv->id_table)
113057fee4a5SEric Miao 		return platform_match_id(pdrv->id_table, pdev) != NULL;
113157fee4a5SEric Miao 
113257fee4a5SEric Miao 	/* fall-back to driver name match */
1133391c0325SGreg Kroah-Hartman 	return (strcmp(pdev->name, drv->name) == 0);
11341da177e4SLinus Torvalds }
11351da177e4SLinus Torvalds 
113625e18499SRafael J. Wysocki #ifdef CONFIG_PM_SLEEP
113725e18499SRafael J. Wysocki 
113825e18499SRafael J. Wysocki static int platform_legacy_suspend(struct device *dev, pm_message_t mesg)
11391da177e4SLinus Torvalds {
1140783ea7d4SMagnus Damm 	struct platform_driver *pdrv = to_platform_driver(dev->driver);
1141783ea7d4SMagnus Damm 	struct platform_device *pdev = to_platform_device(dev);
11421da177e4SLinus Torvalds 	int ret = 0;
11431da177e4SLinus Torvalds 
1144783ea7d4SMagnus Damm 	if (dev->driver && pdrv->suspend)
1145783ea7d4SMagnus Damm 		ret = pdrv->suspend(pdev, mesg);
1146386415d8SDavid Brownell 
1147386415d8SDavid Brownell 	return ret;
1148386415d8SDavid Brownell }
1149386415d8SDavid Brownell 
115025e18499SRafael J. Wysocki static int platform_legacy_resume(struct device *dev)
11511da177e4SLinus Torvalds {
1152783ea7d4SMagnus Damm 	struct platform_driver *pdrv = to_platform_driver(dev->driver);
1153783ea7d4SMagnus Damm 	struct platform_device *pdev = to_platform_device(dev);
11541da177e4SLinus Torvalds 	int ret = 0;
11551da177e4SLinus Torvalds 
1156783ea7d4SMagnus Damm 	if (dev->driver && pdrv->resume)
1157783ea7d4SMagnus Damm 		ret = pdrv->resume(pdev);
11589480e307SRussell King 
11591da177e4SLinus Torvalds 	return ret;
11601da177e4SLinus Torvalds }
11611da177e4SLinus Torvalds 
116269c9dd1eSRafael J. Wysocki #endif /* CONFIG_PM_SLEEP */
11639d730229SMagnus Damm 
116425e18499SRafael J. Wysocki #ifdef CONFIG_SUSPEND
116525e18499SRafael J. Wysocki 
116669c9dd1eSRafael J. Wysocki int platform_pm_suspend(struct device *dev)
116725e18499SRafael J. Wysocki {
116825e18499SRafael J. Wysocki 	struct device_driver *drv = dev->driver;
116925e18499SRafael J. Wysocki 	int ret = 0;
117025e18499SRafael J. Wysocki 
1171adf09493SRafael J. Wysocki 	if (!drv)
1172adf09493SRafael J. Wysocki 		return 0;
1173adf09493SRafael J. Wysocki 
1174adf09493SRafael J. Wysocki 	if (drv->pm) {
117525e18499SRafael J. Wysocki 		if (drv->pm->suspend)
117625e18499SRafael J. Wysocki 			ret = drv->pm->suspend(dev);
117725e18499SRafael J. Wysocki 	} else {
117825e18499SRafael J. Wysocki 		ret = platform_legacy_suspend(dev, PMSG_SUSPEND);
117925e18499SRafael J. Wysocki 	}
118025e18499SRafael J. Wysocki 
118125e18499SRafael J. Wysocki 	return ret;
118225e18499SRafael J. Wysocki }
118325e18499SRafael J. Wysocki 
118469c9dd1eSRafael J. Wysocki int platform_pm_resume(struct device *dev)
118525e18499SRafael J. Wysocki {
118625e18499SRafael J. Wysocki 	struct device_driver *drv = dev->driver;
118725e18499SRafael J. Wysocki 	int ret = 0;
118825e18499SRafael J. Wysocki 
1189adf09493SRafael J. Wysocki 	if (!drv)
1190adf09493SRafael J. Wysocki 		return 0;
1191adf09493SRafael J. Wysocki 
1192adf09493SRafael J. Wysocki 	if (drv->pm) {
119325e18499SRafael J. Wysocki 		if (drv->pm->resume)
119425e18499SRafael J. Wysocki 			ret = drv->pm->resume(dev);
119525e18499SRafael J. Wysocki 	} else {
119625e18499SRafael J. Wysocki 		ret = platform_legacy_resume(dev);
119725e18499SRafael J. Wysocki 	}
119825e18499SRafael J. Wysocki 
119925e18499SRafael J. Wysocki 	return ret;
120025e18499SRafael J. Wysocki }
120125e18499SRafael J. Wysocki 
120269c9dd1eSRafael J. Wysocki #endif /* CONFIG_SUSPEND */
120325e18499SRafael J. Wysocki 
12041f112ceeSRafael J. Wysocki #ifdef CONFIG_HIBERNATE_CALLBACKS
120525e18499SRafael J. Wysocki 
120669c9dd1eSRafael J. Wysocki int platform_pm_freeze(struct device *dev)
120725e18499SRafael J. Wysocki {
120825e18499SRafael J. Wysocki 	struct device_driver *drv = dev->driver;
120925e18499SRafael J. Wysocki 	int ret = 0;
121025e18499SRafael J. Wysocki 
121125e18499SRafael J. Wysocki 	if (!drv)
121225e18499SRafael J. Wysocki 		return 0;
121325e18499SRafael J. Wysocki 
121425e18499SRafael J. Wysocki 	if (drv->pm) {
121525e18499SRafael J. Wysocki 		if (drv->pm->freeze)
121625e18499SRafael J. Wysocki 			ret = drv->pm->freeze(dev);
121725e18499SRafael J. Wysocki 	} else {
121825e18499SRafael J. Wysocki 		ret = platform_legacy_suspend(dev, PMSG_FREEZE);
121925e18499SRafael J. Wysocki 	}
122025e18499SRafael J. Wysocki 
122125e18499SRafael J. Wysocki 	return ret;
122225e18499SRafael J. Wysocki }
122325e18499SRafael J. Wysocki 
122469c9dd1eSRafael J. Wysocki int platform_pm_thaw(struct device *dev)
122525e18499SRafael J. Wysocki {
122625e18499SRafael J. Wysocki 	struct device_driver *drv = dev->driver;
122725e18499SRafael J. Wysocki 	int ret = 0;
122825e18499SRafael J. Wysocki 
1229adf09493SRafael J. Wysocki 	if (!drv)
1230adf09493SRafael J. Wysocki 		return 0;
1231adf09493SRafael J. Wysocki 
1232adf09493SRafael J. Wysocki 	if (drv->pm) {
123325e18499SRafael J. Wysocki 		if (drv->pm->thaw)
123425e18499SRafael J. Wysocki 			ret = drv->pm->thaw(dev);
123525e18499SRafael J. Wysocki 	} else {
123625e18499SRafael J. Wysocki 		ret = platform_legacy_resume(dev);
123725e18499SRafael J. Wysocki 	}
123825e18499SRafael J. Wysocki 
123925e18499SRafael J. Wysocki 	return ret;
124025e18499SRafael J. Wysocki }
124125e18499SRafael J. Wysocki 
124269c9dd1eSRafael J. Wysocki int platform_pm_poweroff(struct device *dev)
124325e18499SRafael J. Wysocki {
124425e18499SRafael J. Wysocki 	struct device_driver *drv = dev->driver;
124525e18499SRafael J. Wysocki 	int ret = 0;
124625e18499SRafael J. Wysocki 
1247adf09493SRafael J. Wysocki 	if (!drv)
1248adf09493SRafael J. Wysocki 		return 0;
1249adf09493SRafael J. Wysocki 
1250adf09493SRafael J. Wysocki 	if (drv->pm) {
125125e18499SRafael J. Wysocki 		if (drv->pm->poweroff)
125225e18499SRafael J. Wysocki 			ret = drv->pm->poweroff(dev);
125325e18499SRafael J. Wysocki 	} else {
125425e18499SRafael J. Wysocki 		ret = platform_legacy_suspend(dev, PMSG_HIBERNATE);
125525e18499SRafael J. Wysocki 	}
125625e18499SRafael J. Wysocki 
125725e18499SRafael J. Wysocki 	return ret;
125825e18499SRafael J. Wysocki }
125925e18499SRafael J. Wysocki 
126069c9dd1eSRafael J. Wysocki int platform_pm_restore(struct device *dev)
126125e18499SRafael J. Wysocki {
126225e18499SRafael J. Wysocki 	struct device_driver *drv = dev->driver;
126325e18499SRafael J. Wysocki 	int ret = 0;
126425e18499SRafael J. Wysocki 
1265adf09493SRafael J. Wysocki 	if (!drv)
1266adf09493SRafael J. Wysocki 		return 0;
1267adf09493SRafael J. Wysocki 
1268adf09493SRafael J. Wysocki 	if (drv->pm) {
126925e18499SRafael J. Wysocki 		if (drv->pm->restore)
127025e18499SRafael J. Wysocki 			ret = drv->pm->restore(dev);
127125e18499SRafael J. Wysocki 	} else {
127225e18499SRafael J. Wysocki 		ret = platform_legacy_resume(dev);
127325e18499SRafael J. Wysocki 	}
127425e18499SRafael J. Wysocki 
127525e18499SRafael J. Wysocki 	return ret;
127625e18499SRafael J. Wysocki }
127725e18499SRafael J. Wysocki 
127869c9dd1eSRafael J. Wysocki #endif /* CONFIG_HIBERNATE_CALLBACKS */
127925e18499SRafael J. Wysocki 
128007397df2SNipun Gupta int platform_dma_configure(struct device *dev)
128107397df2SNipun Gupta {
128207397df2SNipun Gupta 	enum dev_dma_attr attr;
128307397df2SNipun Gupta 	int ret = 0;
128407397df2SNipun Gupta 
128507397df2SNipun Gupta 	if (dev->of_node) {
12863d6ce86eSChristoph Hellwig 		ret = of_dma_configure(dev, dev->of_node, true);
128707397df2SNipun Gupta 	} else if (has_acpi_companion(dev)) {
128807397df2SNipun Gupta 		attr = acpi_get_dma_attr(to_acpi_device_node(dev->fwnode));
128907397df2SNipun Gupta 		ret = acpi_dma_configure(dev, attr);
129007397df2SNipun Gupta 	}
129107397df2SNipun Gupta 
129207397df2SNipun Gupta 	return ret;
129307397df2SNipun Gupta }
129407397df2SNipun Gupta 
1295d9ab7716SDmitry Torokhov static const struct dev_pm_ops platform_dev_pm_ops = {
12968b313a38SRafael J. Wysocki 	.runtime_suspend = pm_generic_runtime_suspend,
12978b313a38SRafael J. Wysocki 	.runtime_resume = pm_generic_runtime_resume,
129869c9dd1eSRafael J. Wysocki 	USE_PLATFORM_PM_SLEEP_OPS
129925e18499SRafael J. Wysocki };
130025e18499SRafael J. Wysocki 
13011da177e4SLinus Torvalds struct bus_type platform_bus_type = {
13021da177e4SLinus Torvalds 	.name		= "platform",
1303d06262e5SGreg Kroah-Hartman 	.dev_groups	= platform_dev_groups,
13041da177e4SLinus Torvalds 	.match		= platform_match,
1305a0245f7aSDavid Brownell 	.uevent		= platform_uevent,
130607397df2SNipun Gupta 	.dma_configure	= platform_dma_configure,
13079d730229SMagnus Damm 	.pm		= &platform_dev_pm_ops,
13081da177e4SLinus Torvalds };
1309a96b2042SDmitry Torokhov EXPORT_SYMBOL_GPL(platform_bus_type);
13101da177e4SLinus Torvalds 
1311492c8872SSami Tolvanen static inline int __platform_match(struct device *dev, const void *drv)
1312492c8872SSami Tolvanen {
1313492c8872SSami Tolvanen 	return platform_match(dev, (struct device_driver *)drv);
1314492c8872SSami Tolvanen }
1315492c8872SSami Tolvanen 
131636f3313dSSuzuki K Poulose /**
131736f3313dSSuzuki K Poulose  * platform_find_device_by_driver - Find a platform device with a given
131836f3313dSSuzuki K Poulose  * driver.
131936f3313dSSuzuki K Poulose  * @start: The device to start the search from.
132036f3313dSSuzuki K Poulose  * @drv: The device driver to look for.
132136f3313dSSuzuki K Poulose  */
132236f3313dSSuzuki K Poulose struct device *platform_find_device_by_driver(struct device *start,
132336f3313dSSuzuki K Poulose 					      const struct device_driver *drv)
132436f3313dSSuzuki K Poulose {
132536f3313dSSuzuki K Poulose 	return bus_find_device(&platform_bus_type, start, drv,
1326492c8872SSami Tolvanen 			       __platform_match);
132736f3313dSSuzuki K Poulose }
132836f3313dSSuzuki K Poulose EXPORT_SYMBOL_GPL(platform_find_device_by_driver);
132936f3313dSSuzuki K Poulose 
1330eecd37e1SGuenter Roeck void __weak __init early_platform_cleanup(void) { }
1331eecd37e1SGuenter Roeck 
13321da177e4SLinus Torvalds int __init platform_bus_init(void)
13331da177e4SLinus Torvalds {
1334fbfb1445SCornelia Huck 	int error;
1335fbfb1445SCornelia Huck 
1336eecd37e1SGuenter Roeck 	early_platform_cleanup();
1337eecd37e1SGuenter Roeck 
1338fbfb1445SCornelia Huck 	error = device_register(&platform_bus);
1339c8ae1674SArvind Yadav 	if (error) {
1340c8ae1674SArvind Yadav 		put_device(&platform_bus);
1341fbfb1445SCornelia Huck 		return error;
1342c8ae1674SArvind Yadav 	}
1343fbfb1445SCornelia Huck 	error =  bus_register(&platform_bus_type);
1344fbfb1445SCornelia Huck 	if (error)
1345fbfb1445SCornelia Huck 		device_unregister(&platform_bus);
1346801d728cSPantelis Antoniou 	of_platform_register_reconfig_notifier();
1347fbfb1445SCornelia Huck 	return error;
13481da177e4SLinus Torvalds }
1349