xref: /linux/drivers/base/platform.c (revision e5f0e38e7ece5b35577faa9bfbe5ec56091ec76b)
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  */
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 
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 *
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  */
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 *
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  */
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
181243e1b77SAndy Shevchenko 	struct fwnode_handle *fwnode = dev_fwnode(&dev->dev);
1829ec36cafSRob Herring 	struct resource *r;
183aff008adSGuenter Roeck 
184243e1b77SAndy Shevchenko 	if (is_of_node(fwnode)) {
185243e1b77SAndy Shevchenko 		ret = of_irq_get(to_of_node(fwnode), num);
186e330b9a6SSergei Shtylyov 		if (ret > 0 || ret == -EPROBE_DEFER)
187a85a6c86SBjorn Helgaas 			goto out;
188aff008adSGuenter Roeck 	}
1899ec36cafSRob Herring 
1909ec36cafSRob Herring 	r = platform_get_resource(dev, IORESOURCE_IRQ, num);
191243e1b77SAndy Shevchenko 	if (is_acpi_device_node(fwnode)) {
192d44fa3d4SAgustin Vega-Frias 		if (r && r->flags & IORESOURCE_DISABLED) {
193243e1b77SAndy Shevchenko 			ret = acpi_irq_get(ACPI_HANDLE_FWNODE(fwnode), num, r);
194d44fa3d4SAgustin Vega-Frias 			if (ret)
195a85a6c86SBjorn Helgaas 				goto out;
196d44fa3d4SAgustin Vega-Frias 		}
197d44fa3d4SAgustin Vega-Frias 	}
198d44fa3d4SAgustin Vega-Frias 
1997085a740SLinus Walleij 	/*
2007085a740SLinus Walleij 	 * The resources may pass trigger flags to the irqs that need
2017085a740SLinus Walleij 	 * to be set up. It so happens that the trigger flags for
2027085a740SLinus Walleij 	 * IORESOURCE_BITS correspond 1-to-1 to the IRQF_TRIGGER*
2037085a740SLinus Walleij 	 * settings.
2047085a740SLinus Walleij 	 */
20560ca5e0dSGuenter Roeck 	if (r && r->flags & IORESOURCE_BITS) {
20660ca5e0dSGuenter Roeck 		struct irq_data *irqd;
20760ca5e0dSGuenter Roeck 
20860ca5e0dSGuenter Roeck 		irqd = irq_get_irq_data(r->start);
209c99f4ebcSAndy Shevchenko 		if (!irqd)
210c99f4ebcSAndy Shevchenko 			goto out_not_found;
21160ca5e0dSGuenter Roeck 		irqd_set_trigger_type(irqd, r->flags & IORESOURCE_BITS);
21260ca5e0dSGuenter Roeck 	}
2131da177e4SLinus Torvalds 
214a85a6c86SBjorn Helgaas 	if (r) {
215a85a6c86SBjorn Helgaas 		ret = r->start;
216a85a6c86SBjorn Helgaas 		goto out;
217a85a6c86SBjorn Helgaas 	}
218daaef255SEnrico Granata 
219daaef255SEnrico Granata 	/*
220daaef255SEnrico Granata 	 * For the index 0 interrupt, allow falling back to GpioInt
221daaef255SEnrico Granata 	 * resources. While a device could have both Interrupt and GpioInt
222daaef255SEnrico Granata 	 * resources, making this fallback ambiguous, in many common cases
223daaef255SEnrico Granata 	 * the device will only expose one IRQ, and this fallback
224daaef255SEnrico Granata 	 * allows a common code path across either kind of resource.
225daaef255SEnrico Granata 	 */
226243e1b77SAndy Shevchenko 	if (num == 0 && is_acpi_device_node(fwnode)) {
227243e1b77SAndy Shevchenko 		ret = acpi_dev_gpio_irq_get(to_acpi_device_node(fwnode), num);
22846c42d84SBrian Norris 		/* Our callers expect -ENXIO for missing IRQs. */
22946c42d84SBrian Norris 		if (ret >= 0 || ret == -EPROBE_DEFER)
230a85a6c86SBjorn Helgaas 			goto out;
23146c42d84SBrian Norris 	}
232daaef255SEnrico Granata 
2335cf8f7dbSAndreas Larsson #endif
234c99f4ebcSAndy Shevchenko out_not_found:
235c99f4ebcSAndy Shevchenko 	ret = -ENXIO;
236a85a6c86SBjorn Helgaas out:
237ce753ad1SSergey Shtylyov 	if (WARN(!ret, "0 is an invalid IRQ number\n"))
238ce753ad1SSergey Shtylyov 		return -EINVAL;
239a85a6c86SBjorn Helgaas 	return ret;
2401da177e4SLinus Torvalds }
241ec4e2906SUwe Kleine-König EXPORT_SYMBOL_GPL(platform_get_irq_optional);
2427723f4c5SStephen Boyd 
2437723f4c5SStephen Boyd /**
2447723f4c5SStephen Boyd  * platform_get_irq - get an IRQ for a device
2457723f4c5SStephen Boyd  * @dev: platform device
2467723f4c5SStephen Boyd  * @num: IRQ number index
2477723f4c5SStephen Boyd  *
2487723f4c5SStephen Boyd  * Gets an IRQ for a platform device and prints an error message if finding the
2497723f4c5SStephen Boyd  * IRQ fails. Device drivers should check the return value for errors so as to
2507723f4c5SStephen Boyd  * not pass a negative integer value to the request_irq() APIs.
2517723f4c5SStephen Boyd  *
252f0825246SMauro Carvalho Chehab  * For example::
253f0825246SMauro Carvalho Chehab  *
2547723f4c5SStephen Boyd  *		int irq = platform_get_irq(pdev, 0);
2557723f4c5SStephen Boyd  *		if (irq < 0)
2567723f4c5SStephen Boyd  *			return irq;
2577723f4c5SStephen Boyd  *
258a85a6c86SBjorn Helgaas  * Return: non-zero IRQ number on success, negative error number on failure.
2597723f4c5SStephen Boyd  */
2607723f4c5SStephen Boyd int platform_get_irq(struct platform_device *dev, unsigned int num)
2617723f4c5SStephen Boyd {
2627723f4c5SStephen Boyd 	int ret;
2637723f4c5SStephen Boyd 
264c2f3f755SGreg Kroah-Hartman 	ret = platform_get_irq_optional(dev, num);
2652043727cSCai Huoqing 	if (ret < 0)
2662043727cSCai Huoqing 		return dev_err_probe(&dev->dev, ret,
2672043727cSCai Huoqing 				     "IRQ index %u not found\n", num);
2687723f4c5SStephen Boyd 
2697723f4c5SStephen Boyd 	return ret;
2707723f4c5SStephen Boyd }
271a96b2042SDmitry Torokhov EXPORT_SYMBOL_GPL(platform_get_irq);
2721da177e4SLinus Torvalds 
2731da177e4SLinus Torvalds /**
2744b83555dSStephen Boyd  * platform_irq_count - Count the number of IRQs a platform device uses
2754b83555dSStephen Boyd  * @dev: platform device
2764b83555dSStephen Boyd  *
2774b83555dSStephen Boyd  * Return: Number of IRQs a platform device uses or EPROBE_DEFER
2784b83555dSStephen Boyd  */
2794b83555dSStephen Boyd int platform_irq_count(struct platform_device *dev)
2804b83555dSStephen Boyd {
2814b83555dSStephen Boyd 	int ret, nr = 0;
2824b83555dSStephen Boyd 
283c2f3f755SGreg Kroah-Hartman 	while ((ret = platform_get_irq_optional(dev, nr)) >= 0)
2844b83555dSStephen Boyd 		nr++;
2854b83555dSStephen Boyd 
2864b83555dSStephen Boyd 	if (ret == -EPROBE_DEFER)
2874b83555dSStephen Boyd 		return ret;
2884b83555dSStephen Boyd 
2894b83555dSStephen Boyd 	return nr;
2904b83555dSStephen Boyd }
2914b83555dSStephen Boyd EXPORT_SYMBOL_GPL(platform_irq_count);
2924b83555dSStephen Boyd 
293e15f2fa9SJohn Garry struct irq_affinity_devres {
294e15f2fa9SJohn Garry 	unsigned int count;
29536b2d7ddSKees Cook 	unsigned int irq[] __counted_by(count);
296e15f2fa9SJohn Garry };
297e15f2fa9SJohn Garry 
298e15f2fa9SJohn Garry static void platform_disable_acpi_irq(struct platform_device *pdev, int index)
299e15f2fa9SJohn Garry {
300e15f2fa9SJohn Garry 	struct resource *r;
301e15f2fa9SJohn Garry 
302e15f2fa9SJohn Garry 	r = platform_get_resource(pdev, IORESOURCE_IRQ, index);
303e15f2fa9SJohn Garry 	if (r)
304e15f2fa9SJohn Garry 		irqresource_disabled(r, 0);
305e15f2fa9SJohn Garry }
306e15f2fa9SJohn Garry 
307e15f2fa9SJohn Garry static void devm_platform_get_irqs_affinity_release(struct device *dev,
308e15f2fa9SJohn Garry 						    void *res)
309e15f2fa9SJohn Garry {
310e15f2fa9SJohn Garry 	struct irq_affinity_devres *ptr = res;
311e15f2fa9SJohn Garry 	int i;
312e15f2fa9SJohn Garry 
313e15f2fa9SJohn Garry 	for (i = 0; i < ptr->count; i++) {
314e15f2fa9SJohn Garry 		irq_dispose_mapping(ptr->irq[i]);
315e15f2fa9SJohn Garry 
316243e1b77SAndy Shevchenko 		if (is_acpi_device_node(dev_fwnode(dev)))
317e15f2fa9SJohn Garry 			platform_disable_acpi_irq(to_platform_device(dev), i);
318e15f2fa9SJohn Garry 	}
319e15f2fa9SJohn Garry }
320e15f2fa9SJohn Garry 
321e15f2fa9SJohn Garry /**
322e15f2fa9SJohn Garry  * devm_platform_get_irqs_affinity - devm method to get a set of IRQs for a
323e15f2fa9SJohn Garry  *				device using an interrupt affinity descriptor
324e15f2fa9SJohn Garry  * @dev: platform device pointer
325e15f2fa9SJohn Garry  * @affd: affinity descriptor
326e15f2fa9SJohn Garry  * @minvec: minimum count of interrupt vectors
327e15f2fa9SJohn Garry  * @maxvec: maximum count of interrupt vectors
328e15f2fa9SJohn Garry  * @irqs: pointer holder for IRQ numbers
329e15f2fa9SJohn Garry  *
330e15f2fa9SJohn Garry  * Gets a set of IRQs for a platform device, and updates IRQ afffinty according
331e15f2fa9SJohn Garry  * to the passed affinity descriptor
332e15f2fa9SJohn Garry  *
333e15f2fa9SJohn Garry  * Return: Number of vectors on success, negative error number on failure.
334e15f2fa9SJohn Garry  */
335e15f2fa9SJohn Garry int devm_platform_get_irqs_affinity(struct platform_device *dev,
336e15f2fa9SJohn Garry 				    struct irq_affinity *affd,
337e15f2fa9SJohn Garry 				    unsigned int minvec,
338e15f2fa9SJohn Garry 				    unsigned int maxvec,
339e15f2fa9SJohn Garry 				    int **irqs)
340e15f2fa9SJohn Garry {
341e15f2fa9SJohn Garry 	struct irq_affinity_devres *ptr;
342e15f2fa9SJohn Garry 	struct irq_affinity_desc *desc;
343e15f2fa9SJohn Garry 	size_t size;
344e15f2fa9SJohn Garry 	int i, ret, nvec;
345e15f2fa9SJohn Garry 
346e15f2fa9SJohn Garry 	if (!affd)
347e15f2fa9SJohn Garry 		return -EPERM;
348e15f2fa9SJohn Garry 
349e15f2fa9SJohn Garry 	if (maxvec < minvec)
350e15f2fa9SJohn Garry 		return -ERANGE;
351e15f2fa9SJohn Garry 
352e15f2fa9SJohn Garry 	nvec = platform_irq_count(dev);
353e1dc2099SJohn Garry 	if (nvec < 0)
354e1dc2099SJohn Garry 		return nvec;
355e15f2fa9SJohn Garry 
356e15f2fa9SJohn Garry 	if (nvec < minvec)
357e15f2fa9SJohn Garry 		return -ENOSPC;
358e15f2fa9SJohn Garry 
359e15f2fa9SJohn Garry 	nvec = irq_calc_affinity_vectors(minvec, nvec, affd);
360e15f2fa9SJohn Garry 	if (nvec < minvec)
361e15f2fa9SJohn Garry 		return -ENOSPC;
362e15f2fa9SJohn Garry 
363e15f2fa9SJohn Garry 	if (nvec > maxvec)
364e15f2fa9SJohn Garry 		nvec = maxvec;
365e15f2fa9SJohn Garry 
366e15f2fa9SJohn Garry 	size = sizeof(*ptr) + sizeof(unsigned int) * nvec;
367e15f2fa9SJohn Garry 	ptr = devres_alloc(devm_platform_get_irqs_affinity_release, size,
368e15f2fa9SJohn Garry 			   GFP_KERNEL);
369e15f2fa9SJohn Garry 	if (!ptr)
370e15f2fa9SJohn Garry 		return -ENOMEM;
371e15f2fa9SJohn Garry 
372e15f2fa9SJohn Garry 	ptr->count = nvec;
373e15f2fa9SJohn Garry 
374e15f2fa9SJohn Garry 	for (i = 0; i < nvec; i++) {
375e15f2fa9SJohn Garry 		int irq = platform_get_irq(dev, i);
376e15f2fa9SJohn Garry 		if (irq < 0) {
377e15f2fa9SJohn Garry 			ret = irq;
378e15f2fa9SJohn Garry 			goto err_free_devres;
379e15f2fa9SJohn Garry 		}
380e15f2fa9SJohn Garry 		ptr->irq[i] = irq;
381e15f2fa9SJohn Garry 	}
382e15f2fa9SJohn Garry 
383e15f2fa9SJohn Garry 	desc = irq_create_affinity_masks(nvec, affd);
384e15f2fa9SJohn Garry 	if (!desc) {
385e15f2fa9SJohn Garry 		ret = -ENOMEM;
386e15f2fa9SJohn Garry 		goto err_free_devres;
387e15f2fa9SJohn Garry 	}
388e15f2fa9SJohn Garry 
389e15f2fa9SJohn Garry 	for (i = 0; i < nvec; i++) {
390e15f2fa9SJohn Garry 		ret = irq_update_affinity_desc(ptr->irq[i], &desc[i]);
391e15f2fa9SJohn Garry 		if (ret) {
392e15f2fa9SJohn Garry 			dev_err(&dev->dev, "failed to update irq%d affinity descriptor (%d)\n",
393e15f2fa9SJohn Garry 				ptr->irq[i], ret);
394e15f2fa9SJohn Garry 			goto err_free_desc;
395e15f2fa9SJohn Garry 		}
396e15f2fa9SJohn Garry 	}
397e15f2fa9SJohn Garry 
398e15f2fa9SJohn Garry 	devres_add(&dev->dev, ptr);
399e15f2fa9SJohn Garry 
400e15f2fa9SJohn Garry 	kfree(desc);
401e15f2fa9SJohn Garry 
402e15f2fa9SJohn Garry 	*irqs = ptr->irq;
403e15f2fa9SJohn Garry 
404e15f2fa9SJohn Garry 	return nvec;
405e15f2fa9SJohn Garry 
406e15f2fa9SJohn Garry err_free_desc:
407e15f2fa9SJohn Garry 	kfree(desc);
408e15f2fa9SJohn Garry err_free_devres:
409e15f2fa9SJohn Garry 	devres_free(ptr);
410e15f2fa9SJohn Garry 	return ret;
411e15f2fa9SJohn Garry }
412e15f2fa9SJohn Garry EXPORT_SYMBOL_GPL(devm_platform_get_irqs_affinity);
413e15f2fa9SJohn Garry 
4144b83555dSStephen Boyd /**
4151da177e4SLinus Torvalds  * platform_get_resource_byname - get a resource for a device by name
4161da177e4SLinus Torvalds  * @dev: platform device
4171da177e4SLinus Torvalds  * @type: resource type
4181da177e4SLinus Torvalds  * @name: resource name
4191da177e4SLinus Torvalds  */
4204a3ad20cSGreg Kroah-Hartman struct resource *platform_get_resource_byname(struct platform_device *dev,
421c0afe7baSLinus Walleij 					      unsigned int type,
422c0afe7baSLinus Walleij 					      const char *name)
4231da177e4SLinus Torvalds {
42439cc539fSSimon Schwartz 	u32 i;
4251da177e4SLinus Torvalds 
4261da177e4SLinus Torvalds 	for (i = 0; i < dev->num_resources; i++) {
4271da177e4SLinus Torvalds 		struct resource *r = &dev->resource[i];
4281da177e4SLinus Torvalds 
4291b8cb929SPeter Ujfalusi 		if (unlikely(!r->name))
4301b8cb929SPeter Ujfalusi 			continue;
4311b8cb929SPeter Ujfalusi 
432c9f66169SMagnus Damm 		if (type == resource_type(r) && !strcmp(r->name, name))
4331da177e4SLinus Torvalds 			return r;
4341da177e4SLinus Torvalds 	}
4351da177e4SLinus Torvalds 	return NULL;
4361da177e4SLinus Torvalds }
437a96b2042SDmitry Torokhov EXPORT_SYMBOL_GPL(platform_get_resource_byname);
4381da177e4SLinus Torvalds 
439f1da567fSHans de Goede static int __platform_get_irq_byname(struct platform_device *dev,
440f1da567fSHans de Goede 				     const char *name)
4411da177e4SLinus Torvalds {
442ad69674eSGrygorii Strashko 	struct resource *r;
443aff008adSGuenter Roeck 	int ret;
444aff008adSGuenter Roeck 
445d4ad017dSSoha Jin 	ret = fwnode_irq_get_byname(dev_fwnode(&dev->dev), name);
446e330b9a6SSergei Shtylyov 	if (ret > 0 || ret == -EPROBE_DEFER)
447aff008adSGuenter Roeck 		return ret;
448ad69674eSGrygorii Strashko 
449ad69674eSGrygorii Strashko 	r = platform_get_resource_byname(dev, IORESOURCE_IRQ, name);
450a85a6c86SBjorn Helgaas 	if (r) {
451ce753ad1SSergey Shtylyov 		if (WARN(!r->start, "0 is an invalid IRQ number\n"))
452ce753ad1SSergey Shtylyov 			return -EINVAL;
4537723f4c5SStephen Boyd 		return r->start;
454a85a6c86SBjorn Helgaas 	}
4557723f4c5SStephen Boyd 
4567723f4c5SStephen Boyd 	return -ENXIO;
4571da177e4SLinus Torvalds }
458f1da567fSHans de Goede 
459f1da567fSHans de Goede /**
460f1da567fSHans de Goede  * platform_get_irq_byname - get an IRQ for a device by name
461f1da567fSHans de Goede  * @dev: platform device
462f1da567fSHans de Goede  * @name: IRQ name
463f1da567fSHans de Goede  *
464f1da567fSHans de Goede  * Get an IRQ like platform_get_irq(), but then by name rather then by index.
465f1da567fSHans de Goede  *
466a85a6c86SBjorn Helgaas  * Return: non-zero IRQ number on success, negative error number on failure.
467f1da567fSHans de Goede  */
468f1da567fSHans de Goede int platform_get_irq_byname(struct platform_device *dev, const char *name)
469f1da567fSHans de Goede {
470f1da567fSHans de Goede 	int ret;
471f1da567fSHans de Goede 
472f1da567fSHans de Goede 	ret = __platform_get_irq_byname(dev, name);
47327446562SSergey Shtylyov 	if (ret < 0)
47427446562SSergey Shtylyov 		return dev_err_probe(&dev->dev, ret, "IRQ %s not found\n",
47527446562SSergey Shtylyov 				     name);
476f1da567fSHans de Goede 	return ret;
477f1da567fSHans de Goede }
478a96b2042SDmitry Torokhov EXPORT_SYMBOL_GPL(platform_get_irq_byname);
4791da177e4SLinus Torvalds 
4801da177e4SLinus Torvalds /**
481f1da567fSHans de Goede  * platform_get_irq_byname_optional - get an optional IRQ for a device by name
482f1da567fSHans de Goede  * @dev: platform device
483f1da567fSHans de Goede  * @name: IRQ name
484f1da567fSHans de Goede  *
485f1da567fSHans de Goede  * Get an optional IRQ by name like platform_get_irq_byname(). Except that it
486f1da567fSHans de Goede  * does not print an error message if an IRQ can not be obtained.
487f1da567fSHans de Goede  *
488a85a6c86SBjorn Helgaas  * Return: non-zero IRQ number on success, negative error number on failure.
489f1da567fSHans de Goede  */
490f1da567fSHans de Goede int platform_get_irq_byname_optional(struct platform_device *dev,
491f1da567fSHans de Goede 				     const char *name)
492f1da567fSHans de Goede {
493f1da567fSHans de Goede 	return __platform_get_irq_byname(dev, name);
494f1da567fSHans de Goede }
495f1da567fSHans de Goede EXPORT_SYMBOL_GPL(platform_get_irq_byname_optional);
496f1da567fSHans de Goede 
497f1da567fSHans de Goede /**
4981da177e4SLinus Torvalds  * platform_add_devices - add a numbers of platform devices
4991da177e4SLinus Torvalds  * @devs: array of platform devices to add
5001da177e4SLinus Torvalds  * @num: number of platform devices in array
50164f79742SUmang Jain  *
50264f79742SUmang Jain  * Return: 0 on success, negative error number on failure.
5031da177e4SLinus Torvalds  */
5041da177e4SLinus Torvalds int platform_add_devices(struct platform_device **devs, int num)
5051da177e4SLinus Torvalds {
5061da177e4SLinus Torvalds 	int i, ret = 0;
5071da177e4SLinus Torvalds 
5081da177e4SLinus Torvalds 	for (i = 0; i < num; i++) {
5091da177e4SLinus Torvalds 		ret = platform_device_register(devs[i]);
5101da177e4SLinus Torvalds 		if (ret) {
5111da177e4SLinus Torvalds 			while (--i >= 0)
5121da177e4SLinus Torvalds 				platform_device_unregister(devs[i]);
5131da177e4SLinus Torvalds 			break;
5141da177e4SLinus Torvalds 		}
5151da177e4SLinus Torvalds 	}
5161da177e4SLinus Torvalds 
5171da177e4SLinus Torvalds 	return ret;
5181da177e4SLinus Torvalds }
519a96b2042SDmitry Torokhov EXPORT_SYMBOL_GPL(platform_add_devices);
5201da177e4SLinus Torvalds 
52137c12e74SRussell King struct platform_object {
52237c12e74SRussell King 	struct platform_device pdev;
5231cec24c5SYann Droneaud 	char name[];
52437c12e74SRussell King };
52537c12e74SRussell King 
526cdfee562SChristoph Hellwig /*
527cdfee562SChristoph Hellwig  * Set up default DMA mask for platform devices if the they weren't
528cdfee562SChristoph Hellwig  * previously set by the architecture / DT.
529cdfee562SChristoph Hellwig  */
530cdfee562SChristoph Hellwig static void setup_pdev_dma_masks(struct platform_device *pdev)
531cdfee562SChristoph Hellwig {
5329495b7e9SUlf Hansson 	pdev->dev.dma_parms = &pdev->dma_parms;
5339495b7e9SUlf Hansson 
534cdfee562SChristoph Hellwig 	if (!pdev->dev.coherent_dma_mask)
535cdfee562SChristoph Hellwig 		pdev->dev.coherent_dma_mask = DMA_BIT_MASK(32);
536e3a36eb6SChristoph Hellwig 	if (!pdev->dev.dma_mask) {
537e3a36eb6SChristoph Hellwig 		pdev->platform_dma_mask = DMA_BIT_MASK(32);
538e3a36eb6SChristoph Hellwig 		pdev->dev.dma_mask = &pdev->platform_dma_mask;
539e3a36eb6SChristoph Hellwig 	}
540cdfee562SChristoph Hellwig };
541cdfee562SChristoph Hellwig 
5421da177e4SLinus Torvalds /**
5433c31f07aSBen Hutchings  * platform_device_put - destroy a platform device
54437c12e74SRussell King  * @pdev: platform device to free
54537c12e74SRussell King  *
5464a3ad20cSGreg Kroah-Hartman  * Free all memory associated with a platform device.  This function must
5474a3ad20cSGreg Kroah-Hartman  * _only_ be externally called in error cases.  All other usage is a bug.
54837c12e74SRussell King  */
54937c12e74SRussell King void platform_device_put(struct platform_device *pdev)
55037c12e74SRussell King {
55199fef587SAndy Shevchenko 	if (!IS_ERR_OR_NULL(pdev))
55237c12e74SRussell King 		put_device(&pdev->dev);
55337c12e74SRussell King }
55437c12e74SRussell King EXPORT_SYMBOL_GPL(platform_device_put);
55537c12e74SRussell King 
55637c12e74SRussell King static void platform_device_release(struct device *dev)
55737c12e74SRussell King {
5584a3ad20cSGreg Kroah-Hartman 	struct platform_object *pa = container_of(dev, struct platform_object,
5594a3ad20cSGreg Kroah-Hartman 						  pdev.dev);
56037c12e74SRussell King 
561cb8be8b4SRob Herring 	of_node_put(pa->pdev.dev.of_node);
56237c12e74SRussell King 	kfree(pa->pdev.dev.platform_data);
563e710d7d5SSamuel Ortiz 	kfree(pa->pdev.mfd_cell);
56437c12e74SRussell King 	kfree(pa->pdev.resource);
5653d713e0eSKim Phillips 	kfree(pa->pdev.driver_override);
56637c12e74SRussell King 	kfree(pa);
56737c12e74SRussell King }
56837c12e74SRussell King 
56937c12e74SRussell King /**
5703c31f07aSBen Hutchings  * platform_device_alloc - create a platform device
57137c12e74SRussell King  * @name: base name of the device we're adding
57237c12e74SRussell King  * @id: instance id
57337c12e74SRussell King  *
57437c12e74SRussell King  * Create a platform device object which can have other objects attached
57537c12e74SRussell King  * to it, and which will have attached objects freed when it is released.
57637c12e74SRussell King  */
5771359555eSJean Delvare struct platform_device *platform_device_alloc(const char *name, int id)
57837c12e74SRussell King {
57937c12e74SRussell King 	struct platform_object *pa;
58037c12e74SRussell King 
5811cec24c5SYann Droneaud 	pa = kzalloc(sizeof(*pa) + strlen(name) + 1, GFP_KERNEL);
58237c12e74SRussell King 	if (pa) {
58337c12e74SRussell King 		strcpy(pa->name, name);
58437c12e74SRussell King 		pa->pdev.name = pa->name;
58537c12e74SRussell King 		pa->pdev.id = id;
58637c12e74SRussell King 		device_initialize(&pa->pdev.dev);
58737c12e74SRussell King 		pa->pdev.dev.release = platform_device_release;
588cdfee562SChristoph Hellwig 		setup_pdev_dma_masks(&pa->pdev);
58937c12e74SRussell King 	}
59037c12e74SRussell King 
59137c12e74SRussell King 	return pa ? &pa->pdev : NULL;
59237c12e74SRussell King }
59337c12e74SRussell King EXPORT_SYMBOL_GPL(platform_device_alloc);
59437c12e74SRussell King 
59537c12e74SRussell King /**
5963c31f07aSBen Hutchings  * platform_device_add_resources - add resources to a platform device
59737c12e74SRussell King  * @pdev: platform device allocated by platform_device_alloc to add resources to
59837c12e74SRussell King  * @res: set of resources that needs to be allocated for the device
59937c12e74SRussell King  * @num: number of resources
60037c12e74SRussell King  *
60137c12e74SRussell King  * Add a copy of the resources to the platform device.  The memory
6024a3ad20cSGreg Kroah-Hartman  * associated with the resources will be freed when the platform device is
6034a3ad20cSGreg Kroah-Hartman  * released.
60437c12e74SRussell King  */
6054a3ad20cSGreg Kroah-Hartman int platform_device_add_resources(struct platform_device *pdev,
6060b7f1a7eSGeert Uytterhoeven 				  const struct resource *res, unsigned int num)
60737c12e74SRussell King {
608cea89623SUwe Kleine-König 	struct resource *r = NULL;
60937c12e74SRussell King 
610cea89623SUwe Kleine-König 	if (res) {
61123c68596SAndy Shevchenko 		r = kmemdup_array(res, num, sizeof(*r), GFP_KERNEL);
612cea89623SUwe Kleine-König 		if (!r)
613cea89623SUwe Kleine-König 			return -ENOMEM;
614cea89623SUwe Kleine-König 	}
615cea89623SUwe Kleine-König 
6164a03d6f7SUwe Kleine-König 	kfree(pdev->resource);
61737c12e74SRussell King 	pdev->resource = r;
61837c12e74SRussell King 	pdev->num_resources = num;
6193e61dfd8SUwe Kleine-König 	return 0;
62037c12e74SRussell King }
62137c12e74SRussell King EXPORT_SYMBOL_GPL(platform_device_add_resources);
62237c12e74SRussell King 
62337c12e74SRussell King /**
6243c31f07aSBen Hutchings  * platform_device_add_data - add platform-specific data to a platform device
62537c12e74SRussell King  * @pdev: platform device allocated by platform_device_alloc to add resources to
62637c12e74SRussell King  * @data: platform specific data for this platform device
62737c12e74SRussell King  * @size: size of platform specific data
62837c12e74SRussell King  *
6294a3ad20cSGreg Kroah-Hartman  * Add a copy of platform specific data to the platform device's
6304a3ad20cSGreg Kroah-Hartman  * platform_data pointer.  The memory associated with the platform data
6314a3ad20cSGreg Kroah-Hartman  * will be freed when the platform device is released.
63237c12e74SRussell King  */
6334a3ad20cSGreg Kroah-Hartman int platform_device_add_data(struct platform_device *pdev, const void *data,
6344a3ad20cSGreg Kroah-Hartman 			     size_t size)
63537c12e74SRussell King {
63627a33f9eSUwe Kleine-König 	void *d = NULL;
63737c12e74SRussell King 
63827a33f9eSUwe Kleine-König 	if (data) {
6395cfc64ceSAnton Vorontsov 		d = kmemdup(data, size, GFP_KERNEL);
64027a33f9eSUwe Kleine-König 		if (!d)
64127a33f9eSUwe Kleine-König 			return -ENOMEM;
64227a33f9eSUwe Kleine-König 	}
64327a33f9eSUwe Kleine-König 
644251e031dSUwe Kleine-König 	kfree(pdev->dev.platform_data);
64537c12e74SRussell King 	pdev->dev.platform_data = d;
646daa41226SAndrew Morton 	return 0;
64737c12e74SRussell King }
64837c12e74SRussell King EXPORT_SYMBOL_GPL(platform_device_add_data);
64937c12e74SRussell King 
65037c12e74SRussell King /**
65137c12e74SRussell King  * platform_device_add - add a platform device to device hierarchy
65267be2dd1SMartin Waitz  * @pdev: platform device we're adding
6531da177e4SLinus Torvalds  *
65437c12e74SRussell King  * This is part 2 of platform_device_register(), though may be called
65537c12e74SRussell King  * separately _iff_ pdev was allocated by platform_device_alloc().
6561da177e4SLinus Torvalds  */
65737c12e74SRussell King int platform_device_add(struct platform_device *pdev)
6581da177e4SLinus Torvalds {
6596136597cSAndy Shevchenko 	struct device *dev = &pdev->dev;
66039cc539fSSimon Schwartz 	u32 i;
66139cc539fSSimon Schwartz 	int ret;
6621da177e4SLinus Torvalds 
6636136597cSAndy Shevchenko 	if (!dev->parent)
6646136597cSAndy Shevchenko 		dev->parent = &platform_bus;
6651da177e4SLinus Torvalds 
6666136597cSAndy Shevchenko 	dev->bus = &platform_bus_type;
6671da177e4SLinus Torvalds 
668689ae231SJean Delvare 	switch (pdev->id) {
669689ae231SJean Delvare 	default:
6706136597cSAndy Shevchenko 		dev_set_name(dev, "%s.%d", pdev->name,  pdev->id);
671689ae231SJean Delvare 		break;
672689ae231SJean Delvare 	case PLATFORM_DEVID_NONE:
6736136597cSAndy Shevchenko 		dev_set_name(dev, "%s", pdev->name);
674689ae231SJean Delvare 		break;
675689ae231SJean Delvare 	case PLATFORM_DEVID_AUTO:
676689ae231SJean Delvare 		/*
677689ae231SJean Delvare 		 * Automatically allocated device ID. We mark it as such so
678689ae231SJean Delvare 		 * that we remember it must be freed, and we append a suffix
679689ae231SJean Delvare 		 * to avoid namespace collision with explicit IDs.
680689ae231SJean Delvare 		 */
6810de75116SBartosz Golaszewski 		ret = ida_alloc(&platform_devid_ida, GFP_KERNEL);
682689ae231SJean Delvare 		if (ret < 0)
683a549e3aaSAndy Shevchenko 			return ret;
684689ae231SJean Delvare 		pdev->id = ret;
685689ae231SJean Delvare 		pdev->id_auto = true;
6866136597cSAndy Shevchenko 		dev_set_name(dev, "%s.%d.auto", pdev->name, pdev->id);
687689ae231SJean Delvare 		break;
688689ae231SJean Delvare 	}
6891da177e4SLinus Torvalds 
6901da177e4SLinus Torvalds 	for (i = 0; i < pdev->num_resources; i++) {
6915da7f709SGreg Kroah-Hartman 		struct resource *p, *r = &pdev->resource[i];
6921da177e4SLinus Torvalds 
6931da177e4SLinus Torvalds 		if (r->name == NULL)
6946136597cSAndy Shevchenko 			r->name = dev_name(dev);
6951da177e4SLinus Torvalds 
6961da177e4SLinus Torvalds 		p = r->parent;
6971da177e4SLinus Torvalds 		if (!p) {
6980e6c861fSGreg Kroah-Hartman 			if (resource_type(r) == IORESOURCE_MEM)
6991da177e4SLinus Torvalds 				p = &iomem_resource;
7000e6c861fSGreg Kroah-Hartman 			else if (resource_type(r) == IORESOURCE_IO)
7011da177e4SLinus Torvalds 				p = &ioport_resource;
7021da177e4SLinus Torvalds 		}
7031da177e4SLinus Torvalds 
70425ebcb7dSAndy Shevchenko 		if (p) {
70525ebcb7dSAndy Shevchenko 			ret = insert_resource(p, r);
70625ebcb7dSAndy Shevchenko 			if (ret) {
7076136597cSAndy Shevchenko 				dev_err(dev, "failed to claim resource %d: %pR\n", i, r);
7085da7f709SGreg Kroah-Hartman 				goto failed;
7095da7f709SGreg Kroah-Hartman 			}
7101da177e4SLinus Torvalds 		}
71125ebcb7dSAndy Shevchenko 	}
7121da177e4SLinus Torvalds 
7136136597cSAndy Shevchenko 	pr_debug("Registering platform device '%s'. Parent at %s\n", dev_name(dev),
7146136597cSAndy Shevchenko 		 dev_name(dev->parent));
7151da177e4SLinus Torvalds 
7166136597cSAndy Shevchenko 	ret = device_add(dev);
717a549e3aaSAndy Shevchenko 	if (ret)
718a549e3aaSAndy Shevchenko 		goto failed;
719a549e3aaSAndy Shevchenko 
720a549e3aaSAndy Shevchenko 	return 0;
7218b2dcebaSGreg Kroah-Hartman 
7225da7f709SGreg Kroah-Hartman  failed:
7238b2dcebaSGreg Kroah-Hartman 	if (pdev->id_auto) {
7240de75116SBartosz Golaszewski 		ida_free(&platform_devid_ida, pdev->id);
7258b2dcebaSGreg Kroah-Hartman 		pdev->id = PLATFORM_DEVID_AUTO;
7268b2dcebaSGreg Kroah-Hartman 	}
7278b2dcebaSGreg Kroah-Hartman 
7280707cfa5SColin Ian King 	while (i--) {
7298b2dcebaSGreg Kroah-Hartman 		struct resource *r = &pdev->resource[i];
7307f5dcaf1SGrant Likely 		if (r->parent)
7318b2dcebaSGreg Kroah-Hartman 			release_resource(r);
7328b2dcebaSGreg Kroah-Hartman 	}
733c9f66169SMagnus Damm 
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  */
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  */
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  */
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  */
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  */
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  */
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 
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 
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  */
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  */
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  */
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  */
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 
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 
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 
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 
112369c9dd1eSRafael J. Wysocki int platform_pm_suspend(struct device *dev)
112425e18499SRafael J. Wysocki {
1125841b7ebfSGreg Kroah-Hartman 	const 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 
114169c9dd1eSRafael J. Wysocki int platform_pm_resume(struct device *dev)
114225e18499SRafael J. Wysocki {
1143841b7ebfSGreg Kroah-Hartman 	const 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 
116369c9dd1eSRafael J. Wysocki int platform_pm_freeze(struct device *dev)
116425e18499SRafael J. Wysocki {
1165841b7ebfSGreg Kroah-Hartman 	const 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 
118169c9dd1eSRafael J. Wysocki int platform_pm_thaw(struct device *dev)
118225e18499SRafael J. Wysocki {
1183841b7ebfSGreg Kroah-Hartman 	const 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 
119969c9dd1eSRafael J. Wysocki int platform_pm_poweroff(struct device *dev)
120025e18499SRafael J. Wysocki {
1201841b7ebfSGreg Kroah-Hartman 	const 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 
121769c9dd1eSRafael J. Wysocki int platform_pm_restore(struct device *dev)
121825e18499SRafael J. Wysocki {
1219841b7ebfSGreg Kroah-Hartman 	const 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  */
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 
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 
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 
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 
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  */
1335d69d8048SGreg Kroah-Hartman static int platform_match(struct device *dev, const 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 
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 
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 
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 
14230edb555aSUwe Kleine-König 	if (drv->remove)
14240edb555aSUwe Kleine-König 		drv->remove(dev);
14259c30921fSUwe Kleine-König 	dev_pm_domain_detach(_dev, true);
14269c30921fSUwe Kleine-König }
14279c30921fSUwe Kleine-König 
14289c30921fSUwe Kleine-König static void platform_shutdown(struct device *_dev)
14299c30921fSUwe Kleine-König {
14309c30921fSUwe Kleine-König 	struct platform_device *dev = to_platform_device(_dev);
143146e85af0SDmitry Baryshkov 	struct platform_driver *drv;
14329c30921fSUwe Kleine-König 
143346e85af0SDmitry Baryshkov 	if (!_dev->driver)
143446e85af0SDmitry Baryshkov 		return;
143546e85af0SDmitry Baryshkov 
143646e85af0SDmitry Baryshkov 	drv = to_platform_driver(_dev->driver);
14379c30921fSUwe Kleine-König 	if (drv->shutdown)
14389c30921fSUwe Kleine-König 		drv->shutdown(dev);
14399c30921fSUwe Kleine-König }
14409c30921fSUwe Kleine-König 
14414a6d9dd5SLu Baolu static int platform_dma_configure(struct device *dev)
144207397df2SNipun Gupta {
1443512881eaSLu Baolu 	struct platform_driver *drv = to_platform_driver(dev->driver);
1444243e1b77SAndy Shevchenko 	struct fwnode_handle *fwnode = dev_fwnode(dev);
144507397df2SNipun Gupta 	enum dev_dma_attr attr;
144607397df2SNipun Gupta 	int ret = 0;
144707397df2SNipun Gupta 
1448243e1b77SAndy Shevchenko 	if (is_of_node(fwnode)) {
1449243e1b77SAndy Shevchenko 		ret = of_dma_configure(dev, to_of_node(fwnode), true);
1450243e1b77SAndy Shevchenko 	} else if (is_acpi_device_node(fwnode)) {
1451243e1b77SAndy Shevchenko 		attr = acpi_get_dma_attr(to_acpi_device_node(fwnode));
145207397df2SNipun Gupta 		ret = acpi_dma_configure(dev, attr);
145307397df2SNipun Gupta 	}
1454a549e3aaSAndy Shevchenko 	if (ret || drv->driver_managed_dma)
1455a549e3aaSAndy Shevchenko 		return ret;
145607397df2SNipun Gupta 
1457512881eaSLu Baolu 	ret = iommu_device_use_default_domain(dev);
1458512881eaSLu Baolu 	if (ret)
1459512881eaSLu Baolu 		arch_teardown_dma_ops(dev);
1460512881eaSLu Baolu 
146107397df2SNipun Gupta 	return ret;
146207397df2SNipun Gupta }
146307397df2SNipun Gupta 
1464512881eaSLu Baolu static void platform_dma_cleanup(struct device *dev)
1465512881eaSLu Baolu {
1466512881eaSLu Baolu 	struct platform_driver *drv = to_platform_driver(dev->driver);
1467512881eaSLu Baolu 
1468512881eaSLu Baolu 	if (!drv->driver_managed_dma)
1469512881eaSLu Baolu 		iommu_device_unuse_default_domain(dev);
1470512881eaSLu Baolu }
1471512881eaSLu Baolu 
1472d9ab7716SDmitry Torokhov static const struct dev_pm_ops platform_dev_pm_ops = {
147386854b43SCai Huoqing 	SET_RUNTIME_PM_OPS(pm_generic_runtime_suspend, pm_generic_runtime_resume, NULL)
147469c9dd1eSRafael J. Wysocki 	USE_PLATFORM_PM_SLEEP_OPS
147525e18499SRafael J. Wysocki };
147625e18499SRafael J. Wysocki 
1477*24e041e1SKunwu Chan const struct bus_type platform_bus_type = {
14781da177e4SLinus Torvalds 	.name		= "platform",
1479d06262e5SGreg Kroah-Hartman 	.dev_groups	= platform_dev_groups,
14801da177e4SLinus Torvalds 	.match		= platform_match,
1481a0245f7aSDavid Brownell 	.uevent		= platform_uevent,
14829c30921fSUwe Kleine-König 	.probe		= platform_probe,
14839c30921fSUwe Kleine-König 	.remove		= platform_remove,
14849c30921fSUwe Kleine-König 	.shutdown	= platform_shutdown,
148507397df2SNipun Gupta 	.dma_configure	= platform_dma_configure,
1486512881eaSLu Baolu 	.dma_cleanup	= platform_dma_cleanup,
14879d730229SMagnus Damm 	.pm		= &platform_dev_pm_ops,
14881da177e4SLinus Torvalds };
1489a96b2042SDmitry Torokhov EXPORT_SYMBOL_GPL(platform_bus_type);
14901da177e4SLinus Torvalds 
1491492c8872SSami Tolvanen static inline int __platform_match(struct device *dev, const void *drv)
1492492c8872SSami Tolvanen {
1493492c8872SSami Tolvanen 	return platform_match(dev, (struct device_driver *)drv);
1494492c8872SSami Tolvanen }
1495492c8872SSami Tolvanen 
149636f3313dSSuzuki K Poulose /**
149736f3313dSSuzuki K Poulose  * platform_find_device_by_driver - Find a platform device with a given
149836f3313dSSuzuki K Poulose  * driver.
149936f3313dSSuzuki K Poulose  * @start: The device to start the search from.
150036f3313dSSuzuki K Poulose  * @drv: The device driver to look for.
150136f3313dSSuzuki K Poulose  */
150236f3313dSSuzuki K Poulose struct device *platform_find_device_by_driver(struct device *start,
150336f3313dSSuzuki K Poulose 					      const struct device_driver *drv)
150436f3313dSSuzuki K Poulose {
150536f3313dSSuzuki K Poulose 	return bus_find_device(&platform_bus_type, start, drv,
1506492c8872SSami Tolvanen 			       __platform_match);
150736f3313dSSuzuki K Poulose }
150836f3313dSSuzuki K Poulose EXPORT_SYMBOL_GPL(platform_find_device_by_driver);
150936f3313dSSuzuki K Poulose 
1510eecd37e1SGuenter Roeck void __weak __init early_platform_cleanup(void) { }
1511eecd37e1SGuenter Roeck 
15121da177e4SLinus Torvalds int __init platform_bus_init(void)
15131da177e4SLinus Torvalds {
1514fbfb1445SCornelia Huck 	int error;
1515fbfb1445SCornelia Huck 
1516eecd37e1SGuenter Roeck 	early_platform_cleanup();
1517eecd37e1SGuenter Roeck 
1518fbfb1445SCornelia Huck 	error = device_register(&platform_bus);
1519c8ae1674SArvind Yadav 	if (error) {
1520c8ae1674SArvind Yadav 		put_device(&platform_bus);
1521fbfb1445SCornelia Huck 		return error;
1522c8ae1674SArvind Yadav 	}
1523fbfb1445SCornelia Huck 	error =  bus_register(&platform_bus_type);
1524fbfb1445SCornelia Huck 	if (error)
1525fbfb1445SCornelia Huck 		device_unregister(&platform_bus);
152673aca58bSRob Herring 
1527fbfb1445SCornelia Huck 	return error;
15281da177e4SLinus Torvalds }
1529