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