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
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 */
platform_get_irq(struct platform_device * dev,unsigned int num)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 */
platform_irq_count(struct platform_device * dev)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
platform_disable_acpi_irq(struct platform_device * pdev,int index)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
devm_platform_get_irqs_affinity_release(struct device * dev,void * res)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 */
devm_platform_get_irqs_affinity(struct platform_device * dev,struct irq_affinity * affd,unsigned int minvec,unsigned int maxvec,int ** irqs)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 */
platform_get_resource_byname(struct platform_device * dev,unsigned int type,const char * name)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
__platform_get_irq_byname(struct platform_device * dev,const char * name)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 */
platform_get_irq_byname(struct platform_device * dev,const char * name)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 */
platform_get_irq_byname_optional(struct platform_device * dev,const char * name)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 */
platform_add_devices(struct platform_device ** devs,int num)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 */
setup_pdev_dma_masks(struct platform_device * pdev)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 */
platform_device_put(struct platform_device * pdev)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
platform_device_release(struct device * dev)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 */
platform_device_alloc(const char * name,int id)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 */
platform_device_add_resources(struct platform_device * pdev,const struct resource * res,unsigned int num)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 */
platform_device_add_data(struct platform_device * pdev,const void * data,size_t size)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 */
platform_device_add(struct platform_device * pdev)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 */
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 {
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
platform_pm_resume(struct device * dev)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
platform_pm_freeze(struct device * dev)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
platform_pm_thaw(struct device * dev)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
platform_pm_poweroff(struct device * dev)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
platform_pm_restore(struct device * dev)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 */
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,const struct device_driver * drv)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
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
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
platform_shutdown(struct device * _dev)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
platform_dma_configure(struct device * dev)14414a6d9dd5SLu Baolu static int platform_dma_configure(struct device *dev)
144207397df2SNipun Gupta {
1443*95deee37SWill McVicker struct device_driver *drv = READ_ONCE(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 }
1454*95deee37SWill McVicker /* @dev->driver may not be valid when we're called from the IOMMU layer */
1455*95deee37SWill McVicker if (ret || !drv || to_platform_driver(drv)->driver_managed_dma)
1456a549e3aaSAndy Shevchenko return ret;
145707397df2SNipun Gupta
1458512881eaSLu Baolu ret = iommu_device_use_default_domain(dev);
1459512881eaSLu Baolu if (ret)
1460512881eaSLu Baolu arch_teardown_dma_ops(dev);
1461512881eaSLu Baolu
146207397df2SNipun Gupta return ret;
146307397df2SNipun Gupta }
146407397df2SNipun Gupta
platform_dma_cleanup(struct device * dev)1465512881eaSLu Baolu static void platform_dma_cleanup(struct device *dev)
1466512881eaSLu Baolu {
1467512881eaSLu Baolu struct platform_driver *drv = to_platform_driver(dev->driver);
1468512881eaSLu Baolu
1469512881eaSLu Baolu if (!drv->driver_managed_dma)
1470512881eaSLu Baolu iommu_device_unuse_default_domain(dev);
1471512881eaSLu Baolu }
1472512881eaSLu Baolu
1473d9ab7716SDmitry Torokhov static const struct dev_pm_ops platform_dev_pm_ops = {
147486854b43SCai Huoqing SET_RUNTIME_PM_OPS(pm_generic_runtime_suspend, pm_generic_runtime_resume, NULL)
147569c9dd1eSRafael J. Wysocki USE_PLATFORM_PM_SLEEP_OPS
147625e18499SRafael J. Wysocki };
147725e18499SRafael J. Wysocki
147824e041e1SKunwu Chan const struct bus_type platform_bus_type = {
14791da177e4SLinus Torvalds .name = "platform",
1480d06262e5SGreg Kroah-Hartman .dev_groups = platform_dev_groups,
14811da177e4SLinus Torvalds .match = platform_match,
1482a0245f7aSDavid Brownell .uevent = platform_uevent,
14839c30921fSUwe Kleine-König .probe = platform_probe,
14849c30921fSUwe Kleine-König .remove = platform_remove,
14859c30921fSUwe Kleine-König .shutdown = platform_shutdown,
148607397df2SNipun Gupta .dma_configure = platform_dma_configure,
1487512881eaSLu Baolu .dma_cleanup = platform_dma_cleanup,
14889d730229SMagnus Damm .pm = &platform_dev_pm_ops,
14891da177e4SLinus Torvalds };
1490a96b2042SDmitry Torokhov EXPORT_SYMBOL_GPL(platform_bus_type);
14911da177e4SLinus Torvalds
__platform_match(struct device * dev,const void * drv)1492492c8872SSami Tolvanen static inline int __platform_match(struct device *dev, const void *drv)
1493492c8872SSami Tolvanen {
1494492c8872SSami Tolvanen return platform_match(dev, (struct device_driver *)drv);
1495492c8872SSami Tolvanen }
1496492c8872SSami Tolvanen
149736f3313dSSuzuki K Poulose /**
149836f3313dSSuzuki K Poulose * platform_find_device_by_driver - Find a platform device with a given
149936f3313dSSuzuki K Poulose * driver.
150036f3313dSSuzuki K Poulose * @start: The device to start the search from.
150136f3313dSSuzuki K Poulose * @drv: The device driver to look for.
150236f3313dSSuzuki K Poulose */
platform_find_device_by_driver(struct device * start,const struct device_driver * drv)150336f3313dSSuzuki K Poulose struct device *platform_find_device_by_driver(struct device *start,
150436f3313dSSuzuki K Poulose const struct device_driver *drv)
150536f3313dSSuzuki K Poulose {
150636f3313dSSuzuki K Poulose return bus_find_device(&platform_bus_type, start, drv,
1507492c8872SSami Tolvanen __platform_match);
150836f3313dSSuzuki K Poulose }
150936f3313dSSuzuki K Poulose EXPORT_SYMBOL_GPL(platform_find_device_by_driver);
151036f3313dSSuzuki K Poulose
early_platform_cleanup(void)1511eecd37e1SGuenter Roeck void __weak __init early_platform_cleanup(void) { }
1512eecd37e1SGuenter Roeck
platform_bus_init(void)15131da177e4SLinus Torvalds int __init platform_bus_init(void)
15141da177e4SLinus Torvalds {
1515fbfb1445SCornelia Huck int error;
1516fbfb1445SCornelia Huck
1517eecd37e1SGuenter Roeck early_platform_cleanup();
1518eecd37e1SGuenter Roeck
1519fbfb1445SCornelia Huck error = device_register(&platform_bus);
1520c8ae1674SArvind Yadav if (error) {
1521c8ae1674SArvind Yadav put_device(&platform_bus);
1522fbfb1445SCornelia Huck return error;
1523c8ae1674SArvind Yadav }
1524fbfb1445SCornelia Huck error = bus_register(&platform_bus_type);
1525fbfb1445SCornelia Huck if (error)
1526fbfb1445SCornelia Huck device_unregister(&platform_bus);
152773aca58bSRob Herring
1528fbfb1445SCornelia Huck return error;
15291da177e4SLinus Torvalds }
1530