xref: /openbmc/linux/drivers/base/platform.c (revision 73aca58b)
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>
18e15f2fa9SJohn Garry #include <linux/interrupt.h>
19e15f2fa9SJohn Garry #include <linux/ioport.h>
201da177e4SLinus Torvalds #include <linux/dma-mapping.h>
2157c8a661SMike Rapoport #include <linux/memblock.h>
221da177e4SLinus Torvalds #include <linux/err.h>
234e57b681STim Schmielau #include <linux/slab.h>
249d730229SMagnus Damm #include <linux/pm_runtime.h>
25f48c767cSUlf Hansson #include <linux/pm_domain.h>
26689ae231SJean Delvare #include <linux/idr.h>
2791e56878SMika Westerberg #include <linux/acpi.h>
2886be408bSSylwester Nawrocki #include <linux/clk/clk-conf.h>
293d713e0eSKim Phillips #include <linux/limits.h>
3000bbc1d8SMika Westerberg #include <linux/property.h>
31967d3010SQian Cai #include <linux/kmemleak.h>
3239cc539fSSimon Schwartz #include <linux/types.h>
33512881eaSLu Baolu #include <linux/iommu.h>
34512881eaSLu Baolu #include <linux/dma-map-ops.h>
351da177e4SLinus Torvalds 
36a1bdc7aaSBen Dooks #include "base.h"
37bed2b42dSRafael J. Wysocki #include "power/power.h"
38a1bdc7aaSBen Dooks 
39689ae231SJean Delvare /* For automatically allocated device IDs */
40689ae231SJean Delvare static DEFINE_IDA(platform_devid_ida);
41689ae231SJean Delvare 
421da177e4SLinus Torvalds struct device platform_bus = {
431e0b2cf9SKay Sievers 	.init_name	= "platform",
441da177e4SLinus Torvalds };
45a96b2042SDmitry Torokhov EXPORT_SYMBOL_GPL(platform_bus);
461da177e4SLinus Torvalds 
471da177e4SLinus Torvalds /**
481da177e4SLinus Torvalds  * platform_get_resource - get a resource for a device
491da177e4SLinus Torvalds  * @dev: platform device
501da177e4SLinus Torvalds  * @type: resource type
511da177e4SLinus Torvalds  * @num: resource index
520c7a6b91SStephen Boyd  *
530c7a6b91SStephen Boyd  * Return: a pointer to the resource or NULL on failure.
541da177e4SLinus Torvalds  */
platform_get_resource(struct platform_device * dev,unsigned int type,unsigned int num)554a3ad20cSGreg Kroah-Hartman struct resource *platform_get_resource(struct platform_device *dev,
564a3ad20cSGreg Kroah-Hartman 				       unsigned int type, unsigned int num)
571da177e4SLinus Torvalds {
5839cc539fSSimon Schwartz 	u32 i;
591da177e4SLinus Torvalds 
601da177e4SLinus Torvalds 	for (i = 0; i < dev->num_resources; i++) {
611da177e4SLinus Torvalds 		struct resource *r = &dev->resource[i];
621da177e4SLinus Torvalds 
63c9f66169SMagnus Damm 		if (type == resource_type(r) && num-- == 0)
641da177e4SLinus Torvalds 			return r;
651da177e4SLinus Torvalds 	}
661da177e4SLinus Torvalds 	return NULL;
671da177e4SLinus Torvalds }
68a96b2042SDmitry Torokhov EXPORT_SYMBOL_GPL(platform_get_resource);
691da177e4SLinus Torvalds 
platform_get_mem_or_io(struct platform_device * dev,unsigned int num)700aec2da4SAndy Shevchenko struct resource *platform_get_mem_or_io(struct platform_device *dev,
710aec2da4SAndy Shevchenko 					unsigned int num)
720aec2da4SAndy Shevchenko {
730aec2da4SAndy Shevchenko 	u32 i;
740aec2da4SAndy Shevchenko 
750aec2da4SAndy Shevchenko 	for (i = 0; i < dev->num_resources; i++) {
760aec2da4SAndy Shevchenko 		struct resource *r = &dev->resource[i];
770aec2da4SAndy Shevchenko 
780aec2da4SAndy Shevchenko 		if ((resource_type(r) & (IORESOURCE_MEM|IORESOURCE_IO)) && num-- == 0)
790aec2da4SAndy Shevchenko 			return r;
800aec2da4SAndy Shevchenko 	}
810aec2da4SAndy Shevchenko 	return NULL;
820aec2da4SAndy Shevchenko }
830aec2da4SAndy Shevchenko EXPORT_SYMBOL_GPL(platform_get_mem_or_io);
840aec2da4SAndy Shevchenko 
85bb6243b4SBartosz Golaszewski #ifdef CONFIG_HAS_IOMEM
861da177e4SLinus Torvalds /**
87890cc39aSDejin Zheng  * devm_platform_get_and_ioremap_resource - call devm_ioremap_resource() for a
88890cc39aSDejin Zheng  *					    platform device and get resource
89890cc39aSDejin Zheng  *
90890cc39aSDejin Zheng  * @pdev: platform device to use both for memory resource lookup as well as
91890cc39aSDejin Zheng  *        resource management
92890cc39aSDejin Zheng  * @index: resource index
93890cc39aSDejin Zheng  * @res: optional output parameter to store a pointer to the obtained resource.
940c7a6b91SStephen Boyd  *
950c7a6b91SStephen Boyd  * Return: a pointer to the remapped memory or an ERR_PTR() encoded error code
960c7a6b91SStephen Boyd  * on failure.
97890cc39aSDejin Zheng  */
98890cc39aSDejin Zheng void __iomem *
devm_platform_get_and_ioremap_resource(struct platform_device * pdev,unsigned int index,struct resource ** res)99890cc39aSDejin Zheng devm_platform_get_and_ioremap_resource(struct platform_device *pdev,
100890cc39aSDejin Zheng 				unsigned int index, struct resource **res)
101890cc39aSDejin Zheng {
102890cc39aSDejin Zheng 	struct resource *r;
103890cc39aSDejin Zheng 
104890cc39aSDejin Zheng 	r = platform_get_resource(pdev, IORESOURCE_MEM, index);
105890cc39aSDejin Zheng 	if (res)
106890cc39aSDejin Zheng 		*res = r;
107890cc39aSDejin Zheng 	return devm_ioremap_resource(&pdev->dev, r);
108890cc39aSDejin Zheng }
109890cc39aSDejin Zheng EXPORT_SYMBOL_GPL(devm_platform_get_and_ioremap_resource);
110890cc39aSDejin Zheng 
111890cc39aSDejin Zheng /**
1127945f929SBartosz Golaszewski  * devm_platform_ioremap_resource - call devm_ioremap_resource() for a platform
1137945f929SBartosz Golaszewski  *				    device
1147945f929SBartosz Golaszewski  *
1157945f929SBartosz Golaszewski  * @pdev: platform device to use both for memory resource lookup as well as
1167067c96eSBartosz Golaszewski  *        resource management
1177945f929SBartosz Golaszewski  * @index: resource index
1180c7a6b91SStephen Boyd  *
1190c7a6b91SStephen Boyd  * Return: a pointer to the remapped memory or an ERR_PTR() encoded error code
1200c7a6b91SStephen Boyd  * on failure.
1217945f929SBartosz Golaszewski  */
devm_platform_ioremap_resource(struct platform_device * pdev,unsigned int index)1227945f929SBartosz Golaszewski void __iomem *devm_platform_ioremap_resource(struct platform_device *pdev,
1237945f929SBartosz Golaszewski 					     unsigned int index)
1247945f929SBartosz Golaszewski {
125fd78901cSDejin Zheng 	return devm_platform_get_and_ioremap_resource(pdev, index, NULL);
1267945f929SBartosz Golaszewski }
1277945f929SBartosz Golaszewski EXPORT_SYMBOL_GPL(devm_platform_ioremap_resource);
128bb6243b4SBartosz Golaszewski 
129bb6243b4SBartosz Golaszewski /**
130c9c8641dSBartosz Golaszewski  * devm_platform_ioremap_resource_byname - call devm_ioremap_resource for
131c9c8641dSBartosz Golaszewski  *					   a platform device, retrieve the
132c9c8641dSBartosz Golaszewski  *					   resource by name
133c9c8641dSBartosz Golaszewski  *
134c9c8641dSBartosz Golaszewski  * @pdev: platform device to use both for memory resource lookup as well as
135c9c8641dSBartosz Golaszewski  *	  resource management
136c9c8641dSBartosz Golaszewski  * @name: name of the resource
1370c7a6b91SStephen Boyd  *
1380c7a6b91SStephen Boyd  * Return: a pointer to the remapped memory or an ERR_PTR() encoded error code
1390c7a6b91SStephen Boyd  * on failure.
140c9c8641dSBartosz Golaszewski  */
141c9c8641dSBartosz Golaszewski void __iomem *
devm_platform_ioremap_resource_byname(struct platform_device * pdev,const char * name)142c9c8641dSBartosz Golaszewski devm_platform_ioremap_resource_byname(struct platform_device *pdev,
143c9c8641dSBartosz Golaszewski 				      const char *name)
144c9c8641dSBartosz Golaszewski {
145c9c8641dSBartosz Golaszewski 	struct resource *res;
146c9c8641dSBartosz Golaszewski 
147c9c8641dSBartosz Golaszewski 	res = platform_get_resource_byname(pdev, IORESOURCE_MEM, name);
148c9c8641dSBartosz Golaszewski 	return devm_ioremap_resource(&pdev->dev, res);
149c9c8641dSBartosz Golaszewski }
150c9c8641dSBartosz Golaszewski EXPORT_SYMBOL_GPL(devm_platform_ioremap_resource_byname);
151837ccda3SBartosz Golaszewski #endif /* CONFIG_HAS_IOMEM */
1527945f929SBartosz Golaszewski 
153c2f3f755SGreg Kroah-Hartman /**
154c2f3f755SGreg Kroah-Hartman  * platform_get_irq_optional - get an optional IRQ for a device
155c2f3f755SGreg Kroah-Hartman  * @dev: platform device
156c2f3f755SGreg Kroah-Hartman  * @num: IRQ number index
157c2f3f755SGreg Kroah-Hartman  *
158c2f3f755SGreg Kroah-Hartman  * Gets an IRQ for a platform device. Device drivers should check the return
159c2f3f755SGreg Kroah-Hartman  * value for errors so as to not pass a negative integer value to the
160c2f3f755SGreg Kroah-Hartman  * request_irq() APIs. This is the same as platform_get_irq(), except that it
161c2f3f755SGreg Kroah-Hartman  * does not print an error message if an IRQ can not be obtained.
162c2f3f755SGreg Kroah-Hartman  *
163c2f3f755SGreg Kroah-Hartman  * For example::
164c2f3f755SGreg Kroah-Hartman  *
165c2f3f755SGreg Kroah-Hartman  *		int irq = platform_get_irq_optional(pdev, 0);
166c2f3f755SGreg Kroah-Hartman  *		if (irq < 0)
167c2f3f755SGreg Kroah-Hartman  *			return irq;
168c2f3f755SGreg Kroah-Hartman  *
169c2f3f755SGreg Kroah-Hartman  * Return: non-zero IRQ number on success, negative error number on failure.
170c2f3f755SGreg Kroah-Hartman  */
platform_get_irq_optional(struct platform_device * dev,unsigned int num)171c2f3f755SGreg Kroah-Hartman int platform_get_irq_optional(struct platform_device *dev, unsigned int num)
1721da177e4SLinus Torvalds {
173a85a6c86SBjorn Helgaas 	int ret;
1745cf8f7dbSAndreas Larsson #ifdef CONFIG_SPARC
1755cf8f7dbSAndreas Larsson 	/* sparc does not have irqs represented as IORESOURCE_IRQ resources */
1765cf8f7dbSAndreas Larsson 	if (!dev || num >= dev->archdata.num_irqs)
177c99f4ebcSAndy Shevchenko 		goto out_not_found;
178a85a6c86SBjorn Helgaas 	ret = dev->archdata.irqs[num];
179a85a6c86SBjorn Helgaas 	goto out;
1805cf8f7dbSAndreas Larsson #else
1819ec36cafSRob Herring 	struct resource *r;
182aff008adSGuenter Roeck 
18371564a26SAndy Shevchenko 	if (IS_ENABLED(CONFIG_OF_IRQ) && dev->dev.of_node) {
184aff008adSGuenter Roeck 		ret = of_irq_get(dev->dev.of_node, num);
185e330b9a6SSergei Shtylyov 		if (ret > 0 || ret == -EPROBE_DEFER)
186a85a6c86SBjorn Helgaas 			goto out;
187aff008adSGuenter Roeck 	}
1889ec36cafSRob Herring 
1899ec36cafSRob Herring 	r = platform_get_resource(dev, IORESOURCE_IRQ, num);
190d44fa3d4SAgustin Vega-Frias 	if (has_acpi_companion(&dev->dev)) {
191d44fa3d4SAgustin Vega-Frias 		if (r && r->flags & IORESOURCE_DISABLED) {
192d44fa3d4SAgustin Vega-Frias 			ret = acpi_irq_get(ACPI_HANDLE(&dev->dev), num, r);
193d44fa3d4SAgustin Vega-Frias 			if (ret)
194a85a6c86SBjorn Helgaas 				goto out;
195d44fa3d4SAgustin Vega-Frias 		}
196d44fa3d4SAgustin Vega-Frias 	}
197d44fa3d4SAgustin Vega-Frias 
1987085a740SLinus Walleij 	/*
1997085a740SLinus Walleij 	 * The resources may pass trigger flags to the irqs that need
2007085a740SLinus Walleij 	 * to be set up. It so happens that the trigger flags for
2017085a740SLinus Walleij 	 * IORESOURCE_BITS correspond 1-to-1 to the IRQF_TRIGGER*
2027085a740SLinus Walleij 	 * settings.
2037085a740SLinus Walleij 	 */
20460ca5e0dSGuenter Roeck 	if (r && r->flags & IORESOURCE_BITS) {
20560ca5e0dSGuenter Roeck 		struct irq_data *irqd;
20660ca5e0dSGuenter Roeck 
20760ca5e0dSGuenter Roeck 		irqd = irq_get_irq_data(r->start);
208c99f4ebcSAndy Shevchenko 		if (!irqd)
209c99f4ebcSAndy Shevchenko 			goto out_not_found;
21060ca5e0dSGuenter Roeck 		irqd_set_trigger_type(irqd, r->flags & IORESOURCE_BITS);
21160ca5e0dSGuenter Roeck 	}
2121da177e4SLinus Torvalds 
213a85a6c86SBjorn Helgaas 	if (r) {
214a85a6c86SBjorn Helgaas 		ret = r->start;
215a85a6c86SBjorn Helgaas 		goto out;
216a85a6c86SBjorn Helgaas 	}
217daaef255SEnrico Granata 
218daaef255SEnrico Granata 	/*
219daaef255SEnrico Granata 	 * For the index 0 interrupt, allow falling back to GpioInt
220daaef255SEnrico Granata 	 * resources. While a device could have both Interrupt and GpioInt
221daaef255SEnrico Granata 	 * resources, making this fallback ambiguous, in many common cases
222daaef255SEnrico Granata 	 * the device will only expose one IRQ, and this fallback
223daaef255SEnrico Granata 	 * allows a common code path across either kind of resource.
224daaef255SEnrico Granata 	 */
22546c42d84SBrian Norris 	if (num == 0 && has_acpi_companion(&dev->dev)) {
22671564a26SAndy Shevchenko 		ret = acpi_dev_gpio_irq_get(ACPI_COMPANION(&dev->dev), num);
22746c42d84SBrian Norris 		/* Our callers expect -ENXIO for missing IRQs. */
22846c42d84SBrian Norris 		if (ret >= 0 || ret == -EPROBE_DEFER)
229a85a6c86SBjorn Helgaas 			goto out;
23046c42d84SBrian Norris 	}
231daaef255SEnrico Granata 
2325cf8f7dbSAndreas Larsson #endif
233c99f4ebcSAndy Shevchenko out_not_found:
234c99f4ebcSAndy Shevchenko 	ret = -ENXIO;
235a85a6c86SBjorn Helgaas out:
236ce753ad1SSergey Shtylyov 	if (WARN(!ret, "0 is an invalid IRQ number\n"))
237ce753ad1SSergey Shtylyov 		return -EINVAL;
238a85a6c86SBjorn Helgaas 	return ret;
2391da177e4SLinus Torvalds }
240ec4e2906SUwe Kleine-König EXPORT_SYMBOL_GPL(platform_get_irq_optional);
2417723f4c5SStephen Boyd 
2427723f4c5SStephen Boyd /**
2437723f4c5SStephen Boyd  * platform_get_irq - get an IRQ for a device
2447723f4c5SStephen Boyd  * @dev: platform device
2457723f4c5SStephen Boyd  * @num: IRQ number index
2467723f4c5SStephen Boyd  *
2477723f4c5SStephen Boyd  * Gets an IRQ for a platform device and prints an error message if finding the
2487723f4c5SStephen Boyd  * IRQ fails. Device drivers should check the return value for errors so as to
2497723f4c5SStephen Boyd  * not pass a negative integer value to the request_irq() APIs.
2507723f4c5SStephen Boyd  *
251f0825246SMauro Carvalho Chehab  * For example::
252f0825246SMauro Carvalho Chehab  *
2537723f4c5SStephen Boyd  *		int irq = platform_get_irq(pdev, 0);
2547723f4c5SStephen Boyd  *		if (irq < 0)
2557723f4c5SStephen Boyd  *			return irq;
2567723f4c5SStephen Boyd  *
257a85a6c86SBjorn Helgaas  * Return: non-zero IRQ number on success, negative error number on failure.
2587723f4c5SStephen Boyd  */
platform_get_irq(struct platform_device * dev,unsigned int num)2597723f4c5SStephen Boyd int platform_get_irq(struct platform_device *dev, unsigned int num)
2607723f4c5SStephen Boyd {
2617723f4c5SStephen Boyd 	int ret;
2627723f4c5SStephen Boyd 
263c2f3f755SGreg Kroah-Hartman 	ret = platform_get_irq_optional(dev, num);
2642043727cSCai Huoqing 	if (ret < 0)
2652043727cSCai Huoqing 		return dev_err_probe(&dev->dev, ret,
2662043727cSCai Huoqing 				     "IRQ index %u not found\n", num);
2677723f4c5SStephen Boyd 
2687723f4c5SStephen Boyd 	return ret;
2697723f4c5SStephen Boyd }
270a96b2042SDmitry Torokhov EXPORT_SYMBOL_GPL(platform_get_irq);
2711da177e4SLinus Torvalds 
2721da177e4SLinus Torvalds /**
2734b83555dSStephen Boyd  * platform_irq_count - Count the number of IRQs a platform device uses
2744b83555dSStephen Boyd  * @dev: platform device
2754b83555dSStephen Boyd  *
2764b83555dSStephen Boyd  * Return: Number of IRQs a platform device uses or EPROBE_DEFER
2774b83555dSStephen Boyd  */
platform_irq_count(struct platform_device * dev)2784b83555dSStephen Boyd int platform_irq_count(struct platform_device *dev)
2794b83555dSStephen Boyd {
2804b83555dSStephen Boyd 	int ret, nr = 0;
2814b83555dSStephen Boyd 
282c2f3f755SGreg Kroah-Hartman 	while ((ret = platform_get_irq_optional(dev, nr)) >= 0)
2834b83555dSStephen Boyd 		nr++;
2844b83555dSStephen Boyd 
2854b83555dSStephen Boyd 	if (ret == -EPROBE_DEFER)
2864b83555dSStephen Boyd 		return ret;
2874b83555dSStephen Boyd 
2884b83555dSStephen Boyd 	return nr;
2894b83555dSStephen Boyd }
2904b83555dSStephen Boyd EXPORT_SYMBOL_GPL(platform_irq_count);
2914b83555dSStephen Boyd 
292e15f2fa9SJohn Garry struct irq_affinity_devres {
293e15f2fa9SJohn Garry 	unsigned int count;
294e15f2fa9SJohn Garry 	unsigned int irq[];
295e15f2fa9SJohn Garry };
296e15f2fa9SJohn Garry 
platform_disable_acpi_irq(struct platform_device * pdev,int index)297e15f2fa9SJohn Garry static void platform_disable_acpi_irq(struct platform_device *pdev, int index)
298e15f2fa9SJohn Garry {
299e15f2fa9SJohn Garry 	struct resource *r;
300e15f2fa9SJohn Garry 
301e15f2fa9SJohn Garry 	r = platform_get_resource(pdev, IORESOURCE_IRQ, index);
302e15f2fa9SJohn Garry 	if (r)
303e15f2fa9SJohn Garry 		irqresource_disabled(r, 0);
304e15f2fa9SJohn Garry }
305e15f2fa9SJohn Garry 
devm_platform_get_irqs_affinity_release(struct device * dev,void * res)306e15f2fa9SJohn Garry static void devm_platform_get_irqs_affinity_release(struct device *dev,
307e15f2fa9SJohn Garry 						    void *res)
308e15f2fa9SJohn Garry {
309e15f2fa9SJohn Garry 	struct irq_affinity_devres *ptr = res;
310e15f2fa9SJohn Garry 	int i;
311e15f2fa9SJohn Garry 
312e15f2fa9SJohn Garry 	for (i = 0; i < ptr->count; i++) {
313e15f2fa9SJohn Garry 		irq_dispose_mapping(ptr->irq[i]);
314e15f2fa9SJohn Garry 
315e15f2fa9SJohn Garry 		if (has_acpi_companion(dev))
316e15f2fa9SJohn Garry 			platform_disable_acpi_irq(to_platform_device(dev), i);
317e15f2fa9SJohn Garry 	}
318e15f2fa9SJohn Garry }
319e15f2fa9SJohn Garry 
320e15f2fa9SJohn Garry /**
321e15f2fa9SJohn Garry  * devm_platform_get_irqs_affinity - devm method to get a set of IRQs for a
322e15f2fa9SJohn Garry  *				device using an interrupt affinity descriptor
323e15f2fa9SJohn Garry  * @dev: platform device pointer
324e15f2fa9SJohn Garry  * @affd: affinity descriptor
325e15f2fa9SJohn Garry  * @minvec: minimum count of interrupt vectors
326e15f2fa9SJohn Garry  * @maxvec: maximum count of interrupt vectors
327e15f2fa9SJohn Garry  * @irqs: pointer holder for IRQ numbers
328e15f2fa9SJohn Garry  *
329e15f2fa9SJohn Garry  * Gets a set of IRQs for a platform device, and updates IRQ afffinty according
330e15f2fa9SJohn Garry  * to the passed affinity descriptor
331e15f2fa9SJohn Garry  *
332e15f2fa9SJohn Garry  * Return: Number of vectors on success, negative error number on failure.
333e15f2fa9SJohn Garry  */
devm_platform_get_irqs_affinity(struct platform_device * dev,struct irq_affinity * affd,unsigned int minvec,unsigned int maxvec,int ** irqs)334e15f2fa9SJohn Garry int devm_platform_get_irqs_affinity(struct platform_device *dev,
335e15f2fa9SJohn Garry 				    struct irq_affinity *affd,
336e15f2fa9SJohn Garry 				    unsigned int minvec,
337e15f2fa9SJohn Garry 				    unsigned int maxvec,
338e15f2fa9SJohn Garry 				    int **irqs)
339e15f2fa9SJohn Garry {
340e15f2fa9SJohn Garry 	struct irq_affinity_devres *ptr;
341e15f2fa9SJohn Garry 	struct irq_affinity_desc *desc;
342e15f2fa9SJohn Garry 	size_t size;
343e15f2fa9SJohn Garry 	int i, ret, nvec;
344e15f2fa9SJohn Garry 
345e15f2fa9SJohn Garry 	if (!affd)
346e15f2fa9SJohn Garry 		return -EPERM;
347e15f2fa9SJohn Garry 
348e15f2fa9SJohn Garry 	if (maxvec < minvec)
349e15f2fa9SJohn Garry 		return -ERANGE;
350e15f2fa9SJohn Garry 
351e15f2fa9SJohn Garry 	nvec = platform_irq_count(dev);
352e1dc2099SJohn Garry 	if (nvec < 0)
353e1dc2099SJohn Garry 		return nvec;
354e15f2fa9SJohn Garry 
355e15f2fa9SJohn Garry 	if (nvec < minvec)
356e15f2fa9SJohn Garry 		return -ENOSPC;
357e15f2fa9SJohn Garry 
358e15f2fa9SJohn Garry 	nvec = irq_calc_affinity_vectors(minvec, nvec, affd);
359e15f2fa9SJohn Garry 	if (nvec < minvec)
360e15f2fa9SJohn Garry 		return -ENOSPC;
361e15f2fa9SJohn Garry 
362e15f2fa9SJohn Garry 	if (nvec > maxvec)
363e15f2fa9SJohn Garry 		nvec = maxvec;
364e15f2fa9SJohn Garry 
365e15f2fa9SJohn Garry 	size = sizeof(*ptr) + sizeof(unsigned int) * nvec;
366e15f2fa9SJohn Garry 	ptr = devres_alloc(devm_platform_get_irqs_affinity_release, size,
367e15f2fa9SJohn Garry 			   GFP_KERNEL);
368e15f2fa9SJohn Garry 	if (!ptr)
369e15f2fa9SJohn Garry 		return -ENOMEM;
370e15f2fa9SJohn Garry 
371e15f2fa9SJohn Garry 	ptr->count = nvec;
372e15f2fa9SJohn Garry 
373e15f2fa9SJohn Garry 	for (i = 0; i < nvec; i++) {
374e15f2fa9SJohn Garry 		int irq = platform_get_irq(dev, i);
375e15f2fa9SJohn Garry 		if (irq < 0) {
376e15f2fa9SJohn Garry 			ret = irq;
377e15f2fa9SJohn Garry 			goto err_free_devres;
378e15f2fa9SJohn Garry 		}
379e15f2fa9SJohn Garry 		ptr->irq[i] = irq;
380e15f2fa9SJohn Garry 	}
381e15f2fa9SJohn Garry 
382e15f2fa9SJohn Garry 	desc = irq_create_affinity_masks(nvec, affd);
383e15f2fa9SJohn Garry 	if (!desc) {
384e15f2fa9SJohn Garry 		ret = -ENOMEM;
385e15f2fa9SJohn Garry 		goto err_free_devres;
386e15f2fa9SJohn Garry 	}
387e15f2fa9SJohn Garry 
388e15f2fa9SJohn Garry 	for (i = 0; i < nvec; i++) {
389e15f2fa9SJohn Garry 		ret = irq_update_affinity_desc(ptr->irq[i], &desc[i]);
390e15f2fa9SJohn Garry 		if (ret) {
391e15f2fa9SJohn Garry 			dev_err(&dev->dev, "failed to update irq%d affinity descriptor (%d)\n",
392e15f2fa9SJohn Garry 				ptr->irq[i], ret);
393e15f2fa9SJohn Garry 			goto err_free_desc;
394e15f2fa9SJohn Garry 		}
395e15f2fa9SJohn Garry 	}
396e15f2fa9SJohn Garry 
397e15f2fa9SJohn Garry 	devres_add(&dev->dev, ptr);
398e15f2fa9SJohn Garry 
399e15f2fa9SJohn Garry 	kfree(desc);
400e15f2fa9SJohn Garry 
401e15f2fa9SJohn Garry 	*irqs = ptr->irq;
402e15f2fa9SJohn Garry 
403e15f2fa9SJohn Garry 	return nvec;
404e15f2fa9SJohn Garry 
405e15f2fa9SJohn Garry err_free_desc:
406e15f2fa9SJohn Garry 	kfree(desc);
407e15f2fa9SJohn Garry err_free_devres:
408e15f2fa9SJohn Garry 	devres_free(ptr);
409e15f2fa9SJohn Garry 	return ret;
410e15f2fa9SJohn Garry }
411e15f2fa9SJohn Garry EXPORT_SYMBOL_GPL(devm_platform_get_irqs_affinity);
412e15f2fa9SJohn Garry 
4134b83555dSStephen Boyd /**
4141da177e4SLinus Torvalds  * platform_get_resource_byname - get a resource for a device by name
4151da177e4SLinus Torvalds  * @dev: platform device
4161da177e4SLinus Torvalds  * @type: resource type
4171da177e4SLinus Torvalds  * @name: resource name
4181da177e4SLinus Torvalds  */
platform_get_resource_byname(struct platform_device * dev,unsigned int type,const char * name)4194a3ad20cSGreg Kroah-Hartman struct resource *platform_get_resource_byname(struct platform_device *dev,
420c0afe7baSLinus Walleij 					      unsigned int type,
421c0afe7baSLinus Walleij 					      const char *name)
4221da177e4SLinus Torvalds {
42339cc539fSSimon Schwartz 	u32 i;
4241da177e4SLinus Torvalds 
4251da177e4SLinus Torvalds 	for (i = 0; i < dev->num_resources; i++) {
4261da177e4SLinus Torvalds 		struct resource *r = &dev->resource[i];
4271da177e4SLinus Torvalds 
4281b8cb929SPeter Ujfalusi 		if (unlikely(!r->name))
4291b8cb929SPeter Ujfalusi 			continue;
4301b8cb929SPeter Ujfalusi 
431c9f66169SMagnus Damm 		if (type == resource_type(r) && !strcmp(r->name, name))
4321da177e4SLinus Torvalds 			return r;
4331da177e4SLinus Torvalds 	}
4341da177e4SLinus Torvalds 	return NULL;
4351da177e4SLinus Torvalds }
436a96b2042SDmitry Torokhov EXPORT_SYMBOL_GPL(platform_get_resource_byname);
4371da177e4SLinus Torvalds 
__platform_get_irq_byname(struct platform_device * dev,const char * name)438f1da567fSHans de Goede static int __platform_get_irq_byname(struct platform_device *dev,
439f1da567fSHans de Goede 				     const char *name)
4401da177e4SLinus Torvalds {
441ad69674eSGrygorii Strashko 	struct resource *r;
442aff008adSGuenter Roeck 	int ret;
443aff008adSGuenter Roeck 
444d4ad017dSSoha Jin 	ret = fwnode_irq_get_byname(dev_fwnode(&dev->dev), name);
445e330b9a6SSergei Shtylyov 	if (ret > 0 || ret == -EPROBE_DEFER)
446aff008adSGuenter Roeck 		return ret;
447ad69674eSGrygorii Strashko 
448ad69674eSGrygorii Strashko 	r = platform_get_resource_byname(dev, IORESOURCE_IRQ, name);
449a85a6c86SBjorn Helgaas 	if (r) {
450ce753ad1SSergey Shtylyov 		if (WARN(!r->start, "0 is an invalid IRQ number\n"))
451ce753ad1SSergey Shtylyov 			return -EINVAL;
4527723f4c5SStephen Boyd 		return r->start;
453a85a6c86SBjorn Helgaas 	}
4547723f4c5SStephen Boyd 
4557723f4c5SStephen Boyd 	return -ENXIO;
4561da177e4SLinus Torvalds }
457f1da567fSHans de Goede 
458f1da567fSHans de Goede /**
459f1da567fSHans de Goede  * platform_get_irq_byname - get an IRQ for a device by name
460f1da567fSHans de Goede  * @dev: platform device
461f1da567fSHans de Goede  * @name: IRQ name
462f1da567fSHans de Goede  *
463f1da567fSHans de Goede  * Get an IRQ like platform_get_irq(), but then by name rather then by index.
464f1da567fSHans de Goede  *
465a85a6c86SBjorn Helgaas  * Return: non-zero IRQ number on success, negative error number on failure.
466f1da567fSHans de Goede  */
platform_get_irq_byname(struct platform_device * dev,const char * name)467f1da567fSHans de Goede int platform_get_irq_byname(struct platform_device *dev, const char *name)
468f1da567fSHans de Goede {
469f1da567fSHans de Goede 	int ret;
470f1da567fSHans de Goede 
471f1da567fSHans de Goede 	ret = __platform_get_irq_byname(dev, name);
47227446562SSergey Shtylyov 	if (ret < 0)
47327446562SSergey Shtylyov 		return dev_err_probe(&dev->dev, ret, "IRQ %s not found\n",
47427446562SSergey Shtylyov 				     name);
475f1da567fSHans de Goede 	return ret;
476f1da567fSHans de Goede }
477a96b2042SDmitry Torokhov EXPORT_SYMBOL_GPL(platform_get_irq_byname);
4781da177e4SLinus Torvalds 
4791da177e4SLinus Torvalds /**
480f1da567fSHans de Goede  * platform_get_irq_byname_optional - get an optional IRQ for a device by name
481f1da567fSHans de Goede  * @dev: platform device
482f1da567fSHans de Goede  * @name: IRQ name
483f1da567fSHans de Goede  *
484f1da567fSHans de Goede  * Get an optional IRQ by name like platform_get_irq_byname(). Except that it
485f1da567fSHans de Goede  * does not print an error message if an IRQ can not be obtained.
486f1da567fSHans de Goede  *
487a85a6c86SBjorn Helgaas  * Return: non-zero IRQ number on success, negative error number on failure.
488f1da567fSHans de Goede  */
platform_get_irq_byname_optional(struct platform_device * dev,const char * name)489f1da567fSHans de Goede int platform_get_irq_byname_optional(struct platform_device *dev,
490f1da567fSHans de Goede 				     const char *name)
491f1da567fSHans de Goede {
492f1da567fSHans de Goede 	return __platform_get_irq_byname(dev, name);
493f1da567fSHans de Goede }
494f1da567fSHans de Goede EXPORT_SYMBOL_GPL(platform_get_irq_byname_optional);
495f1da567fSHans de Goede 
496f1da567fSHans de Goede /**
4971da177e4SLinus Torvalds  * platform_add_devices - add a numbers of platform devices
4981da177e4SLinus Torvalds  * @devs: array of platform devices to add
4991da177e4SLinus Torvalds  * @num: number of platform devices in array
50064f79742SUmang Jain  *
50164f79742SUmang Jain  * Return: 0 on success, negative error number on failure.
5021da177e4SLinus Torvalds  */
platform_add_devices(struct platform_device ** devs,int num)5031da177e4SLinus Torvalds int platform_add_devices(struct platform_device **devs, int num)
5041da177e4SLinus Torvalds {
5051da177e4SLinus Torvalds 	int i, ret = 0;
5061da177e4SLinus Torvalds 
5071da177e4SLinus Torvalds 	for (i = 0; i < num; i++) {
5081da177e4SLinus Torvalds 		ret = platform_device_register(devs[i]);
5091da177e4SLinus Torvalds 		if (ret) {
5101da177e4SLinus Torvalds 			while (--i >= 0)
5111da177e4SLinus Torvalds 				platform_device_unregister(devs[i]);
5121da177e4SLinus Torvalds 			break;
5131da177e4SLinus Torvalds 		}
5141da177e4SLinus Torvalds 	}
5151da177e4SLinus Torvalds 
5161da177e4SLinus Torvalds 	return ret;
5171da177e4SLinus Torvalds }
518a96b2042SDmitry Torokhov EXPORT_SYMBOL_GPL(platform_add_devices);
5191da177e4SLinus Torvalds 
52037c12e74SRussell King struct platform_object {
52137c12e74SRussell King 	struct platform_device pdev;
5221cec24c5SYann Droneaud 	char name[];
52337c12e74SRussell King };
52437c12e74SRussell King 
525cdfee562SChristoph Hellwig /*
526cdfee562SChristoph Hellwig  * Set up default DMA mask for platform devices if the they weren't
527cdfee562SChristoph Hellwig  * previously set by the architecture / DT.
528cdfee562SChristoph Hellwig  */
setup_pdev_dma_masks(struct platform_device * pdev)529cdfee562SChristoph Hellwig static void setup_pdev_dma_masks(struct platform_device *pdev)
530cdfee562SChristoph Hellwig {
5319495b7e9SUlf Hansson 	pdev->dev.dma_parms = &pdev->dma_parms;
5329495b7e9SUlf Hansson 
533cdfee562SChristoph Hellwig 	if (!pdev->dev.coherent_dma_mask)
534cdfee562SChristoph Hellwig 		pdev->dev.coherent_dma_mask = DMA_BIT_MASK(32);
535e3a36eb6SChristoph Hellwig 	if (!pdev->dev.dma_mask) {
536e3a36eb6SChristoph Hellwig 		pdev->platform_dma_mask = DMA_BIT_MASK(32);
537e3a36eb6SChristoph Hellwig 		pdev->dev.dma_mask = &pdev->platform_dma_mask;
538e3a36eb6SChristoph Hellwig 	}
539cdfee562SChristoph Hellwig };
540cdfee562SChristoph Hellwig 
5411da177e4SLinus Torvalds /**
5423c31f07aSBen Hutchings  * platform_device_put - destroy a platform device
54337c12e74SRussell King  * @pdev: platform device to free
54437c12e74SRussell King  *
5454a3ad20cSGreg Kroah-Hartman  * Free all memory associated with a platform device.  This function must
5464a3ad20cSGreg Kroah-Hartman  * _only_ be externally called in error cases.  All other usage is a bug.
54737c12e74SRussell King  */
platform_device_put(struct platform_device * pdev)54837c12e74SRussell King void platform_device_put(struct platform_device *pdev)
54937c12e74SRussell King {
55099fef587SAndy Shevchenko 	if (!IS_ERR_OR_NULL(pdev))
55137c12e74SRussell King 		put_device(&pdev->dev);
55237c12e74SRussell King }
55337c12e74SRussell King EXPORT_SYMBOL_GPL(platform_device_put);
55437c12e74SRussell King 
platform_device_release(struct device * dev)55537c12e74SRussell King static void platform_device_release(struct device *dev)
55637c12e74SRussell King {
5574a3ad20cSGreg Kroah-Hartman 	struct platform_object *pa = container_of(dev, struct platform_object,
5584a3ad20cSGreg Kroah-Hartman 						  pdev.dev);
55937c12e74SRussell King 
560cb8be8b4SRob Herring 	of_node_put(pa->pdev.dev.of_node);
56137c12e74SRussell King 	kfree(pa->pdev.dev.platform_data);
562e710d7d5SSamuel Ortiz 	kfree(pa->pdev.mfd_cell);
56337c12e74SRussell King 	kfree(pa->pdev.resource);
5643d713e0eSKim Phillips 	kfree(pa->pdev.driver_override);
56537c12e74SRussell King 	kfree(pa);
56637c12e74SRussell King }
56737c12e74SRussell King 
56837c12e74SRussell King /**
5693c31f07aSBen Hutchings  * platform_device_alloc - create a platform device
57037c12e74SRussell King  * @name: base name of the device we're adding
57137c12e74SRussell King  * @id: instance id
57237c12e74SRussell King  *
57337c12e74SRussell King  * Create a platform device object which can have other objects attached
57437c12e74SRussell King  * to it, and which will have attached objects freed when it is released.
57537c12e74SRussell King  */
platform_device_alloc(const char * name,int id)5761359555eSJean Delvare struct platform_device *platform_device_alloc(const char *name, int id)
57737c12e74SRussell King {
57837c12e74SRussell King 	struct platform_object *pa;
57937c12e74SRussell King 
5801cec24c5SYann Droneaud 	pa = kzalloc(sizeof(*pa) + strlen(name) + 1, GFP_KERNEL);
58137c12e74SRussell King 	if (pa) {
58237c12e74SRussell King 		strcpy(pa->name, name);
58337c12e74SRussell King 		pa->pdev.name = pa->name;
58437c12e74SRussell King 		pa->pdev.id = id;
58537c12e74SRussell King 		device_initialize(&pa->pdev.dev);
58637c12e74SRussell King 		pa->pdev.dev.release = platform_device_release;
587cdfee562SChristoph Hellwig 		setup_pdev_dma_masks(&pa->pdev);
58837c12e74SRussell King 	}
58937c12e74SRussell King 
59037c12e74SRussell King 	return pa ? &pa->pdev : NULL;
59137c12e74SRussell King }
59237c12e74SRussell King EXPORT_SYMBOL_GPL(platform_device_alloc);
59337c12e74SRussell King 
59437c12e74SRussell King /**
5953c31f07aSBen Hutchings  * platform_device_add_resources - add resources to a platform device
59637c12e74SRussell King  * @pdev: platform device allocated by platform_device_alloc to add resources to
59737c12e74SRussell King  * @res: set of resources that needs to be allocated for the device
59837c12e74SRussell King  * @num: number of resources
59937c12e74SRussell King  *
60037c12e74SRussell King  * Add a copy of the resources to the platform device.  The memory
6014a3ad20cSGreg Kroah-Hartman  * associated with the resources will be freed when the platform device is
6024a3ad20cSGreg Kroah-Hartman  * released.
60337c12e74SRussell King  */
platform_device_add_resources(struct platform_device * pdev,const struct resource * res,unsigned int num)6044a3ad20cSGreg Kroah-Hartman int platform_device_add_resources(struct platform_device *pdev,
6050b7f1a7eSGeert Uytterhoeven 				  const struct resource *res, unsigned int num)
60637c12e74SRussell King {
607cea89623SUwe Kleine-König 	struct resource *r = NULL;
60837c12e74SRussell King 
609cea89623SUwe Kleine-König 	if (res) {
6103e61dfd8SUwe Kleine-König 		r = kmemdup(res, sizeof(struct resource) * num, GFP_KERNEL);
611cea89623SUwe Kleine-König 		if (!r)
612cea89623SUwe Kleine-König 			return -ENOMEM;
613cea89623SUwe Kleine-König 	}
614cea89623SUwe Kleine-König 
6154a03d6f7SUwe Kleine-König 	kfree(pdev->resource);
61637c12e74SRussell King 	pdev->resource = r;
61737c12e74SRussell King 	pdev->num_resources = num;
6183e61dfd8SUwe Kleine-König 	return 0;
61937c12e74SRussell King }
62037c12e74SRussell King EXPORT_SYMBOL_GPL(platform_device_add_resources);
62137c12e74SRussell King 
62237c12e74SRussell King /**
6233c31f07aSBen Hutchings  * platform_device_add_data - add platform-specific data to a platform device
62437c12e74SRussell King  * @pdev: platform device allocated by platform_device_alloc to add resources to
62537c12e74SRussell King  * @data: platform specific data for this platform device
62637c12e74SRussell King  * @size: size of platform specific data
62737c12e74SRussell King  *
6284a3ad20cSGreg Kroah-Hartman  * Add a copy of platform specific data to the platform device's
6294a3ad20cSGreg Kroah-Hartman  * platform_data pointer.  The memory associated with the platform data
6304a3ad20cSGreg Kroah-Hartman  * will be freed when the platform device is released.
63137c12e74SRussell King  */
platform_device_add_data(struct platform_device * pdev,const void * data,size_t size)6324a3ad20cSGreg Kroah-Hartman int platform_device_add_data(struct platform_device *pdev, const void *data,
6334a3ad20cSGreg Kroah-Hartman 			     size_t size)
63437c12e74SRussell King {
63527a33f9eSUwe Kleine-König 	void *d = NULL;
63637c12e74SRussell King 
63727a33f9eSUwe Kleine-König 	if (data) {
6385cfc64ceSAnton Vorontsov 		d = kmemdup(data, size, GFP_KERNEL);
63927a33f9eSUwe Kleine-König 		if (!d)
64027a33f9eSUwe Kleine-König 			return -ENOMEM;
64127a33f9eSUwe Kleine-König 	}
64227a33f9eSUwe Kleine-König 
643251e031dSUwe Kleine-König 	kfree(pdev->dev.platform_data);
64437c12e74SRussell King 	pdev->dev.platform_data = d;
645daa41226SAndrew Morton 	return 0;
64637c12e74SRussell King }
64737c12e74SRussell King EXPORT_SYMBOL_GPL(platform_device_add_data);
64837c12e74SRussell King 
64937c12e74SRussell King /**
65037c12e74SRussell King  * platform_device_add - add a platform device to device hierarchy
65167be2dd1SMartin Waitz  * @pdev: platform device we're adding
6521da177e4SLinus Torvalds  *
65337c12e74SRussell King  * This is part 2 of platform_device_register(), though may be called
65437c12e74SRussell King  * separately _iff_ pdev was allocated by platform_device_alloc().
6551da177e4SLinus Torvalds  */
platform_device_add(struct platform_device * pdev)65637c12e74SRussell King int platform_device_add(struct platform_device *pdev)
6571da177e4SLinus Torvalds {
65839cc539fSSimon Schwartz 	u32 i;
65939cc539fSSimon Schwartz 	int ret;
6601da177e4SLinus Torvalds 
6611da177e4SLinus Torvalds 	if (!pdev)
6621da177e4SLinus Torvalds 		return -EINVAL;
6631da177e4SLinus Torvalds 
6641da177e4SLinus Torvalds 	if (!pdev->dev.parent)
6651da177e4SLinus Torvalds 		pdev->dev.parent = &platform_bus;
6661da177e4SLinus Torvalds 
6671da177e4SLinus Torvalds 	pdev->dev.bus = &platform_bus_type;
6681da177e4SLinus Torvalds 
669689ae231SJean Delvare 	switch (pdev->id) {
670689ae231SJean Delvare 	default:
6711e0b2cf9SKay Sievers 		dev_set_name(&pdev->dev, "%s.%d", pdev->name,  pdev->id);
672689ae231SJean Delvare 		break;
673689ae231SJean Delvare 	case PLATFORM_DEVID_NONE:
674acc0e90fSGreg Kroah-Hartman 		dev_set_name(&pdev->dev, "%s", pdev->name);
675689ae231SJean Delvare 		break;
676689ae231SJean Delvare 	case PLATFORM_DEVID_AUTO:
677689ae231SJean Delvare 		/*
678689ae231SJean Delvare 		 * Automatically allocated device ID. We mark it as such so
679689ae231SJean Delvare 		 * that we remember it must be freed, and we append a suffix
680689ae231SJean Delvare 		 * to avoid namespace collision with explicit IDs.
681689ae231SJean Delvare 		 */
6820de75116SBartosz Golaszewski 		ret = ida_alloc(&platform_devid_ida, GFP_KERNEL);
683689ae231SJean Delvare 		if (ret < 0)
6845da7f709SGreg Kroah-Hartman 			goto err_out;
685689ae231SJean Delvare 		pdev->id = ret;
686689ae231SJean Delvare 		pdev->id_auto = true;
687689ae231SJean Delvare 		dev_set_name(&pdev->dev, "%s.%d.auto", pdev->name, pdev->id);
688689ae231SJean Delvare 		break;
689689ae231SJean Delvare 	}
6901da177e4SLinus Torvalds 
6911da177e4SLinus Torvalds 	for (i = 0; i < pdev->num_resources; i++) {
6925da7f709SGreg Kroah-Hartman 		struct resource *p, *r = &pdev->resource[i];
6931da177e4SLinus Torvalds 
6941da177e4SLinus Torvalds 		if (r->name == NULL)
6951e0b2cf9SKay Sievers 			r->name = dev_name(&pdev->dev);
6961da177e4SLinus Torvalds 
6971da177e4SLinus Torvalds 		p = r->parent;
6981da177e4SLinus Torvalds 		if (!p) {
6990e6c861fSGreg Kroah-Hartman 			if (resource_type(r) == IORESOURCE_MEM)
7001da177e4SLinus Torvalds 				p = &iomem_resource;
7010e6c861fSGreg Kroah-Hartman 			else if (resource_type(r) == IORESOURCE_IO)
7021da177e4SLinus Torvalds 				p = &ioport_resource;
7031da177e4SLinus Torvalds 		}
7041da177e4SLinus Torvalds 
70525ebcb7dSAndy Shevchenko 		if (p) {
70625ebcb7dSAndy Shevchenko 			ret = insert_resource(p, r);
70725ebcb7dSAndy Shevchenko 			if (ret) {
7088a18f428SChen Yu 				dev_err(&pdev->dev, "failed to claim resource %d: %pR\n", i, r);
7095da7f709SGreg Kroah-Hartman 				goto failed;
7105da7f709SGreg Kroah-Hartman 			}
7111da177e4SLinus Torvalds 		}
71225ebcb7dSAndy Shevchenko 	}
7131da177e4SLinus Torvalds 
7141da177e4SLinus Torvalds 	pr_debug("Registering platform device '%s'. Parent at %s\n",
7151e0b2cf9SKay Sievers 		 dev_name(&pdev->dev), dev_name(pdev->dev.parent));
7161da177e4SLinus Torvalds 
717e3915532SRussell King 	ret = device_add(&pdev->dev);
7188b2dcebaSGreg Kroah-Hartman 	if (ret == 0)
7198b2dcebaSGreg Kroah-Hartman 		return ret;
7208b2dcebaSGreg Kroah-Hartman 
7215da7f709SGreg Kroah-Hartman  failed:
7228b2dcebaSGreg Kroah-Hartman 	if (pdev->id_auto) {
7230de75116SBartosz Golaszewski 		ida_free(&platform_devid_ida, pdev->id);
7248b2dcebaSGreg Kroah-Hartman 		pdev->id = PLATFORM_DEVID_AUTO;
7258b2dcebaSGreg Kroah-Hartman 	}
7268b2dcebaSGreg Kroah-Hartman 
7270707cfa5SColin Ian King 	while (i--) {
7288b2dcebaSGreg Kroah-Hartman 		struct resource *r = &pdev->resource[i];
7297f5dcaf1SGrant Likely 		if (r->parent)
7308b2dcebaSGreg Kroah-Hartman 			release_resource(r);
7318b2dcebaSGreg Kroah-Hartman 	}
732c9f66169SMagnus Damm 
7335da7f709SGreg Kroah-Hartman  err_out:
7341da177e4SLinus Torvalds 	return ret;
7351da177e4SLinus Torvalds }
73637c12e74SRussell King EXPORT_SYMBOL_GPL(platform_device_add);
73737c12e74SRussell King 
73837c12e74SRussell King /**
73993ce3061SDmitry Torokhov  * platform_device_del - remove a platform-level device
74093ce3061SDmitry Torokhov  * @pdev: platform device we're removing
74193ce3061SDmitry Torokhov  *
74293ce3061SDmitry Torokhov  * Note that this function will also release all memory- and port-based
7434a3ad20cSGreg Kroah-Hartman  * resources owned by the device (@dev->resource).  This function must
7444a3ad20cSGreg Kroah-Hartman  * _only_ be externally called in error cases.  All other usage is a bug.
74593ce3061SDmitry Torokhov  */
platform_device_del(struct platform_device * pdev)74693ce3061SDmitry Torokhov void platform_device_del(struct platform_device *pdev)
74793ce3061SDmitry Torokhov {
74839cc539fSSimon Schwartz 	u32 i;
74993ce3061SDmitry Torokhov 
75099fef587SAndy Shevchenko 	if (!IS_ERR_OR_NULL(pdev)) {
751dc4c15d4SJean Delvare 		device_del(&pdev->dev);
7528b2dcebaSGreg Kroah-Hartman 
7538b2dcebaSGreg Kroah-Hartman 		if (pdev->id_auto) {
7540de75116SBartosz Golaszewski 			ida_free(&platform_devid_ida, pdev->id);
7558b2dcebaSGreg Kroah-Hartman 			pdev->id = PLATFORM_DEVID_AUTO;
7568b2dcebaSGreg Kroah-Hartman 		}
7578b2dcebaSGreg Kroah-Hartman 
7588b2dcebaSGreg Kroah-Hartman 		for (i = 0; i < pdev->num_resources; i++) {
7598b2dcebaSGreg Kroah-Hartman 			struct resource *r = &pdev->resource[i];
7607f5dcaf1SGrant Likely 			if (r->parent)
7618b2dcebaSGreg Kroah-Hartman 				release_resource(r);
7628b2dcebaSGreg Kroah-Hartman 		}
7638b2dcebaSGreg Kroah-Hartman 	}
76493ce3061SDmitry Torokhov }
76593ce3061SDmitry Torokhov EXPORT_SYMBOL_GPL(platform_device_del);
76693ce3061SDmitry Torokhov 
76793ce3061SDmitry Torokhov /**
76837c12e74SRussell King  * platform_device_register - add a platform-level device
76937c12e74SRussell King  * @pdev: platform device we're adding
77067e532a4SJohan Hovold  *
77167e532a4SJohan Hovold  * NOTE: _Never_ directly free @pdev after calling this function, even if it
77267e532a4SJohan Hovold  * returned an error! Always use platform_device_put() to give up the
77367e532a4SJohan Hovold  * reference initialised in this function instead.
77437c12e74SRussell King  */
platform_device_register(struct platform_device * pdev)77537c12e74SRussell King int platform_device_register(struct platform_device *pdev)
77637c12e74SRussell King {
77737c12e74SRussell King 	device_initialize(&pdev->dev);
778cdfee562SChristoph Hellwig 	setup_pdev_dma_masks(pdev);
77937c12e74SRussell King 	return platform_device_add(pdev);
78037c12e74SRussell King }
781a96b2042SDmitry Torokhov EXPORT_SYMBOL_GPL(platform_device_register);
7821da177e4SLinus Torvalds 
7831da177e4SLinus Torvalds /**
78493ce3061SDmitry Torokhov  * platform_device_unregister - unregister a platform-level device
78593ce3061SDmitry Torokhov  * @pdev: platform device we're unregistering
7861da177e4SLinus Torvalds  *
78780682fa9SUwe Zeisberger  * Unregistration is done in 2 steps. First we release all resources
7882d7b5a70SJean Delvare  * and remove it from the subsystem, then we drop reference count by
78993ce3061SDmitry Torokhov  * calling platform_device_put().
7901da177e4SLinus Torvalds  */
platform_device_unregister(struct platform_device * pdev)7911da177e4SLinus Torvalds void platform_device_unregister(struct platform_device *pdev)
7921da177e4SLinus Torvalds {
79393ce3061SDmitry Torokhov 	platform_device_del(pdev);
79493ce3061SDmitry Torokhov 	platform_device_put(pdev);
7951da177e4SLinus Torvalds }
796a96b2042SDmitry Torokhov EXPORT_SYMBOL_GPL(platform_device_unregister);
7971da177e4SLinus Torvalds 
7981da177e4SLinus Torvalds /**
79901dcc60aSUwe Kleine-König  * platform_device_register_full - add a platform-level device with
80044f28bdeSUwe Kleine-König  * resources and platform-specific data
80144f28bdeSUwe Kleine-König  *
80201dcc60aSUwe Kleine-König  * @pdevinfo: data used to create device
803d8bf2540SDmitry Baryshkov  *
804f0eae0edSJani Nikula  * Returns &struct platform_device pointer on success, or ERR_PTR() on error.
805d8bf2540SDmitry Baryshkov  */
platform_device_register_full(const struct platform_device_info * pdevinfo)80601dcc60aSUwe Kleine-König struct platform_device *platform_device_register_full(
8075a3072beSUwe Kleine-König 		const struct platform_device_info *pdevinfo)
808d8bf2540SDmitry Baryshkov {
80945bb08deSColin Ian King 	int ret;
810d8bf2540SDmitry Baryshkov 	struct platform_device *pdev;
811d8bf2540SDmitry Baryshkov 
81201dcc60aSUwe Kleine-König 	pdev = platform_device_alloc(pdevinfo->name, pdevinfo->id);
81344f28bdeSUwe Kleine-König 	if (!pdev)
81436cf3b13SJohannes Berg 		return ERR_PTR(-ENOMEM);
81501dcc60aSUwe Kleine-König 
81601dcc60aSUwe Kleine-König 	pdev->dev.parent = pdevinfo->parent;
817ce793486SRafael J. Wysocki 	pdev->dev.fwnode = pdevinfo->fwnode;
8182c1ea6abSMans Rullgard 	pdev->dev.of_node = of_node_get(to_of_node(pdev->dev.fwnode));
8192c1ea6abSMans Rullgard 	pdev->dev.of_node_reused = pdevinfo->of_node_reused;
82001dcc60aSUwe Kleine-König 
82101dcc60aSUwe Kleine-König 	if (pdevinfo->dma_mask) {
822e3a36eb6SChristoph Hellwig 		pdev->platform_dma_mask = pdevinfo->dma_mask;
823e3a36eb6SChristoph Hellwig 		pdev->dev.dma_mask = &pdev->platform_dma_mask;
82401dcc60aSUwe Kleine-König 		pdev->dev.coherent_dma_mask = pdevinfo->dma_mask;
82501dcc60aSUwe Kleine-König 	}
826d8bf2540SDmitry Baryshkov 
82701dcc60aSUwe Kleine-König 	ret = platform_device_add_resources(pdev,
82801dcc60aSUwe Kleine-König 			pdevinfo->res, pdevinfo->num_res);
82944f28bdeSUwe Kleine-König 	if (ret)
83044f28bdeSUwe Kleine-König 		goto err;
831d8bf2540SDmitry Baryshkov 
83201dcc60aSUwe Kleine-König 	ret = platform_device_add_data(pdev,
83301dcc60aSUwe Kleine-König 			pdevinfo->data, pdevinfo->size_data);
83444f28bdeSUwe Kleine-König 	if (ret)
83544f28bdeSUwe Kleine-König 		goto err;
83644f28bdeSUwe Kleine-König 
837f4d05266SHeikki Krogerus 	if (pdevinfo->properties) {
838bd1e336aSHeikki Krogerus 		ret = device_create_managed_software_node(&pdev->dev,
839bd1e336aSHeikki Krogerus 							  pdevinfo->properties, NULL);
84000bbc1d8SMika Westerberg 		if (ret)
84100bbc1d8SMika Westerberg 			goto err;
84200bbc1d8SMika Westerberg 	}
84300bbc1d8SMika Westerberg 
84444f28bdeSUwe Kleine-König 	ret = platform_device_add(pdev);
84544f28bdeSUwe Kleine-König 	if (ret) {
84644f28bdeSUwe Kleine-König err:
8477b199811SRafael J. Wysocki 		ACPI_COMPANION_SET(&pdev->dev, NULL);
84844f28bdeSUwe Kleine-König 		platform_device_put(pdev);
84944f28bdeSUwe Kleine-König 		return ERR_PTR(ret);
85044f28bdeSUwe Kleine-König 	}
851d8bf2540SDmitry Baryshkov 
852d8bf2540SDmitry Baryshkov 	return pdev;
853d8bf2540SDmitry Baryshkov }
85401dcc60aSUwe Kleine-König EXPORT_SYMBOL_GPL(platform_device_register_full);
855d8bf2540SDmitry Baryshkov 
85600d3dcddSRussell King /**
8579447057eSLibo Chen  * __platform_driver_register - register a driver for platform-level devices
85800d3dcddSRussell King  * @drv: platform driver structure
85908801f96SRandy Dunlap  * @owner: owning module/driver
86000d3dcddSRussell King  */
__platform_driver_register(struct platform_driver * drv,struct module * owner)8619447057eSLibo Chen int __platform_driver_register(struct platform_driver *drv,
8629447057eSLibo Chen 				struct module *owner)
86300d3dcddSRussell King {
8649447057eSLibo Chen 	drv->driver.owner = owner;
86500d3dcddSRussell King 	drv->driver.bus = &platform_bus_type;
866783ea7d4SMagnus Damm 
86700d3dcddSRussell King 	return driver_register(&drv->driver);
86800d3dcddSRussell King }
8699447057eSLibo Chen EXPORT_SYMBOL_GPL(__platform_driver_register);
87000d3dcddSRussell King 
87100d3dcddSRussell King /**
8723c31f07aSBen Hutchings  * platform_driver_unregister - unregister a driver for platform-level devices
87300d3dcddSRussell King  * @drv: platform driver structure
87400d3dcddSRussell King  */
platform_driver_unregister(struct platform_driver * drv)87500d3dcddSRussell King void platform_driver_unregister(struct platform_driver *drv)
87600d3dcddSRussell King {
87700d3dcddSRussell King 	driver_unregister(&drv->driver);
87800d3dcddSRussell King }
87900d3dcddSRussell King EXPORT_SYMBOL_GPL(platform_driver_unregister);
88000d3dcddSRussell King 
platform_probe_fail(struct platform_device * pdev)88116085668SUwe Kleine-König static int platform_probe_fail(struct platform_device *pdev)
882e21d740aSUwe Kleine-König {
883e21d740aSUwe Kleine-König 	return -ENXIO;
884e21d740aSUwe Kleine-König }
885e21d740aSUwe Kleine-König 
is_bound_to_driver(struct device * dev,void * driver)88640b3880dSGreg Kroah-Hartman static int is_bound_to_driver(struct device *dev, void *driver)
88740b3880dSGreg Kroah-Hartman {
88840b3880dSGreg Kroah-Hartman 	if (dev->driver == driver)
88940b3880dSGreg Kroah-Hartman 		return 1;
89040b3880dSGreg Kroah-Hartman 	return 0;
89140b3880dSGreg Kroah-Hartman }
89240b3880dSGreg Kroah-Hartman 
893c67334fbSDavid Brownell /**
894c3b50dc2SWolfram Sang  * __platform_driver_probe - register driver for non-hotpluggable device
895c67334fbSDavid Brownell  * @drv: platform driver structure
8963f9120b0SJohan Hovold  * @probe: the driver probe routine, probably from an __init section
897c3b50dc2SWolfram Sang  * @module: module which will be the owner of the driver
898c67334fbSDavid Brownell  *
899c67334fbSDavid Brownell  * Use this instead of platform_driver_register() when you know the device
900c67334fbSDavid Brownell  * is not hotpluggable and has already been registered, and you want to
901c67334fbSDavid Brownell  * remove its run-once probe() infrastructure from memory after the driver
902c67334fbSDavid Brownell  * has bound to the device.
903c67334fbSDavid Brownell  *
904c67334fbSDavid Brownell  * One typical use for this would be with drivers for controllers integrated
905c67334fbSDavid Brownell  * into system-on-chip processors, where the controller devices have been
906c67334fbSDavid Brownell  * configured as part of board setup.
907c67334fbSDavid Brownell  *
9083f9120b0SJohan Hovold  * Note that this is incompatible with deferred probing.
909647c86d0SFabio Porcedda  *
910c67334fbSDavid Brownell  * Returns zero if the driver registered and bound to a device, else returns
911c67334fbSDavid Brownell  * a negative error code and with the driver not registered.
912c67334fbSDavid Brownell  */
__platform_driver_probe(struct platform_driver * drv,int (* probe)(struct platform_device *),struct module * module)913c3b50dc2SWolfram Sang int __init_or_module __platform_driver_probe(struct platform_driver *drv,
914c3b50dc2SWolfram Sang 		int (*probe)(struct platform_device *), struct module *module)
915c67334fbSDavid Brownell {
916b4ce0bf7SGreg Kroah-Hartman 	int retval;
917c67334fbSDavid Brownell 
9185c36eb2aSDmitry Torokhov 	if (drv->driver.probe_type == PROBE_PREFER_ASYNCHRONOUS) {
9195c36eb2aSDmitry Torokhov 		pr_err("%s: drivers registered with %s can not be probed asynchronously\n",
9205c36eb2aSDmitry Torokhov 			 drv->driver.name, __func__);
9215c36eb2aSDmitry Torokhov 		return -EINVAL;
9225c36eb2aSDmitry Torokhov 	}
9235c36eb2aSDmitry Torokhov 
9245c36eb2aSDmitry Torokhov 	/*
9255c36eb2aSDmitry Torokhov 	 * We have to run our probes synchronously because we check if
9265c36eb2aSDmitry Torokhov 	 * we find any devices to bind to and exit with error if there
9275c36eb2aSDmitry Torokhov 	 * are any.
9285c36eb2aSDmitry Torokhov 	 */
9295c36eb2aSDmitry Torokhov 	drv->driver.probe_type = PROBE_FORCE_SYNCHRONOUS;
9305c36eb2aSDmitry Torokhov 
9313f9120b0SJohan Hovold 	/*
9323f9120b0SJohan Hovold 	 * Prevent driver from requesting probe deferral to avoid further
9333f9120b0SJohan Hovold 	 * futile probe attempts.
9343f9120b0SJohan Hovold 	 */
9353f9120b0SJohan Hovold 	drv->prevent_deferred_probe = true;
9363f9120b0SJohan Hovold 
9371a6f2a75SDmitry Torokhov 	/* make sure driver won't have bind/unbind attributes */
9381a6f2a75SDmitry Torokhov 	drv->driver.suppress_bind_attrs = true;
9391a6f2a75SDmitry Torokhov 
940c67334fbSDavid Brownell 	/* temporary section violation during probe() */
941c67334fbSDavid Brownell 	drv->probe = probe;
942b4ce0bf7SGreg Kroah-Hartman 	retval = __platform_driver_register(drv, module);
943388bcc6eSKuppuswamy Sathyanarayanan 	if (retval)
944388bcc6eSKuppuswamy Sathyanarayanan 		return retval;
945c67334fbSDavid Brownell 
94640b3880dSGreg Kroah-Hartman 	/* Force all new probes of this driver to fail */
94716085668SUwe Kleine-König 	drv->probe = platform_probe_fail;
948c67334fbSDavid Brownell 
94940b3880dSGreg Kroah-Hartman 	/* Walk all platform devices and see if any actually bound to this driver.
95040b3880dSGreg Kroah-Hartman 	 * If not, return an error as the device should have done so by now.
95140b3880dSGreg Kroah-Hartman 	 */
95240b3880dSGreg Kroah-Hartman 	if (!bus_for_each_dev(&platform_bus_type, NULL, &drv->driver, is_bound_to_driver)) {
95340b3880dSGreg Kroah-Hartman 		retval = -ENODEV;
954c67334fbSDavid Brownell 		platform_driver_unregister(drv);
95540b3880dSGreg Kroah-Hartman 	}
95640b3880dSGreg Kroah-Hartman 
957c67334fbSDavid Brownell 	return retval;
958c67334fbSDavid Brownell }
959c3b50dc2SWolfram Sang EXPORT_SYMBOL_GPL(__platform_driver_probe);
9601da177e4SLinus Torvalds 
961ecdf6cebSDmitry Torokhov /**
962291f653aSWolfram Sang  * __platform_create_bundle - register driver and create corresponding device
963ecdf6cebSDmitry Torokhov  * @driver: platform driver structure
964ecdf6cebSDmitry Torokhov  * @probe: the driver probe routine, probably from an __init section
965ecdf6cebSDmitry Torokhov  * @res: set of resources that needs to be allocated for the device
966ecdf6cebSDmitry Torokhov  * @n_res: number of resources
967ecdf6cebSDmitry Torokhov  * @data: platform specific data for this platform device
968ecdf6cebSDmitry Torokhov  * @size: size of platform specific data
969291f653aSWolfram Sang  * @module: module which will be the owner of the driver
970ecdf6cebSDmitry Torokhov  *
971ecdf6cebSDmitry Torokhov  * Use this in legacy-style modules that probe hardware directly and
972ecdf6cebSDmitry Torokhov  * register a single platform device and corresponding platform driver.
973f0eae0edSJani Nikula  *
974f0eae0edSJani Nikula  * Returns &struct platform_device pointer on success, or ERR_PTR() on error.
975ecdf6cebSDmitry Torokhov  */
__platform_create_bundle(struct platform_driver * driver,int (* probe)(struct platform_device *),struct resource * res,unsigned int n_res,const void * data,size_t size,struct module * module)976291f653aSWolfram Sang struct platform_device * __init_or_module __platform_create_bundle(
977ecdf6cebSDmitry Torokhov 			struct platform_driver *driver,
978ecdf6cebSDmitry Torokhov 			int (*probe)(struct platform_device *),
979ecdf6cebSDmitry Torokhov 			struct resource *res, unsigned int n_res,
980291f653aSWolfram Sang 			const void *data, size_t size, struct module *module)
981ecdf6cebSDmitry Torokhov {
982ecdf6cebSDmitry Torokhov 	struct platform_device *pdev;
983ecdf6cebSDmitry Torokhov 	int error;
984ecdf6cebSDmitry Torokhov 
985ecdf6cebSDmitry Torokhov 	pdev = platform_device_alloc(driver->driver.name, -1);
986ecdf6cebSDmitry Torokhov 	if (!pdev) {
987ecdf6cebSDmitry Torokhov 		error = -ENOMEM;
988ecdf6cebSDmitry Torokhov 		goto err_out;
989ecdf6cebSDmitry Torokhov 	}
990ecdf6cebSDmitry Torokhov 
991ecdf6cebSDmitry Torokhov 	error = platform_device_add_resources(pdev, res, n_res);
992ecdf6cebSDmitry Torokhov 	if (error)
993ecdf6cebSDmitry Torokhov 		goto err_pdev_put;
994ecdf6cebSDmitry Torokhov 
995ecdf6cebSDmitry Torokhov 	error = platform_device_add_data(pdev, data, size);
996ecdf6cebSDmitry Torokhov 	if (error)
997ecdf6cebSDmitry Torokhov 		goto err_pdev_put;
998ecdf6cebSDmitry Torokhov 
999ecdf6cebSDmitry Torokhov 	error = platform_device_add(pdev);
1000ecdf6cebSDmitry Torokhov 	if (error)
1001ecdf6cebSDmitry Torokhov 		goto err_pdev_put;
1002ecdf6cebSDmitry Torokhov 
1003291f653aSWolfram Sang 	error = __platform_driver_probe(driver, probe, module);
1004ecdf6cebSDmitry Torokhov 	if (error)
1005ecdf6cebSDmitry Torokhov 		goto err_pdev_del;
1006ecdf6cebSDmitry Torokhov 
1007ecdf6cebSDmitry Torokhov 	return pdev;
1008ecdf6cebSDmitry Torokhov 
1009ecdf6cebSDmitry Torokhov err_pdev_del:
1010ecdf6cebSDmitry Torokhov 	platform_device_del(pdev);
1011ecdf6cebSDmitry Torokhov err_pdev_put:
1012ecdf6cebSDmitry Torokhov 	platform_device_put(pdev);
1013ecdf6cebSDmitry Torokhov err_out:
1014ecdf6cebSDmitry Torokhov 	return ERR_PTR(error);
1015ecdf6cebSDmitry Torokhov }
1016291f653aSWolfram Sang EXPORT_SYMBOL_GPL(__platform_create_bundle);
1017ecdf6cebSDmitry Torokhov 
1018dbe2256dSThierry Reding /**
1019dbe2256dSThierry Reding  * __platform_register_drivers - register an array of platform drivers
1020dbe2256dSThierry Reding  * @drivers: an array of drivers to register
1021dbe2256dSThierry Reding  * @count: the number of drivers to register
1022dbe2256dSThierry Reding  * @owner: module owning the drivers
1023dbe2256dSThierry Reding  *
1024dbe2256dSThierry Reding  * Registers platform drivers specified by an array. On failure to register a
1025dbe2256dSThierry Reding  * driver, all previously registered drivers will be unregistered. Callers of
1026dbe2256dSThierry Reding  * this API should use platform_unregister_drivers() to unregister drivers in
1027dbe2256dSThierry Reding  * the reverse order.
1028dbe2256dSThierry Reding  *
1029dbe2256dSThierry Reding  * Returns: 0 on success or a negative error code on failure.
1030dbe2256dSThierry Reding  */
__platform_register_drivers(struct platform_driver * const * drivers,unsigned int count,struct module * owner)1031dbe2256dSThierry Reding int __platform_register_drivers(struct platform_driver * const *drivers,
1032dbe2256dSThierry Reding 				unsigned int count, struct module *owner)
1033dbe2256dSThierry Reding {
1034dbe2256dSThierry Reding 	unsigned int i;
1035dbe2256dSThierry Reding 	int err;
1036dbe2256dSThierry Reding 
1037dbe2256dSThierry Reding 	for (i = 0; i < count; i++) {
1038dbe2256dSThierry Reding 		pr_debug("registering platform driver %ps\n", drivers[i]);
1039dbe2256dSThierry Reding 
1040dbe2256dSThierry Reding 		err = __platform_driver_register(drivers[i], owner);
1041dbe2256dSThierry Reding 		if (err < 0) {
1042dbe2256dSThierry Reding 			pr_err("failed to register platform driver %ps: %d\n",
1043dbe2256dSThierry Reding 			       drivers[i], err);
1044dbe2256dSThierry Reding 			goto error;
1045dbe2256dSThierry Reding 		}
1046dbe2256dSThierry Reding 	}
1047dbe2256dSThierry Reding 
1048dbe2256dSThierry Reding 	return 0;
1049dbe2256dSThierry Reding 
1050dbe2256dSThierry Reding error:
1051dbe2256dSThierry Reding 	while (i--) {
1052dbe2256dSThierry Reding 		pr_debug("unregistering platform driver %ps\n", drivers[i]);
1053dbe2256dSThierry Reding 		platform_driver_unregister(drivers[i]);
1054dbe2256dSThierry Reding 	}
1055dbe2256dSThierry Reding 
1056dbe2256dSThierry Reding 	return err;
1057dbe2256dSThierry Reding }
1058dbe2256dSThierry Reding EXPORT_SYMBOL_GPL(__platform_register_drivers);
1059dbe2256dSThierry Reding 
1060dbe2256dSThierry Reding /**
1061dbe2256dSThierry Reding  * platform_unregister_drivers - unregister an array of platform drivers
1062dbe2256dSThierry Reding  * @drivers: an array of drivers to unregister
1063dbe2256dSThierry Reding  * @count: the number of drivers to unregister
1064dbe2256dSThierry Reding  *
1065c82c83c3STang Bin  * Unregisters platform drivers specified by an array. This is typically used
1066dbe2256dSThierry Reding  * to complement an earlier call to platform_register_drivers(). Drivers are
1067dbe2256dSThierry Reding  * unregistered in the reverse order in which they were registered.
1068dbe2256dSThierry Reding  */
platform_unregister_drivers(struct platform_driver * const * drivers,unsigned int count)1069dbe2256dSThierry Reding void platform_unregister_drivers(struct platform_driver * const *drivers,
1070dbe2256dSThierry Reding 				 unsigned int count)
1071dbe2256dSThierry Reding {
1072dbe2256dSThierry Reding 	while (count--) {
1073dbe2256dSThierry Reding 		pr_debug("unregistering platform driver %ps\n", drivers[count]);
1074dbe2256dSThierry Reding 		platform_driver_unregister(drivers[count]);
1075dbe2256dSThierry Reding 	}
1076dbe2256dSThierry Reding }
1077dbe2256dSThierry Reding EXPORT_SYMBOL_GPL(platform_unregister_drivers);
1078dbe2256dSThierry Reding 
platform_match_id(const struct platform_device_id * id,struct platform_device * pdev)107957fee4a5SEric Miao static const struct platform_device_id *platform_match_id(
1080831fad2fSUwe Kleine-König 			const struct platform_device_id *id,
108157fee4a5SEric Miao 			struct platform_device *pdev)
108257fee4a5SEric Miao {
108357fee4a5SEric Miao 	while (id->name[0]) {
1084391c0325SGreg Kroah-Hartman 		if (strcmp(pdev->name, id->name) == 0) {
108557fee4a5SEric Miao 			pdev->id_entry = id;
108657fee4a5SEric Miao 			return id;
108757fee4a5SEric Miao 		}
108857fee4a5SEric Miao 		id++;
108957fee4a5SEric Miao 	}
109057fee4a5SEric Miao 	return NULL;
109157fee4a5SEric Miao }
109257fee4a5SEric Miao 
109325e18499SRafael J. Wysocki #ifdef CONFIG_PM_SLEEP
109425e18499SRafael J. Wysocki 
platform_legacy_suspend(struct device * dev,pm_message_t mesg)109525e18499SRafael J. Wysocki static int platform_legacy_suspend(struct device *dev, pm_message_t mesg)
10961da177e4SLinus Torvalds {
1097783ea7d4SMagnus Damm 	struct platform_driver *pdrv = to_platform_driver(dev->driver);
1098783ea7d4SMagnus Damm 	struct platform_device *pdev = to_platform_device(dev);
10991da177e4SLinus Torvalds 	int ret = 0;
11001da177e4SLinus Torvalds 
1101783ea7d4SMagnus Damm 	if (dev->driver && pdrv->suspend)
1102783ea7d4SMagnus Damm 		ret = pdrv->suspend(pdev, mesg);
1103386415d8SDavid Brownell 
1104386415d8SDavid Brownell 	return ret;
1105386415d8SDavid Brownell }
1106386415d8SDavid Brownell 
platform_legacy_resume(struct device * dev)110725e18499SRafael J. Wysocki static int platform_legacy_resume(struct device *dev)
11081da177e4SLinus Torvalds {
1109783ea7d4SMagnus Damm 	struct platform_driver *pdrv = to_platform_driver(dev->driver);
1110783ea7d4SMagnus Damm 	struct platform_device *pdev = to_platform_device(dev);
11111da177e4SLinus Torvalds 	int ret = 0;
11121da177e4SLinus Torvalds 
1113783ea7d4SMagnus Damm 	if (dev->driver && pdrv->resume)
1114783ea7d4SMagnus Damm 		ret = pdrv->resume(pdev);
11159480e307SRussell King 
11161da177e4SLinus Torvalds 	return ret;
11171da177e4SLinus Torvalds }
11181da177e4SLinus Torvalds 
111969c9dd1eSRafael J. Wysocki #endif /* CONFIG_PM_SLEEP */
11209d730229SMagnus Damm 
112125e18499SRafael J. Wysocki #ifdef CONFIG_SUSPEND
112225e18499SRafael J. Wysocki 
platform_pm_suspend(struct device * dev)112369c9dd1eSRafael J. Wysocki int platform_pm_suspend(struct device *dev)
112425e18499SRafael J. Wysocki {
112525e18499SRafael J. Wysocki 	struct device_driver *drv = dev->driver;
112625e18499SRafael J. Wysocki 	int ret = 0;
112725e18499SRafael J. Wysocki 
1128adf09493SRafael J. Wysocki 	if (!drv)
1129adf09493SRafael J. Wysocki 		return 0;
1130adf09493SRafael J. Wysocki 
1131adf09493SRafael J. Wysocki 	if (drv->pm) {
113225e18499SRafael J. Wysocki 		if (drv->pm->suspend)
113325e18499SRafael J. Wysocki 			ret = drv->pm->suspend(dev);
113425e18499SRafael J. Wysocki 	} else {
113525e18499SRafael J. Wysocki 		ret = platform_legacy_suspend(dev, PMSG_SUSPEND);
113625e18499SRafael J. Wysocki 	}
113725e18499SRafael J. Wysocki 
113825e18499SRafael J. Wysocki 	return ret;
113925e18499SRafael J. Wysocki }
114025e18499SRafael J. Wysocki 
platform_pm_resume(struct device * dev)114169c9dd1eSRafael J. Wysocki int platform_pm_resume(struct device *dev)
114225e18499SRafael J. Wysocki {
114325e18499SRafael J. Wysocki 	struct device_driver *drv = dev->driver;
114425e18499SRafael J. Wysocki 	int ret = 0;
114525e18499SRafael J. Wysocki 
1146adf09493SRafael J. Wysocki 	if (!drv)
1147adf09493SRafael J. Wysocki 		return 0;
1148adf09493SRafael J. Wysocki 
1149adf09493SRafael J. Wysocki 	if (drv->pm) {
115025e18499SRafael J. Wysocki 		if (drv->pm->resume)
115125e18499SRafael J. Wysocki 			ret = drv->pm->resume(dev);
115225e18499SRafael J. Wysocki 	} else {
115325e18499SRafael J. Wysocki 		ret = platform_legacy_resume(dev);
115425e18499SRafael J. Wysocki 	}
115525e18499SRafael J. Wysocki 
115625e18499SRafael J. Wysocki 	return ret;
115725e18499SRafael J. Wysocki }
115825e18499SRafael J. Wysocki 
115969c9dd1eSRafael J. Wysocki #endif /* CONFIG_SUSPEND */
116025e18499SRafael J. Wysocki 
11611f112ceeSRafael J. Wysocki #ifdef CONFIG_HIBERNATE_CALLBACKS
116225e18499SRafael J. Wysocki 
platform_pm_freeze(struct device * dev)116369c9dd1eSRafael J. Wysocki int platform_pm_freeze(struct device *dev)
116425e18499SRafael J. Wysocki {
116525e18499SRafael J. Wysocki 	struct device_driver *drv = dev->driver;
116625e18499SRafael J. Wysocki 	int ret = 0;
116725e18499SRafael J. Wysocki 
116825e18499SRafael J. Wysocki 	if (!drv)
116925e18499SRafael J. Wysocki 		return 0;
117025e18499SRafael J. Wysocki 
117125e18499SRafael J. Wysocki 	if (drv->pm) {
117225e18499SRafael J. Wysocki 		if (drv->pm->freeze)
117325e18499SRafael J. Wysocki 			ret = drv->pm->freeze(dev);
117425e18499SRafael J. Wysocki 	} else {
117525e18499SRafael J. Wysocki 		ret = platform_legacy_suspend(dev, PMSG_FREEZE);
117625e18499SRafael J. Wysocki 	}
117725e18499SRafael J. Wysocki 
117825e18499SRafael J. Wysocki 	return ret;
117925e18499SRafael J. Wysocki }
118025e18499SRafael J. Wysocki 
platform_pm_thaw(struct device * dev)118169c9dd1eSRafael J. Wysocki int platform_pm_thaw(struct device *dev)
118225e18499SRafael J. Wysocki {
118325e18499SRafael J. Wysocki 	struct device_driver *drv = dev->driver;
118425e18499SRafael J. Wysocki 	int ret = 0;
118525e18499SRafael J. Wysocki 
1186adf09493SRafael J. Wysocki 	if (!drv)
1187adf09493SRafael J. Wysocki 		return 0;
1188adf09493SRafael J. Wysocki 
1189adf09493SRafael J. Wysocki 	if (drv->pm) {
119025e18499SRafael J. Wysocki 		if (drv->pm->thaw)
119125e18499SRafael J. Wysocki 			ret = drv->pm->thaw(dev);
119225e18499SRafael J. Wysocki 	} else {
119325e18499SRafael J. Wysocki 		ret = platform_legacy_resume(dev);
119425e18499SRafael J. Wysocki 	}
119525e18499SRafael J. Wysocki 
119625e18499SRafael J. Wysocki 	return ret;
119725e18499SRafael J. Wysocki }
119825e18499SRafael J. Wysocki 
platform_pm_poweroff(struct device * dev)119969c9dd1eSRafael J. Wysocki int platform_pm_poweroff(struct device *dev)
120025e18499SRafael J. Wysocki {
120125e18499SRafael J. Wysocki 	struct device_driver *drv = dev->driver;
120225e18499SRafael J. Wysocki 	int ret = 0;
120325e18499SRafael J. Wysocki 
1204adf09493SRafael J. Wysocki 	if (!drv)
1205adf09493SRafael J. Wysocki 		return 0;
1206adf09493SRafael J. Wysocki 
1207adf09493SRafael J. Wysocki 	if (drv->pm) {
120825e18499SRafael J. Wysocki 		if (drv->pm->poweroff)
120925e18499SRafael J. Wysocki 			ret = drv->pm->poweroff(dev);
121025e18499SRafael J. Wysocki 	} else {
121125e18499SRafael J. Wysocki 		ret = platform_legacy_suspend(dev, PMSG_HIBERNATE);
121225e18499SRafael J. Wysocki 	}
121325e18499SRafael J. Wysocki 
121425e18499SRafael J. Wysocki 	return ret;
121525e18499SRafael J. Wysocki }
121625e18499SRafael J. Wysocki 
platform_pm_restore(struct device * dev)121769c9dd1eSRafael J. Wysocki int platform_pm_restore(struct device *dev)
121825e18499SRafael J. Wysocki {
121925e18499SRafael J. Wysocki 	struct device_driver *drv = dev->driver;
122025e18499SRafael J. Wysocki 	int ret = 0;
122125e18499SRafael J. Wysocki 
1222adf09493SRafael J. Wysocki 	if (!drv)
1223adf09493SRafael J. Wysocki 		return 0;
1224adf09493SRafael J. Wysocki 
1225adf09493SRafael J. Wysocki 	if (drv->pm) {
122625e18499SRafael J. Wysocki 		if (drv->pm->restore)
122725e18499SRafael J. Wysocki 			ret = drv->pm->restore(dev);
122825e18499SRafael J. Wysocki 	} else {
122925e18499SRafael J. Wysocki 		ret = platform_legacy_resume(dev);
123025e18499SRafael J. Wysocki 	}
123125e18499SRafael J. Wysocki 
123225e18499SRafael J. Wysocki 	return ret;
123325e18499SRafael J. Wysocki }
123425e18499SRafael J. Wysocki 
123569c9dd1eSRafael J. Wysocki #endif /* CONFIG_HIBERNATE_CALLBACKS */
123625e18499SRafael J. Wysocki 
1237e21d740aSUwe Kleine-König /* modalias support enables more hands-off userspace setup:
1238e21d740aSUwe Kleine-König  * (a) environment variable lets new-style hotplug events work once system is
1239e21d740aSUwe Kleine-König  *     fully running:  "modprobe $MODALIAS"
1240e21d740aSUwe Kleine-König  * (b) sysfs attribute lets new-style coldplug recover from hotplug events
1241e21d740aSUwe Kleine-König  *     mishandled before system is fully running:  "modprobe $(cat modalias)"
1242e21d740aSUwe Kleine-König  */
modalias_show(struct device * dev,struct device_attribute * attr,char * buf)1243e21d740aSUwe Kleine-König static ssize_t modalias_show(struct device *dev,
1244e21d740aSUwe Kleine-König 			     struct device_attribute *attr, char *buf)
1245e21d740aSUwe Kleine-König {
1246e21d740aSUwe Kleine-König 	struct platform_device *pdev = to_platform_device(dev);
1247e21d740aSUwe Kleine-König 	int len;
1248e21d740aSUwe Kleine-König 
1249e21d740aSUwe Kleine-König 	len = of_device_modalias(dev, buf, PAGE_SIZE);
1250e21d740aSUwe Kleine-König 	if (len != -ENODEV)
1251e21d740aSUwe Kleine-König 		return len;
1252e21d740aSUwe Kleine-König 
1253e21d740aSUwe Kleine-König 	len = acpi_device_modalias(dev, buf, PAGE_SIZE - 1);
1254e21d740aSUwe Kleine-König 	if (len != -ENODEV)
1255e21d740aSUwe Kleine-König 		return len;
1256e21d740aSUwe Kleine-König 
1257e21d740aSUwe Kleine-König 	return sysfs_emit(buf, "platform:%s\n", pdev->name);
1258e21d740aSUwe Kleine-König }
1259e21d740aSUwe Kleine-König static DEVICE_ATTR_RO(modalias);
1260e21d740aSUwe Kleine-König 
numa_node_show(struct device * dev,struct device_attribute * attr,char * buf)1261e21d740aSUwe Kleine-König static ssize_t numa_node_show(struct device *dev,
1262e21d740aSUwe Kleine-König 			      struct device_attribute *attr, char *buf)
1263e21d740aSUwe Kleine-König {
1264e21d740aSUwe Kleine-König 	return sysfs_emit(buf, "%d\n", dev_to_node(dev));
1265e21d740aSUwe Kleine-König }
1266e21d740aSUwe Kleine-König static DEVICE_ATTR_RO(numa_node);
1267e21d740aSUwe Kleine-König 
driver_override_show(struct device * dev,struct device_attribute * attr,char * buf)1268e21d740aSUwe Kleine-König static ssize_t driver_override_show(struct device *dev,
1269e21d740aSUwe Kleine-König 				    struct device_attribute *attr, char *buf)
1270e21d740aSUwe Kleine-König {
1271e21d740aSUwe Kleine-König 	struct platform_device *pdev = to_platform_device(dev);
1272e21d740aSUwe Kleine-König 	ssize_t len;
1273e21d740aSUwe Kleine-König 
1274e21d740aSUwe Kleine-König 	device_lock(dev);
1275e21d740aSUwe Kleine-König 	len = sysfs_emit(buf, "%s\n", pdev->driver_override);
1276e21d740aSUwe Kleine-König 	device_unlock(dev);
1277e21d740aSUwe Kleine-König 
1278e21d740aSUwe Kleine-König 	return len;
1279e21d740aSUwe Kleine-König }
1280e21d740aSUwe Kleine-König 
driver_override_store(struct device * dev,struct device_attribute * attr,const char * buf,size_t count)1281e21d740aSUwe Kleine-König static ssize_t driver_override_store(struct device *dev,
1282e21d740aSUwe Kleine-König 				     struct device_attribute *attr,
1283e21d740aSUwe Kleine-König 				     const char *buf, size_t count)
1284e21d740aSUwe Kleine-König {
1285e21d740aSUwe Kleine-König 	struct platform_device *pdev = to_platform_device(dev);
12866c2f4211SKrzysztof Kozlowski 	int ret;
1287e21d740aSUwe Kleine-König 
12886c2f4211SKrzysztof Kozlowski 	ret = driver_set_override(dev, &pdev->driver_override, buf, count);
12896c2f4211SKrzysztof Kozlowski 	if (ret)
12906c2f4211SKrzysztof Kozlowski 		return ret;
1291e21d740aSUwe Kleine-König 
1292e21d740aSUwe Kleine-König 	return count;
1293e21d740aSUwe Kleine-König }
1294e21d740aSUwe Kleine-König static DEVICE_ATTR_RW(driver_override);
1295e21d740aSUwe Kleine-König 
1296e21d740aSUwe Kleine-König static struct attribute *platform_dev_attrs[] = {
1297e21d740aSUwe Kleine-König 	&dev_attr_modalias.attr,
1298e21d740aSUwe Kleine-König 	&dev_attr_numa_node.attr,
1299e21d740aSUwe Kleine-König 	&dev_attr_driver_override.attr,
1300e21d740aSUwe Kleine-König 	NULL,
1301e21d740aSUwe Kleine-König };
1302e21d740aSUwe Kleine-König 
platform_dev_attrs_visible(struct kobject * kobj,struct attribute * a,int n)1303e21d740aSUwe Kleine-König static umode_t platform_dev_attrs_visible(struct kobject *kobj, struct attribute *a,
1304e21d740aSUwe Kleine-König 		int n)
1305e21d740aSUwe Kleine-König {
1306e21d740aSUwe Kleine-König 	struct device *dev = container_of(kobj, typeof(*dev), kobj);
1307e21d740aSUwe Kleine-König 
1308e21d740aSUwe Kleine-König 	if (a == &dev_attr_numa_node.attr &&
1309e21d740aSUwe Kleine-König 			dev_to_node(dev) == NUMA_NO_NODE)
1310e21d740aSUwe Kleine-König 		return 0;
1311e21d740aSUwe Kleine-König 
1312e21d740aSUwe Kleine-König 	return a->mode;
1313e21d740aSUwe Kleine-König }
1314e21d740aSUwe Kleine-König 
13155a576764SRikard Falkeborn static const struct attribute_group platform_dev_group = {
1316e21d740aSUwe Kleine-König 	.attrs = platform_dev_attrs,
1317e21d740aSUwe Kleine-König 	.is_visible = platform_dev_attrs_visible,
1318e21d740aSUwe Kleine-König };
1319e21d740aSUwe Kleine-König __ATTRIBUTE_GROUPS(platform_dev);
1320e21d740aSUwe Kleine-König 
1321e21d740aSUwe Kleine-König 
1322e21d740aSUwe Kleine-König /**
1323e21d740aSUwe Kleine-König  * platform_match - bind platform device to platform driver.
1324e21d740aSUwe Kleine-König  * @dev: device.
1325e21d740aSUwe Kleine-König  * @drv: driver.
1326e21d740aSUwe Kleine-König  *
1327e21d740aSUwe Kleine-König  * Platform device IDs are assumed to be encoded like this:
1328e21d740aSUwe Kleine-König  * "<name><instance>", where <name> is a short description of the type of
1329e21d740aSUwe Kleine-König  * device, like "pci" or "floppy", and <instance> is the enumerated
1330e21d740aSUwe Kleine-König  * instance of the device, like '0' or '42'.  Driver IDs are simply
1331e21d740aSUwe Kleine-König  * "<name>".  So, extract the <name> from the platform_device structure,
1332e21d740aSUwe Kleine-König  * and compare it against the name of the driver. Return whether they match
1333e21d740aSUwe Kleine-König  * or not.
1334e21d740aSUwe Kleine-König  */
platform_match(struct device * dev,struct device_driver * drv)1335e21d740aSUwe Kleine-König static int platform_match(struct device *dev, struct device_driver *drv)
1336e21d740aSUwe Kleine-König {
1337e21d740aSUwe Kleine-König 	struct platform_device *pdev = to_platform_device(dev);
1338e21d740aSUwe Kleine-König 	struct platform_driver *pdrv = to_platform_driver(drv);
1339e21d740aSUwe Kleine-König 
1340e21d740aSUwe Kleine-König 	/* When driver_override is set, only bind to the matching driver */
1341e21d740aSUwe Kleine-König 	if (pdev->driver_override)
1342e21d740aSUwe Kleine-König 		return !strcmp(pdev->driver_override, drv->name);
1343e21d740aSUwe Kleine-König 
1344e21d740aSUwe Kleine-König 	/* Attempt an OF style match first */
1345e21d740aSUwe Kleine-König 	if (of_driver_match_device(dev, drv))
1346e21d740aSUwe Kleine-König 		return 1;
1347e21d740aSUwe Kleine-König 
1348e21d740aSUwe Kleine-König 	/* Then try ACPI style match */
1349e21d740aSUwe Kleine-König 	if (acpi_driver_match_device(dev, drv))
1350e21d740aSUwe Kleine-König 		return 1;
1351e21d740aSUwe Kleine-König 
1352e21d740aSUwe Kleine-König 	/* Then try to match against the id table */
1353e21d740aSUwe Kleine-König 	if (pdrv->id_table)
1354e21d740aSUwe Kleine-König 		return platform_match_id(pdrv->id_table, pdev) != NULL;
1355e21d740aSUwe Kleine-König 
1356e21d740aSUwe Kleine-König 	/* fall-back to driver name match */
1357e21d740aSUwe Kleine-König 	return (strcmp(pdev->name, drv->name) == 0);
1358e21d740aSUwe Kleine-König }
1359e21d740aSUwe Kleine-König 
platform_uevent(const struct device * dev,struct kobj_uevent_env * env)13602a81ada3SGreg Kroah-Hartman static int platform_uevent(const struct device *dev, struct kobj_uevent_env *env)
1361e21d740aSUwe Kleine-König {
13622a81ada3SGreg Kroah-Hartman 	const struct platform_device *pdev = to_platform_device(dev);
1363e21d740aSUwe Kleine-König 	int rc;
1364e21d740aSUwe Kleine-König 
1365e21d740aSUwe Kleine-König 	/* Some devices have extra OF data and an OF-style MODALIAS */
1366e21d740aSUwe Kleine-König 	rc = of_device_uevent_modalias(dev, env);
1367e21d740aSUwe Kleine-König 	if (rc != -ENODEV)
1368e21d740aSUwe Kleine-König 		return rc;
1369e21d740aSUwe Kleine-König 
1370e21d740aSUwe Kleine-König 	rc = acpi_device_uevent_modalias(dev, env);
1371e21d740aSUwe Kleine-König 	if (rc != -ENODEV)
1372e21d740aSUwe Kleine-König 		return rc;
1373e21d740aSUwe Kleine-König 
1374e21d740aSUwe Kleine-König 	add_uevent_var(env, "MODALIAS=%s%s", PLATFORM_MODULE_PREFIX,
1375e21d740aSUwe Kleine-König 			pdev->name);
1376e21d740aSUwe Kleine-König 	return 0;
1377e21d740aSUwe Kleine-König }
1378e21d740aSUwe Kleine-König 
platform_probe(struct device * _dev)13799c30921fSUwe Kleine-König static int platform_probe(struct device *_dev)
13809c30921fSUwe Kleine-König {
13819c30921fSUwe Kleine-König 	struct platform_driver *drv = to_platform_driver(_dev->driver);
13829c30921fSUwe Kleine-König 	struct platform_device *dev = to_platform_device(_dev);
13839c30921fSUwe Kleine-König 	int ret;
13849c30921fSUwe Kleine-König 
13859c30921fSUwe Kleine-König 	/*
13869c30921fSUwe Kleine-König 	 * A driver registered using platform_driver_probe() cannot be bound
13879c30921fSUwe Kleine-König 	 * again later because the probe function usually lives in __init code
13889c30921fSUwe Kleine-König 	 * and so is gone. For these drivers .probe is set to
13899c30921fSUwe Kleine-König 	 * platform_probe_fail in __platform_driver_probe(). Don't even prepare
13909c30921fSUwe Kleine-König 	 * clocks and PM domains for these to match the traditional behaviour.
13919c30921fSUwe Kleine-König 	 */
13929c30921fSUwe Kleine-König 	if (unlikely(drv->probe == platform_probe_fail))
13939c30921fSUwe Kleine-König 		return -ENXIO;
13949c30921fSUwe Kleine-König 
13959c30921fSUwe Kleine-König 	ret = of_clk_set_defaults(_dev->of_node, false);
13969c30921fSUwe Kleine-König 	if (ret < 0)
13979c30921fSUwe Kleine-König 		return ret;
13989c30921fSUwe Kleine-König 
13999c30921fSUwe Kleine-König 	ret = dev_pm_domain_attach(_dev, true);
14009c30921fSUwe Kleine-König 	if (ret)
14019c30921fSUwe Kleine-König 		goto out;
14029c30921fSUwe Kleine-König 
14039c30921fSUwe Kleine-König 	if (drv->probe) {
14049c30921fSUwe Kleine-König 		ret = drv->probe(dev);
14059c30921fSUwe Kleine-König 		if (ret)
14069c30921fSUwe Kleine-König 			dev_pm_domain_detach(_dev, true);
14079c30921fSUwe Kleine-König 	}
14089c30921fSUwe Kleine-König 
14099c30921fSUwe Kleine-König out:
14109c30921fSUwe Kleine-König 	if (drv->prevent_deferred_probe && ret == -EPROBE_DEFER) {
14119c30921fSUwe Kleine-König 		dev_warn(_dev, "probe deferral not supported\n");
14129c30921fSUwe Kleine-König 		ret = -ENXIO;
14139c30921fSUwe Kleine-König 	}
14149c30921fSUwe Kleine-König 
14159c30921fSUwe Kleine-König 	return ret;
14169c30921fSUwe Kleine-König }
14179c30921fSUwe Kleine-König 
platform_remove(struct device * _dev)1418fc7a6209SUwe Kleine-König static void platform_remove(struct device *_dev)
14199c30921fSUwe Kleine-König {
14209c30921fSUwe Kleine-König 	struct platform_driver *drv = to_platform_driver(_dev->driver);
14219c30921fSUwe Kleine-König 	struct platform_device *dev = to_platform_device(_dev);
14229c30921fSUwe Kleine-König 
14235c5a7680SUwe Kleine-König 	if (drv->remove_new) {
14245c5a7680SUwe Kleine-König 		drv->remove_new(dev);
14255c5a7680SUwe Kleine-König 	} else if (drv->remove) {
1426e5e1c209SUwe Kleine-König 		int ret = drv->remove(dev);
1427e5e1c209SUwe Kleine-König 
1428e5e1c209SUwe Kleine-König 		if (ret)
1429e5e1c209SUwe Kleine-König 			dev_warn(_dev, "remove callback returned a non-zero value. This will be ignored.\n");
1430e5e1c209SUwe Kleine-König 	}
14319c30921fSUwe Kleine-König 	dev_pm_domain_detach(_dev, true);
14329c30921fSUwe Kleine-König }
14339c30921fSUwe Kleine-König 
platform_shutdown(struct device * _dev)14349c30921fSUwe Kleine-König static void platform_shutdown(struct device *_dev)
14359c30921fSUwe Kleine-König {
14369c30921fSUwe Kleine-König 	struct platform_device *dev = to_platform_device(_dev);
143746e85af0SDmitry Baryshkov 	struct platform_driver *drv;
14389c30921fSUwe Kleine-König 
143946e85af0SDmitry Baryshkov 	if (!_dev->driver)
144046e85af0SDmitry Baryshkov 		return;
144146e85af0SDmitry Baryshkov 
144246e85af0SDmitry Baryshkov 	drv = to_platform_driver(_dev->driver);
14439c30921fSUwe Kleine-König 	if (drv->shutdown)
14449c30921fSUwe Kleine-König 		drv->shutdown(dev);
14459c30921fSUwe Kleine-König }
14469c30921fSUwe Kleine-König 
platform_dma_configure(struct device * dev)14474a6d9dd5SLu Baolu static int platform_dma_configure(struct device *dev)
144807397df2SNipun Gupta {
1449512881eaSLu Baolu 	struct platform_driver *drv = to_platform_driver(dev->driver);
145007397df2SNipun Gupta 	enum dev_dma_attr attr;
145107397df2SNipun Gupta 	int ret = 0;
145207397df2SNipun Gupta 
145307397df2SNipun Gupta 	if (dev->of_node) {
14543d6ce86eSChristoph Hellwig 		ret = of_dma_configure(dev, dev->of_node, true);
145507397df2SNipun Gupta 	} else if (has_acpi_companion(dev)) {
145607397df2SNipun Gupta 		attr = acpi_get_dma_attr(to_acpi_device_node(dev->fwnode));
145707397df2SNipun Gupta 		ret = acpi_dma_configure(dev, attr);
145807397df2SNipun Gupta 	}
145907397df2SNipun Gupta 
1460512881eaSLu Baolu 	if (!ret && !drv->driver_managed_dma) {
1461512881eaSLu Baolu 		ret = iommu_device_use_default_domain(dev);
1462512881eaSLu Baolu 		if (ret)
1463512881eaSLu Baolu 			arch_teardown_dma_ops(dev);
1464512881eaSLu Baolu 	}
1465512881eaSLu Baolu 
146607397df2SNipun Gupta 	return ret;
146707397df2SNipun Gupta }
146807397df2SNipun Gupta 
platform_dma_cleanup(struct device * dev)1469512881eaSLu Baolu static void platform_dma_cleanup(struct device *dev)
1470512881eaSLu Baolu {
1471512881eaSLu Baolu 	struct platform_driver *drv = to_platform_driver(dev->driver);
1472512881eaSLu Baolu 
1473512881eaSLu Baolu 	if (!drv->driver_managed_dma)
1474512881eaSLu Baolu 		iommu_device_unuse_default_domain(dev);
1475512881eaSLu Baolu }
1476512881eaSLu Baolu 
1477d9ab7716SDmitry Torokhov static const struct dev_pm_ops platform_dev_pm_ops = {
147886854b43SCai Huoqing 	SET_RUNTIME_PM_OPS(pm_generic_runtime_suspend, pm_generic_runtime_resume, NULL)
147969c9dd1eSRafael J. Wysocki 	USE_PLATFORM_PM_SLEEP_OPS
148025e18499SRafael J. Wysocki };
148125e18499SRafael J. Wysocki 
14821da177e4SLinus Torvalds struct bus_type platform_bus_type = {
14831da177e4SLinus Torvalds 	.name		= "platform",
1484d06262e5SGreg Kroah-Hartman 	.dev_groups	= platform_dev_groups,
14851da177e4SLinus Torvalds 	.match		= platform_match,
1486a0245f7aSDavid Brownell 	.uevent		= platform_uevent,
14879c30921fSUwe Kleine-König 	.probe		= platform_probe,
14889c30921fSUwe Kleine-König 	.remove		= platform_remove,
14899c30921fSUwe Kleine-König 	.shutdown	= platform_shutdown,
149007397df2SNipun Gupta 	.dma_configure	= platform_dma_configure,
1491512881eaSLu Baolu 	.dma_cleanup	= platform_dma_cleanup,
14929d730229SMagnus Damm 	.pm		= &platform_dev_pm_ops,
14931da177e4SLinus Torvalds };
1494a96b2042SDmitry Torokhov EXPORT_SYMBOL_GPL(platform_bus_type);
14951da177e4SLinus Torvalds 
__platform_match(struct device * dev,const void * drv)1496492c8872SSami Tolvanen static inline int __platform_match(struct device *dev, const void *drv)
1497492c8872SSami Tolvanen {
1498492c8872SSami Tolvanen 	return platform_match(dev, (struct device_driver *)drv);
1499492c8872SSami Tolvanen }
1500492c8872SSami Tolvanen 
150136f3313dSSuzuki K Poulose /**
150236f3313dSSuzuki K Poulose  * platform_find_device_by_driver - Find a platform device with a given
150336f3313dSSuzuki K Poulose  * driver.
150436f3313dSSuzuki K Poulose  * @start: The device to start the search from.
150536f3313dSSuzuki K Poulose  * @drv: The device driver to look for.
150636f3313dSSuzuki K Poulose  */
platform_find_device_by_driver(struct device * start,const struct device_driver * drv)150736f3313dSSuzuki K Poulose struct device *platform_find_device_by_driver(struct device *start,
150836f3313dSSuzuki K Poulose 					      const struct device_driver *drv)
150936f3313dSSuzuki K Poulose {
151036f3313dSSuzuki K Poulose 	return bus_find_device(&platform_bus_type, start, drv,
1511492c8872SSami Tolvanen 			       __platform_match);
151236f3313dSSuzuki K Poulose }
151336f3313dSSuzuki K Poulose EXPORT_SYMBOL_GPL(platform_find_device_by_driver);
151436f3313dSSuzuki K Poulose 
early_platform_cleanup(void)1515eecd37e1SGuenter Roeck void __weak __init early_platform_cleanup(void) { }
1516eecd37e1SGuenter Roeck 
platform_bus_init(void)15171da177e4SLinus Torvalds int __init platform_bus_init(void)
15181da177e4SLinus Torvalds {
1519fbfb1445SCornelia Huck 	int error;
1520fbfb1445SCornelia Huck 
1521eecd37e1SGuenter Roeck 	early_platform_cleanup();
1522eecd37e1SGuenter Roeck 
1523fbfb1445SCornelia Huck 	error = device_register(&platform_bus);
1524c8ae1674SArvind Yadav 	if (error) {
1525c8ae1674SArvind Yadav 		put_device(&platform_bus);
1526fbfb1445SCornelia Huck 		return error;
1527c8ae1674SArvind Yadav 	}
1528fbfb1445SCornelia Huck 	error =  bus_register(&platform_bus_type);
1529fbfb1445SCornelia Huck 	if (error)
1530fbfb1445SCornelia Huck 		device_unregister(&platform_bus);
1531*73aca58bSRob Herring 
1532fbfb1445SCornelia Huck 	return error;
15331da177e4SLinus Torvalds }
1534