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> 181da177e4SLinus Torvalds #include <linux/dma-mapping.h> 1957c8a661SMike Rapoport #include <linux/memblock.h> 201da177e4SLinus Torvalds #include <linux/err.h> 214e57b681STim Schmielau #include <linux/slab.h> 229d730229SMagnus Damm #include <linux/pm_runtime.h> 23f48c767cSUlf Hansson #include <linux/pm_domain.h> 24689ae231SJean Delvare #include <linux/idr.h> 2591e56878SMika Westerberg #include <linux/acpi.h> 2686be408bSSylwester Nawrocki #include <linux/clk/clk-conf.h> 273d713e0eSKim Phillips #include <linux/limits.h> 2800bbc1d8SMika Westerberg #include <linux/property.h> 29967d3010SQian Cai #include <linux/kmemleak.h> 3039cc539fSSimon Schwartz #include <linux/types.h> 311da177e4SLinus Torvalds 32a1bdc7aaSBen Dooks #include "base.h" 33bed2b42dSRafael J. Wysocki #include "power/power.h" 34a1bdc7aaSBen Dooks 35689ae231SJean Delvare /* For automatically allocated device IDs */ 36689ae231SJean Delvare static DEFINE_IDA(platform_devid_ida); 37689ae231SJean Delvare 381da177e4SLinus Torvalds struct device platform_bus = { 391e0b2cf9SKay Sievers .init_name = "platform", 401da177e4SLinus Torvalds }; 41a96b2042SDmitry Torokhov EXPORT_SYMBOL_GPL(platform_bus); 421da177e4SLinus Torvalds 431da177e4SLinus Torvalds /** 441da177e4SLinus Torvalds * platform_get_resource - get a resource for a device 451da177e4SLinus Torvalds * @dev: platform device 461da177e4SLinus Torvalds * @type: resource type 471da177e4SLinus Torvalds * @num: resource index 481da177e4SLinus Torvalds */ 494a3ad20cSGreg Kroah-Hartman struct resource *platform_get_resource(struct platform_device *dev, 504a3ad20cSGreg Kroah-Hartman unsigned int type, unsigned int num) 511da177e4SLinus Torvalds { 5239cc539fSSimon Schwartz u32 i; 531da177e4SLinus Torvalds 541da177e4SLinus Torvalds for (i = 0; i < dev->num_resources; i++) { 551da177e4SLinus Torvalds struct resource *r = &dev->resource[i]; 561da177e4SLinus Torvalds 57c9f66169SMagnus Damm if (type == resource_type(r) && num-- == 0) 581da177e4SLinus Torvalds return r; 591da177e4SLinus Torvalds } 601da177e4SLinus Torvalds return NULL; 611da177e4SLinus Torvalds } 62a96b2042SDmitry Torokhov EXPORT_SYMBOL_GPL(platform_get_resource); 631da177e4SLinus Torvalds 64bb6243b4SBartosz Golaszewski #ifdef CONFIG_HAS_IOMEM 651da177e4SLinus Torvalds /** 667945f929SBartosz Golaszewski * devm_platform_ioremap_resource - call devm_ioremap_resource() for a platform 677945f929SBartosz Golaszewski * device 687945f929SBartosz Golaszewski * 697945f929SBartosz Golaszewski * @pdev: platform device to use both for memory resource lookup as well as 707067c96eSBartosz Golaszewski * resource management 717945f929SBartosz Golaszewski * @index: resource index 727945f929SBartosz Golaszewski */ 737945f929SBartosz Golaszewski void __iomem *devm_platform_ioremap_resource(struct platform_device *pdev, 747945f929SBartosz Golaszewski unsigned int index) 757945f929SBartosz Golaszewski { 767945f929SBartosz Golaszewski struct resource *res; 777945f929SBartosz Golaszewski 787945f929SBartosz Golaszewski res = platform_get_resource(pdev, IORESOURCE_MEM, index); 797945f929SBartosz Golaszewski return devm_ioremap_resource(&pdev->dev, res); 807945f929SBartosz Golaszewski } 817945f929SBartosz Golaszewski EXPORT_SYMBOL_GPL(devm_platform_ioremap_resource); 82bb6243b4SBartosz Golaszewski 83bb6243b4SBartosz Golaszewski /** 84bb6243b4SBartosz Golaszewski * devm_platform_ioremap_resource_wc - write-combined variant of 85bb6243b4SBartosz Golaszewski * devm_platform_ioremap_resource() 86bb6243b4SBartosz Golaszewski * 87bb6243b4SBartosz Golaszewski * @pdev: platform device to use both for memory resource lookup as well as 88bb6243b4SBartosz Golaszewski * resource management 89bb6243b4SBartosz Golaszewski * @index: resource index 90bb6243b4SBartosz Golaszewski */ 91bb6243b4SBartosz Golaszewski void __iomem *devm_platform_ioremap_resource_wc(struct platform_device *pdev, 92bb6243b4SBartosz Golaszewski unsigned int index) 93bb6243b4SBartosz Golaszewski { 94bb6243b4SBartosz Golaszewski struct resource *res; 95bb6243b4SBartosz Golaszewski 96bb6243b4SBartosz Golaszewski res = platform_get_resource(pdev, IORESOURCE_MEM, index); 97bb6243b4SBartosz Golaszewski return devm_ioremap_resource_wc(&pdev->dev, res); 98bb6243b4SBartosz Golaszewski } 99c9c8641dSBartosz Golaszewski 100c9c8641dSBartosz Golaszewski /** 101c9c8641dSBartosz Golaszewski * devm_platform_ioremap_resource_byname - call devm_ioremap_resource for 102c9c8641dSBartosz Golaszewski * a platform device, retrieve the 103c9c8641dSBartosz Golaszewski * resource by name 104c9c8641dSBartosz Golaszewski * 105c9c8641dSBartosz Golaszewski * @pdev: platform device to use both for memory resource lookup as well as 106c9c8641dSBartosz Golaszewski * resource management 107c9c8641dSBartosz Golaszewski * @name: name of the resource 108c9c8641dSBartosz Golaszewski */ 109c9c8641dSBartosz Golaszewski void __iomem * 110c9c8641dSBartosz Golaszewski devm_platform_ioremap_resource_byname(struct platform_device *pdev, 111c9c8641dSBartosz Golaszewski const char *name) 112c9c8641dSBartosz Golaszewski { 113c9c8641dSBartosz Golaszewski struct resource *res; 114c9c8641dSBartosz Golaszewski 115c9c8641dSBartosz Golaszewski res = platform_get_resource_byname(pdev, IORESOURCE_MEM, name); 116c9c8641dSBartosz Golaszewski return devm_ioremap_resource(&pdev->dev, res); 117c9c8641dSBartosz Golaszewski } 118c9c8641dSBartosz Golaszewski EXPORT_SYMBOL_GPL(devm_platform_ioremap_resource_byname); 119837ccda3SBartosz Golaszewski #endif /* CONFIG_HAS_IOMEM */ 1207945f929SBartosz Golaszewski 121ec4e2906SUwe Kleine-König /** 122ec4e2906SUwe Kleine-König * platform_get_irq_optional - get an optional IRQ for a device 123ec4e2906SUwe Kleine-König * @dev: platform device 124ec4e2906SUwe Kleine-König * @num: IRQ number index 125ec4e2906SUwe Kleine-König * 126ec4e2906SUwe Kleine-König * Gets an IRQ for a platform device. Device drivers should check the return 127ec4e2906SUwe Kleine-König * value for errors so as to not pass a negative integer value to the 128ec4e2906SUwe Kleine-König * request_irq() APIs. This is the same as platform_get_irq(), except that it 129ec4e2906SUwe Kleine-König * does not print an error message if an IRQ can not be obtained. 130ec4e2906SUwe Kleine-König * 131ec4e2906SUwe Kleine-König * Example: 132ec4e2906SUwe Kleine-König * int irq = platform_get_irq_optional(pdev, 0); 133ec4e2906SUwe Kleine-König * if (irq < 0) 134ec4e2906SUwe Kleine-König * return irq; 135ec4e2906SUwe Kleine-König * 136ec4e2906SUwe Kleine-König * Return: IRQ number on success, negative error number on failure. 137ec4e2906SUwe Kleine-König */ 138ec4e2906SUwe Kleine-König int platform_get_irq_optional(struct platform_device *dev, unsigned int num) 1391da177e4SLinus Torvalds { 1405cf8f7dbSAndreas Larsson #ifdef CONFIG_SPARC 1415cf8f7dbSAndreas Larsson /* sparc does not have irqs represented as IORESOURCE_IRQ resources */ 1425cf8f7dbSAndreas Larsson if (!dev || num >= dev->archdata.num_irqs) 1435cf8f7dbSAndreas Larsson return -ENXIO; 1445cf8f7dbSAndreas Larsson return dev->archdata.irqs[num]; 1455cf8f7dbSAndreas Larsson #else 1469ec36cafSRob Herring struct resource *r; 147aff008adSGuenter Roeck int ret; 148aff008adSGuenter Roeck 14971564a26SAndy Shevchenko if (IS_ENABLED(CONFIG_OF_IRQ) && dev->dev.of_node) { 150aff008adSGuenter Roeck ret = of_irq_get(dev->dev.of_node, num); 151e330b9a6SSergei Shtylyov if (ret > 0 || ret == -EPROBE_DEFER) 152aff008adSGuenter Roeck return ret; 153aff008adSGuenter Roeck } 1549ec36cafSRob Herring 1559ec36cafSRob Herring r = platform_get_resource(dev, IORESOURCE_IRQ, num); 156d44fa3d4SAgustin Vega-Frias if (has_acpi_companion(&dev->dev)) { 157d44fa3d4SAgustin Vega-Frias if (r && r->flags & IORESOURCE_DISABLED) { 158d44fa3d4SAgustin Vega-Frias ret = acpi_irq_get(ACPI_HANDLE(&dev->dev), num, r); 159d44fa3d4SAgustin Vega-Frias if (ret) 160d44fa3d4SAgustin Vega-Frias return ret; 161d44fa3d4SAgustin Vega-Frias } 162d44fa3d4SAgustin Vega-Frias } 163d44fa3d4SAgustin Vega-Frias 1647085a740SLinus Walleij /* 1657085a740SLinus Walleij * The resources may pass trigger flags to the irqs that need 1667085a740SLinus Walleij * to be set up. It so happens that the trigger flags for 1677085a740SLinus Walleij * IORESOURCE_BITS correspond 1-to-1 to the IRQF_TRIGGER* 1687085a740SLinus Walleij * settings. 1697085a740SLinus Walleij */ 17060ca5e0dSGuenter Roeck if (r && r->flags & IORESOURCE_BITS) { 17160ca5e0dSGuenter Roeck struct irq_data *irqd; 17260ca5e0dSGuenter Roeck 17360ca5e0dSGuenter Roeck irqd = irq_get_irq_data(r->start); 17460ca5e0dSGuenter Roeck if (!irqd) 17560ca5e0dSGuenter Roeck return -ENXIO; 17660ca5e0dSGuenter Roeck irqd_set_trigger_type(irqd, r->flags & IORESOURCE_BITS); 17760ca5e0dSGuenter Roeck } 1781da177e4SLinus Torvalds 179daaef255SEnrico Granata if (r) 180daaef255SEnrico Granata return r->start; 181daaef255SEnrico Granata 182daaef255SEnrico Granata /* 183daaef255SEnrico Granata * For the index 0 interrupt, allow falling back to GpioInt 184daaef255SEnrico Granata * resources. While a device could have both Interrupt and GpioInt 185daaef255SEnrico Granata * resources, making this fallback ambiguous, in many common cases 186daaef255SEnrico Granata * the device will only expose one IRQ, and this fallback 187daaef255SEnrico Granata * allows a common code path across either kind of resource. 188daaef255SEnrico Granata */ 18946c42d84SBrian Norris if (num == 0 && has_acpi_companion(&dev->dev)) { 19071564a26SAndy Shevchenko ret = acpi_dev_gpio_irq_get(ACPI_COMPANION(&dev->dev), num); 19146c42d84SBrian Norris /* Our callers expect -ENXIO for missing IRQs. */ 19246c42d84SBrian Norris if (ret >= 0 || ret == -EPROBE_DEFER) 19346c42d84SBrian Norris return ret; 19446c42d84SBrian Norris } 195daaef255SEnrico Granata 196daaef255SEnrico Granata return -ENXIO; 1975cf8f7dbSAndreas Larsson #endif 1981da177e4SLinus Torvalds } 199ec4e2906SUwe Kleine-König EXPORT_SYMBOL_GPL(platform_get_irq_optional); 2007723f4c5SStephen Boyd 2017723f4c5SStephen Boyd /** 2027723f4c5SStephen Boyd * platform_get_irq - get an IRQ for a device 2037723f4c5SStephen Boyd * @dev: platform device 2047723f4c5SStephen Boyd * @num: IRQ number index 2057723f4c5SStephen Boyd * 2067723f4c5SStephen Boyd * Gets an IRQ for a platform device and prints an error message if finding the 2077723f4c5SStephen Boyd * IRQ fails. Device drivers should check the return value for errors so as to 2087723f4c5SStephen Boyd * not pass a negative integer value to the request_irq() APIs. 2097723f4c5SStephen Boyd * 2107723f4c5SStephen Boyd * Example: 2117723f4c5SStephen Boyd * int irq = platform_get_irq(pdev, 0); 2127723f4c5SStephen Boyd * if (irq < 0) 2137723f4c5SStephen Boyd * return irq; 2147723f4c5SStephen Boyd * 2157723f4c5SStephen Boyd * Return: IRQ number on success, negative error number on failure. 2167723f4c5SStephen Boyd */ 2177723f4c5SStephen Boyd int platform_get_irq(struct platform_device *dev, unsigned int num) 2187723f4c5SStephen Boyd { 2197723f4c5SStephen Boyd int ret; 2207723f4c5SStephen Boyd 221ec4e2906SUwe Kleine-König ret = platform_get_irq_optional(dev, num); 2227723f4c5SStephen Boyd if (ret < 0 && ret != -EPROBE_DEFER) 2237723f4c5SStephen Boyd dev_err(&dev->dev, "IRQ index %u not found\n", num); 2247723f4c5SStephen Boyd 2257723f4c5SStephen Boyd return ret; 2267723f4c5SStephen Boyd } 227a96b2042SDmitry Torokhov EXPORT_SYMBOL_GPL(platform_get_irq); 2281da177e4SLinus Torvalds 2291da177e4SLinus Torvalds /** 2304b83555dSStephen Boyd * platform_irq_count - Count the number of IRQs a platform device uses 2314b83555dSStephen Boyd * @dev: platform device 2324b83555dSStephen Boyd * 2334b83555dSStephen Boyd * Return: Number of IRQs a platform device uses or EPROBE_DEFER 2344b83555dSStephen Boyd */ 2354b83555dSStephen Boyd int platform_irq_count(struct platform_device *dev) 2364b83555dSStephen Boyd { 2374b83555dSStephen Boyd int ret, nr = 0; 2384b83555dSStephen Boyd 239ec4e2906SUwe Kleine-König while ((ret = platform_get_irq_optional(dev, nr)) >= 0) 2404b83555dSStephen Boyd nr++; 2414b83555dSStephen Boyd 2424b83555dSStephen Boyd if (ret == -EPROBE_DEFER) 2434b83555dSStephen Boyd return ret; 2444b83555dSStephen Boyd 2454b83555dSStephen Boyd return nr; 2464b83555dSStephen Boyd } 2474b83555dSStephen Boyd EXPORT_SYMBOL_GPL(platform_irq_count); 2484b83555dSStephen Boyd 2494b83555dSStephen Boyd /** 2501da177e4SLinus Torvalds * platform_get_resource_byname - get a resource for a device by name 2511da177e4SLinus Torvalds * @dev: platform device 2521da177e4SLinus Torvalds * @type: resource type 2531da177e4SLinus Torvalds * @name: resource name 2541da177e4SLinus Torvalds */ 2554a3ad20cSGreg Kroah-Hartman struct resource *platform_get_resource_byname(struct platform_device *dev, 256c0afe7baSLinus Walleij unsigned int type, 257c0afe7baSLinus Walleij const char *name) 2581da177e4SLinus Torvalds { 25939cc539fSSimon Schwartz u32 i; 2601da177e4SLinus Torvalds 2611da177e4SLinus Torvalds for (i = 0; i < dev->num_resources; i++) { 2621da177e4SLinus Torvalds struct resource *r = &dev->resource[i]; 2631da177e4SLinus Torvalds 2641b8cb929SPeter Ujfalusi if (unlikely(!r->name)) 2651b8cb929SPeter Ujfalusi continue; 2661b8cb929SPeter Ujfalusi 267c9f66169SMagnus Damm if (type == resource_type(r) && !strcmp(r->name, name)) 2681da177e4SLinus Torvalds return r; 2691da177e4SLinus Torvalds } 2701da177e4SLinus Torvalds return NULL; 2711da177e4SLinus Torvalds } 272a96b2042SDmitry Torokhov EXPORT_SYMBOL_GPL(platform_get_resource_byname); 2731da177e4SLinus Torvalds 274f1da567fSHans de Goede static int __platform_get_irq_byname(struct platform_device *dev, 275f1da567fSHans de Goede const char *name) 2761da177e4SLinus Torvalds { 277ad69674eSGrygorii Strashko struct resource *r; 278aff008adSGuenter Roeck int ret; 279aff008adSGuenter Roeck 28071564a26SAndy Shevchenko if (IS_ENABLED(CONFIG_OF_IRQ) && dev->dev.of_node) { 281aff008adSGuenter Roeck ret = of_irq_get_byname(dev->dev.of_node, name); 282e330b9a6SSergei Shtylyov if (ret > 0 || ret == -EPROBE_DEFER) 283aff008adSGuenter Roeck return ret; 284aff008adSGuenter Roeck } 285ad69674eSGrygorii Strashko 286ad69674eSGrygorii Strashko r = platform_get_resource_byname(dev, IORESOURCE_IRQ, name); 2877723f4c5SStephen Boyd if (r) 2887723f4c5SStephen Boyd return r->start; 2897723f4c5SStephen Boyd 2907723f4c5SStephen Boyd return -ENXIO; 2911da177e4SLinus Torvalds } 292f1da567fSHans de Goede 293f1da567fSHans de Goede /** 294f1da567fSHans de Goede * platform_get_irq_byname - get an IRQ for a device by name 295f1da567fSHans de Goede * @dev: platform device 296f1da567fSHans de Goede * @name: IRQ name 297f1da567fSHans de Goede * 298f1da567fSHans de Goede * Get an IRQ like platform_get_irq(), but then by name rather then by index. 299f1da567fSHans de Goede * 300f1da567fSHans de Goede * Return: IRQ number on success, negative error number on failure. 301f1da567fSHans de Goede */ 302f1da567fSHans de Goede int platform_get_irq_byname(struct platform_device *dev, const char *name) 303f1da567fSHans de Goede { 304f1da567fSHans de Goede int ret; 305f1da567fSHans de Goede 306f1da567fSHans de Goede ret = __platform_get_irq_byname(dev, name); 307f1da567fSHans de Goede if (ret < 0 && ret != -EPROBE_DEFER) 308f1da567fSHans de Goede dev_err(&dev->dev, "IRQ %s not found\n", name); 309f1da567fSHans de Goede 310f1da567fSHans de Goede return ret; 311f1da567fSHans de Goede } 312a96b2042SDmitry Torokhov EXPORT_SYMBOL_GPL(platform_get_irq_byname); 3131da177e4SLinus Torvalds 3141da177e4SLinus Torvalds /** 315f1da567fSHans de Goede * platform_get_irq_byname_optional - get an optional IRQ for a device by name 316f1da567fSHans de Goede * @dev: platform device 317f1da567fSHans de Goede * @name: IRQ name 318f1da567fSHans de Goede * 319f1da567fSHans de Goede * Get an optional IRQ by name like platform_get_irq_byname(). Except that it 320f1da567fSHans de Goede * does not print an error message if an IRQ can not be obtained. 321f1da567fSHans de Goede * 322f1da567fSHans de Goede * Return: IRQ number on success, negative error number on failure. 323f1da567fSHans de Goede */ 324f1da567fSHans de Goede int platform_get_irq_byname_optional(struct platform_device *dev, 325f1da567fSHans de Goede const char *name) 326f1da567fSHans de Goede { 327f1da567fSHans de Goede return __platform_get_irq_byname(dev, name); 328f1da567fSHans de Goede } 329f1da567fSHans de Goede EXPORT_SYMBOL_GPL(platform_get_irq_byname_optional); 330f1da567fSHans de Goede 331f1da567fSHans de Goede /** 3321da177e4SLinus Torvalds * platform_add_devices - add a numbers of platform devices 3331da177e4SLinus Torvalds * @devs: array of platform devices to add 3341da177e4SLinus Torvalds * @num: number of platform devices in array 3351da177e4SLinus Torvalds */ 3361da177e4SLinus Torvalds int platform_add_devices(struct platform_device **devs, int num) 3371da177e4SLinus Torvalds { 3381da177e4SLinus Torvalds int i, ret = 0; 3391da177e4SLinus Torvalds 3401da177e4SLinus Torvalds for (i = 0; i < num; i++) { 3411da177e4SLinus Torvalds ret = platform_device_register(devs[i]); 3421da177e4SLinus Torvalds if (ret) { 3431da177e4SLinus Torvalds while (--i >= 0) 3441da177e4SLinus Torvalds platform_device_unregister(devs[i]); 3451da177e4SLinus Torvalds break; 3461da177e4SLinus Torvalds } 3471da177e4SLinus Torvalds } 3481da177e4SLinus Torvalds 3491da177e4SLinus Torvalds return ret; 3501da177e4SLinus Torvalds } 351a96b2042SDmitry Torokhov EXPORT_SYMBOL_GPL(platform_add_devices); 3521da177e4SLinus Torvalds 35337c12e74SRussell King struct platform_object { 35437c12e74SRussell King struct platform_device pdev; 3551cec24c5SYann Droneaud char name[]; 35637c12e74SRussell King }; 35737c12e74SRussell King 358cdfee562SChristoph Hellwig /* 359cdfee562SChristoph Hellwig * Set up default DMA mask for platform devices if the they weren't 360cdfee562SChristoph Hellwig * previously set by the architecture / DT. 361cdfee562SChristoph Hellwig */ 362cdfee562SChristoph Hellwig static void setup_pdev_dma_masks(struct platform_device *pdev) 363cdfee562SChristoph Hellwig { 364cdfee562SChristoph Hellwig if (!pdev->dev.coherent_dma_mask) 365cdfee562SChristoph Hellwig pdev->dev.coherent_dma_mask = DMA_BIT_MASK(32); 366cdfee562SChristoph Hellwig if (!pdev->dma_mask) 367cdfee562SChristoph Hellwig pdev->dma_mask = DMA_BIT_MASK(32); 368cdfee562SChristoph Hellwig if (!pdev->dev.dma_mask) 369cdfee562SChristoph Hellwig pdev->dev.dma_mask = &pdev->dma_mask; 370cdfee562SChristoph Hellwig }; 371cdfee562SChristoph Hellwig 3721da177e4SLinus Torvalds /** 3733c31f07aSBen Hutchings * platform_device_put - destroy a platform device 37437c12e74SRussell King * @pdev: platform device to free 37537c12e74SRussell King * 3764a3ad20cSGreg Kroah-Hartman * Free all memory associated with a platform device. This function must 3774a3ad20cSGreg Kroah-Hartman * _only_ be externally called in error cases. All other usage is a bug. 37837c12e74SRussell King */ 37937c12e74SRussell King void platform_device_put(struct platform_device *pdev) 38037c12e74SRussell King { 38199fef587SAndy Shevchenko if (!IS_ERR_OR_NULL(pdev)) 38237c12e74SRussell King put_device(&pdev->dev); 38337c12e74SRussell King } 38437c12e74SRussell King EXPORT_SYMBOL_GPL(platform_device_put); 38537c12e74SRussell King 38637c12e74SRussell King static void platform_device_release(struct device *dev) 38737c12e74SRussell King { 3884a3ad20cSGreg Kroah-Hartman struct platform_object *pa = container_of(dev, struct platform_object, 3894a3ad20cSGreg Kroah-Hartman pdev.dev); 39037c12e74SRussell King 3917096d042SGrant Likely of_device_node_put(&pa->pdev.dev); 39237c12e74SRussell King kfree(pa->pdev.dev.platform_data); 393e710d7d5SSamuel Ortiz kfree(pa->pdev.mfd_cell); 39437c12e74SRussell King kfree(pa->pdev.resource); 3953d713e0eSKim Phillips kfree(pa->pdev.driver_override); 39637c12e74SRussell King kfree(pa); 39737c12e74SRussell King } 39837c12e74SRussell King 39937c12e74SRussell King /** 4003c31f07aSBen Hutchings * platform_device_alloc - create a platform device 40137c12e74SRussell King * @name: base name of the device we're adding 40237c12e74SRussell King * @id: instance id 40337c12e74SRussell King * 40437c12e74SRussell King * Create a platform device object which can have other objects attached 40537c12e74SRussell King * to it, and which will have attached objects freed when it is released. 40637c12e74SRussell King */ 4071359555eSJean Delvare struct platform_device *platform_device_alloc(const char *name, int id) 40837c12e74SRussell King { 40937c12e74SRussell King struct platform_object *pa; 41037c12e74SRussell King 4111cec24c5SYann Droneaud pa = kzalloc(sizeof(*pa) + strlen(name) + 1, GFP_KERNEL); 41237c12e74SRussell King if (pa) { 41337c12e74SRussell King strcpy(pa->name, name); 41437c12e74SRussell King pa->pdev.name = pa->name; 41537c12e74SRussell King pa->pdev.id = id; 41637c12e74SRussell King device_initialize(&pa->pdev.dev); 41737c12e74SRussell King pa->pdev.dev.release = platform_device_release; 418cdfee562SChristoph Hellwig setup_pdev_dma_masks(&pa->pdev); 41937c12e74SRussell King } 42037c12e74SRussell King 42137c12e74SRussell King return pa ? &pa->pdev : NULL; 42237c12e74SRussell King } 42337c12e74SRussell King EXPORT_SYMBOL_GPL(platform_device_alloc); 42437c12e74SRussell King 42537c12e74SRussell King /** 4263c31f07aSBen Hutchings * platform_device_add_resources - add resources to a platform device 42737c12e74SRussell King * @pdev: platform device allocated by platform_device_alloc to add resources to 42837c12e74SRussell King * @res: set of resources that needs to be allocated for the device 42937c12e74SRussell King * @num: number of resources 43037c12e74SRussell King * 43137c12e74SRussell King * Add a copy of the resources to the platform device. The memory 4324a3ad20cSGreg Kroah-Hartman * associated with the resources will be freed when the platform device is 4334a3ad20cSGreg Kroah-Hartman * released. 43437c12e74SRussell King */ 4354a3ad20cSGreg Kroah-Hartman int platform_device_add_resources(struct platform_device *pdev, 4360b7f1a7eSGeert Uytterhoeven const struct resource *res, unsigned int num) 43737c12e74SRussell King { 438cea89623SUwe Kleine-König struct resource *r = NULL; 43937c12e74SRussell King 440cea89623SUwe Kleine-König if (res) { 4413e61dfd8SUwe Kleine-König r = kmemdup(res, sizeof(struct resource) * num, GFP_KERNEL); 442cea89623SUwe Kleine-König if (!r) 443cea89623SUwe Kleine-König return -ENOMEM; 444cea89623SUwe Kleine-König } 445cea89623SUwe Kleine-König 4464a03d6f7SUwe Kleine-König kfree(pdev->resource); 44737c12e74SRussell King pdev->resource = r; 44837c12e74SRussell King pdev->num_resources = num; 4493e61dfd8SUwe Kleine-König return 0; 45037c12e74SRussell King } 45137c12e74SRussell King EXPORT_SYMBOL_GPL(platform_device_add_resources); 45237c12e74SRussell King 45337c12e74SRussell King /** 4543c31f07aSBen Hutchings * platform_device_add_data - add platform-specific data to a platform device 45537c12e74SRussell King * @pdev: platform device allocated by platform_device_alloc to add resources to 45637c12e74SRussell King * @data: platform specific data for this platform device 45737c12e74SRussell King * @size: size of platform specific data 45837c12e74SRussell King * 4594a3ad20cSGreg Kroah-Hartman * Add a copy of platform specific data to the platform device's 4604a3ad20cSGreg Kroah-Hartman * platform_data pointer. The memory associated with the platform data 4614a3ad20cSGreg Kroah-Hartman * will be freed when the platform device is released. 46237c12e74SRussell King */ 4634a3ad20cSGreg Kroah-Hartman int platform_device_add_data(struct platform_device *pdev, const void *data, 4644a3ad20cSGreg Kroah-Hartman size_t size) 46537c12e74SRussell King { 46627a33f9eSUwe Kleine-König void *d = NULL; 46737c12e74SRussell King 46827a33f9eSUwe Kleine-König if (data) { 4695cfc64ceSAnton Vorontsov d = kmemdup(data, size, GFP_KERNEL); 47027a33f9eSUwe Kleine-König if (!d) 47127a33f9eSUwe Kleine-König return -ENOMEM; 47227a33f9eSUwe Kleine-König } 47327a33f9eSUwe Kleine-König 474251e031dSUwe Kleine-König kfree(pdev->dev.platform_data); 47537c12e74SRussell King pdev->dev.platform_data = d; 476daa41226SAndrew Morton return 0; 47737c12e74SRussell King } 47837c12e74SRussell King EXPORT_SYMBOL_GPL(platform_device_add_data); 47937c12e74SRussell King 48037c12e74SRussell King /** 48100bbc1d8SMika Westerberg * platform_device_add_properties - add built-in properties to a platform device 48200bbc1d8SMika Westerberg * @pdev: platform device to add properties to 483f4d05266SHeikki Krogerus * @properties: null terminated array of properties to add 48400bbc1d8SMika Westerberg * 485f4d05266SHeikki Krogerus * The function will take deep copy of @properties and attach the copy to the 486f4d05266SHeikki Krogerus * platform device. The memory associated with properties will be freed when the 487f4d05266SHeikki Krogerus * platform device is released. 48800bbc1d8SMika Westerberg */ 48900bbc1d8SMika Westerberg int platform_device_add_properties(struct platform_device *pdev, 490277036f0SJan Kiszka const struct property_entry *properties) 49100bbc1d8SMika Westerberg { 492f4d05266SHeikki Krogerus return device_add_properties(&pdev->dev, properties); 49300bbc1d8SMika Westerberg } 49400bbc1d8SMika Westerberg EXPORT_SYMBOL_GPL(platform_device_add_properties); 49500bbc1d8SMika Westerberg 49600bbc1d8SMika Westerberg /** 49737c12e74SRussell King * platform_device_add - add a platform device to device hierarchy 49867be2dd1SMartin Waitz * @pdev: platform device we're adding 4991da177e4SLinus Torvalds * 50037c12e74SRussell King * This is part 2 of platform_device_register(), though may be called 50137c12e74SRussell King * separately _iff_ pdev was allocated by platform_device_alloc(). 5021da177e4SLinus Torvalds */ 50337c12e74SRussell King int platform_device_add(struct platform_device *pdev) 5041da177e4SLinus Torvalds { 50539cc539fSSimon Schwartz u32 i; 50639cc539fSSimon Schwartz int ret; 5071da177e4SLinus Torvalds 5081da177e4SLinus Torvalds if (!pdev) 5091da177e4SLinus Torvalds return -EINVAL; 5101da177e4SLinus Torvalds 5111da177e4SLinus Torvalds if (!pdev->dev.parent) 5121da177e4SLinus Torvalds pdev->dev.parent = &platform_bus; 5131da177e4SLinus Torvalds 5141da177e4SLinus Torvalds pdev->dev.bus = &platform_bus_type; 5151da177e4SLinus Torvalds 516689ae231SJean Delvare switch (pdev->id) { 517689ae231SJean Delvare default: 5181e0b2cf9SKay Sievers dev_set_name(&pdev->dev, "%s.%d", pdev->name, pdev->id); 519689ae231SJean Delvare break; 520689ae231SJean Delvare case PLATFORM_DEVID_NONE: 521acc0e90fSGreg Kroah-Hartman dev_set_name(&pdev->dev, "%s", pdev->name); 522689ae231SJean Delvare break; 523689ae231SJean Delvare case PLATFORM_DEVID_AUTO: 524689ae231SJean Delvare /* 525689ae231SJean Delvare * Automatically allocated device ID. We mark it as such so 526689ae231SJean Delvare * that we remember it must be freed, and we append a suffix 527689ae231SJean Delvare * to avoid namespace collision with explicit IDs. 528689ae231SJean Delvare */ 529689ae231SJean Delvare ret = ida_simple_get(&platform_devid_ida, 0, 0, GFP_KERNEL); 530689ae231SJean Delvare if (ret < 0) 5315da7f709SGreg Kroah-Hartman goto err_out; 532689ae231SJean Delvare pdev->id = ret; 533689ae231SJean Delvare pdev->id_auto = true; 534689ae231SJean Delvare dev_set_name(&pdev->dev, "%s.%d.auto", pdev->name, pdev->id); 535689ae231SJean Delvare break; 536689ae231SJean Delvare } 5371da177e4SLinus Torvalds 5381da177e4SLinus Torvalds for (i = 0; i < pdev->num_resources; i++) { 5395da7f709SGreg Kroah-Hartman struct resource *p, *r = &pdev->resource[i]; 5401da177e4SLinus Torvalds 5411da177e4SLinus Torvalds if (r->name == NULL) 5421e0b2cf9SKay Sievers r->name = dev_name(&pdev->dev); 5431da177e4SLinus Torvalds 5441da177e4SLinus Torvalds p = r->parent; 5451da177e4SLinus Torvalds if (!p) { 5460e6c861fSGreg Kroah-Hartman if (resource_type(r) == IORESOURCE_MEM) 5471da177e4SLinus Torvalds p = &iomem_resource; 5480e6c861fSGreg Kroah-Hartman else if (resource_type(r) == IORESOURCE_IO) 5491da177e4SLinus Torvalds p = &ioport_resource; 5501da177e4SLinus Torvalds } 5511da177e4SLinus Torvalds 55225ebcb7dSAndy Shevchenko if (p) { 55325ebcb7dSAndy Shevchenko ret = insert_resource(p, r); 55425ebcb7dSAndy Shevchenko if (ret) { 5558a18f428SChen Yu dev_err(&pdev->dev, "failed to claim resource %d: %pR\n", i, r); 5565da7f709SGreg Kroah-Hartman goto failed; 5575da7f709SGreg Kroah-Hartman } 5581da177e4SLinus Torvalds } 55925ebcb7dSAndy Shevchenko } 5601da177e4SLinus Torvalds 5611da177e4SLinus Torvalds pr_debug("Registering platform device '%s'. Parent at %s\n", 5621e0b2cf9SKay Sievers dev_name(&pdev->dev), dev_name(pdev->dev.parent)); 5631da177e4SLinus Torvalds 564e3915532SRussell King ret = device_add(&pdev->dev); 5658b2dcebaSGreg Kroah-Hartman if (ret == 0) 5668b2dcebaSGreg Kroah-Hartman return ret; 5678b2dcebaSGreg Kroah-Hartman 5685da7f709SGreg Kroah-Hartman failed: 5698b2dcebaSGreg Kroah-Hartman if (pdev->id_auto) { 5708b2dcebaSGreg Kroah-Hartman ida_simple_remove(&platform_devid_ida, pdev->id); 5718b2dcebaSGreg Kroah-Hartman pdev->id = PLATFORM_DEVID_AUTO; 5728b2dcebaSGreg Kroah-Hartman } 5738b2dcebaSGreg Kroah-Hartman 5740707cfa5SColin Ian King while (i--) { 5758b2dcebaSGreg Kroah-Hartman struct resource *r = &pdev->resource[i]; 5767f5dcaf1SGrant Likely if (r->parent) 5778b2dcebaSGreg Kroah-Hartman release_resource(r); 5788b2dcebaSGreg Kroah-Hartman } 579c9f66169SMagnus Damm 5805da7f709SGreg Kroah-Hartman err_out: 5811da177e4SLinus Torvalds return ret; 5821da177e4SLinus Torvalds } 58337c12e74SRussell King EXPORT_SYMBOL_GPL(platform_device_add); 58437c12e74SRussell King 58537c12e74SRussell King /** 58693ce3061SDmitry Torokhov * platform_device_del - remove a platform-level device 58793ce3061SDmitry Torokhov * @pdev: platform device we're removing 58893ce3061SDmitry Torokhov * 58993ce3061SDmitry Torokhov * Note that this function will also release all memory- and port-based 5904a3ad20cSGreg Kroah-Hartman * resources owned by the device (@dev->resource). This function must 5914a3ad20cSGreg Kroah-Hartman * _only_ be externally called in error cases. All other usage is a bug. 59293ce3061SDmitry Torokhov */ 59393ce3061SDmitry Torokhov void platform_device_del(struct platform_device *pdev) 59493ce3061SDmitry Torokhov { 59539cc539fSSimon Schwartz u32 i; 59693ce3061SDmitry Torokhov 59799fef587SAndy Shevchenko if (!IS_ERR_OR_NULL(pdev)) { 598dc4c15d4SJean Delvare device_del(&pdev->dev); 5998b2dcebaSGreg Kroah-Hartman 6008b2dcebaSGreg Kroah-Hartman if (pdev->id_auto) { 6018b2dcebaSGreg Kroah-Hartman ida_simple_remove(&platform_devid_ida, pdev->id); 6028b2dcebaSGreg Kroah-Hartman pdev->id = PLATFORM_DEVID_AUTO; 6038b2dcebaSGreg Kroah-Hartman } 6048b2dcebaSGreg Kroah-Hartman 6058b2dcebaSGreg Kroah-Hartman for (i = 0; i < pdev->num_resources; i++) { 6068b2dcebaSGreg Kroah-Hartman struct resource *r = &pdev->resource[i]; 6077f5dcaf1SGrant Likely if (r->parent) 6088b2dcebaSGreg Kroah-Hartman release_resource(r); 6098b2dcebaSGreg Kroah-Hartman } 6108b2dcebaSGreg Kroah-Hartman } 61193ce3061SDmitry Torokhov } 61293ce3061SDmitry Torokhov EXPORT_SYMBOL_GPL(platform_device_del); 61393ce3061SDmitry Torokhov 61493ce3061SDmitry Torokhov /** 61537c12e74SRussell King * platform_device_register - add a platform-level device 61637c12e74SRussell King * @pdev: platform device we're adding 61737c12e74SRussell King */ 61837c12e74SRussell King int platform_device_register(struct platform_device *pdev) 61937c12e74SRussell King { 62037c12e74SRussell King device_initialize(&pdev->dev); 621cdfee562SChristoph Hellwig setup_pdev_dma_masks(pdev); 62237c12e74SRussell King return platform_device_add(pdev); 62337c12e74SRussell King } 624a96b2042SDmitry Torokhov EXPORT_SYMBOL_GPL(platform_device_register); 6251da177e4SLinus Torvalds 6261da177e4SLinus Torvalds /** 62793ce3061SDmitry Torokhov * platform_device_unregister - unregister a platform-level device 62893ce3061SDmitry Torokhov * @pdev: platform device we're unregistering 6291da177e4SLinus Torvalds * 63080682fa9SUwe Zeisberger * Unregistration is done in 2 steps. First we release all resources 6312d7b5a70SJean Delvare * and remove it from the subsystem, then we drop reference count by 63293ce3061SDmitry Torokhov * calling platform_device_put(). 6331da177e4SLinus Torvalds */ 6341da177e4SLinus Torvalds void platform_device_unregister(struct platform_device *pdev) 6351da177e4SLinus Torvalds { 63693ce3061SDmitry Torokhov platform_device_del(pdev); 63793ce3061SDmitry Torokhov platform_device_put(pdev); 6381da177e4SLinus Torvalds } 639a96b2042SDmitry Torokhov EXPORT_SYMBOL_GPL(platform_device_unregister); 6401da177e4SLinus Torvalds 6411da177e4SLinus Torvalds /** 64201dcc60aSUwe Kleine-König * platform_device_register_full - add a platform-level device with 64344f28bdeSUwe Kleine-König * resources and platform-specific data 64444f28bdeSUwe Kleine-König * 64501dcc60aSUwe Kleine-König * @pdevinfo: data used to create device 646d8bf2540SDmitry Baryshkov * 647f0eae0edSJani Nikula * Returns &struct platform_device pointer on success, or ERR_PTR() on error. 648d8bf2540SDmitry Baryshkov */ 64901dcc60aSUwe Kleine-König struct platform_device *platform_device_register_full( 6505a3072beSUwe Kleine-König const struct platform_device_info *pdevinfo) 651d8bf2540SDmitry Baryshkov { 65244f28bdeSUwe Kleine-König int ret = -ENOMEM; 653d8bf2540SDmitry Baryshkov struct platform_device *pdev; 654d8bf2540SDmitry Baryshkov 65501dcc60aSUwe Kleine-König pdev = platform_device_alloc(pdevinfo->name, pdevinfo->id); 65644f28bdeSUwe Kleine-König if (!pdev) 65736cf3b13SJohannes Berg return ERR_PTR(-ENOMEM); 65801dcc60aSUwe Kleine-König 65901dcc60aSUwe Kleine-König pdev->dev.parent = pdevinfo->parent; 660ce793486SRafael J. Wysocki pdev->dev.fwnode = pdevinfo->fwnode; 6612c1ea6abSMans Rullgard pdev->dev.of_node = of_node_get(to_of_node(pdev->dev.fwnode)); 6622c1ea6abSMans Rullgard pdev->dev.of_node_reused = pdevinfo->of_node_reused; 66301dcc60aSUwe Kleine-König 66401dcc60aSUwe Kleine-König if (pdevinfo->dma_mask) { 66501dcc60aSUwe Kleine-König /* 66601dcc60aSUwe Kleine-König * This memory isn't freed when the device is put, 66701dcc60aSUwe Kleine-König * I don't have a nice idea for that though. Conceptually 66801dcc60aSUwe Kleine-König * dma_mask in struct device should not be a pointer. 66901dcc60aSUwe Kleine-König * See http://thread.gmane.org/gmane.linux.kernel.pci/9081 67001dcc60aSUwe Kleine-König */ 67101dcc60aSUwe Kleine-König pdev->dev.dma_mask = 67201dcc60aSUwe Kleine-König kmalloc(sizeof(*pdev->dev.dma_mask), GFP_KERNEL); 67301dcc60aSUwe Kleine-König if (!pdev->dev.dma_mask) 67444f28bdeSUwe Kleine-König goto err; 675d8bf2540SDmitry Baryshkov 676967d3010SQian Cai kmemleak_ignore(pdev->dev.dma_mask); 677967d3010SQian Cai 67801dcc60aSUwe Kleine-König *pdev->dev.dma_mask = pdevinfo->dma_mask; 67901dcc60aSUwe Kleine-König pdev->dev.coherent_dma_mask = pdevinfo->dma_mask; 68001dcc60aSUwe Kleine-König } 681d8bf2540SDmitry Baryshkov 68201dcc60aSUwe Kleine-König ret = platform_device_add_resources(pdev, 68301dcc60aSUwe Kleine-König pdevinfo->res, pdevinfo->num_res); 68444f28bdeSUwe Kleine-König if (ret) 68544f28bdeSUwe Kleine-König goto err; 686d8bf2540SDmitry Baryshkov 68701dcc60aSUwe Kleine-König ret = platform_device_add_data(pdev, 68801dcc60aSUwe Kleine-König pdevinfo->data, pdevinfo->size_data); 68944f28bdeSUwe Kleine-König if (ret) 69044f28bdeSUwe Kleine-König goto err; 69144f28bdeSUwe Kleine-König 692f4d05266SHeikki Krogerus if (pdevinfo->properties) { 693f4d05266SHeikki Krogerus ret = platform_device_add_properties(pdev, 694f4d05266SHeikki Krogerus pdevinfo->properties); 69500bbc1d8SMika Westerberg if (ret) 69600bbc1d8SMika Westerberg goto err; 69700bbc1d8SMika Westerberg } 69800bbc1d8SMika Westerberg 69944f28bdeSUwe Kleine-König ret = platform_device_add(pdev); 70044f28bdeSUwe Kleine-König if (ret) { 70144f28bdeSUwe Kleine-König err: 7027b199811SRafael J. Wysocki ACPI_COMPANION_SET(&pdev->dev, NULL); 70301dcc60aSUwe Kleine-König kfree(pdev->dev.dma_mask); 70444f28bdeSUwe Kleine-König platform_device_put(pdev); 70544f28bdeSUwe Kleine-König return ERR_PTR(ret); 70644f28bdeSUwe Kleine-König } 707d8bf2540SDmitry Baryshkov 708d8bf2540SDmitry Baryshkov return pdev; 709d8bf2540SDmitry Baryshkov } 71001dcc60aSUwe Kleine-König EXPORT_SYMBOL_GPL(platform_device_register_full); 711d8bf2540SDmitry Baryshkov 71200d3dcddSRussell King static int platform_drv_probe(struct device *_dev) 71300d3dcddSRussell King { 71400d3dcddSRussell King struct platform_driver *drv = to_platform_driver(_dev->driver); 71500d3dcddSRussell King struct platform_device *dev = to_platform_device(_dev); 71694d76d5dSRafael J. Wysocki int ret; 71700d3dcddSRussell King 71886be408bSSylwester Nawrocki ret = of_clk_set_defaults(_dev->of_node, false); 71986be408bSSylwester Nawrocki if (ret < 0) 72086be408bSSylwester Nawrocki return ret; 72186be408bSSylwester Nawrocki 722cb518413SUlf Hansson ret = dev_pm_domain_attach(_dev, true); 72388a9769eSUlf Hansson if (ret) 72488a9769eSUlf Hansson goto out; 72588a9769eSUlf Hansson 72625cad69fSMartin Wilck if (drv->probe) { 72794d76d5dSRafael J. Wysocki ret = drv->probe(dev); 7289383f4c6SJosh Cartwright if (ret) 729cb518413SUlf Hansson dev_pm_domain_detach(_dev, true); 730cb518413SUlf Hansson } 73194d76d5dSRafael J. Wysocki 73288a9769eSUlf Hansson out: 7333f9120b0SJohan Hovold if (drv->prevent_deferred_probe && ret == -EPROBE_DEFER) { 7343f9120b0SJohan Hovold dev_warn(_dev, "probe deferral not supported\n"); 7353f9120b0SJohan Hovold ret = -ENXIO; 7363f9120b0SJohan Hovold } 7373f9120b0SJohan Hovold 73894d76d5dSRafael J. Wysocki return ret; 73900d3dcddSRussell King } 74000d3dcddSRussell King 741c67334fbSDavid Brownell static int platform_drv_probe_fail(struct device *_dev) 742c67334fbSDavid Brownell { 743c67334fbSDavid Brownell return -ENXIO; 744c67334fbSDavid Brownell } 745c67334fbSDavid Brownell 74600d3dcddSRussell King static int platform_drv_remove(struct device *_dev) 74700d3dcddSRussell King { 74800d3dcddSRussell King struct platform_driver *drv = to_platform_driver(_dev->driver); 74900d3dcddSRussell King struct platform_device *dev = to_platform_device(_dev); 750b8b2c7d8SUwe Kleine-König int ret = 0; 75100d3dcddSRussell King 752b8b2c7d8SUwe Kleine-König if (drv->remove) 75394d76d5dSRafael J. Wysocki ret = drv->remove(dev); 754cb518413SUlf Hansson dev_pm_domain_detach(_dev, true); 75594d76d5dSRafael J. Wysocki 75694d76d5dSRafael J. Wysocki return ret; 75700d3dcddSRussell King } 75800d3dcddSRussell King 75900d3dcddSRussell King static void platform_drv_shutdown(struct device *_dev) 76000d3dcddSRussell King { 76100d3dcddSRussell King struct platform_driver *drv = to_platform_driver(_dev->driver); 76200d3dcddSRussell King struct platform_device *dev = to_platform_device(_dev); 76300d3dcddSRussell King 764b8b2c7d8SUwe Kleine-König if (drv->shutdown) 76500d3dcddSRussell King drv->shutdown(dev); 76600d3dcddSRussell King } 76700d3dcddSRussell King 76800d3dcddSRussell King /** 7699447057eSLibo Chen * __platform_driver_register - register a driver for platform-level devices 77000d3dcddSRussell King * @drv: platform driver structure 77108801f96SRandy Dunlap * @owner: owning module/driver 77200d3dcddSRussell King */ 7739447057eSLibo Chen int __platform_driver_register(struct platform_driver *drv, 7749447057eSLibo Chen struct module *owner) 77500d3dcddSRussell King { 7769447057eSLibo Chen drv->driver.owner = owner; 77700d3dcddSRussell King drv->driver.bus = &platform_bus_type; 77800d3dcddSRussell King drv->driver.probe = platform_drv_probe; 77900d3dcddSRussell King drv->driver.remove = platform_drv_remove; 78000d3dcddSRussell King drv->driver.shutdown = platform_drv_shutdown; 781783ea7d4SMagnus Damm 78200d3dcddSRussell King return driver_register(&drv->driver); 78300d3dcddSRussell King } 7849447057eSLibo Chen EXPORT_SYMBOL_GPL(__platform_driver_register); 78500d3dcddSRussell King 78600d3dcddSRussell King /** 7873c31f07aSBen Hutchings * platform_driver_unregister - unregister a driver for platform-level devices 78800d3dcddSRussell King * @drv: platform driver structure 78900d3dcddSRussell King */ 79000d3dcddSRussell King void platform_driver_unregister(struct platform_driver *drv) 79100d3dcddSRussell King { 79200d3dcddSRussell King driver_unregister(&drv->driver); 79300d3dcddSRussell King } 79400d3dcddSRussell King EXPORT_SYMBOL_GPL(platform_driver_unregister); 79500d3dcddSRussell King 796c67334fbSDavid Brownell /** 797c3b50dc2SWolfram Sang * __platform_driver_probe - register driver for non-hotpluggable device 798c67334fbSDavid Brownell * @drv: platform driver structure 7993f9120b0SJohan Hovold * @probe: the driver probe routine, probably from an __init section 800c3b50dc2SWolfram Sang * @module: module which will be the owner of the driver 801c67334fbSDavid Brownell * 802c67334fbSDavid Brownell * Use this instead of platform_driver_register() when you know the device 803c67334fbSDavid Brownell * is not hotpluggable and has already been registered, and you want to 804c67334fbSDavid Brownell * remove its run-once probe() infrastructure from memory after the driver 805c67334fbSDavid Brownell * has bound to the device. 806c67334fbSDavid Brownell * 807c67334fbSDavid Brownell * One typical use for this would be with drivers for controllers integrated 808c67334fbSDavid Brownell * into system-on-chip processors, where the controller devices have been 809c67334fbSDavid Brownell * configured as part of board setup. 810c67334fbSDavid Brownell * 8113f9120b0SJohan Hovold * Note that this is incompatible with deferred probing. 812647c86d0SFabio Porcedda * 813c67334fbSDavid Brownell * Returns zero if the driver registered and bound to a device, else returns 814c67334fbSDavid Brownell * a negative error code and with the driver not registered. 815c67334fbSDavid Brownell */ 816c3b50dc2SWolfram Sang int __init_or_module __platform_driver_probe(struct platform_driver *drv, 817c3b50dc2SWolfram Sang int (*probe)(struct platform_device *), struct module *module) 818c67334fbSDavid Brownell { 819c67334fbSDavid Brownell int retval, code; 820c67334fbSDavid Brownell 8215c36eb2aSDmitry Torokhov if (drv->driver.probe_type == PROBE_PREFER_ASYNCHRONOUS) { 8225c36eb2aSDmitry Torokhov pr_err("%s: drivers registered with %s can not be probed asynchronously\n", 8235c36eb2aSDmitry Torokhov drv->driver.name, __func__); 8245c36eb2aSDmitry Torokhov return -EINVAL; 8255c36eb2aSDmitry Torokhov } 8265c36eb2aSDmitry Torokhov 8275c36eb2aSDmitry Torokhov /* 8285c36eb2aSDmitry Torokhov * We have to run our probes synchronously because we check if 8295c36eb2aSDmitry Torokhov * we find any devices to bind to and exit with error if there 8305c36eb2aSDmitry Torokhov * are any. 8315c36eb2aSDmitry Torokhov */ 8325c36eb2aSDmitry Torokhov drv->driver.probe_type = PROBE_FORCE_SYNCHRONOUS; 8335c36eb2aSDmitry Torokhov 8343f9120b0SJohan Hovold /* 8353f9120b0SJohan Hovold * Prevent driver from requesting probe deferral to avoid further 8363f9120b0SJohan Hovold * futile probe attempts. 8373f9120b0SJohan Hovold */ 8383f9120b0SJohan Hovold drv->prevent_deferred_probe = true; 8393f9120b0SJohan Hovold 8401a6f2a75SDmitry Torokhov /* make sure driver won't have bind/unbind attributes */ 8411a6f2a75SDmitry Torokhov drv->driver.suppress_bind_attrs = true; 8421a6f2a75SDmitry Torokhov 843c67334fbSDavid Brownell /* temporary section violation during probe() */ 844c67334fbSDavid Brownell drv->probe = probe; 845c3b50dc2SWolfram Sang retval = code = __platform_driver_register(drv, module); 846c67334fbSDavid Brownell 8471a6f2a75SDmitry Torokhov /* 8481a6f2a75SDmitry Torokhov * Fixup that section violation, being paranoid about code scanning 849c67334fbSDavid Brownell * the list of drivers in order to probe new devices. Check to see 850c67334fbSDavid Brownell * if the probe was successful, and make sure any forced probes of 851c67334fbSDavid Brownell * new devices fail. 852c67334fbSDavid Brownell */ 853d79d3244SPatrick Pannuto spin_lock(&drv->driver.bus->p->klist_drivers.k_lock); 854c67334fbSDavid Brownell drv->probe = NULL; 855e5dd1278SGreg Kroah-Hartman if (code == 0 && list_empty(&drv->driver.p->klist_devices.k_list)) 856c67334fbSDavid Brownell retval = -ENODEV; 857c67334fbSDavid Brownell drv->driver.probe = platform_drv_probe_fail; 858d79d3244SPatrick Pannuto spin_unlock(&drv->driver.bus->p->klist_drivers.k_lock); 859c67334fbSDavid Brownell 860c67334fbSDavid Brownell if (code != retval) 861c67334fbSDavid Brownell platform_driver_unregister(drv); 862c67334fbSDavid Brownell return retval; 863c67334fbSDavid Brownell } 864c3b50dc2SWolfram Sang EXPORT_SYMBOL_GPL(__platform_driver_probe); 8651da177e4SLinus Torvalds 866ecdf6cebSDmitry Torokhov /** 867291f653aSWolfram Sang * __platform_create_bundle - register driver and create corresponding device 868ecdf6cebSDmitry Torokhov * @driver: platform driver structure 869ecdf6cebSDmitry Torokhov * @probe: the driver probe routine, probably from an __init section 870ecdf6cebSDmitry Torokhov * @res: set of resources that needs to be allocated for the device 871ecdf6cebSDmitry Torokhov * @n_res: number of resources 872ecdf6cebSDmitry Torokhov * @data: platform specific data for this platform device 873ecdf6cebSDmitry Torokhov * @size: size of platform specific data 874291f653aSWolfram Sang * @module: module which will be the owner of the driver 875ecdf6cebSDmitry Torokhov * 876ecdf6cebSDmitry Torokhov * Use this in legacy-style modules that probe hardware directly and 877ecdf6cebSDmitry Torokhov * register a single platform device and corresponding platform driver. 878f0eae0edSJani Nikula * 879f0eae0edSJani Nikula * Returns &struct platform_device pointer on success, or ERR_PTR() on error. 880ecdf6cebSDmitry Torokhov */ 881291f653aSWolfram Sang struct platform_device * __init_or_module __platform_create_bundle( 882ecdf6cebSDmitry Torokhov struct platform_driver *driver, 883ecdf6cebSDmitry Torokhov int (*probe)(struct platform_device *), 884ecdf6cebSDmitry Torokhov struct resource *res, unsigned int n_res, 885291f653aSWolfram Sang const void *data, size_t size, struct module *module) 886ecdf6cebSDmitry Torokhov { 887ecdf6cebSDmitry Torokhov struct platform_device *pdev; 888ecdf6cebSDmitry Torokhov int error; 889ecdf6cebSDmitry Torokhov 890ecdf6cebSDmitry Torokhov pdev = platform_device_alloc(driver->driver.name, -1); 891ecdf6cebSDmitry Torokhov if (!pdev) { 892ecdf6cebSDmitry Torokhov error = -ENOMEM; 893ecdf6cebSDmitry Torokhov goto err_out; 894ecdf6cebSDmitry Torokhov } 895ecdf6cebSDmitry Torokhov 896ecdf6cebSDmitry Torokhov error = platform_device_add_resources(pdev, res, n_res); 897ecdf6cebSDmitry Torokhov if (error) 898ecdf6cebSDmitry Torokhov goto err_pdev_put; 899ecdf6cebSDmitry Torokhov 900ecdf6cebSDmitry Torokhov error = platform_device_add_data(pdev, data, size); 901ecdf6cebSDmitry Torokhov if (error) 902ecdf6cebSDmitry Torokhov goto err_pdev_put; 903ecdf6cebSDmitry Torokhov 904ecdf6cebSDmitry Torokhov error = platform_device_add(pdev); 905ecdf6cebSDmitry Torokhov if (error) 906ecdf6cebSDmitry Torokhov goto err_pdev_put; 907ecdf6cebSDmitry Torokhov 908291f653aSWolfram Sang error = __platform_driver_probe(driver, probe, module); 909ecdf6cebSDmitry Torokhov if (error) 910ecdf6cebSDmitry Torokhov goto err_pdev_del; 911ecdf6cebSDmitry Torokhov 912ecdf6cebSDmitry Torokhov return pdev; 913ecdf6cebSDmitry Torokhov 914ecdf6cebSDmitry Torokhov err_pdev_del: 915ecdf6cebSDmitry Torokhov platform_device_del(pdev); 916ecdf6cebSDmitry Torokhov err_pdev_put: 917ecdf6cebSDmitry Torokhov platform_device_put(pdev); 918ecdf6cebSDmitry Torokhov err_out: 919ecdf6cebSDmitry Torokhov return ERR_PTR(error); 920ecdf6cebSDmitry Torokhov } 921291f653aSWolfram Sang EXPORT_SYMBOL_GPL(__platform_create_bundle); 922ecdf6cebSDmitry Torokhov 923dbe2256dSThierry Reding /** 924dbe2256dSThierry Reding * __platform_register_drivers - register an array of platform drivers 925dbe2256dSThierry Reding * @drivers: an array of drivers to register 926dbe2256dSThierry Reding * @count: the number of drivers to register 927dbe2256dSThierry Reding * @owner: module owning the drivers 928dbe2256dSThierry Reding * 929dbe2256dSThierry Reding * Registers platform drivers specified by an array. On failure to register a 930dbe2256dSThierry Reding * driver, all previously registered drivers will be unregistered. Callers of 931dbe2256dSThierry Reding * this API should use platform_unregister_drivers() to unregister drivers in 932dbe2256dSThierry Reding * the reverse order. 933dbe2256dSThierry Reding * 934dbe2256dSThierry Reding * Returns: 0 on success or a negative error code on failure. 935dbe2256dSThierry Reding */ 936dbe2256dSThierry Reding int __platform_register_drivers(struct platform_driver * const *drivers, 937dbe2256dSThierry Reding unsigned int count, struct module *owner) 938dbe2256dSThierry Reding { 939dbe2256dSThierry Reding unsigned int i; 940dbe2256dSThierry Reding int err; 941dbe2256dSThierry Reding 942dbe2256dSThierry Reding for (i = 0; i < count; i++) { 943dbe2256dSThierry Reding pr_debug("registering platform driver %ps\n", drivers[i]); 944dbe2256dSThierry Reding 945dbe2256dSThierry Reding err = __platform_driver_register(drivers[i], owner); 946dbe2256dSThierry Reding if (err < 0) { 947dbe2256dSThierry Reding pr_err("failed to register platform driver %ps: %d\n", 948dbe2256dSThierry Reding drivers[i], err); 949dbe2256dSThierry Reding goto error; 950dbe2256dSThierry Reding } 951dbe2256dSThierry Reding } 952dbe2256dSThierry Reding 953dbe2256dSThierry Reding return 0; 954dbe2256dSThierry Reding 955dbe2256dSThierry Reding error: 956dbe2256dSThierry Reding while (i--) { 957dbe2256dSThierry Reding pr_debug("unregistering platform driver %ps\n", drivers[i]); 958dbe2256dSThierry Reding platform_driver_unregister(drivers[i]); 959dbe2256dSThierry Reding } 960dbe2256dSThierry Reding 961dbe2256dSThierry Reding return err; 962dbe2256dSThierry Reding } 963dbe2256dSThierry Reding EXPORT_SYMBOL_GPL(__platform_register_drivers); 964dbe2256dSThierry Reding 965dbe2256dSThierry Reding /** 966dbe2256dSThierry Reding * platform_unregister_drivers - unregister an array of platform drivers 967dbe2256dSThierry Reding * @drivers: an array of drivers to unregister 968dbe2256dSThierry Reding * @count: the number of drivers to unregister 969dbe2256dSThierry Reding * 970dbe2256dSThierry Reding * Unegisters platform drivers specified by an array. This is typically used 971dbe2256dSThierry Reding * to complement an earlier call to platform_register_drivers(). Drivers are 972dbe2256dSThierry Reding * unregistered in the reverse order in which they were registered. 973dbe2256dSThierry Reding */ 974dbe2256dSThierry Reding void platform_unregister_drivers(struct platform_driver * const *drivers, 975dbe2256dSThierry Reding unsigned int count) 976dbe2256dSThierry Reding { 977dbe2256dSThierry Reding while (count--) { 978dbe2256dSThierry Reding pr_debug("unregistering platform driver %ps\n", drivers[count]); 979dbe2256dSThierry Reding platform_driver_unregister(drivers[count]); 980dbe2256dSThierry Reding } 981dbe2256dSThierry Reding } 982dbe2256dSThierry Reding EXPORT_SYMBOL_GPL(platform_unregister_drivers); 983dbe2256dSThierry Reding 984a0245f7aSDavid Brownell /* modalias support enables more hands-off userspace setup: 985a0245f7aSDavid Brownell * (a) environment variable lets new-style hotplug events work once system is 986a0245f7aSDavid Brownell * fully running: "modprobe $MODALIAS" 987a0245f7aSDavid Brownell * (b) sysfs attribute lets new-style coldplug recover from hotplug events 988a0245f7aSDavid Brownell * mishandled before system is fully running: "modprobe $(cat modalias)" 989a0245f7aSDavid Brownell */ 9904a3ad20cSGreg Kroah-Hartman static ssize_t modalias_show(struct device *dev, struct device_attribute *a, 9914a3ad20cSGreg Kroah-Hartman char *buf) 992a0245f7aSDavid Brownell { 993a0245f7aSDavid Brownell struct platform_device *pdev = to_platform_device(dev); 9948c4ff6d0SZhang Rui int len; 9958c4ff6d0SZhang Rui 9960634c295SRob Herring len = of_device_modalias(dev, buf, PAGE_SIZE); 997b9f73067SZhang Rui if (len != -ENODEV) 998b9f73067SZhang Rui return len; 999b9f73067SZhang Rui 10008c4ff6d0SZhang Rui len = acpi_device_modalias(dev, buf, PAGE_SIZE -1); 10018c4ff6d0SZhang Rui if (len != -ENODEV) 10028c4ff6d0SZhang Rui return len; 10038c4ff6d0SZhang Rui 1004391c0325SGreg Kroah-Hartman len = snprintf(buf, PAGE_SIZE, "platform:%s\n", pdev->name); 1005a0245f7aSDavid Brownell 1006a0245f7aSDavid Brownell return (len >= PAGE_SIZE) ? (PAGE_SIZE - 1) : len; 1007a0245f7aSDavid Brownell } 1008d06262e5SGreg Kroah-Hartman static DEVICE_ATTR_RO(modalias); 1009a0245f7aSDavid Brownell 10103d713e0eSKim Phillips static ssize_t driver_override_store(struct device *dev, 10113d713e0eSKim Phillips struct device_attribute *attr, 10123d713e0eSKim Phillips const char *buf, size_t count) 10133d713e0eSKim Phillips { 10143d713e0eSKim Phillips struct platform_device *pdev = to_platform_device(dev); 101562655397SAdrian Salido char *driver_override, *old, *cp; 10163d713e0eSKim Phillips 1017bf563b01SNicolai Stange /* We need to keep extra room for a newline */ 1018bf563b01SNicolai Stange if (count >= (PAGE_SIZE - 1)) 10193d713e0eSKim Phillips return -EINVAL; 10203d713e0eSKim Phillips 10213d713e0eSKim Phillips driver_override = kstrndup(buf, count, GFP_KERNEL); 10223d713e0eSKim Phillips if (!driver_override) 10233d713e0eSKim Phillips return -ENOMEM; 10243d713e0eSKim Phillips 10253d713e0eSKim Phillips cp = strchr(driver_override, '\n'); 10263d713e0eSKim Phillips if (cp) 10273d713e0eSKim Phillips *cp = '\0'; 10283d713e0eSKim Phillips 102962655397SAdrian Salido device_lock(dev); 103062655397SAdrian Salido old = pdev->driver_override; 10313d713e0eSKim Phillips if (strlen(driver_override)) { 10323d713e0eSKim Phillips pdev->driver_override = driver_override; 10333d713e0eSKim Phillips } else { 10343d713e0eSKim Phillips kfree(driver_override); 10353d713e0eSKim Phillips pdev->driver_override = NULL; 10363d713e0eSKim Phillips } 103762655397SAdrian Salido device_unlock(dev); 10383d713e0eSKim Phillips 10393d713e0eSKim Phillips kfree(old); 10403d713e0eSKim Phillips 10413d713e0eSKim Phillips return count; 10423d713e0eSKim Phillips } 10433d713e0eSKim Phillips 10443d713e0eSKim Phillips static ssize_t driver_override_show(struct device *dev, 10453d713e0eSKim Phillips struct device_attribute *attr, char *buf) 10463d713e0eSKim Phillips { 10473d713e0eSKim Phillips struct platform_device *pdev = to_platform_device(dev); 104862655397SAdrian Salido ssize_t len; 10493d713e0eSKim Phillips 105062655397SAdrian Salido device_lock(dev); 105162655397SAdrian Salido len = sprintf(buf, "%s\n", pdev->driver_override); 105262655397SAdrian Salido device_unlock(dev); 105362655397SAdrian Salido return len; 10543d713e0eSKim Phillips } 10553d713e0eSKim Phillips static DEVICE_ATTR_RW(driver_override); 10563d713e0eSKim Phillips 10573d713e0eSKim Phillips 1058d06262e5SGreg Kroah-Hartman static struct attribute *platform_dev_attrs[] = { 1059d06262e5SGreg Kroah-Hartman &dev_attr_modalias.attr, 10603d713e0eSKim Phillips &dev_attr_driver_override.attr, 1061d06262e5SGreg Kroah-Hartman NULL, 1062a0245f7aSDavid Brownell }; 1063d06262e5SGreg Kroah-Hartman ATTRIBUTE_GROUPS(platform_dev); 1064a0245f7aSDavid Brownell 10657eff2e7aSKay Sievers static int platform_uevent(struct device *dev, struct kobj_uevent_env *env) 1066a0245f7aSDavid Brownell { 1067a0245f7aSDavid Brownell struct platform_device *pdev = to_platform_device(dev); 1068eca39301SGrant Likely int rc; 1069eca39301SGrant Likely 1070eca39301SGrant Likely /* Some devices have extra OF data and an OF-style MODALIAS */ 107107d57a32SGrant Likely rc = of_device_uevent_modalias(dev, env); 1072eca39301SGrant Likely if (rc != -ENODEV) 1073eca39301SGrant Likely return rc; 1074a0245f7aSDavid Brownell 10758c4ff6d0SZhang Rui rc = acpi_device_uevent_modalias(dev, env); 10768c4ff6d0SZhang Rui if (rc != -ENODEV) 10778c4ff6d0SZhang Rui return rc; 10788c4ff6d0SZhang Rui 107957fee4a5SEric Miao add_uevent_var(env, "MODALIAS=%s%s", PLATFORM_MODULE_PREFIX, 1080391c0325SGreg Kroah-Hartman pdev->name); 1081a0245f7aSDavid Brownell return 0; 1082a0245f7aSDavid Brownell } 1083a0245f7aSDavid Brownell 108457fee4a5SEric Miao static const struct platform_device_id *platform_match_id( 1085831fad2fSUwe Kleine-König const struct platform_device_id *id, 108657fee4a5SEric Miao struct platform_device *pdev) 108757fee4a5SEric Miao { 108857fee4a5SEric Miao while (id->name[0]) { 1089391c0325SGreg Kroah-Hartman if (strcmp(pdev->name, id->name) == 0) { 109057fee4a5SEric Miao pdev->id_entry = id; 109157fee4a5SEric Miao return id; 109257fee4a5SEric Miao } 109357fee4a5SEric Miao id++; 109457fee4a5SEric Miao } 109557fee4a5SEric Miao return NULL; 109657fee4a5SEric Miao } 109757fee4a5SEric Miao 10981da177e4SLinus Torvalds /** 10991da177e4SLinus Torvalds * platform_match - bind platform device to platform driver. 11001da177e4SLinus Torvalds * @dev: device. 11011da177e4SLinus Torvalds * @drv: driver. 11021da177e4SLinus Torvalds * 11031da177e4SLinus Torvalds * Platform device IDs are assumed to be encoded like this: 11044a3ad20cSGreg Kroah-Hartman * "<name><instance>", where <name> is a short description of the type of 11054a3ad20cSGreg Kroah-Hartman * device, like "pci" or "floppy", and <instance> is the enumerated 11064a3ad20cSGreg Kroah-Hartman * instance of the device, like '0' or '42'. Driver IDs are simply 11074a3ad20cSGreg Kroah-Hartman * "<name>". So, extract the <name> from the platform_device structure, 11084a3ad20cSGreg Kroah-Hartman * and compare it against the name of the driver. Return whether they match 11094a3ad20cSGreg Kroah-Hartman * or not. 11101da177e4SLinus Torvalds */ 11111da177e4SLinus Torvalds static int platform_match(struct device *dev, struct device_driver *drv) 11121da177e4SLinus Torvalds { 111371b3e0c1SEric Miao struct platform_device *pdev = to_platform_device(dev); 111457fee4a5SEric Miao struct platform_driver *pdrv = to_platform_driver(drv); 11151da177e4SLinus Torvalds 11163d713e0eSKim Phillips /* When driver_override is set, only bind to the matching driver */ 11173d713e0eSKim Phillips if (pdev->driver_override) 11183d713e0eSKim Phillips return !strcmp(pdev->driver_override, drv->name); 11193d713e0eSKim Phillips 112005212157SGrant Likely /* Attempt an OF style match first */ 112105212157SGrant Likely if (of_driver_match_device(dev, drv)) 112205212157SGrant Likely return 1; 112305212157SGrant Likely 112491e56878SMika Westerberg /* Then try ACPI style match */ 112591e56878SMika Westerberg if (acpi_driver_match_device(dev, drv)) 112691e56878SMika Westerberg return 1; 112791e56878SMika Westerberg 112805212157SGrant Likely /* Then try to match against the id table */ 112957fee4a5SEric Miao if (pdrv->id_table) 113057fee4a5SEric Miao return platform_match_id(pdrv->id_table, pdev) != NULL; 113157fee4a5SEric Miao 113257fee4a5SEric Miao /* fall-back to driver name match */ 1133391c0325SGreg Kroah-Hartman return (strcmp(pdev->name, drv->name) == 0); 11341da177e4SLinus Torvalds } 11351da177e4SLinus Torvalds 113625e18499SRafael J. Wysocki #ifdef CONFIG_PM_SLEEP 113725e18499SRafael J. Wysocki 113825e18499SRafael J. Wysocki static int platform_legacy_suspend(struct device *dev, pm_message_t mesg) 11391da177e4SLinus Torvalds { 1140783ea7d4SMagnus Damm struct platform_driver *pdrv = to_platform_driver(dev->driver); 1141783ea7d4SMagnus Damm struct platform_device *pdev = to_platform_device(dev); 11421da177e4SLinus Torvalds int ret = 0; 11431da177e4SLinus Torvalds 1144783ea7d4SMagnus Damm if (dev->driver && pdrv->suspend) 1145783ea7d4SMagnus Damm ret = pdrv->suspend(pdev, mesg); 1146386415d8SDavid Brownell 1147386415d8SDavid Brownell return ret; 1148386415d8SDavid Brownell } 1149386415d8SDavid Brownell 115025e18499SRafael J. Wysocki static int platform_legacy_resume(struct device *dev) 11511da177e4SLinus Torvalds { 1152783ea7d4SMagnus Damm struct platform_driver *pdrv = to_platform_driver(dev->driver); 1153783ea7d4SMagnus Damm struct platform_device *pdev = to_platform_device(dev); 11541da177e4SLinus Torvalds int ret = 0; 11551da177e4SLinus Torvalds 1156783ea7d4SMagnus Damm if (dev->driver && pdrv->resume) 1157783ea7d4SMagnus Damm ret = pdrv->resume(pdev); 11589480e307SRussell King 11591da177e4SLinus Torvalds return ret; 11601da177e4SLinus Torvalds } 11611da177e4SLinus Torvalds 116269c9dd1eSRafael J. Wysocki #endif /* CONFIG_PM_SLEEP */ 11639d730229SMagnus Damm 116425e18499SRafael J. Wysocki #ifdef CONFIG_SUSPEND 116525e18499SRafael J. Wysocki 116669c9dd1eSRafael J. Wysocki int platform_pm_suspend(struct device *dev) 116725e18499SRafael J. Wysocki { 116825e18499SRafael J. Wysocki struct device_driver *drv = dev->driver; 116925e18499SRafael J. Wysocki int ret = 0; 117025e18499SRafael J. Wysocki 1171adf09493SRafael J. Wysocki if (!drv) 1172adf09493SRafael J. Wysocki return 0; 1173adf09493SRafael J. Wysocki 1174adf09493SRafael J. Wysocki if (drv->pm) { 117525e18499SRafael J. Wysocki if (drv->pm->suspend) 117625e18499SRafael J. Wysocki ret = drv->pm->suspend(dev); 117725e18499SRafael J. Wysocki } else { 117825e18499SRafael J. Wysocki ret = platform_legacy_suspend(dev, PMSG_SUSPEND); 117925e18499SRafael J. Wysocki } 118025e18499SRafael J. Wysocki 118125e18499SRafael J. Wysocki return ret; 118225e18499SRafael J. Wysocki } 118325e18499SRafael J. Wysocki 118469c9dd1eSRafael J. Wysocki int platform_pm_resume(struct device *dev) 118525e18499SRafael J. Wysocki { 118625e18499SRafael J. Wysocki struct device_driver *drv = dev->driver; 118725e18499SRafael J. Wysocki int ret = 0; 118825e18499SRafael J. Wysocki 1189adf09493SRafael J. Wysocki if (!drv) 1190adf09493SRafael J. Wysocki return 0; 1191adf09493SRafael J. Wysocki 1192adf09493SRafael J. Wysocki if (drv->pm) { 119325e18499SRafael J. Wysocki if (drv->pm->resume) 119425e18499SRafael J. Wysocki ret = drv->pm->resume(dev); 119525e18499SRafael J. Wysocki } else { 119625e18499SRafael J. Wysocki ret = platform_legacy_resume(dev); 119725e18499SRafael J. Wysocki } 119825e18499SRafael J. Wysocki 119925e18499SRafael J. Wysocki return ret; 120025e18499SRafael J. Wysocki } 120125e18499SRafael J. Wysocki 120269c9dd1eSRafael J. Wysocki #endif /* CONFIG_SUSPEND */ 120325e18499SRafael J. Wysocki 12041f112ceeSRafael J. Wysocki #ifdef CONFIG_HIBERNATE_CALLBACKS 120525e18499SRafael J. Wysocki 120669c9dd1eSRafael J. Wysocki int platform_pm_freeze(struct device *dev) 120725e18499SRafael J. Wysocki { 120825e18499SRafael J. Wysocki struct device_driver *drv = dev->driver; 120925e18499SRafael J. Wysocki int ret = 0; 121025e18499SRafael J. Wysocki 121125e18499SRafael J. Wysocki if (!drv) 121225e18499SRafael J. Wysocki return 0; 121325e18499SRafael J. Wysocki 121425e18499SRafael J. Wysocki if (drv->pm) { 121525e18499SRafael J. Wysocki if (drv->pm->freeze) 121625e18499SRafael J. Wysocki ret = drv->pm->freeze(dev); 121725e18499SRafael J. Wysocki } else { 121825e18499SRafael J. Wysocki ret = platform_legacy_suspend(dev, PMSG_FREEZE); 121925e18499SRafael J. Wysocki } 122025e18499SRafael J. Wysocki 122125e18499SRafael J. Wysocki return ret; 122225e18499SRafael J. Wysocki } 122325e18499SRafael J. Wysocki 122469c9dd1eSRafael J. Wysocki int platform_pm_thaw(struct device *dev) 122525e18499SRafael J. Wysocki { 122625e18499SRafael J. Wysocki struct device_driver *drv = dev->driver; 122725e18499SRafael J. Wysocki int ret = 0; 122825e18499SRafael J. Wysocki 1229adf09493SRafael J. Wysocki if (!drv) 1230adf09493SRafael J. Wysocki return 0; 1231adf09493SRafael J. Wysocki 1232adf09493SRafael J. Wysocki if (drv->pm) { 123325e18499SRafael J. Wysocki if (drv->pm->thaw) 123425e18499SRafael J. Wysocki ret = drv->pm->thaw(dev); 123525e18499SRafael J. Wysocki } else { 123625e18499SRafael J. Wysocki ret = platform_legacy_resume(dev); 123725e18499SRafael J. Wysocki } 123825e18499SRafael J. Wysocki 123925e18499SRafael J. Wysocki return ret; 124025e18499SRafael J. Wysocki } 124125e18499SRafael J. Wysocki 124269c9dd1eSRafael J. Wysocki int platform_pm_poweroff(struct device *dev) 124325e18499SRafael J. Wysocki { 124425e18499SRafael J. Wysocki struct device_driver *drv = dev->driver; 124525e18499SRafael J. Wysocki int ret = 0; 124625e18499SRafael J. Wysocki 1247adf09493SRafael J. Wysocki if (!drv) 1248adf09493SRafael J. Wysocki return 0; 1249adf09493SRafael J. Wysocki 1250adf09493SRafael J. Wysocki if (drv->pm) { 125125e18499SRafael J. Wysocki if (drv->pm->poweroff) 125225e18499SRafael J. Wysocki ret = drv->pm->poweroff(dev); 125325e18499SRafael J. Wysocki } else { 125425e18499SRafael J. Wysocki ret = platform_legacy_suspend(dev, PMSG_HIBERNATE); 125525e18499SRafael J. Wysocki } 125625e18499SRafael J. Wysocki 125725e18499SRafael J. Wysocki return ret; 125825e18499SRafael J. Wysocki } 125925e18499SRafael J. Wysocki 126069c9dd1eSRafael J. Wysocki int platform_pm_restore(struct device *dev) 126125e18499SRafael J. Wysocki { 126225e18499SRafael J. Wysocki struct device_driver *drv = dev->driver; 126325e18499SRafael J. Wysocki int ret = 0; 126425e18499SRafael J. Wysocki 1265adf09493SRafael J. Wysocki if (!drv) 1266adf09493SRafael J. Wysocki return 0; 1267adf09493SRafael J. Wysocki 1268adf09493SRafael J. Wysocki if (drv->pm) { 126925e18499SRafael J. Wysocki if (drv->pm->restore) 127025e18499SRafael J. Wysocki ret = drv->pm->restore(dev); 127125e18499SRafael J. Wysocki } else { 127225e18499SRafael J. Wysocki ret = platform_legacy_resume(dev); 127325e18499SRafael J. Wysocki } 127425e18499SRafael J. Wysocki 127525e18499SRafael J. Wysocki return ret; 127625e18499SRafael J. Wysocki } 127725e18499SRafael J. Wysocki 127869c9dd1eSRafael J. Wysocki #endif /* CONFIG_HIBERNATE_CALLBACKS */ 127925e18499SRafael J. Wysocki 128007397df2SNipun Gupta int platform_dma_configure(struct device *dev) 128107397df2SNipun Gupta { 128207397df2SNipun Gupta enum dev_dma_attr attr; 128307397df2SNipun Gupta int ret = 0; 128407397df2SNipun Gupta 128507397df2SNipun Gupta if (dev->of_node) { 12863d6ce86eSChristoph Hellwig ret = of_dma_configure(dev, dev->of_node, true); 128707397df2SNipun Gupta } else if (has_acpi_companion(dev)) { 128807397df2SNipun Gupta attr = acpi_get_dma_attr(to_acpi_device_node(dev->fwnode)); 128907397df2SNipun Gupta ret = acpi_dma_configure(dev, attr); 129007397df2SNipun Gupta } 129107397df2SNipun Gupta 129207397df2SNipun Gupta return ret; 129307397df2SNipun Gupta } 129407397df2SNipun Gupta 1295d9ab7716SDmitry Torokhov static const struct dev_pm_ops platform_dev_pm_ops = { 12968b313a38SRafael J. Wysocki .runtime_suspend = pm_generic_runtime_suspend, 12978b313a38SRafael J. Wysocki .runtime_resume = pm_generic_runtime_resume, 129869c9dd1eSRafael J. Wysocki USE_PLATFORM_PM_SLEEP_OPS 129925e18499SRafael J. Wysocki }; 130025e18499SRafael J. Wysocki 13011da177e4SLinus Torvalds struct bus_type platform_bus_type = { 13021da177e4SLinus Torvalds .name = "platform", 1303d06262e5SGreg Kroah-Hartman .dev_groups = platform_dev_groups, 13041da177e4SLinus Torvalds .match = platform_match, 1305a0245f7aSDavid Brownell .uevent = platform_uevent, 130607397df2SNipun Gupta .dma_configure = platform_dma_configure, 13079d730229SMagnus Damm .pm = &platform_dev_pm_ops, 13081da177e4SLinus Torvalds }; 1309a96b2042SDmitry Torokhov EXPORT_SYMBOL_GPL(platform_bus_type); 13101da177e4SLinus Torvalds 1311492c8872SSami Tolvanen static inline int __platform_match(struct device *dev, const void *drv) 1312492c8872SSami Tolvanen { 1313492c8872SSami Tolvanen return platform_match(dev, (struct device_driver *)drv); 1314492c8872SSami Tolvanen } 1315492c8872SSami Tolvanen 131636f3313dSSuzuki K Poulose /** 131736f3313dSSuzuki K Poulose * platform_find_device_by_driver - Find a platform device with a given 131836f3313dSSuzuki K Poulose * driver. 131936f3313dSSuzuki K Poulose * @start: The device to start the search from. 132036f3313dSSuzuki K Poulose * @drv: The device driver to look for. 132136f3313dSSuzuki K Poulose */ 132236f3313dSSuzuki K Poulose struct device *platform_find_device_by_driver(struct device *start, 132336f3313dSSuzuki K Poulose const struct device_driver *drv) 132436f3313dSSuzuki K Poulose { 132536f3313dSSuzuki K Poulose return bus_find_device(&platform_bus_type, start, drv, 1326492c8872SSami Tolvanen __platform_match); 132736f3313dSSuzuki K Poulose } 132836f3313dSSuzuki K Poulose EXPORT_SYMBOL_GPL(platform_find_device_by_driver); 132936f3313dSSuzuki K Poulose 1330eecd37e1SGuenter Roeck void __weak __init early_platform_cleanup(void) { } 1331eecd37e1SGuenter Roeck 13321da177e4SLinus Torvalds int __init platform_bus_init(void) 13331da177e4SLinus Torvalds { 1334fbfb1445SCornelia Huck int error; 1335fbfb1445SCornelia Huck 1336eecd37e1SGuenter Roeck early_platform_cleanup(); 1337eecd37e1SGuenter Roeck 1338fbfb1445SCornelia Huck error = device_register(&platform_bus); 1339c8ae1674SArvind Yadav if (error) { 1340c8ae1674SArvind Yadav put_device(&platform_bus); 1341fbfb1445SCornelia Huck return error; 1342c8ae1674SArvind Yadav } 1343fbfb1445SCornelia Huck error = bus_register(&platform_bus_type); 1344fbfb1445SCornelia Huck if (error) 1345fbfb1445SCornelia Huck device_unregister(&platform_bus); 1346801d728cSPantelis Antoniou of_platform_register_reconfig_notifier(); 1347fbfb1445SCornelia Huck return error; 13481da177e4SLinus Torvalds } 1349