1989d42e8SGreg Kroah-Hartman // SPDX-License-Identifier: GPL-2.0 21da177e4SLinus Torvalds /* 31da177e4SLinus Torvalds * platform.c - platform 'pseudo' bus for legacy devices 41da177e4SLinus Torvalds * 51da177e4SLinus Torvalds * Copyright (c) 2002-3 Patrick Mochel 61da177e4SLinus Torvalds * Copyright (c) 2002-3 Open Source Development Labs 71da177e4SLinus Torvalds * 8fe34c89dSMauro Carvalho Chehab * Please see Documentation/driver-api/driver-model/platform.rst for more 91da177e4SLinus Torvalds * information. 101da177e4SLinus Torvalds */ 111da177e4SLinus Torvalds 12daa41226SAndrew Morton #include <linux/string.h> 13d052d1beSRussell King #include <linux/platform_device.h> 1405212157SGrant Likely #include <linux/of_device.h> 159ec36cafSRob Herring #include <linux/of_irq.h> 161da177e4SLinus Torvalds #include <linux/module.h> 171da177e4SLinus Torvalds #include <linux/init.h> 18e15f2fa9SJohn Garry #include <linux/interrupt.h> 19e15f2fa9SJohn Garry #include <linux/ioport.h> 201da177e4SLinus Torvalds #include <linux/dma-mapping.h> 2157c8a661SMike Rapoport #include <linux/memblock.h> 221da177e4SLinus Torvalds #include <linux/err.h> 234e57b681STim Schmielau #include <linux/slab.h> 249d730229SMagnus Damm #include <linux/pm_runtime.h> 25f48c767cSUlf Hansson #include <linux/pm_domain.h> 26689ae231SJean Delvare #include <linux/idr.h> 2791e56878SMika Westerberg #include <linux/acpi.h> 2886be408bSSylwester Nawrocki #include <linux/clk/clk-conf.h> 293d713e0eSKim Phillips #include <linux/limits.h> 3000bbc1d8SMika Westerberg #include <linux/property.h> 31967d3010SQian Cai #include <linux/kmemleak.h> 3239cc539fSSimon Schwartz #include <linux/types.h> 33512881eaSLu Baolu #include <linux/iommu.h> 34512881eaSLu Baolu #include <linux/dma-map-ops.h> 351da177e4SLinus Torvalds 36a1bdc7aaSBen Dooks #include "base.h" 37bed2b42dSRafael J. Wysocki #include "power/power.h" 38a1bdc7aaSBen Dooks 39689ae231SJean Delvare /* For automatically allocated device IDs */ 40689ae231SJean Delvare static DEFINE_IDA(platform_devid_ida); 41689ae231SJean Delvare 421da177e4SLinus Torvalds struct device platform_bus = { 431e0b2cf9SKay Sievers .init_name = "platform", 441da177e4SLinus Torvalds }; 45a96b2042SDmitry Torokhov EXPORT_SYMBOL_GPL(platform_bus); 461da177e4SLinus Torvalds 471da177e4SLinus Torvalds /** 481da177e4SLinus Torvalds * platform_get_resource - get a resource for a device 491da177e4SLinus Torvalds * @dev: platform device 501da177e4SLinus Torvalds * @type: resource type 511da177e4SLinus Torvalds * @num: resource index 520c7a6b91SStephen Boyd * 530c7a6b91SStephen Boyd * Return: a pointer to the resource or NULL on failure. 541da177e4SLinus Torvalds */ 554a3ad20cSGreg Kroah-Hartman struct resource *platform_get_resource(struct platform_device *dev, 564a3ad20cSGreg Kroah-Hartman unsigned int type, unsigned int num) 571da177e4SLinus Torvalds { 5839cc539fSSimon Schwartz u32 i; 591da177e4SLinus Torvalds 601da177e4SLinus Torvalds for (i = 0; i < dev->num_resources; i++) { 611da177e4SLinus Torvalds struct resource *r = &dev->resource[i]; 621da177e4SLinus Torvalds 63c9f66169SMagnus Damm if (type == resource_type(r) && num-- == 0) 641da177e4SLinus Torvalds return r; 651da177e4SLinus Torvalds } 661da177e4SLinus Torvalds return NULL; 671da177e4SLinus Torvalds } 68a96b2042SDmitry Torokhov EXPORT_SYMBOL_GPL(platform_get_resource); 691da177e4SLinus Torvalds 700aec2da4SAndy Shevchenko struct resource *platform_get_mem_or_io(struct platform_device *dev, 710aec2da4SAndy Shevchenko unsigned int num) 720aec2da4SAndy Shevchenko { 730aec2da4SAndy Shevchenko u32 i; 740aec2da4SAndy Shevchenko 750aec2da4SAndy Shevchenko for (i = 0; i < dev->num_resources; i++) { 760aec2da4SAndy Shevchenko struct resource *r = &dev->resource[i]; 770aec2da4SAndy Shevchenko 780aec2da4SAndy Shevchenko if ((resource_type(r) & (IORESOURCE_MEM|IORESOURCE_IO)) && num-- == 0) 790aec2da4SAndy Shevchenko return r; 800aec2da4SAndy Shevchenko } 810aec2da4SAndy Shevchenko return NULL; 820aec2da4SAndy Shevchenko } 830aec2da4SAndy Shevchenko EXPORT_SYMBOL_GPL(platform_get_mem_or_io); 840aec2da4SAndy Shevchenko 85bb6243b4SBartosz Golaszewski #ifdef CONFIG_HAS_IOMEM 861da177e4SLinus Torvalds /** 87890cc39aSDejin Zheng * devm_platform_get_and_ioremap_resource - call devm_ioremap_resource() for a 88890cc39aSDejin Zheng * platform device and get resource 89890cc39aSDejin Zheng * 90890cc39aSDejin Zheng * @pdev: platform device to use both for memory resource lookup as well as 91890cc39aSDejin Zheng * resource management 92890cc39aSDejin Zheng * @index: resource index 93890cc39aSDejin Zheng * @res: optional output parameter to store a pointer to the obtained resource. 940c7a6b91SStephen Boyd * 950c7a6b91SStephen Boyd * Return: a pointer to the remapped memory or an ERR_PTR() encoded error code 960c7a6b91SStephen Boyd * on failure. 97890cc39aSDejin Zheng */ 98890cc39aSDejin Zheng void __iomem * 99890cc39aSDejin Zheng devm_platform_get_and_ioremap_resource(struct platform_device *pdev, 100890cc39aSDejin Zheng unsigned int index, struct resource **res) 101890cc39aSDejin Zheng { 102890cc39aSDejin Zheng struct resource *r; 103890cc39aSDejin Zheng 104890cc39aSDejin Zheng r = platform_get_resource(pdev, IORESOURCE_MEM, index); 105890cc39aSDejin Zheng if (res) 106890cc39aSDejin Zheng *res = r; 107890cc39aSDejin Zheng return devm_ioremap_resource(&pdev->dev, r); 108890cc39aSDejin Zheng } 109890cc39aSDejin Zheng EXPORT_SYMBOL_GPL(devm_platform_get_and_ioremap_resource); 110890cc39aSDejin Zheng 111890cc39aSDejin Zheng /** 1127945f929SBartosz Golaszewski * devm_platform_ioremap_resource - call devm_ioremap_resource() for a platform 1137945f929SBartosz Golaszewski * device 1147945f929SBartosz Golaszewski * 1157945f929SBartosz Golaszewski * @pdev: platform device to use both for memory resource lookup as well as 1167067c96eSBartosz Golaszewski * resource management 1177945f929SBartosz Golaszewski * @index: resource index 1180c7a6b91SStephen Boyd * 1190c7a6b91SStephen Boyd * Return: a pointer to the remapped memory or an ERR_PTR() encoded error code 1200c7a6b91SStephen Boyd * on failure. 1217945f929SBartosz Golaszewski */ 1227945f929SBartosz Golaszewski void __iomem *devm_platform_ioremap_resource(struct platform_device *pdev, 1237945f929SBartosz Golaszewski unsigned int index) 1247945f929SBartosz Golaszewski { 125fd78901cSDejin Zheng return devm_platform_get_and_ioremap_resource(pdev, index, NULL); 1267945f929SBartosz Golaszewski } 1277945f929SBartosz Golaszewski EXPORT_SYMBOL_GPL(devm_platform_ioremap_resource); 128bb6243b4SBartosz Golaszewski 129bb6243b4SBartosz Golaszewski /** 130c9c8641dSBartosz Golaszewski * devm_platform_ioremap_resource_byname - call devm_ioremap_resource for 131c9c8641dSBartosz Golaszewski * a platform device, retrieve the 132c9c8641dSBartosz Golaszewski * resource by name 133c9c8641dSBartosz Golaszewski * 134c9c8641dSBartosz Golaszewski * @pdev: platform device to use both for memory resource lookup as well as 135c9c8641dSBartosz Golaszewski * resource management 136c9c8641dSBartosz Golaszewski * @name: name of the resource 1370c7a6b91SStephen Boyd * 1380c7a6b91SStephen Boyd * Return: a pointer to the remapped memory or an ERR_PTR() encoded error code 1390c7a6b91SStephen Boyd * on failure. 140c9c8641dSBartosz Golaszewski */ 141c9c8641dSBartosz Golaszewski void __iomem * 142c9c8641dSBartosz Golaszewski devm_platform_ioremap_resource_byname(struct platform_device *pdev, 143c9c8641dSBartosz Golaszewski const char *name) 144c9c8641dSBartosz Golaszewski { 145c9c8641dSBartosz Golaszewski struct resource *res; 146c9c8641dSBartosz Golaszewski 147c9c8641dSBartosz Golaszewski res = platform_get_resource_byname(pdev, IORESOURCE_MEM, name); 148c9c8641dSBartosz Golaszewski return devm_ioremap_resource(&pdev->dev, res); 149c9c8641dSBartosz Golaszewski } 150c9c8641dSBartosz Golaszewski EXPORT_SYMBOL_GPL(devm_platform_ioremap_resource_byname); 151837ccda3SBartosz Golaszewski #endif /* CONFIG_HAS_IOMEM */ 1527945f929SBartosz Golaszewski 153c2f3f755SGreg Kroah-Hartman /** 154c2f3f755SGreg Kroah-Hartman * platform_get_irq_optional - get an optional IRQ for a device 155c2f3f755SGreg Kroah-Hartman * @dev: platform device 156c2f3f755SGreg Kroah-Hartman * @num: IRQ number index 157c2f3f755SGreg Kroah-Hartman * 158c2f3f755SGreg Kroah-Hartman * Gets an IRQ for a platform device. Device drivers should check the return 159c2f3f755SGreg Kroah-Hartman * value for errors so as to not pass a negative integer value to the 160c2f3f755SGreg Kroah-Hartman * request_irq() APIs. This is the same as platform_get_irq(), except that it 161c2f3f755SGreg Kroah-Hartman * does not print an error message if an IRQ can not be obtained. 162c2f3f755SGreg Kroah-Hartman * 163c2f3f755SGreg Kroah-Hartman * For example:: 164c2f3f755SGreg Kroah-Hartman * 165c2f3f755SGreg Kroah-Hartman * int irq = platform_get_irq_optional(pdev, 0); 166c2f3f755SGreg Kroah-Hartman * if (irq < 0) 167c2f3f755SGreg Kroah-Hartman * return irq; 168c2f3f755SGreg Kroah-Hartman * 169c2f3f755SGreg Kroah-Hartman * Return: non-zero IRQ number on success, negative error number on failure. 170c2f3f755SGreg Kroah-Hartman */ 171c2f3f755SGreg Kroah-Hartman int platform_get_irq_optional(struct platform_device *dev, unsigned int num) 1721da177e4SLinus Torvalds { 173a85a6c86SBjorn Helgaas int ret; 1745cf8f7dbSAndreas Larsson #ifdef CONFIG_SPARC 1755cf8f7dbSAndreas Larsson /* sparc does not have irqs represented as IORESOURCE_IRQ resources */ 1765cf8f7dbSAndreas Larsson if (!dev || num >= dev->archdata.num_irqs) 177c99f4ebcSAndy Shevchenko goto out_not_found; 178a85a6c86SBjorn Helgaas ret = dev->archdata.irqs[num]; 179a85a6c86SBjorn Helgaas goto out; 1805cf8f7dbSAndreas Larsson #else 181243e1b77SAndy Shevchenko struct fwnode_handle *fwnode = dev_fwnode(&dev->dev); 1829ec36cafSRob Herring struct resource *r; 183aff008adSGuenter Roeck 184243e1b77SAndy Shevchenko if (is_of_node(fwnode)) { 185243e1b77SAndy Shevchenko ret = of_irq_get(to_of_node(fwnode), num); 186e330b9a6SSergei Shtylyov if (ret > 0 || ret == -EPROBE_DEFER) 187a85a6c86SBjorn Helgaas goto out; 188aff008adSGuenter Roeck } 1899ec36cafSRob Herring 1909ec36cafSRob Herring r = platform_get_resource(dev, IORESOURCE_IRQ, num); 191243e1b77SAndy Shevchenko if (is_acpi_device_node(fwnode)) { 192d44fa3d4SAgustin Vega-Frias if (r && r->flags & IORESOURCE_DISABLED) { 193243e1b77SAndy Shevchenko ret = acpi_irq_get(ACPI_HANDLE_FWNODE(fwnode), num, r); 194d44fa3d4SAgustin Vega-Frias if (ret) 195a85a6c86SBjorn Helgaas goto out; 196d44fa3d4SAgustin Vega-Frias } 197d44fa3d4SAgustin Vega-Frias } 198d44fa3d4SAgustin Vega-Frias 1997085a740SLinus Walleij /* 2007085a740SLinus Walleij * The resources may pass trigger flags to the irqs that need 2017085a740SLinus Walleij * to be set up. It so happens that the trigger flags for 2027085a740SLinus Walleij * IORESOURCE_BITS correspond 1-to-1 to the IRQF_TRIGGER* 2037085a740SLinus Walleij * settings. 2047085a740SLinus Walleij */ 20560ca5e0dSGuenter Roeck if (r && r->flags & IORESOURCE_BITS) { 20660ca5e0dSGuenter Roeck struct irq_data *irqd; 20760ca5e0dSGuenter Roeck 20860ca5e0dSGuenter Roeck irqd = irq_get_irq_data(r->start); 209c99f4ebcSAndy Shevchenko if (!irqd) 210c99f4ebcSAndy Shevchenko goto out_not_found; 21160ca5e0dSGuenter Roeck irqd_set_trigger_type(irqd, r->flags & IORESOURCE_BITS); 21260ca5e0dSGuenter Roeck } 2131da177e4SLinus Torvalds 214a85a6c86SBjorn Helgaas if (r) { 215a85a6c86SBjorn Helgaas ret = r->start; 216a85a6c86SBjorn Helgaas goto out; 217a85a6c86SBjorn Helgaas } 218daaef255SEnrico Granata 219daaef255SEnrico Granata /* 220daaef255SEnrico Granata * For the index 0 interrupt, allow falling back to GpioInt 221daaef255SEnrico Granata * resources. While a device could have both Interrupt and GpioInt 222daaef255SEnrico Granata * resources, making this fallback ambiguous, in many common cases 223daaef255SEnrico Granata * the device will only expose one IRQ, and this fallback 224daaef255SEnrico Granata * allows a common code path across either kind of resource. 225daaef255SEnrico Granata */ 226243e1b77SAndy Shevchenko if (num == 0 && is_acpi_device_node(fwnode)) { 227243e1b77SAndy Shevchenko ret = acpi_dev_gpio_irq_get(to_acpi_device_node(fwnode), num); 22846c42d84SBrian Norris /* Our callers expect -ENXIO for missing IRQs. */ 22946c42d84SBrian Norris if (ret >= 0 || ret == -EPROBE_DEFER) 230a85a6c86SBjorn Helgaas goto out; 23146c42d84SBrian Norris } 232daaef255SEnrico Granata 2335cf8f7dbSAndreas Larsson #endif 234c99f4ebcSAndy Shevchenko out_not_found: 235c99f4ebcSAndy Shevchenko ret = -ENXIO; 236a85a6c86SBjorn Helgaas out: 237ce753ad1SSergey Shtylyov if (WARN(!ret, "0 is an invalid IRQ number\n")) 238ce753ad1SSergey Shtylyov return -EINVAL; 239a85a6c86SBjorn Helgaas return ret; 2401da177e4SLinus Torvalds } 241ec4e2906SUwe Kleine-König EXPORT_SYMBOL_GPL(platform_get_irq_optional); 2427723f4c5SStephen Boyd 2437723f4c5SStephen Boyd /** 2447723f4c5SStephen Boyd * platform_get_irq - get an IRQ for a device 2457723f4c5SStephen Boyd * @dev: platform device 2467723f4c5SStephen Boyd * @num: IRQ number index 2477723f4c5SStephen Boyd * 2487723f4c5SStephen Boyd * Gets an IRQ for a platform device and prints an error message if finding the 2497723f4c5SStephen Boyd * IRQ fails. Device drivers should check the return value for errors so as to 2507723f4c5SStephen Boyd * not pass a negative integer value to the request_irq() APIs. 2517723f4c5SStephen Boyd * 252f0825246SMauro Carvalho Chehab * For example:: 253f0825246SMauro Carvalho Chehab * 2547723f4c5SStephen Boyd * int irq = platform_get_irq(pdev, 0); 2557723f4c5SStephen Boyd * if (irq < 0) 2567723f4c5SStephen Boyd * return irq; 2577723f4c5SStephen Boyd * 258a85a6c86SBjorn Helgaas * Return: non-zero IRQ number on success, negative error number on failure. 2597723f4c5SStephen Boyd */ 2607723f4c5SStephen Boyd int platform_get_irq(struct platform_device *dev, unsigned int num) 2617723f4c5SStephen Boyd { 2627723f4c5SStephen Boyd int ret; 2637723f4c5SStephen Boyd 264c2f3f755SGreg Kroah-Hartman ret = platform_get_irq_optional(dev, num); 2652043727cSCai Huoqing if (ret < 0) 2662043727cSCai Huoqing return dev_err_probe(&dev->dev, ret, 2672043727cSCai Huoqing "IRQ index %u not found\n", num); 2687723f4c5SStephen Boyd 2697723f4c5SStephen Boyd return ret; 2707723f4c5SStephen Boyd } 271a96b2042SDmitry Torokhov EXPORT_SYMBOL_GPL(platform_get_irq); 2721da177e4SLinus Torvalds 2731da177e4SLinus Torvalds /** 2744b83555dSStephen Boyd * platform_irq_count - Count the number of IRQs a platform device uses 2754b83555dSStephen Boyd * @dev: platform device 2764b83555dSStephen Boyd * 2774b83555dSStephen Boyd * Return: Number of IRQs a platform device uses or EPROBE_DEFER 2784b83555dSStephen Boyd */ 2794b83555dSStephen Boyd int platform_irq_count(struct platform_device *dev) 2804b83555dSStephen Boyd { 2814b83555dSStephen Boyd int ret, nr = 0; 2824b83555dSStephen Boyd 283c2f3f755SGreg Kroah-Hartman while ((ret = platform_get_irq_optional(dev, nr)) >= 0) 2844b83555dSStephen Boyd nr++; 2854b83555dSStephen Boyd 2864b83555dSStephen Boyd if (ret == -EPROBE_DEFER) 2874b83555dSStephen Boyd return ret; 2884b83555dSStephen Boyd 2894b83555dSStephen Boyd return nr; 2904b83555dSStephen Boyd } 2914b83555dSStephen Boyd EXPORT_SYMBOL_GPL(platform_irq_count); 2924b83555dSStephen Boyd 293e15f2fa9SJohn Garry struct irq_affinity_devres { 294e15f2fa9SJohn Garry unsigned int count; 29536b2d7ddSKees Cook unsigned int irq[] __counted_by(count); 296e15f2fa9SJohn Garry }; 297e15f2fa9SJohn Garry 298e15f2fa9SJohn Garry static void platform_disable_acpi_irq(struct platform_device *pdev, int index) 299e15f2fa9SJohn Garry { 300e15f2fa9SJohn Garry struct resource *r; 301e15f2fa9SJohn Garry 302e15f2fa9SJohn Garry r = platform_get_resource(pdev, IORESOURCE_IRQ, index); 303e15f2fa9SJohn Garry if (r) 304e15f2fa9SJohn Garry irqresource_disabled(r, 0); 305e15f2fa9SJohn Garry } 306e15f2fa9SJohn Garry 307e15f2fa9SJohn Garry static void devm_platform_get_irqs_affinity_release(struct device *dev, 308e15f2fa9SJohn Garry void *res) 309e15f2fa9SJohn Garry { 310e15f2fa9SJohn Garry struct irq_affinity_devres *ptr = res; 311e15f2fa9SJohn Garry int i; 312e15f2fa9SJohn Garry 313e15f2fa9SJohn Garry for (i = 0; i < ptr->count; i++) { 314e15f2fa9SJohn Garry irq_dispose_mapping(ptr->irq[i]); 315e15f2fa9SJohn Garry 316243e1b77SAndy Shevchenko if (is_acpi_device_node(dev_fwnode(dev))) 317e15f2fa9SJohn Garry platform_disable_acpi_irq(to_platform_device(dev), i); 318e15f2fa9SJohn Garry } 319e15f2fa9SJohn Garry } 320e15f2fa9SJohn Garry 321e15f2fa9SJohn Garry /** 322e15f2fa9SJohn Garry * devm_platform_get_irqs_affinity - devm method to get a set of IRQs for a 323e15f2fa9SJohn Garry * device using an interrupt affinity descriptor 324e15f2fa9SJohn Garry * @dev: platform device pointer 325e15f2fa9SJohn Garry * @affd: affinity descriptor 326e15f2fa9SJohn Garry * @minvec: minimum count of interrupt vectors 327e15f2fa9SJohn Garry * @maxvec: maximum count of interrupt vectors 328e15f2fa9SJohn Garry * @irqs: pointer holder for IRQ numbers 329e15f2fa9SJohn Garry * 330e15f2fa9SJohn Garry * Gets a set of IRQs for a platform device, and updates IRQ afffinty according 331e15f2fa9SJohn Garry * to the passed affinity descriptor 332e15f2fa9SJohn Garry * 333e15f2fa9SJohn Garry * Return: Number of vectors on success, negative error number on failure. 334e15f2fa9SJohn Garry */ 335e15f2fa9SJohn Garry int devm_platform_get_irqs_affinity(struct platform_device *dev, 336e15f2fa9SJohn Garry struct irq_affinity *affd, 337e15f2fa9SJohn Garry unsigned int minvec, 338e15f2fa9SJohn Garry unsigned int maxvec, 339e15f2fa9SJohn Garry int **irqs) 340e15f2fa9SJohn Garry { 341e15f2fa9SJohn Garry struct irq_affinity_devres *ptr; 342e15f2fa9SJohn Garry struct irq_affinity_desc *desc; 343e15f2fa9SJohn Garry size_t size; 344e15f2fa9SJohn Garry int i, ret, nvec; 345e15f2fa9SJohn Garry 346e15f2fa9SJohn Garry if (!affd) 347e15f2fa9SJohn Garry return -EPERM; 348e15f2fa9SJohn Garry 349e15f2fa9SJohn Garry if (maxvec < minvec) 350e15f2fa9SJohn Garry return -ERANGE; 351e15f2fa9SJohn Garry 352e15f2fa9SJohn Garry nvec = platform_irq_count(dev); 353e1dc2099SJohn Garry if (nvec < 0) 354e1dc2099SJohn Garry return nvec; 355e15f2fa9SJohn Garry 356e15f2fa9SJohn Garry if (nvec < minvec) 357e15f2fa9SJohn Garry return -ENOSPC; 358e15f2fa9SJohn Garry 359e15f2fa9SJohn Garry nvec = irq_calc_affinity_vectors(minvec, nvec, affd); 360e15f2fa9SJohn Garry if (nvec < minvec) 361e15f2fa9SJohn Garry return -ENOSPC; 362e15f2fa9SJohn Garry 363e15f2fa9SJohn Garry if (nvec > maxvec) 364e15f2fa9SJohn Garry nvec = maxvec; 365e15f2fa9SJohn Garry 366e15f2fa9SJohn Garry size = sizeof(*ptr) + sizeof(unsigned int) * nvec; 367e15f2fa9SJohn Garry ptr = devres_alloc(devm_platform_get_irqs_affinity_release, size, 368e15f2fa9SJohn Garry GFP_KERNEL); 369e15f2fa9SJohn Garry if (!ptr) 370e15f2fa9SJohn Garry return -ENOMEM; 371e15f2fa9SJohn Garry 372e15f2fa9SJohn Garry ptr->count = nvec; 373e15f2fa9SJohn Garry 374e15f2fa9SJohn Garry for (i = 0; i < nvec; i++) { 375e15f2fa9SJohn Garry int irq = platform_get_irq(dev, i); 376e15f2fa9SJohn Garry if (irq < 0) { 377e15f2fa9SJohn Garry ret = irq; 378e15f2fa9SJohn Garry goto err_free_devres; 379e15f2fa9SJohn Garry } 380e15f2fa9SJohn Garry ptr->irq[i] = irq; 381e15f2fa9SJohn Garry } 382e15f2fa9SJohn Garry 383e15f2fa9SJohn Garry desc = irq_create_affinity_masks(nvec, affd); 384e15f2fa9SJohn Garry if (!desc) { 385e15f2fa9SJohn Garry ret = -ENOMEM; 386e15f2fa9SJohn Garry goto err_free_devres; 387e15f2fa9SJohn Garry } 388e15f2fa9SJohn Garry 389e15f2fa9SJohn Garry for (i = 0; i < nvec; i++) { 390e15f2fa9SJohn Garry ret = irq_update_affinity_desc(ptr->irq[i], &desc[i]); 391e15f2fa9SJohn Garry if (ret) { 392e15f2fa9SJohn Garry dev_err(&dev->dev, "failed to update irq%d affinity descriptor (%d)\n", 393e15f2fa9SJohn Garry ptr->irq[i], ret); 394e15f2fa9SJohn Garry goto err_free_desc; 395e15f2fa9SJohn Garry } 396e15f2fa9SJohn Garry } 397e15f2fa9SJohn Garry 398e15f2fa9SJohn Garry devres_add(&dev->dev, ptr); 399e15f2fa9SJohn Garry 400e15f2fa9SJohn Garry kfree(desc); 401e15f2fa9SJohn Garry 402e15f2fa9SJohn Garry *irqs = ptr->irq; 403e15f2fa9SJohn Garry 404e15f2fa9SJohn Garry return nvec; 405e15f2fa9SJohn Garry 406e15f2fa9SJohn Garry err_free_desc: 407e15f2fa9SJohn Garry kfree(desc); 408e15f2fa9SJohn Garry err_free_devres: 409e15f2fa9SJohn Garry devres_free(ptr); 410e15f2fa9SJohn Garry return ret; 411e15f2fa9SJohn Garry } 412e15f2fa9SJohn Garry EXPORT_SYMBOL_GPL(devm_platform_get_irqs_affinity); 413e15f2fa9SJohn Garry 4144b83555dSStephen Boyd /** 4151da177e4SLinus Torvalds * platform_get_resource_byname - get a resource for a device by name 4161da177e4SLinus Torvalds * @dev: platform device 4171da177e4SLinus Torvalds * @type: resource type 4181da177e4SLinus Torvalds * @name: resource name 4191da177e4SLinus Torvalds */ 4204a3ad20cSGreg Kroah-Hartman struct resource *platform_get_resource_byname(struct platform_device *dev, 421c0afe7baSLinus Walleij unsigned int type, 422c0afe7baSLinus Walleij const char *name) 4231da177e4SLinus Torvalds { 42439cc539fSSimon Schwartz u32 i; 4251da177e4SLinus Torvalds 4261da177e4SLinus Torvalds for (i = 0; i < dev->num_resources; i++) { 4271da177e4SLinus Torvalds struct resource *r = &dev->resource[i]; 4281da177e4SLinus Torvalds 4291b8cb929SPeter Ujfalusi if (unlikely(!r->name)) 4301b8cb929SPeter Ujfalusi continue; 4311b8cb929SPeter Ujfalusi 432c9f66169SMagnus Damm if (type == resource_type(r) && !strcmp(r->name, name)) 4331da177e4SLinus Torvalds return r; 4341da177e4SLinus Torvalds } 4351da177e4SLinus Torvalds return NULL; 4361da177e4SLinus Torvalds } 437a96b2042SDmitry Torokhov EXPORT_SYMBOL_GPL(platform_get_resource_byname); 4381da177e4SLinus Torvalds 439f1da567fSHans de Goede static int __platform_get_irq_byname(struct platform_device *dev, 440f1da567fSHans de Goede const char *name) 4411da177e4SLinus Torvalds { 442ad69674eSGrygorii Strashko struct resource *r; 443aff008adSGuenter Roeck int ret; 444aff008adSGuenter Roeck 445d4ad017dSSoha Jin ret = fwnode_irq_get_byname(dev_fwnode(&dev->dev), name); 446e330b9a6SSergei Shtylyov if (ret > 0 || ret == -EPROBE_DEFER) 447aff008adSGuenter Roeck return ret; 448ad69674eSGrygorii Strashko 449ad69674eSGrygorii Strashko r = platform_get_resource_byname(dev, IORESOURCE_IRQ, name); 450a85a6c86SBjorn Helgaas if (r) { 451ce753ad1SSergey Shtylyov if (WARN(!r->start, "0 is an invalid IRQ number\n")) 452ce753ad1SSergey Shtylyov return -EINVAL; 4537723f4c5SStephen Boyd return r->start; 454a85a6c86SBjorn Helgaas } 4557723f4c5SStephen Boyd 4567723f4c5SStephen Boyd return -ENXIO; 4571da177e4SLinus Torvalds } 458f1da567fSHans de Goede 459f1da567fSHans de Goede /** 460f1da567fSHans de Goede * platform_get_irq_byname - get an IRQ for a device by name 461f1da567fSHans de Goede * @dev: platform device 462f1da567fSHans de Goede * @name: IRQ name 463f1da567fSHans de Goede * 464f1da567fSHans de Goede * Get an IRQ like platform_get_irq(), but then by name rather then by index. 465f1da567fSHans de Goede * 466a85a6c86SBjorn Helgaas * Return: non-zero IRQ number on success, negative error number on failure. 467f1da567fSHans de Goede */ 468f1da567fSHans de Goede int platform_get_irq_byname(struct platform_device *dev, const char *name) 469f1da567fSHans de Goede { 470f1da567fSHans de Goede int ret; 471f1da567fSHans de Goede 472f1da567fSHans de Goede ret = __platform_get_irq_byname(dev, name); 47327446562SSergey Shtylyov if (ret < 0) 47427446562SSergey Shtylyov return dev_err_probe(&dev->dev, ret, "IRQ %s not found\n", 47527446562SSergey Shtylyov name); 476f1da567fSHans de Goede return ret; 477f1da567fSHans de Goede } 478a96b2042SDmitry Torokhov EXPORT_SYMBOL_GPL(platform_get_irq_byname); 4791da177e4SLinus Torvalds 4801da177e4SLinus Torvalds /** 481f1da567fSHans de Goede * platform_get_irq_byname_optional - get an optional IRQ for a device by name 482f1da567fSHans de Goede * @dev: platform device 483f1da567fSHans de Goede * @name: IRQ name 484f1da567fSHans de Goede * 485f1da567fSHans de Goede * Get an optional IRQ by name like platform_get_irq_byname(). Except that it 486f1da567fSHans de Goede * does not print an error message if an IRQ can not be obtained. 487f1da567fSHans de Goede * 488a85a6c86SBjorn Helgaas * Return: non-zero IRQ number on success, negative error number on failure. 489f1da567fSHans de Goede */ 490f1da567fSHans de Goede int platform_get_irq_byname_optional(struct platform_device *dev, 491f1da567fSHans de Goede const char *name) 492f1da567fSHans de Goede { 493f1da567fSHans de Goede return __platform_get_irq_byname(dev, name); 494f1da567fSHans de Goede } 495f1da567fSHans de Goede EXPORT_SYMBOL_GPL(platform_get_irq_byname_optional); 496f1da567fSHans de Goede 497f1da567fSHans de Goede /** 4981da177e4SLinus Torvalds * platform_add_devices - add a numbers of platform devices 4991da177e4SLinus Torvalds * @devs: array of platform devices to add 5001da177e4SLinus Torvalds * @num: number of platform devices in array 50164f79742SUmang Jain * 50264f79742SUmang Jain * Return: 0 on success, negative error number on failure. 5031da177e4SLinus Torvalds */ 5041da177e4SLinus Torvalds int platform_add_devices(struct platform_device **devs, int num) 5051da177e4SLinus Torvalds { 5061da177e4SLinus Torvalds int i, ret = 0; 5071da177e4SLinus Torvalds 5081da177e4SLinus Torvalds for (i = 0; i < num; i++) { 5091da177e4SLinus Torvalds ret = platform_device_register(devs[i]); 5101da177e4SLinus Torvalds if (ret) { 5111da177e4SLinus Torvalds while (--i >= 0) 5121da177e4SLinus Torvalds platform_device_unregister(devs[i]); 5131da177e4SLinus Torvalds break; 5141da177e4SLinus Torvalds } 5151da177e4SLinus Torvalds } 5161da177e4SLinus Torvalds 5171da177e4SLinus Torvalds return ret; 5181da177e4SLinus Torvalds } 519a96b2042SDmitry Torokhov EXPORT_SYMBOL_GPL(platform_add_devices); 5201da177e4SLinus Torvalds 52137c12e74SRussell King struct platform_object { 52237c12e74SRussell King struct platform_device pdev; 5231cec24c5SYann Droneaud char name[]; 52437c12e74SRussell King }; 52537c12e74SRussell King 526cdfee562SChristoph Hellwig /* 527cdfee562SChristoph Hellwig * Set up default DMA mask for platform devices if the they weren't 528cdfee562SChristoph Hellwig * previously set by the architecture / DT. 529cdfee562SChristoph Hellwig */ 530cdfee562SChristoph Hellwig static void setup_pdev_dma_masks(struct platform_device *pdev) 531cdfee562SChristoph Hellwig { 5329495b7e9SUlf Hansson pdev->dev.dma_parms = &pdev->dma_parms; 5339495b7e9SUlf Hansson 534cdfee562SChristoph Hellwig if (!pdev->dev.coherent_dma_mask) 535cdfee562SChristoph Hellwig pdev->dev.coherent_dma_mask = DMA_BIT_MASK(32); 536e3a36eb6SChristoph Hellwig if (!pdev->dev.dma_mask) { 537e3a36eb6SChristoph Hellwig pdev->platform_dma_mask = DMA_BIT_MASK(32); 538e3a36eb6SChristoph Hellwig pdev->dev.dma_mask = &pdev->platform_dma_mask; 539e3a36eb6SChristoph Hellwig } 540cdfee562SChristoph Hellwig }; 541cdfee562SChristoph Hellwig 5421da177e4SLinus Torvalds /** 5433c31f07aSBen Hutchings * platform_device_put - destroy a platform device 54437c12e74SRussell King * @pdev: platform device to free 54537c12e74SRussell King * 5464a3ad20cSGreg Kroah-Hartman * Free all memory associated with a platform device. This function must 5474a3ad20cSGreg Kroah-Hartman * _only_ be externally called in error cases. All other usage is a bug. 54837c12e74SRussell King */ 54937c12e74SRussell King void platform_device_put(struct platform_device *pdev) 55037c12e74SRussell King { 55199fef587SAndy Shevchenko if (!IS_ERR_OR_NULL(pdev)) 55237c12e74SRussell King put_device(&pdev->dev); 55337c12e74SRussell King } 55437c12e74SRussell King EXPORT_SYMBOL_GPL(platform_device_put); 55537c12e74SRussell King 55637c12e74SRussell King static void platform_device_release(struct device *dev) 55737c12e74SRussell King { 5584a3ad20cSGreg Kroah-Hartman struct platform_object *pa = container_of(dev, struct platform_object, 5594a3ad20cSGreg Kroah-Hartman pdev.dev); 56037c12e74SRussell King 561cb8be8b4SRob Herring of_node_put(pa->pdev.dev.of_node); 56237c12e74SRussell King kfree(pa->pdev.dev.platform_data); 563e710d7d5SSamuel Ortiz kfree(pa->pdev.mfd_cell); 56437c12e74SRussell King kfree(pa->pdev.resource); 5653d713e0eSKim Phillips kfree(pa->pdev.driver_override); 56637c12e74SRussell King kfree(pa); 56737c12e74SRussell King } 56837c12e74SRussell King 56937c12e74SRussell King /** 5703c31f07aSBen Hutchings * platform_device_alloc - create a platform device 57137c12e74SRussell King * @name: base name of the device we're adding 57237c12e74SRussell King * @id: instance id 57337c12e74SRussell King * 57437c12e74SRussell King * Create a platform device object which can have other objects attached 57537c12e74SRussell King * to it, and which will have attached objects freed when it is released. 57637c12e74SRussell King */ 5771359555eSJean Delvare struct platform_device *platform_device_alloc(const char *name, int id) 57837c12e74SRussell King { 57937c12e74SRussell King struct platform_object *pa; 58037c12e74SRussell King 5811cec24c5SYann Droneaud pa = kzalloc(sizeof(*pa) + strlen(name) + 1, GFP_KERNEL); 58237c12e74SRussell King if (pa) { 58337c12e74SRussell King strcpy(pa->name, name); 58437c12e74SRussell King pa->pdev.name = pa->name; 58537c12e74SRussell King pa->pdev.id = id; 58637c12e74SRussell King device_initialize(&pa->pdev.dev); 58737c12e74SRussell King pa->pdev.dev.release = platform_device_release; 588cdfee562SChristoph Hellwig setup_pdev_dma_masks(&pa->pdev); 58937c12e74SRussell King } 59037c12e74SRussell King 59137c12e74SRussell King return pa ? &pa->pdev : NULL; 59237c12e74SRussell King } 59337c12e74SRussell King EXPORT_SYMBOL_GPL(platform_device_alloc); 59437c12e74SRussell King 59537c12e74SRussell King /** 5963c31f07aSBen Hutchings * platform_device_add_resources - add resources to a platform device 59737c12e74SRussell King * @pdev: platform device allocated by platform_device_alloc to add resources to 59837c12e74SRussell King * @res: set of resources that needs to be allocated for the device 59937c12e74SRussell King * @num: number of resources 60037c12e74SRussell King * 60137c12e74SRussell King * Add a copy of the resources to the platform device. The memory 6024a3ad20cSGreg Kroah-Hartman * associated with the resources will be freed when the platform device is 6034a3ad20cSGreg Kroah-Hartman * released. 60437c12e74SRussell King */ 6054a3ad20cSGreg Kroah-Hartman int platform_device_add_resources(struct platform_device *pdev, 6060b7f1a7eSGeert Uytterhoeven const struct resource *res, unsigned int num) 60737c12e74SRussell King { 608cea89623SUwe Kleine-König struct resource *r = NULL; 60937c12e74SRussell King 610cea89623SUwe Kleine-König if (res) { 61123c68596SAndy Shevchenko r = kmemdup_array(res, num, sizeof(*r), GFP_KERNEL); 612cea89623SUwe Kleine-König if (!r) 613cea89623SUwe Kleine-König return -ENOMEM; 614cea89623SUwe Kleine-König } 615cea89623SUwe Kleine-König 6164a03d6f7SUwe Kleine-König kfree(pdev->resource); 61737c12e74SRussell King pdev->resource = r; 61837c12e74SRussell King pdev->num_resources = num; 6193e61dfd8SUwe Kleine-König return 0; 62037c12e74SRussell King } 62137c12e74SRussell King EXPORT_SYMBOL_GPL(platform_device_add_resources); 62237c12e74SRussell King 62337c12e74SRussell King /** 6243c31f07aSBen Hutchings * platform_device_add_data - add platform-specific data to a platform device 62537c12e74SRussell King * @pdev: platform device allocated by platform_device_alloc to add resources to 62637c12e74SRussell King * @data: platform specific data for this platform device 62737c12e74SRussell King * @size: size of platform specific data 62837c12e74SRussell King * 6294a3ad20cSGreg Kroah-Hartman * Add a copy of platform specific data to the platform device's 6304a3ad20cSGreg Kroah-Hartman * platform_data pointer. The memory associated with the platform data 6314a3ad20cSGreg Kroah-Hartman * will be freed when the platform device is released. 63237c12e74SRussell King */ 6334a3ad20cSGreg Kroah-Hartman int platform_device_add_data(struct platform_device *pdev, const void *data, 6344a3ad20cSGreg Kroah-Hartman size_t size) 63537c12e74SRussell King { 63627a33f9eSUwe Kleine-König void *d = NULL; 63737c12e74SRussell King 63827a33f9eSUwe Kleine-König if (data) { 6395cfc64ceSAnton Vorontsov d = kmemdup(data, size, GFP_KERNEL); 64027a33f9eSUwe Kleine-König if (!d) 64127a33f9eSUwe Kleine-König return -ENOMEM; 64227a33f9eSUwe Kleine-König } 64327a33f9eSUwe Kleine-König 644251e031dSUwe Kleine-König kfree(pdev->dev.platform_data); 64537c12e74SRussell King pdev->dev.platform_data = d; 646daa41226SAndrew Morton return 0; 64737c12e74SRussell King } 64837c12e74SRussell King EXPORT_SYMBOL_GPL(platform_device_add_data); 64937c12e74SRussell King 65037c12e74SRussell King /** 65137c12e74SRussell King * platform_device_add - add a platform device to device hierarchy 65267be2dd1SMartin Waitz * @pdev: platform device we're adding 6531da177e4SLinus Torvalds * 65437c12e74SRussell King * This is part 2 of platform_device_register(), though may be called 65537c12e74SRussell King * separately _iff_ pdev was allocated by platform_device_alloc(). 6561da177e4SLinus Torvalds */ 65737c12e74SRussell King int platform_device_add(struct platform_device *pdev) 6581da177e4SLinus Torvalds { 6596136597cSAndy Shevchenko struct device *dev = &pdev->dev; 66039cc539fSSimon Schwartz u32 i; 66139cc539fSSimon Schwartz int ret; 6621da177e4SLinus Torvalds 6636136597cSAndy Shevchenko if (!dev->parent) 6646136597cSAndy Shevchenko dev->parent = &platform_bus; 6651da177e4SLinus Torvalds 6666136597cSAndy Shevchenko dev->bus = &platform_bus_type; 6671da177e4SLinus Torvalds 668689ae231SJean Delvare switch (pdev->id) { 669689ae231SJean Delvare default: 6706136597cSAndy Shevchenko dev_set_name(dev, "%s.%d", pdev->name, pdev->id); 671689ae231SJean Delvare break; 672689ae231SJean Delvare case PLATFORM_DEVID_NONE: 6736136597cSAndy Shevchenko dev_set_name(dev, "%s", pdev->name); 674689ae231SJean Delvare break; 675689ae231SJean Delvare case PLATFORM_DEVID_AUTO: 676689ae231SJean Delvare /* 677689ae231SJean Delvare * Automatically allocated device ID. We mark it as such so 678689ae231SJean Delvare * that we remember it must be freed, and we append a suffix 679689ae231SJean Delvare * to avoid namespace collision with explicit IDs. 680689ae231SJean Delvare */ 6810de75116SBartosz Golaszewski ret = ida_alloc(&platform_devid_ida, GFP_KERNEL); 682689ae231SJean Delvare if (ret < 0) 683a549e3aaSAndy Shevchenko return ret; 684689ae231SJean Delvare pdev->id = ret; 685689ae231SJean Delvare pdev->id_auto = true; 6866136597cSAndy Shevchenko dev_set_name(dev, "%s.%d.auto", pdev->name, pdev->id); 687689ae231SJean Delvare break; 688689ae231SJean Delvare } 6891da177e4SLinus Torvalds 6901da177e4SLinus Torvalds for (i = 0; i < pdev->num_resources; i++) { 6915da7f709SGreg Kroah-Hartman struct resource *p, *r = &pdev->resource[i]; 6921da177e4SLinus Torvalds 6931da177e4SLinus Torvalds if (r->name == NULL) 6946136597cSAndy Shevchenko r->name = dev_name(dev); 6951da177e4SLinus Torvalds 6961da177e4SLinus Torvalds p = r->parent; 6971da177e4SLinus Torvalds if (!p) { 6980e6c861fSGreg Kroah-Hartman if (resource_type(r) == IORESOURCE_MEM) 6991da177e4SLinus Torvalds p = &iomem_resource; 7000e6c861fSGreg Kroah-Hartman else if (resource_type(r) == IORESOURCE_IO) 7011da177e4SLinus Torvalds p = &ioport_resource; 7021da177e4SLinus Torvalds } 7031da177e4SLinus Torvalds 70425ebcb7dSAndy Shevchenko if (p) { 70525ebcb7dSAndy Shevchenko ret = insert_resource(p, r); 70625ebcb7dSAndy Shevchenko if (ret) { 7076136597cSAndy Shevchenko dev_err(dev, "failed to claim resource %d: %pR\n", i, r); 7085da7f709SGreg Kroah-Hartman goto failed; 7095da7f709SGreg Kroah-Hartman } 7101da177e4SLinus Torvalds } 71125ebcb7dSAndy Shevchenko } 7121da177e4SLinus Torvalds 7136136597cSAndy Shevchenko pr_debug("Registering platform device '%s'. Parent at %s\n", dev_name(dev), 7146136597cSAndy Shevchenko dev_name(dev->parent)); 7151da177e4SLinus Torvalds 7166136597cSAndy Shevchenko ret = device_add(dev); 717a549e3aaSAndy Shevchenko if (ret) 718a549e3aaSAndy Shevchenko goto failed; 719a549e3aaSAndy Shevchenko 720a549e3aaSAndy Shevchenko return 0; 7218b2dcebaSGreg Kroah-Hartman 7225da7f709SGreg Kroah-Hartman failed: 7238b2dcebaSGreg Kroah-Hartman if (pdev->id_auto) { 7240de75116SBartosz Golaszewski ida_free(&platform_devid_ida, pdev->id); 7258b2dcebaSGreg Kroah-Hartman pdev->id = PLATFORM_DEVID_AUTO; 7268b2dcebaSGreg Kroah-Hartman } 7278b2dcebaSGreg Kroah-Hartman 7280707cfa5SColin Ian King while (i--) { 7298b2dcebaSGreg Kroah-Hartman struct resource *r = &pdev->resource[i]; 7307f5dcaf1SGrant Likely if (r->parent) 7318b2dcebaSGreg Kroah-Hartman release_resource(r); 7328b2dcebaSGreg Kroah-Hartman } 733c9f66169SMagnus Damm 7341da177e4SLinus Torvalds return ret; 7351da177e4SLinus Torvalds } 73637c12e74SRussell King EXPORT_SYMBOL_GPL(platform_device_add); 73737c12e74SRussell King 73837c12e74SRussell King /** 73993ce3061SDmitry Torokhov * platform_device_del - remove a platform-level device 74093ce3061SDmitry Torokhov * @pdev: platform device we're removing 74193ce3061SDmitry Torokhov * 74293ce3061SDmitry Torokhov * Note that this function will also release all memory- and port-based 7434a3ad20cSGreg Kroah-Hartman * resources owned by the device (@dev->resource). This function must 7444a3ad20cSGreg Kroah-Hartman * _only_ be externally called in error cases. All other usage is a bug. 74593ce3061SDmitry Torokhov */ 74693ce3061SDmitry Torokhov void platform_device_del(struct platform_device *pdev) 74793ce3061SDmitry Torokhov { 74839cc539fSSimon Schwartz u32 i; 74993ce3061SDmitry Torokhov 75099fef587SAndy Shevchenko if (!IS_ERR_OR_NULL(pdev)) { 751dc4c15d4SJean Delvare device_del(&pdev->dev); 7528b2dcebaSGreg Kroah-Hartman 7538b2dcebaSGreg Kroah-Hartman if (pdev->id_auto) { 7540de75116SBartosz Golaszewski ida_free(&platform_devid_ida, pdev->id); 7558b2dcebaSGreg Kroah-Hartman pdev->id = PLATFORM_DEVID_AUTO; 7568b2dcebaSGreg Kroah-Hartman } 7578b2dcebaSGreg Kroah-Hartman 7588b2dcebaSGreg Kroah-Hartman for (i = 0; i < pdev->num_resources; i++) { 7598b2dcebaSGreg Kroah-Hartman struct resource *r = &pdev->resource[i]; 7607f5dcaf1SGrant Likely if (r->parent) 7618b2dcebaSGreg Kroah-Hartman release_resource(r); 7628b2dcebaSGreg Kroah-Hartman } 7638b2dcebaSGreg Kroah-Hartman } 76493ce3061SDmitry Torokhov } 76593ce3061SDmitry Torokhov EXPORT_SYMBOL_GPL(platform_device_del); 76693ce3061SDmitry Torokhov 76793ce3061SDmitry Torokhov /** 76837c12e74SRussell King * platform_device_register - add a platform-level device 76937c12e74SRussell King * @pdev: platform device we're adding 77067e532a4SJohan Hovold * 77167e532a4SJohan Hovold * NOTE: _Never_ directly free @pdev after calling this function, even if it 77267e532a4SJohan Hovold * returned an error! Always use platform_device_put() to give up the 77367e532a4SJohan Hovold * reference initialised in this function instead. 77437c12e74SRussell King */ 77537c12e74SRussell King int platform_device_register(struct platform_device *pdev) 77637c12e74SRussell King { 77737c12e74SRussell King device_initialize(&pdev->dev); 778cdfee562SChristoph Hellwig setup_pdev_dma_masks(pdev); 77937c12e74SRussell King return platform_device_add(pdev); 78037c12e74SRussell King } 781a96b2042SDmitry Torokhov EXPORT_SYMBOL_GPL(platform_device_register); 7821da177e4SLinus Torvalds 7831da177e4SLinus Torvalds /** 78493ce3061SDmitry Torokhov * platform_device_unregister - unregister a platform-level device 78593ce3061SDmitry Torokhov * @pdev: platform device we're unregistering 7861da177e4SLinus Torvalds * 78780682fa9SUwe Zeisberger * Unregistration is done in 2 steps. First we release all resources 7882d7b5a70SJean Delvare * and remove it from the subsystem, then we drop reference count by 78993ce3061SDmitry Torokhov * calling platform_device_put(). 7901da177e4SLinus Torvalds */ 7911da177e4SLinus Torvalds void platform_device_unregister(struct platform_device *pdev) 7921da177e4SLinus Torvalds { 79393ce3061SDmitry Torokhov platform_device_del(pdev); 79493ce3061SDmitry Torokhov platform_device_put(pdev); 7951da177e4SLinus Torvalds } 796a96b2042SDmitry Torokhov EXPORT_SYMBOL_GPL(platform_device_unregister); 7971da177e4SLinus Torvalds 7981da177e4SLinus Torvalds /** 79901dcc60aSUwe Kleine-König * platform_device_register_full - add a platform-level device with 80044f28bdeSUwe Kleine-König * resources and platform-specific data 80144f28bdeSUwe Kleine-König * 80201dcc60aSUwe Kleine-König * @pdevinfo: data used to create device 803d8bf2540SDmitry Baryshkov * 804f0eae0edSJani Nikula * Returns &struct platform_device pointer on success, or ERR_PTR() on error. 805d8bf2540SDmitry Baryshkov */ 80601dcc60aSUwe Kleine-König struct platform_device *platform_device_register_full( 8075a3072beSUwe Kleine-König const struct platform_device_info *pdevinfo) 808d8bf2540SDmitry Baryshkov { 80945bb08deSColin Ian King int ret; 810d8bf2540SDmitry Baryshkov struct platform_device *pdev; 811d8bf2540SDmitry Baryshkov 81201dcc60aSUwe Kleine-König pdev = platform_device_alloc(pdevinfo->name, pdevinfo->id); 81344f28bdeSUwe Kleine-König if (!pdev) 81436cf3b13SJohannes Berg return ERR_PTR(-ENOMEM); 81501dcc60aSUwe Kleine-König 81601dcc60aSUwe Kleine-König pdev->dev.parent = pdevinfo->parent; 817ce793486SRafael J. Wysocki pdev->dev.fwnode = pdevinfo->fwnode; 8182c1ea6abSMans Rullgard pdev->dev.of_node = of_node_get(to_of_node(pdev->dev.fwnode)); 8192c1ea6abSMans Rullgard pdev->dev.of_node_reused = pdevinfo->of_node_reused; 82001dcc60aSUwe Kleine-König 82101dcc60aSUwe Kleine-König if (pdevinfo->dma_mask) { 822e3a36eb6SChristoph Hellwig pdev->platform_dma_mask = pdevinfo->dma_mask; 823e3a36eb6SChristoph Hellwig pdev->dev.dma_mask = &pdev->platform_dma_mask; 82401dcc60aSUwe Kleine-König pdev->dev.coherent_dma_mask = pdevinfo->dma_mask; 82501dcc60aSUwe Kleine-König } 826d8bf2540SDmitry Baryshkov 82701dcc60aSUwe Kleine-König ret = platform_device_add_resources(pdev, 82801dcc60aSUwe Kleine-König pdevinfo->res, pdevinfo->num_res); 82944f28bdeSUwe Kleine-König if (ret) 83044f28bdeSUwe Kleine-König goto err; 831d8bf2540SDmitry Baryshkov 83201dcc60aSUwe Kleine-König ret = platform_device_add_data(pdev, 83301dcc60aSUwe Kleine-König pdevinfo->data, pdevinfo->size_data); 83444f28bdeSUwe Kleine-König if (ret) 83544f28bdeSUwe Kleine-König goto err; 83644f28bdeSUwe Kleine-König 837f4d05266SHeikki Krogerus if (pdevinfo->properties) { 838bd1e336aSHeikki Krogerus ret = device_create_managed_software_node(&pdev->dev, 839bd1e336aSHeikki Krogerus pdevinfo->properties, NULL); 84000bbc1d8SMika Westerberg if (ret) 84100bbc1d8SMika Westerberg goto err; 84200bbc1d8SMika Westerberg } 84300bbc1d8SMika Westerberg 84444f28bdeSUwe Kleine-König ret = platform_device_add(pdev); 84544f28bdeSUwe Kleine-König if (ret) { 84644f28bdeSUwe Kleine-König err: 8477b199811SRafael J. Wysocki ACPI_COMPANION_SET(&pdev->dev, NULL); 84844f28bdeSUwe Kleine-König platform_device_put(pdev); 84944f28bdeSUwe Kleine-König return ERR_PTR(ret); 85044f28bdeSUwe Kleine-König } 851d8bf2540SDmitry Baryshkov 852d8bf2540SDmitry Baryshkov return pdev; 853d8bf2540SDmitry Baryshkov } 85401dcc60aSUwe Kleine-König EXPORT_SYMBOL_GPL(platform_device_register_full); 855d8bf2540SDmitry Baryshkov 85600d3dcddSRussell King /** 8579447057eSLibo Chen * __platform_driver_register - register a driver for platform-level devices 85800d3dcddSRussell King * @drv: platform driver structure 85908801f96SRandy Dunlap * @owner: owning module/driver 86000d3dcddSRussell King */ 8619447057eSLibo Chen int __platform_driver_register(struct platform_driver *drv, 8629447057eSLibo Chen struct module *owner) 86300d3dcddSRussell King { 8649447057eSLibo Chen drv->driver.owner = owner; 86500d3dcddSRussell King drv->driver.bus = &platform_bus_type; 866783ea7d4SMagnus Damm 86700d3dcddSRussell King return driver_register(&drv->driver); 86800d3dcddSRussell King } 8699447057eSLibo Chen EXPORT_SYMBOL_GPL(__platform_driver_register); 87000d3dcddSRussell King 87100d3dcddSRussell King /** 8723c31f07aSBen Hutchings * platform_driver_unregister - unregister a driver for platform-level devices 87300d3dcddSRussell King * @drv: platform driver structure 87400d3dcddSRussell King */ 87500d3dcddSRussell King void platform_driver_unregister(struct platform_driver *drv) 87600d3dcddSRussell King { 87700d3dcddSRussell King driver_unregister(&drv->driver); 87800d3dcddSRussell King } 87900d3dcddSRussell King EXPORT_SYMBOL_GPL(platform_driver_unregister); 88000d3dcddSRussell King 88116085668SUwe Kleine-König static int platform_probe_fail(struct platform_device *pdev) 882e21d740aSUwe Kleine-König { 883e21d740aSUwe Kleine-König return -ENXIO; 884e21d740aSUwe Kleine-König } 885e21d740aSUwe Kleine-König 88640b3880dSGreg Kroah-Hartman static int is_bound_to_driver(struct device *dev, void *driver) 88740b3880dSGreg Kroah-Hartman { 88840b3880dSGreg Kroah-Hartman if (dev->driver == driver) 88940b3880dSGreg Kroah-Hartman return 1; 89040b3880dSGreg Kroah-Hartman return 0; 89140b3880dSGreg Kroah-Hartman } 89240b3880dSGreg Kroah-Hartman 893c67334fbSDavid Brownell /** 894c3b50dc2SWolfram Sang * __platform_driver_probe - register driver for non-hotpluggable device 895c67334fbSDavid Brownell * @drv: platform driver structure 8963f9120b0SJohan Hovold * @probe: the driver probe routine, probably from an __init section 897c3b50dc2SWolfram Sang * @module: module which will be the owner of the driver 898c67334fbSDavid Brownell * 899c67334fbSDavid Brownell * Use this instead of platform_driver_register() when you know the device 900c67334fbSDavid Brownell * is not hotpluggable and has already been registered, and you want to 901c67334fbSDavid Brownell * remove its run-once probe() infrastructure from memory after the driver 902c67334fbSDavid Brownell * has bound to the device. 903c67334fbSDavid Brownell * 904c67334fbSDavid Brownell * One typical use for this would be with drivers for controllers integrated 905c67334fbSDavid Brownell * into system-on-chip processors, where the controller devices have been 906c67334fbSDavid Brownell * configured as part of board setup. 907c67334fbSDavid Brownell * 9083f9120b0SJohan Hovold * Note that this is incompatible with deferred probing. 909647c86d0SFabio Porcedda * 910c67334fbSDavid Brownell * Returns zero if the driver registered and bound to a device, else returns 911c67334fbSDavid Brownell * a negative error code and with the driver not registered. 912c67334fbSDavid Brownell */ 913c3b50dc2SWolfram Sang int __init_or_module __platform_driver_probe(struct platform_driver *drv, 914c3b50dc2SWolfram Sang int (*probe)(struct platform_device *), struct module *module) 915c67334fbSDavid Brownell { 916b4ce0bf7SGreg Kroah-Hartman int retval; 917c67334fbSDavid Brownell 9185c36eb2aSDmitry Torokhov if (drv->driver.probe_type == PROBE_PREFER_ASYNCHRONOUS) { 9195c36eb2aSDmitry Torokhov pr_err("%s: drivers registered with %s can not be probed asynchronously\n", 9205c36eb2aSDmitry Torokhov drv->driver.name, __func__); 9215c36eb2aSDmitry Torokhov return -EINVAL; 9225c36eb2aSDmitry Torokhov } 9235c36eb2aSDmitry Torokhov 9245c36eb2aSDmitry Torokhov /* 9255c36eb2aSDmitry Torokhov * We have to run our probes synchronously because we check if 9265c36eb2aSDmitry Torokhov * we find any devices to bind to and exit with error if there 9275c36eb2aSDmitry Torokhov * are any. 9285c36eb2aSDmitry Torokhov */ 9295c36eb2aSDmitry Torokhov drv->driver.probe_type = PROBE_FORCE_SYNCHRONOUS; 9305c36eb2aSDmitry Torokhov 9313f9120b0SJohan Hovold /* 9323f9120b0SJohan Hovold * Prevent driver from requesting probe deferral to avoid further 9333f9120b0SJohan Hovold * futile probe attempts. 9343f9120b0SJohan Hovold */ 9353f9120b0SJohan Hovold drv->prevent_deferred_probe = true; 9363f9120b0SJohan Hovold 9371a6f2a75SDmitry Torokhov /* make sure driver won't have bind/unbind attributes */ 9381a6f2a75SDmitry Torokhov drv->driver.suppress_bind_attrs = true; 9391a6f2a75SDmitry Torokhov 940c67334fbSDavid Brownell /* temporary section violation during probe() */ 941c67334fbSDavid Brownell drv->probe = probe; 942b4ce0bf7SGreg Kroah-Hartman retval = __platform_driver_register(drv, module); 943388bcc6eSKuppuswamy Sathyanarayanan if (retval) 944388bcc6eSKuppuswamy Sathyanarayanan return retval; 945c67334fbSDavid Brownell 94640b3880dSGreg Kroah-Hartman /* Force all new probes of this driver to fail */ 94716085668SUwe Kleine-König drv->probe = platform_probe_fail; 948c67334fbSDavid Brownell 94940b3880dSGreg Kroah-Hartman /* Walk all platform devices and see if any actually bound to this driver. 95040b3880dSGreg Kroah-Hartman * If not, return an error as the device should have done so by now. 95140b3880dSGreg Kroah-Hartman */ 95240b3880dSGreg Kroah-Hartman if (!bus_for_each_dev(&platform_bus_type, NULL, &drv->driver, is_bound_to_driver)) { 95340b3880dSGreg Kroah-Hartman retval = -ENODEV; 954c67334fbSDavid Brownell platform_driver_unregister(drv); 95540b3880dSGreg Kroah-Hartman } 95640b3880dSGreg Kroah-Hartman 957c67334fbSDavid Brownell return retval; 958c67334fbSDavid Brownell } 959c3b50dc2SWolfram Sang EXPORT_SYMBOL_GPL(__platform_driver_probe); 9601da177e4SLinus Torvalds 961ecdf6cebSDmitry Torokhov /** 962291f653aSWolfram Sang * __platform_create_bundle - register driver and create corresponding device 963ecdf6cebSDmitry Torokhov * @driver: platform driver structure 964ecdf6cebSDmitry Torokhov * @probe: the driver probe routine, probably from an __init section 965ecdf6cebSDmitry Torokhov * @res: set of resources that needs to be allocated for the device 966ecdf6cebSDmitry Torokhov * @n_res: number of resources 967ecdf6cebSDmitry Torokhov * @data: platform specific data for this platform device 968ecdf6cebSDmitry Torokhov * @size: size of platform specific data 969291f653aSWolfram Sang * @module: module which will be the owner of the driver 970ecdf6cebSDmitry Torokhov * 971ecdf6cebSDmitry Torokhov * Use this in legacy-style modules that probe hardware directly and 972ecdf6cebSDmitry Torokhov * register a single platform device and corresponding platform driver. 973f0eae0edSJani Nikula * 974f0eae0edSJani Nikula * Returns &struct platform_device pointer on success, or ERR_PTR() on error. 975ecdf6cebSDmitry Torokhov */ 976291f653aSWolfram Sang struct platform_device * __init_or_module __platform_create_bundle( 977ecdf6cebSDmitry Torokhov struct platform_driver *driver, 978ecdf6cebSDmitry Torokhov int (*probe)(struct platform_device *), 979ecdf6cebSDmitry Torokhov struct resource *res, unsigned int n_res, 980291f653aSWolfram Sang const void *data, size_t size, struct module *module) 981ecdf6cebSDmitry Torokhov { 982ecdf6cebSDmitry Torokhov struct platform_device *pdev; 983ecdf6cebSDmitry Torokhov int error; 984ecdf6cebSDmitry Torokhov 985ecdf6cebSDmitry Torokhov pdev = platform_device_alloc(driver->driver.name, -1); 986ecdf6cebSDmitry Torokhov if (!pdev) { 987ecdf6cebSDmitry Torokhov error = -ENOMEM; 988ecdf6cebSDmitry Torokhov goto err_out; 989ecdf6cebSDmitry Torokhov } 990ecdf6cebSDmitry Torokhov 991ecdf6cebSDmitry Torokhov error = platform_device_add_resources(pdev, res, n_res); 992ecdf6cebSDmitry Torokhov if (error) 993ecdf6cebSDmitry Torokhov goto err_pdev_put; 994ecdf6cebSDmitry Torokhov 995ecdf6cebSDmitry Torokhov error = platform_device_add_data(pdev, data, size); 996ecdf6cebSDmitry Torokhov if (error) 997ecdf6cebSDmitry Torokhov goto err_pdev_put; 998ecdf6cebSDmitry Torokhov 999ecdf6cebSDmitry Torokhov error = platform_device_add(pdev); 1000ecdf6cebSDmitry Torokhov if (error) 1001ecdf6cebSDmitry Torokhov goto err_pdev_put; 1002ecdf6cebSDmitry Torokhov 1003291f653aSWolfram Sang error = __platform_driver_probe(driver, probe, module); 1004ecdf6cebSDmitry Torokhov if (error) 1005ecdf6cebSDmitry Torokhov goto err_pdev_del; 1006ecdf6cebSDmitry Torokhov 1007ecdf6cebSDmitry Torokhov return pdev; 1008ecdf6cebSDmitry Torokhov 1009ecdf6cebSDmitry Torokhov err_pdev_del: 1010ecdf6cebSDmitry Torokhov platform_device_del(pdev); 1011ecdf6cebSDmitry Torokhov err_pdev_put: 1012ecdf6cebSDmitry Torokhov platform_device_put(pdev); 1013ecdf6cebSDmitry Torokhov err_out: 1014ecdf6cebSDmitry Torokhov return ERR_PTR(error); 1015ecdf6cebSDmitry Torokhov } 1016291f653aSWolfram Sang EXPORT_SYMBOL_GPL(__platform_create_bundle); 1017ecdf6cebSDmitry Torokhov 1018dbe2256dSThierry Reding /** 1019dbe2256dSThierry Reding * __platform_register_drivers - register an array of platform drivers 1020dbe2256dSThierry Reding * @drivers: an array of drivers to register 1021dbe2256dSThierry Reding * @count: the number of drivers to register 1022dbe2256dSThierry Reding * @owner: module owning the drivers 1023dbe2256dSThierry Reding * 1024dbe2256dSThierry Reding * Registers platform drivers specified by an array. On failure to register a 1025dbe2256dSThierry Reding * driver, all previously registered drivers will be unregistered. Callers of 1026dbe2256dSThierry Reding * this API should use platform_unregister_drivers() to unregister drivers in 1027dbe2256dSThierry Reding * the reverse order. 1028dbe2256dSThierry Reding * 1029dbe2256dSThierry Reding * Returns: 0 on success or a negative error code on failure. 1030dbe2256dSThierry Reding */ 1031dbe2256dSThierry Reding int __platform_register_drivers(struct platform_driver * const *drivers, 1032dbe2256dSThierry Reding unsigned int count, struct module *owner) 1033dbe2256dSThierry Reding { 1034dbe2256dSThierry Reding unsigned int i; 1035dbe2256dSThierry Reding int err; 1036dbe2256dSThierry Reding 1037dbe2256dSThierry Reding for (i = 0; i < count; i++) { 1038dbe2256dSThierry Reding pr_debug("registering platform driver %ps\n", drivers[i]); 1039dbe2256dSThierry Reding 1040dbe2256dSThierry Reding err = __platform_driver_register(drivers[i], owner); 1041dbe2256dSThierry Reding if (err < 0) { 1042dbe2256dSThierry Reding pr_err("failed to register platform driver %ps: %d\n", 1043dbe2256dSThierry Reding drivers[i], err); 1044dbe2256dSThierry Reding goto error; 1045dbe2256dSThierry Reding } 1046dbe2256dSThierry Reding } 1047dbe2256dSThierry Reding 1048dbe2256dSThierry Reding return 0; 1049dbe2256dSThierry Reding 1050dbe2256dSThierry Reding error: 1051dbe2256dSThierry Reding while (i--) { 1052dbe2256dSThierry Reding pr_debug("unregistering platform driver %ps\n", drivers[i]); 1053dbe2256dSThierry Reding platform_driver_unregister(drivers[i]); 1054dbe2256dSThierry Reding } 1055dbe2256dSThierry Reding 1056dbe2256dSThierry Reding return err; 1057dbe2256dSThierry Reding } 1058dbe2256dSThierry Reding EXPORT_SYMBOL_GPL(__platform_register_drivers); 1059dbe2256dSThierry Reding 1060dbe2256dSThierry Reding /** 1061dbe2256dSThierry Reding * platform_unregister_drivers - unregister an array of platform drivers 1062dbe2256dSThierry Reding * @drivers: an array of drivers to unregister 1063dbe2256dSThierry Reding * @count: the number of drivers to unregister 1064dbe2256dSThierry Reding * 1065c82c83c3STang Bin * Unregisters platform drivers specified by an array. This is typically used 1066dbe2256dSThierry Reding * to complement an earlier call to platform_register_drivers(). Drivers are 1067dbe2256dSThierry Reding * unregistered in the reverse order in which they were registered. 1068dbe2256dSThierry Reding */ 1069dbe2256dSThierry Reding void platform_unregister_drivers(struct platform_driver * const *drivers, 1070dbe2256dSThierry Reding unsigned int count) 1071dbe2256dSThierry Reding { 1072dbe2256dSThierry Reding while (count--) { 1073dbe2256dSThierry Reding pr_debug("unregistering platform driver %ps\n", drivers[count]); 1074dbe2256dSThierry Reding platform_driver_unregister(drivers[count]); 1075dbe2256dSThierry Reding } 1076dbe2256dSThierry Reding } 1077dbe2256dSThierry Reding EXPORT_SYMBOL_GPL(platform_unregister_drivers); 1078dbe2256dSThierry Reding 107957fee4a5SEric Miao static const struct platform_device_id *platform_match_id( 1080831fad2fSUwe Kleine-König const struct platform_device_id *id, 108157fee4a5SEric Miao struct platform_device *pdev) 108257fee4a5SEric Miao { 108357fee4a5SEric Miao while (id->name[0]) { 1084391c0325SGreg Kroah-Hartman if (strcmp(pdev->name, id->name) == 0) { 108557fee4a5SEric Miao pdev->id_entry = id; 108657fee4a5SEric Miao return id; 108757fee4a5SEric Miao } 108857fee4a5SEric Miao id++; 108957fee4a5SEric Miao } 109057fee4a5SEric Miao return NULL; 109157fee4a5SEric Miao } 109257fee4a5SEric Miao 109325e18499SRafael J. Wysocki #ifdef CONFIG_PM_SLEEP 109425e18499SRafael J. Wysocki 109525e18499SRafael J. Wysocki static int platform_legacy_suspend(struct device *dev, pm_message_t mesg) 10961da177e4SLinus Torvalds { 1097783ea7d4SMagnus Damm struct platform_driver *pdrv = to_platform_driver(dev->driver); 1098783ea7d4SMagnus Damm struct platform_device *pdev = to_platform_device(dev); 10991da177e4SLinus Torvalds int ret = 0; 11001da177e4SLinus Torvalds 1101783ea7d4SMagnus Damm if (dev->driver && pdrv->suspend) 1102783ea7d4SMagnus Damm ret = pdrv->suspend(pdev, mesg); 1103386415d8SDavid Brownell 1104386415d8SDavid Brownell return ret; 1105386415d8SDavid Brownell } 1106386415d8SDavid Brownell 110725e18499SRafael J. Wysocki static int platform_legacy_resume(struct device *dev) 11081da177e4SLinus Torvalds { 1109783ea7d4SMagnus Damm struct platform_driver *pdrv = to_platform_driver(dev->driver); 1110783ea7d4SMagnus Damm struct platform_device *pdev = to_platform_device(dev); 11111da177e4SLinus Torvalds int ret = 0; 11121da177e4SLinus Torvalds 1113783ea7d4SMagnus Damm if (dev->driver && pdrv->resume) 1114783ea7d4SMagnus Damm ret = pdrv->resume(pdev); 11159480e307SRussell King 11161da177e4SLinus Torvalds return ret; 11171da177e4SLinus Torvalds } 11181da177e4SLinus Torvalds 111969c9dd1eSRafael J. Wysocki #endif /* CONFIG_PM_SLEEP */ 11209d730229SMagnus Damm 112125e18499SRafael J. Wysocki #ifdef CONFIG_SUSPEND 112225e18499SRafael J. Wysocki 112369c9dd1eSRafael J. Wysocki int platform_pm_suspend(struct device *dev) 112425e18499SRafael J. Wysocki { 1125841b7ebfSGreg Kroah-Hartman const struct device_driver *drv = dev->driver; 112625e18499SRafael J. Wysocki int ret = 0; 112725e18499SRafael J. Wysocki 1128adf09493SRafael J. Wysocki if (!drv) 1129adf09493SRafael J. Wysocki return 0; 1130adf09493SRafael J. Wysocki 1131adf09493SRafael J. Wysocki if (drv->pm) { 113225e18499SRafael J. Wysocki if (drv->pm->suspend) 113325e18499SRafael J. Wysocki ret = drv->pm->suspend(dev); 113425e18499SRafael J. Wysocki } else { 113525e18499SRafael J. Wysocki ret = platform_legacy_suspend(dev, PMSG_SUSPEND); 113625e18499SRafael J. Wysocki } 113725e18499SRafael J. Wysocki 113825e18499SRafael J. Wysocki return ret; 113925e18499SRafael J. Wysocki } 114025e18499SRafael J. Wysocki 114169c9dd1eSRafael J. Wysocki int platform_pm_resume(struct device *dev) 114225e18499SRafael J. Wysocki { 1143841b7ebfSGreg Kroah-Hartman const struct device_driver *drv = dev->driver; 114425e18499SRafael J. Wysocki int ret = 0; 114525e18499SRafael J. Wysocki 1146adf09493SRafael J. Wysocki if (!drv) 1147adf09493SRafael J. Wysocki return 0; 1148adf09493SRafael J. Wysocki 1149adf09493SRafael J. Wysocki if (drv->pm) { 115025e18499SRafael J. Wysocki if (drv->pm->resume) 115125e18499SRafael J. Wysocki ret = drv->pm->resume(dev); 115225e18499SRafael J. Wysocki } else { 115325e18499SRafael J. Wysocki ret = platform_legacy_resume(dev); 115425e18499SRafael J. Wysocki } 115525e18499SRafael J. Wysocki 115625e18499SRafael J. Wysocki return ret; 115725e18499SRafael J. Wysocki } 115825e18499SRafael J. Wysocki 115969c9dd1eSRafael J. Wysocki #endif /* CONFIG_SUSPEND */ 116025e18499SRafael J. Wysocki 11611f112ceeSRafael J. Wysocki #ifdef CONFIG_HIBERNATE_CALLBACKS 116225e18499SRafael J. Wysocki 116369c9dd1eSRafael J. Wysocki int platform_pm_freeze(struct device *dev) 116425e18499SRafael J. Wysocki { 1165841b7ebfSGreg Kroah-Hartman const struct device_driver *drv = dev->driver; 116625e18499SRafael J. Wysocki int ret = 0; 116725e18499SRafael J. Wysocki 116825e18499SRafael J. Wysocki if (!drv) 116925e18499SRafael J. Wysocki return 0; 117025e18499SRafael J. Wysocki 117125e18499SRafael J. Wysocki if (drv->pm) { 117225e18499SRafael J. Wysocki if (drv->pm->freeze) 117325e18499SRafael J. Wysocki ret = drv->pm->freeze(dev); 117425e18499SRafael J. Wysocki } else { 117525e18499SRafael J. Wysocki ret = platform_legacy_suspend(dev, PMSG_FREEZE); 117625e18499SRafael J. Wysocki } 117725e18499SRafael J. Wysocki 117825e18499SRafael J. Wysocki return ret; 117925e18499SRafael J. Wysocki } 118025e18499SRafael J. Wysocki 118169c9dd1eSRafael J. Wysocki int platform_pm_thaw(struct device *dev) 118225e18499SRafael J. Wysocki { 1183841b7ebfSGreg Kroah-Hartman const struct device_driver *drv = dev->driver; 118425e18499SRafael J. Wysocki int ret = 0; 118525e18499SRafael J. Wysocki 1186adf09493SRafael J. Wysocki if (!drv) 1187adf09493SRafael J. Wysocki return 0; 1188adf09493SRafael J. Wysocki 1189adf09493SRafael J. Wysocki if (drv->pm) { 119025e18499SRafael J. Wysocki if (drv->pm->thaw) 119125e18499SRafael J. Wysocki ret = drv->pm->thaw(dev); 119225e18499SRafael J. Wysocki } else { 119325e18499SRafael J. Wysocki ret = platform_legacy_resume(dev); 119425e18499SRafael J. Wysocki } 119525e18499SRafael J. Wysocki 119625e18499SRafael J. Wysocki return ret; 119725e18499SRafael J. Wysocki } 119825e18499SRafael J. Wysocki 119969c9dd1eSRafael J. Wysocki int platform_pm_poweroff(struct device *dev) 120025e18499SRafael J. Wysocki { 1201841b7ebfSGreg Kroah-Hartman const struct device_driver *drv = dev->driver; 120225e18499SRafael J. Wysocki int ret = 0; 120325e18499SRafael J. Wysocki 1204adf09493SRafael J. Wysocki if (!drv) 1205adf09493SRafael J. Wysocki return 0; 1206adf09493SRafael J. Wysocki 1207adf09493SRafael J. Wysocki if (drv->pm) { 120825e18499SRafael J. Wysocki if (drv->pm->poweroff) 120925e18499SRafael J. Wysocki ret = drv->pm->poweroff(dev); 121025e18499SRafael J. Wysocki } else { 121125e18499SRafael J. Wysocki ret = platform_legacy_suspend(dev, PMSG_HIBERNATE); 121225e18499SRafael J. Wysocki } 121325e18499SRafael J. Wysocki 121425e18499SRafael J. Wysocki return ret; 121525e18499SRafael J. Wysocki } 121625e18499SRafael J. Wysocki 121769c9dd1eSRafael J. Wysocki int platform_pm_restore(struct device *dev) 121825e18499SRafael J. Wysocki { 1219841b7ebfSGreg Kroah-Hartman const struct device_driver *drv = dev->driver; 122025e18499SRafael J. Wysocki int ret = 0; 122125e18499SRafael J. Wysocki 1222adf09493SRafael J. Wysocki if (!drv) 1223adf09493SRafael J. Wysocki return 0; 1224adf09493SRafael J. Wysocki 1225adf09493SRafael J. Wysocki if (drv->pm) { 122625e18499SRafael J. Wysocki if (drv->pm->restore) 122725e18499SRafael J. Wysocki ret = drv->pm->restore(dev); 122825e18499SRafael J. Wysocki } else { 122925e18499SRafael J. Wysocki ret = platform_legacy_resume(dev); 123025e18499SRafael J. Wysocki } 123125e18499SRafael J. Wysocki 123225e18499SRafael J. Wysocki return ret; 123325e18499SRafael J. Wysocki } 123425e18499SRafael J. Wysocki 123569c9dd1eSRafael J. Wysocki #endif /* CONFIG_HIBERNATE_CALLBACKS */ 123625e18499SRafael J. Wysocki 1237e21d740aSUwe Kleine-König /* modalias support enables more hands-off userspace setup: 1238e21d740aSUwe Kleine-König * (a) environment variable lets new-style hotplug events work once system is 1239e21d740aSUwe Kleine-König * fully running: "modprobe $MODALIAS" 1240e21d740aSUwe Kleine-König * (b) sysfs attribute lets new-style coldplug recover from hotplug events 1241e21d740aSUwe Kleine-König * mishandled before system is fully running: "modprobe $(cat modalias)" 1242e21d740aSUwe Kleine-König */ 1243e21d740aSUwe Kleine-König static ssize_t modalias_show(struct device *dev, 1244e21d740aSUwe Kleine-König struct device_attribute *attr, char *buf) 1245e21d740aSUwe Kleine-König { 1246e21d740aSUwe Kleine-König struct platform_device *pdev = to_platform_device(dev); 1247e21d740aSUwe Kleine-König int len; 1248e21d740aSUwe Kleine-König 1249e21d740aSUwe Kleine-König len = of_device_modalias(dev, buf, PAGE_SIZE); 1250e21d740aSUwe Kleine-König if (len != -ENODEV) 1251e21d740aSUwe Kleine-König return len; 1252e21d740aSUwe Kleine-König 1253e21d740aSUwe Kleine-König len = acpi_device_modalias(dev, buf, PAGE_SIZE - 1); 1254e21d740aSUwe Kleine-König if (len != -ENODEV) 1255e21d740aSUwe Kleine-König return len; 1256e21d740aSUwe Kleine-König 1257e21d740aSUwe Kleine-König return sysfs_emit(buf, "platform:%s\n", pdev->name); 1258e21d740aSUwe Kleine-König } 1259e21d740aSUwe Kleine-König static DEVICE_ATTR_RO(modalias); 1260e21d740aSUwe Kleine-König 1261e21d740aSUwe Kleine-König static ssize_t numa_node_show(struct device *dev, 1262e21d740aSUwe Kleine-König struct device_attribute *attr, char *buf) 1263e21d740aSUwe Kleine-König { 1264e21d740aSUwe Kleine-König return sysfs_emit(buf, "%d\n", dev_to_node(dev)); 1265e21d740aSUwe Kleine-König } 1266e21d740aSUwe Kleine-König static DEVICE_ATTR_RO(numa_node); 1267e21d740aSUwe Kleine-König 1268e21d740aSUwe Kleine-König static ssize_t driver_override_show(struct device *dev, 1269e21d740aSUwe Kleine-König struct device_attribute *attr, char *buf) 1270e21d740aSUwe Kleine-König { 1271e21d740aSUwe Kleine-König struct platform_device *pdev = to_platform_device(dev); 1272e21d740aSUwe Kleine-König ssize_t len; 1273e21d740aSUwe Kleine-König 1274e21d740aSUwe Kleine-König device_lock(dev); 1275e21d740aSUwe Kleine-König len = sysfs_emit(buf, "%s\n", pdev->driver_override); 1276e21d740aSUwe Kleine-König device_unlock(dev); 1277e21d740aSUwe Kleine-König 1278e21d740aSUwe Kleine-König return len; 1279e21d740aSUwe Kleine-König } 1280e21d740aSUwe Kleine-König 1281e21d740aSUwe Kleine-König static ssize_t driver_override_store(struct device *dev, 1282e21d740aSUwe Kleine-König struct device_attribute *attr, 1283e21d740aSUwe Kleine-König const char *buf, size_t count) 1284e21d740aSUwe Kleine-König { 1285e21d740aSUwe Kleine-König struct platform_device *pdev = to_platform_device(dev); 12866c2f4211SKrzysztof Kozlowski int ret; 1287e21d740aSUwe Kleine-König 12886c2f4211SKrzysztof Kozlowski ret = driver_set_override(dev, &pdev->driver_override, buf, count); 12896c2f4211SKrzysztof Kozlowski if (ret) 12906c2f4211SKrzysztof Kozlowski return ret; 1291e21d740aSUwe Kleine-König 1292e21d740aSUwe Kleine-König return count; 1293e21d740aSUwe Kleine-König } 1294e21d740aSUwe Kleine-König static DEVICE_ATTR_RW(driver_override); 1295e21d740aSUwe Kleine-König 1296e21d740aSUwe Kleine-König static struct attribute *platform_dev_attrs[] = { 1297e21d740aSUwe Kleine-König &dev_attr_modalias.attr, 1298e21d740aSUwe Kleine-König &dev_attr_numa_node.attr, 1299e21d740aSUwe Kleine-König &dev_attr_driver_override.attr, 1300e21d740aSUwe Kleine-König NULL, 1301e21d740aSUwe Kleine-König }; 1302e21d740aSUwe Kleine-König 1303e21d740aSUwe Kleine-König static umode_t platform_dev_attrs_visible(struct kobject *kobj, struct attribute *a, 1304e21d740aSUwe Kleine-König int n) 1305e21d740aSUwe Kleine-König { 1306e21d740aSUwe Kleine-König struct device *dev = container_of(kobj, typeof(*dev), kobj); 1307e21d740aSUwe Kleine-König 1308e21d740aSUwe Kleine-König if (a == &dev_attr_numa_node.attr && 1309e21d740aSUwe Kleine-König dev_to_node(dev) == NUMA_NO_NODE) 1310e21d740aSUwe Kleine-König return 0; 1311e21d740aSUwe Kleine-König 1312e21d740aSUwe Kleine-König return a->mode; 1313e21d740aSUwe Kleine-König } 1314e21d740aSUwe Kleine-König 13155a576764SRikard Falkeborn static const struct attribute_group platform_dev_group = { 1316e21d740aSUwe Kleine-König .attrs = platform_dev_attrs, 1317e21d740aSUwe Kleine-König .is_visible = platform_dev_attrs_visible, 1318e21d740aSUwe Kleine-König }; 1319e21d740aSUwe Kleine-König __ATTRIBUTE_GROUPS(platform_dev); 1320e21d740aSUwe Kleine-König 1321e21d740aSUwe Kleine-König 1322e21d740aSUwe Kleine-König /** 1323e21d740aSUwe Kleine-König * platform_match - bind platform device to platform driver. 1324e21d740aSUwe Kleine-König * @dev: device. 1325e21d740aSUwe Kleine-König * @drv: driver. 1326e21d740aSUwe Kleine-König * 1327e21d740aSUwe Kleine-König * Platform device IDs are assumed to be encoded like this: 1328e21d740aSUwe Kleine-König * "<name><instance>", where <name> is a short description of the type of 1329e21d740aSUwe Kleine-König * device, like "pci" or "floppy", and <instance> is the enumerated 1330e21d740aSUwe Kleine-König * instance of the device, like '0' or '42'. Driver IDs are simply 1331e21d740aSUwe Kleine-König * "<name>". So, extract the <name> from the platform_device structure, 1332e21d740aSUwe Kleine-König * and compare it against the name of the driver. Return whether they match 1333e21d740aSUwe Kleine-König * or not. 1334e21d740aSUwe Kleine-König */ 1335d69d8048SGreg Kroah-Hartman static int platform_match(struct device *dev, const struct device_driver *drv) 1336e21d740aSUwe Kleine-König { 1337e21d740aSUwe Kleine-König struct platform_device *pdev = to_platform_device(dev); 1338e21d740aSUwe Kleine-König struct platform_driver *pdrv = to_platform_driver(drv); 1339e21d740aSUwe Kleine-König 1340e21d740aSUwe Kleine-König /* When driver_override is set, only bind to the matching driver */ 1341e21d740aSUwe Kleine-König if (pdev->driver_override) 1342e21d740aSUwe Kleine-König return !strcmp(pdev->driver_override, drv->name); 1343e21d740aSUwe Kleine-König 1344e21d740aSUwe Kleine-König /* Attempt an OF style match first */ 1345e21d740aSUwe Kleine-König if (of_driver_match_device(dev, drv)) 1346e21d740aSUwe Kleine-König return 1; 1347e21d740aSUwe Kleine-König 1348e21d740aSUwe Kleine-König /* Then try ACPI style match */ 1349e21d740aSUwe Kleine-König if (acpi_driver_match_device(dev, drv)) 1350e21d740aSUwe Kleine-König return 1; 1351e21d740aSUwe Kleine-König 1352e21d740aSUwe Kleine-König /* Then try to match against the id table */ 1353e21d740aSUwe Kleine-König if (pdrv->id_table) 1354e21d740aSUwe Kleine-König return platform_match_id(pdrv->id_table, pdev) != NULL; 1355e21d740aSUwe Kleine-König 1356e21d740aSUwe Kleine-König /* fall-back to driver name match */ 1357e21d740aSUwe Kleine-König return (strcmp(pdev->name, drv->name) == 0); 1358e21d740aSUwe Kleine-König } 1359e21d740aSUwe Kleine-König 13602a81ada3SGreg Kroah-Hartman static int platform_uevent(const struct device *dev, struct kobj_uevent_env *env) 1361e21d740aSUwe Kleine-König { 13622a81ada3SGreg Kroah-Hartman const struct platform_device *pdev = to_platform_device(dev); 1363e21d740aSUwe Kleine-König int rc; 1364e21d740aSUwe Kleine-König 1365e21d740aSUwe Kleine-König /* Some devices have extra OF data and an OF-style MODALIAS */ 1366e21d740aSUwe Kleine-König rc = of_device_uevent_modalias(dev, env); 1367e21d740aSUwe Kleine-König if (rc != -ENODEV) 1368e21d740aSUwe Kleine-König return rc; 1369e21d740aSUwe Kleine-König 1370e21d740aSUwe Kleine-König rc = acpi_device_uevent_modalias(dev, env); 1371e21d740aSUwe Kleine-König if (rc != -ENODEV) 1372e21d740aSUwe Kleine-König return rc; 1373e21d740aSUwe Kleine-König 1374e21d740aSUwe Kleine-König add_uevent_var(env, "MODALIAS=%s%s", PLATFORM_MODULE_PREFIX, 1375e21d740aSUwe Kleine-König pdev->name); 1376e21d740aSUwe Kleine-König return 0; 1377e21d740aSUwe Kleine-König } 1378e21d740aSUwe Kleine-König 13799c30921fSUwe Kleine-König static int platform_probe(struct device *_dev) 13809c30921fSUwe Kleine-König { 13819c30921fSUwe Kleine-König struct platform_driver *drv = to_platform_driver(_dev->driver); 13829c30921fSUwe Kleine-König struct platform_device *dev = to_platform_device(_dev); 13839c30921fSUwe Kleine-König int ret; 13849c30921fSUwe Kleine-König 13859c30921fSUwe Kleine-König /* 13869c30921fSUwe Kleine-König * A driver registered using platform_driver_probe() cannot be bound 13879c30921fSUwe Kleine-König * again later because the probe function usually lives in __init code 13889c30921fSUwe Kleine-König * and so is gone. For these drivers .probe is set to 13899c30921fSUwe Kleine-König * platform_probe_fail in __platform_driver_probe(). Don't even prepare 13909c30921fSUwe Kleine-König * clocks and PM domains for these to match the traditional behaviour. 13919c30921fSUwe Kleine-König */ 13929c30921fSUwe Kleine-König if (unlikely(drv->probe == platform_probe_fail)) 13939c30921fSUwe Kleine-König return -ENXIO; 13949c30921fSUwe Kleine-König 13959c30921fSUwe Kleine-König ret = of_clk_set_defaults(_dev->of_node, false); 13969c30921fSUwe Kleine-König if (ret < 0) 13979c30921fSUwe Kleine-König return ret; 13989c30921fSUwe Kleine-König 13999c30921fSUwe Kleine-König ret = dev_pm_domain_attach(_dev, true); 14009c30921fSUwe Kleine-König if (ret) 14019c30921fSUwe Kleine-König goto out; 14029c30921fSUwe Kleine-König 14039c30921fSUwe Kleine-König if (drv->probe) { 14049c30921fSUwe Kleine-König ret = drv->probe(dev); 14059c30921fSUwe Kleine-König if (ret) 14069c30921fSUwe Kleine-König dev_pm_domain_detach(_dev, true); 14079c30921fSUwe Kleine-König } 14089c30921fSUwe Kleine-König 14099c30921fSUwe Kleine-König out: 14109c30921fSUwe Kleine-König if (drv->prevent_deferred_probe && ret == -EPROBE_DEFER) { 14119c30921fSUwe Kleine-König dev_warn(_dev, "probe deferral not supported\n"); 14129c30921fSUwe Kleine-König ret = -ENXIO; 14139c30921fSUwe Kleine-König } 14149c30921fSUwe Kleine-König 14159c30921fSUwe Kleine-König return ret; 14169c30921fSUwe Kleine-König } 14179c30921fSUwe Kleine-König 1418fc7a6209SUwe Kleine-König static void platform_remove(struct device *_dev) 14199c30921fSUwe Kleine-König { 14209c30921fSUwe Kleine-König struct platform_driver *drv = to_platform_driver(_dev->driver); 14219c30921fSUwe Kleine-König struct platform_device *dev = to_platform_device(_dev); 14229c30921fSUwe Kleine-König 14230edb555aSUwe Kleine-König if (drv->remove) 14240edb555aSUwe Kleine-König drv->remove(dev); 14259c30921fSUwe Kleine-König dev_pm_domain_detach(_dev, true); 14269c30921fSUwe Kleine-König } 14279c30921fSUwe Kleine-König 14289c30921fSUwe Kleine-König static void platform_shutdown(struct device *_dev) 14299c30921fSUwe Kleine-König { 14309c30921fSUwe Kleine-König struct platform_device *dev = to_platform_device(_dev); 143146e85af0SDmitry Baryshkov struct platform_driver *drv; 14329c30921fSUwe Kleine-König 143346e85af0SDmitry Baryshkov if (!_dev->driver) 143446e85af0SDmitry Baryshkov return; 143546e85af0SDmitry Baryshkov 143646e85af0SDmitry Baryshkov drv = to_platform_driver(_dev->driver); 14379c30921fSUwe Kleine-König if (drv->shutdown) 14389c30921fSUwe Kleine-König drv->shutdown(dev); 14399c30921fSUwe Kleine-König } 14409c30921fSUwe Kleine-König 14414a6d9dd5SLu Baolu static int platform_dma_configure(struct device *dev) 144207397df2SNipun Gupta { 1443512881eaSLu Baolu struct platform_driver *drv = to_platform_driver(dev->driver); 1444243e1b77SAndy Shevchenko struct fwnode_handle *fwnode = dev_fwnode(dev); 144507397df2SNipun Gupta enum dev_dma_attr attr; 144607397df2SNipun Gupta int ret = 0; 144707397df2SNipun Gupta 1448243e1b77SAndy Shevchenko if (is_of_node(fwnode)) { 1449243e1b77SAndy Shevchenko ret = of_dma_configure(dev, to_of_node(fwnode), true); 1450243e1b77SAndy Shevchenko } else if (is_acpi_device_node(fwnode)) { 1451243e1b77SAndy Shevchenko attr = acpi_get_dma_attr(to_acpi_device_node(fwnode)); 145207397df2SNipun Gupta ret = acpi_dma_configure(dev, attr); 145307397df2SNipun Gupta } 1454a549e3aaSAndy Shevchenko if (ret || drv->driver_managed_dma) 1455a549e3aaSAndy Shevchenko return ret; 145607397df2SNipun Gupta 1457512881eaSLu Baolu ret = iommu_device_use_default_domain(dev); 1458512881eaSLu Baolu if (ret) 1459512881eaSLu Baolu arch_teardown_dma_ops(dev); 1460512881eaSLu Baolu 146107397df2SNipun Gupta return ret; 146207397df2SNipun Gupta } 146307397df2SNipun Gupta 1464512881eaSLu Baolu static void platform_dma_cleanup(struct device *dev) 1465512881eaSLu Baolu { 1466512881eaSLu Baolu struct platform_driver *drv = to_platform_driver(dev->driver); 1467512881eaSLu Baolu 1468512881eaSLu Baolu if (!drv->driver_managed_dma) 1469512881eaSLu Baolu iommu_device_unuse_default_domain(dev); 1470512881eaSLu Baolu } 1471512881eaSLu Baolu 1472d9ab7716SDmitry Torokhov static const struct dev_pm_ops platform_dev_pm_ops = { 147386854b43SCai Huoqing SET_RUNTIME_PM_OPS(pm_generic_runtime_suspend, pm_generic_runtime_resume, NULL) 147469c9dd1eSRafael J. Wysocki USE_PLATFORM_PM_SLEEP_OPS 147525e18499SRafael J. Wysocki }; 147625e18499SRafael J. Wysocki 1477*24e041e1SKunwu Chan const struct bus_type platform_bus_type = { 14781da177e4SLinus Torvalds .name = "platform", 1479d06262e5SGreg Kroah-Hartman .dev_groups = platform_dev_groups, 14801da177e4SLinus Torvalds .match = platform_match, 1481a0245f7aSDavid Brownell .uevent = platform_uevent, 14829c30921fSUwe Kleine-König .probe = platform_probe, 14839c30921fSUwe Kleine-König .remove = platform_remove, 14849c30921fSUwe Kleine-König .shutdown = platform_shutdown, 148507397df2SNipun Gupta .dma_configure = platform_dma_configure, 1486512881eaSLu Baolu .dma_cleanup = platform_dma_cleanup, 14879d730229SMagnus Damm .pm = &platform_dev_pm_ops, 14881da177e4SLinus Torvalds }; 1489a96b2042SDmitry Torokhov EXPORT_SYMBOL_GPL(platform_bus_type); 14901da177e4SLinus Torvalds 1491492c8872SSami Tolvanen static inline int __platform_match(struct device *dev, const void *drv) 1492492c8872SSami Tolvanen { 1493492c8872SSami Tolvanen return platform_match(dev, (struct device_driver *)drv); 1494492c8872SSami Tolvanen } 1495492c8872SSami Tolvanen 149636f3313dSSuzuki K Poulose /** 149736f3313dSSuzuki K Poulose * platform_find_device_by_driver - Find a platform device with a given 149836f3313dSSuzuki K Poulose * driver. 149936f3313dSSuzuki K Poulose * @start: The device to start the search from. 150036f3313dSSuzuki K Poulose * @drv: The device driver to look for. 150136f3313dSSuzuki K Poulose */ 150236f3313dSSuzuki K Poulose struct device *platform_find_device_by_driver(struct device *start, 150336f3313dSSuzuki K Poulose const struct device_driver *drv) 150436f3313dSSuzuki K Poulose { 150536f3313dSSuzuki K Poulose return bus_find_device(&platform_bus_type, start, drv, 1506492c8872SSami Tolvanen __platform_match); 150736f3313dSSuzuki K Poulose } 150836f3313dSSuzuki K Poulose EXPORT_SYMBOL_GPL(platform_find_device_by_driver); 150936f3313dSSuzuki K Poulose 1510eecd37e1SGuenter Roeck void __weak __init early_platform_cleanup(void) { } 1511eecd37e1SGuenter Roeck 15121da177e4SLinus Torvalds int __init platform_bus_init(void) 15131da177e4SLinus Torvalds { 1514fbfb1445SCornelia Huck int error; 1515fbfb1445SCornelia Huck 1516eecd37e1SGuenter Roeck early_platform_cleanup(); 1517eecd37e1SGuenter Roeck 1518fbfb1445SCornelia Huck error = device_register(&platform_bus); 1519c8ae1674SArvind Yadav if (error) { 1520c8ae1674SArvind Yadav put_device(&platform_bus); 1521fbfb1445SCornelia Huck return error; 1522c8ae1674SArvind Yadav } 1523fbfb1445SCornelia Huck error = bus_register(&platform_bus_type); 1524fbfb1445SCornelia Huck if (error) 1525fbfb1445SCornelia Huck device_unregister(&platform_bus); 152673aca58bSRob Herring 1527fbfb1445SCornelia Huck return error; 15281da177e4SLinus Torvalds } 1529