11da177e4SLinus Torvalds /* 21da177e4SLinus Torvalds * platform.c - platform 'pseudo' bus for legacy devices 31da177e4SLinus Torvalds * 41da177e4SLinus Torvalds * Copyright (c) 2002-3 Patrick Mochel 51da177e4SLinus Torvalds * Copyright (c) 2002-3 Open Source Development Labs 61da177e4SLinus Torvalds * 71da177e4SLinus Torvalds * This file is released under the GPLv2 81da177e4SLinus Torvalds * 91da177e4SLinus Torvalds * Please see Documentation/driver-model/platform.txt for more 101da177e4SLinus Torvalds * information. 111da177e4SLinus Torvalds */ 121da177e4SLinus Torvalds 13daa41226SAndrew Morton #include <linux/string.h> 14d052d1beSRussell King #include <linux/platform_device.h> 1505212157SGrant Likely #include <linux/of_device.h> 169ec36cafSRob Herring #include <linux/of_irq.h> 171da177e4SLinus Torvalds #include <linux/module.h> 181da177e4SLinus Torvalds #include <linux/init.h> 191da177e4SLinus Torvalds #include <linux/dma-mapping.h> 201da177e4SLinus Torvalds #include <linux/bootmem.h> 211da177e4SLinus Torvalds #include <linux/err.h> 224e57b681STim Schmielau #include <linux/slab.h> 239d730229SMagnus Damm #include <linux/pm_runtime.h> 24f48c767cSUlf Hansson #include <linux/pm_domain.h> 25689ae231SJean Delvare #include <linux/idr.h> 2691e56878SMika Westerberg #include <linux/acpi.h> 2786be408bSSylwester Nawrocki #include <linux/clk/clk-conf.h> 283d713e0eSKim Phillips #include <linux/limits.h> 2900bbc1d8SMika Westerberg #include <linux/property.h> 301da177e4SLinus Torvalds 31a1bdc7aaSBen Dooks #include "base.h" 32bed2b42dSRafael J. Wysocki #include "power/power.h" 33a1bdc7aaSBen Dooks 34689ae231SJean Delvare /* For automatically allocated device IDs */ 35689ae231SJean Delvare static DEFINE_IDA(platform_devid_ida); 36689ae231SJean Delvare 371da177e4SLinus Torvalds struct device platform_bus = { 381e0b2cf9SKay Sievers .init_name = "platform", 391da177e4SLinus Torvalds }; 40a96b2042SDmitry Torokhov EXPORT_SYMBOL_GPL(platform_bus); 411da177e4SLinus Torvalds 421da177e4SLinus Torvalds /** 43a77ce816SKumar Gala * arch_setup_pdev_archdata - Allow manipulation of archdata before its used 447de636faSRandy Dunlap * @pdev: platform device 45a77ce816SKumar Gala * 46a77ce816SKumar Gala * This is called before platform_device_add() such that any pdev_archdata may 47a77ce816SKumar Gala * be setup before the platform_notifier is called. So if a user needs to 48a77ce816SKumar Gala * manipulate any relevant information in the pdev_archdata they can do: 49a77ce816SKumar Gala * 50b1d6d822SSebastian Andrzej Siewior * platform_device_alloc() 51a77ce816SKumar Gala * ... manipulate ... 52a77ce816SKumar Gala * platform_device_add() 53a77ce816SKumar Gala * 54a77ce816SKumar Gala * And if they don't care they can just call platform_device_register() and 55a77ce816SKumar Gala * everything will just work out. 56a77ce816SKumar Gala */ 57a77ce816SKumar Gala void __weak arch_setup_pdev_archdata(struct platform_device *pdev) 58a77ce816SKumar Gala { 59a77ce816SKumar Gala } 60a77ce816SKumar Gala 61a77ce816SKumar Gala /** 621da177e4SLinus Torvalds * platform_get_resource - get a resource for a device 631da177e4SLinus Torvalds * @dev: platform device 641da177e4SLinus Torvalds * @type: resource type 651da177e4SLinus Torvalds * @num: resource index 661da177e4SLinus Torvalds */ 674a3ad20cSGreg Kroah-Hartman struct resource *platform_get_resource(struct platform_device *dev, 684a3ad20cSGreg Kroah-Hartman unsigned int type, unsigned int num) 691da177e4SLinus Torvalds { 701da177e4SLinus Torvalds int i; 711da177e4SLinus Torvalds 721da177e4SLinus Torvalds for (i = 0; i < dev->num_resources; i++) { 731da177e4SLinus Torvalds struct resource *r = &dev->resource[i]; 741da177e4SLinus Torvalds 75c9f66169SMagnus Damm if (type == resource_type(r) && num-- == 0) 761da177e4SLinus Torvalds return r; 771da177e4SLinus Torvalds } 781da177e4SLinus Torvalds return NULL; 791da177e4SLinus Torvalds } 80a96b2042SDmitry Torokhov EXPORT_SYMBOL_GPL(platform_get_resource); 811da177e4SLinus Torvalds 821da177e4SLinus Torvalds /** 831da177e4SLinus Torvalds * platform_get_irq - get an IRQ for a device 841da177e4SLinus Torvalds * @dev: platform device 851da177e4SLinus Torvalds * @num: IRQ number index 861da177e4SLinus Torvalds */ 871da177e4SLinus Torvalds int platform_get_irq(struct platform_device *dev, unsigned int num) 881da177e4SLinus Torvalds { 895cf8f7dbSAndreas Larsson #ifdef CONFIG_SPARC 905cf8f7dbSAndreas Larsson /* sparc does not have irqs represented as IORESOURCE_IRQ resources */ 915cf8f7dbSAndreas Larsson if (!dev || num >= dev->archdata.num_irqs) 925cf8f7dbSAndreas Larsson return -ENXIO; 935cf8f7dbSAndreas Larsson return dev->archdata.irqs[num]; 945cf8f7dbSAndreas Larsson #else 959ec36cafSRob Herring struct resource *r; 96aff008adSGuenter Roeck if (IS_ENABLED(CONFIG_OF_IRQ) && dev->dev.of_node) { 97aff008adSGuenter Roeck int ret; 98aff008adSGuenter Roeck 99aff008adSGuenter Roeck ret = of_irq_get(dev->dev.of_node, num); 100e330b9a6SSergei Shtylyov if (ret > 0 || ret == -EPROBE_DEFER) 101aff008adSGuenter Roeck return ret; 102aff008adSGuenter Roeck } 1039ec36cafSRob Herring 1049ec36cafSRob Herring r = platform_get_resource(dev, IORESOURCE_IRQ, num); 105d44fa3d4SAgustin Vega-Frias if (has_acpi_companion(&dev->dev)) { 106d44fa3d4SAgustin Vega-Frias if (r && r->flags & IORESOURCE_DISABLED) { 107d44fa3d4SAgustin Vega-Frias int ret; 108d44fa3d4SAgustin Vega-Frias 109d44fa3d4SAgustin Vega-Frias ret = acpi_irq_get(ACPI_HANDLE(&dev->dev), num, r); 110d44fa3d4SAgustin Vega-Frias if (ret) 111d44fa3d4SAgustin Vega-Frias return ret; 112d44fa3d4SAgustin Vega-Frias } 113d44fa3d4SAgustin Vega-Frias } 114d44fa3d4SAgustin Vega-Frias 1157085a740SLinus Walleij /* 1167085a740SLinus Walleij * The resources may pass trigger flags to the irqs that need 1177085a740SLinus Walleij * to be set up. It so happens that the trigger flags for 1187085a740SLinus Walleij * IORESOURCE_BITS correspond 1-to-1 to the IRQF_TRIGGER* 1197085a740SLinus Walleij * settings. 1207085a740SLinus Walleij */ 12160ca5e0dSGuenter Roeck if (r && r->flags & IORESOURCE_BITS) { 12260ca5e0dSGuenter Roeck struct irq_data *irqd; 12360ca5e0dSGuenter Roeck 12460ca5e0dSGuenter Roeck irqd = irq_get_irq_data(r->start); 12560ca5e0dSGuenter Roeck if (!irqd) 12660ca5e0dSGuenter Roeck return -ENXIO; 12760ca5e0dSGuenter Roeck irqd_set_trigger_type(irqd, r->flags & IORESOURCE_BITS); 12860ca5e0dSGuenter Roeck } 1291da177e4SLinus Torvalds 130305b3228SDavid Vrabel return r ? r->start : -ENXIO; 1315cf8f7dbSAndreas Larsson #endif 1321da177e4SLinus Torvalds } 133a96b2042SDmitry Torokhov EXPORT_SYMBOL_GPL(platform_get_irq); 1341da177e4SLinus Torvalds 1351da177e4SLinus Torvalds /** 1364b83555dSStephen Boyd * platform_irq_count - Count the number of IRQs a platform device uses 1374b83555dSStephen Boyd * @dev: platform device 1384b83555dSStephen Boyd * 1394b83555dSStephen Boyd * Return: Number of IRQs a platform device uses or EPROBE_DEFER 1404b83555dSStephen Boyd */ 1414b83555dSStephen Boyd int platform_irq_count(struct platform_device *dev) 1424b83555dSStephen Boyd { 1434b83555dSStephen Boyd int ret, nr = 0; 1444b83555dSStephen Boyd 1454b83555dSStephen Boyd while ((ret = platform_get_irq(dev, nr)) >= 0) 1464b83555dSStephen Boyd nr++; 1474b83555dSStephen Boyd 1484b83555dSStephen Boyd if (ret == -EPROBE_DEFER) 1494b83555dSStephen Boyd return ret; 1504b83555dSStephen Boyd 1514b83555dSStephen Boyd return nr; 1524b83555dSStephen Boyd } 1534b83555dSStephen Boyd EXPORT_SYMBOL_GPL(platform_irq_count); 1544b83555dSStephen Boyd 1554b83555dSStephen Boyd /** 1561da177e4SLinus Torvalds * platform_get_resource_byname - get a resource for a device by name 1571da177e4SLinus Torvalds * @dev: platform device 1581da177e4SLinus Torvalds * @type: resource type 1591da177e4SLinus Torvalds * @name: resource name 1601da177e4SLinus Torvalds */ 1614a3ad20cSGreg Kroah-Hartman struct resource *platform_get_resource_byname(struct platform_device *dev, 162c0afe7baSLinus Walleij unsigned int type, 163c0afe7baSLinus Walleij const char *name) 1641da177e4SLinus Torvalds { 1651da177e4SLinus Torvalds int i; 1661da177e4SLinus Torvalds 1671da177e4SLinus Torvalds for (i = 0; i < dev->num_resources; i++) { 1681da177e4SLinus Torvalds struct resource *r = &dev->resource[i]; 1691da177e4SLinus Torvalds 1701b8cb929SPeter Ujfalusi if (unlikely(!r->name)) 1711b8cb929SPeter Ujfalusi continue; 1721b8cb929SPeter Ujfalusi 173c9f66169SMagnus Damm if (type == resource_type(r) && !strcmp(r->name, name)) 1741da177e4SLinus Torvalds return r; 1751da177e4SLinus Torvalds } 1761da177e4SLinus Torvalds return NULL; 1771da177e4SLinus Torvalds } 178a96b2042SDmitry Torokhov EXPORT_SYMBOL_GPL(platform_get_resource_byname); 1791da177e4SLinus Torvalds 1801da177e4SLinus Torvalds /** 181d6ff8551SWolfram Sang * platform_get_irq_byname - get an IRQ for a device by name 1821da177e4SLinus Torvalds * @dev: platform device 1831da177e4SLinus Torvalds * @name: IRQ name 1841da177e4SLinus Torvalds */ 185c0afe7baSLinus Walleij int platform_get_irq_byname(struct platform_device *dev, const char *name) 1861da177e4SLinus Torvalds { 187ad69674eSGrygorii Strashko struct resource *r; 1881da177e4SLinus Torvalds 189aff008adSGuenter Roeck if (IS_ENABLED(CONFIG_OF_IRQ) && dev->dev.of_node) { 190aff008adSGuenter Roeck int ret; 191aff008adSGuenter Roeck 192aff008adSGuenter Roeck ret = of_irq_get_byname(dev->dev.of_node, name); 193e330b9a6SSergei Shtylyov if (ret > 0 || ret == -EPROBE_DEFER) 194aff008adSGuenter Roeck return ret; 195aff008adSGuenter Roeck } 196ad69674eSGrygorii Strashko 197ad69674eSGrygorii Strashko r = platform_get_resource_byname(dev, IORESOURCE_IRQ, name); 198305b3228SDavid Vrabel return r ? r->start : -ENXIO; 1991da177e4SLinus Torvalds } 200a96b2042SDmitry Torokhov EXPORT_SYMBOL_GPL(platform_get_irq_byname); 2011da177e4SLinus Torvalds 2021da177e4SLinus Torvalds /** 2031da177e4SLinus Torvalds * platform_add_devices - add a numbers of platform devices 2041da177e4SLinus Torvalds * @devs: array of platform devices to add 2051da177e4SLinus Torvalds * @num: number of platform devices in array 2061da177e4SLinus Torvalds */ 2071da177e4SLinus Torvalds int platform_add_devices(struct platform_device **devs, int num) 2081da177e4SLinus Torvalds { 2091da177e4SLinus Torvalds int i, ret = 0; 2101da177e4SLinus Torvalds 2111da177e4SLinus Torvalds for (i = 0; i < num; i++) { 2121da177e4SLinus Torvalds ret = platform_device_register(devs[i]); 2131da177e4SLinus Torvalds if (ret) { 2141da177e4SLinus Torvalds while (--i >= 0) 2151da177e4SLinus Torvalds platform_device_unregister(devs[i]); 2161da177e4SLinus Torvalds break; 2171da177e4SLinus Torvalds } 2181da177e4SLinus Torvalds } 2191da177e4SLinus Torvalds 2201da177e4SLinus Torvalds return ret; 2211da177e4SLinus Torvalds } 222a96b2042SDmitry Torokhov EXPORT_SYMBOL_GPL(platform_add_devices); 2231da177e4SLinus Torvalds 22437c12e74SRussell King struct platform_object { 22537c12e74SRussell King struct platform_device pdev; 2261cec24c5SYann Droneaud char name[]; 22737c12e74SRussell King }; 22837c12e74SRussell King 2291da177e4SLinus Torvalds /** 2303c31f07aSBen Hutchings * platform_device_put - destroy a platform device 23137c12e74SRussell King * @pdev: platform device to free 23237c12e74SRussell King * 2334a3ad20cSGreg Kroah-Hartman * Free all memory associated with a platform device. This function must 2344a3ad20cSGreg Kroah-Hartman * _only_ be externally called in error cases. All other usage is a bug. 23537c12e74SRussell King */ 23637c12e74SRussell King void platform_device_put(struct platform_device *pdev) 23737c12e74SRussell King { 23837c12e74SRussell King if (pdev) 23937c12e74SRussell King put_device(&pdev->dev); 24037c12e74SRussell King } 24137c12e74SRussell King EXPORT_SYMBOL_GPL(platform_device_put); 24237c12e74SRussell King 24337c12e74SRussell King static void platform_device_release(struct device *dev) 24437c12e74SRussell King { 2454a3ad20cSGreg Kroah-Hartman struct platform_object *pa = container_of(dev, struct platform_object, 2464a3ad20cSGreg Kroah-Hartman pdev.dev); 24737c12e74SRussell King 2487096d042SGrant Likely of_device_node_put(&pa->pdev.dev); 24937c12e74SRussell King kfree(pa->pdev.dev.platform_data); 250e710d7d5SSamuel Ortiz kfree(pa->pdev.mfd_cell); 25137c12e74SRussell King kfree(pa->pdev.resource); 2523d713e0eSKim Phillips kfree(pa->pdev.driver_override); 25337c12e74SRussell King kfree(pa); 25437c12e74SRussell King } 25537c12e74SRussell King 25637c12e74SRussell King /** 2573c31f07aSBen Hutchings * platform_device_alloc - create a platform device 25837c12e74SRussell King * @name: base name of the device we're adding 25937c12e74SRussell King * @id: instance id 26037c12e74SRussell King * 26137c12e74SRussell King * Create a platform device object which can have other objects attached 26237c12e74SRussell King * to it, and which will have attached objects freed when it is released. 26337c12e74SRussell King */ 2641359555eSJean Delvare struct platform_device *platform_device_alloc(const char *name, int id) 26537c12e74SRussell King { 26637c12e74SRussell King struct platform_object *pa; 26737c12e74SRussell King 2681cec24c5SYann Droneaud pa = kzalloc(sizeof(*pa) + strlen(name) + 1, GFP_KERNEL); 26937c12e74SRussell King if (pa) { 27037c12e74SRussell King strcpy(pa->name, name); 27137c12e74SRussell King pa->pdev.name = pa->name; 27237c12e74SRussell King pa->pdev.id = id; 27337c12e74SRussell King device_initialize(&pa->pdev.dev); 27437c12e74SRussell King pa->pdev.dev.release = platform_device_release; 275a77ce816SKumar Gala arch_setup_pdev_archdata(&pa->pdev); 27637c12e74SRussell King } 27737c12e74SRussell King 27837c12e74SRussell King return pa ? &pa->pdev : NULL; 27937c12e74SRussell King } 28037c12e74SRussell King EXPORT_SYMBOL_GPL(platform_device_alloc); 28137c12e74SRussell King 28237c12e74SRussell King /** 2833c31f07aSBen Hutchings * platform_device_add_resources - add resources to a platform device 28437c12e74SRussell King * @pdev: platform device allocated by platform_device_alloc to add resources to 28537c12e74SRussell King * @res: set of resources that needs to be allocated for the device 28637c12e74SRussell King * @num: number of resources 28737c12e74SRussell King * 28837c12e74SRussell King * Add a copy of the resources to the platform device. The memory 2894a3ad20cSGreg Kroah-Hartman * associated with the resources will be freed when the platform device is 2904a3ad20cSGreg Kroah-Hartman * released. 29137c12e74SRussell King */ 2924a3ad20cSGreg Kroah-Hartman int platform_device_add_resources(struct platform_device *pdev, 2930b7f1a7eSGeert Uytterhoeven const struct resource *res, unsigned int num) 29437c12e74SRussell King { 295cea89623SUwe Kleine-König struct resource *r = NULL; 29637c12e74SRussell King 297cea89623SUwe Kleine-König if (res) { 2983e61dfd8SUwe Kleine-König r = kmemdup(res, sizeof(struct resource) * num, GFP_KERNEL); 299cea89623SUwe Kleine-König if (!r) 300cea89623SUwe Kleine-König return -ENOMEM; 301cea89623SUwe Kleine-König } 302cea89623SUwe Kleine-König 3034a03d6f7SUwe Kleine-König kfree(pdev->resource); 30437c12e74SRussell King pdev->resource = r; 30537c12e74SRussell King pdev->num_resources = num; 3063e61dfd8SUwe Kleine-König return 0; 30737c12e74SRussell King } 30837c12e74SRussell King EXPORT_SYMBOL_GPL(platform_device_add_resources); 30937c12e74SRussell King 31037c12e74SRussell King /** 3113c31f07aSBen Hutchings * platform_device_add_data - add platform-specific data to a platform device 31237c12e74SRussell King * @pdev: platform device allocated by platform_device_alloc to add resources to 31337c12e74SRussell King * @data: platform specific data for this platform device 31437c12e74SRussell King * @size: size of platform specific data 31537c12e74SRussell King * 3164a3ad20cSGreg Kroah-Hartman * Add a copy of platform specific data to the platform device's 3174a3ad20cSGreg Kroah-Hartman * platform_data pointer. The memory associated with the platform data 3184a3ad20cSGreg Kroah-Hartman * will be freed when the platform device is released. 31937c12e74SRussell King */ 3204a3ad20cSGreg Kroah-Hartman int platform_device_add_data(struct platform_device *pdev, const void *data, 3214a3ad20cSGreg Kroah-Hartman size_t size) 32237c12e74SRussell King { 32327a33f9eSUwe Kleine-König void *d = NULL; 32437c12e74SRussell King 32527a33f9eSUwe Kleine-König if (data) { 3265cfc64ceSAnton Vorontsov d = kmemdup(data, size, GFP_KERNEL); 32727a33f9eSUwe Kleine-König if (!d) 32827a33f9eSUwe Kleine-König return -ENOMEM; 32927a33f9eSUwe Kleine-König } 33027a33f9eSUwe Kleine-König 331251e031dSUwe Kleine-König kfree(pdev->dev.platform_data); 33237c12e74SRussell King pdev->dev.platform_data = d; 333daa41226SAndrew Morton return 0; 33437c12e74SRussell King } 33537c12e74SRussell King EXPORT_SYMBOL_GPL(platform_device_add_data); 33637c12e74SRussell King 33737c12e74SRussell King /** 33800bbc1d8SMika Westerberg * platform_device_add_properties - add built-in properties to a platform device 33900bbc1d8SMika Westerberg * @pdev: platform device to add properties to 340f4d05266SHeikki Krogerus * @properties: null terminated array of properties to add 34100bbc1d8SMika Westerberg * 342f4d05266SHeikki Krogerus * The function will take deep copy of @properties and attach the copy to the 343f4d05266SHeikki Krogerus * platform device. The memory associated with properties will be freed when the 344f4d05266SHeikki Krogerus * platform device is released. 34500bbc1d8SMika Westerberg */ 34600bbc1d8SMika Westerberg int platform_device_add_properties(struct platform_device *pdev, 347277036f0SJan Kiszka const struct property_entry *properties) 34800bbc1d8SMika Westerberg { 349f4d05266SHeikki Krogerus return device_add_properties(&pdev->dev, properties); 35000bbc1d8SMika Westerberg } 35100bbc1d8SMika Westerberg EXPORT_SYMBOL_GPL(platform_device_add_properties); 35200bbc1d8SMika Westerberg 35300bbc1d8SMika Westerberg /** 35437c12e74SRussell King * platform_device_add - add a platform device to device hierarchy 35567be2dd1SMartin Waitz * @pdev: platform device we're adding 3561da177e4SLinus Torvalds * 35737c12e74SRussell King * This is part 2 of platform_device_register(), though may be called 35837c12e74SRussell King * separately _iff_ pdev was allocated by platform_device_alloc(). 3591da177e4SLinus Torvalds */ 36037c12e74SRussell King int platform_device_add(struct platform_device *pdev) 3611da177e4SLinus Torvalds { 362689ae231SJean Delvare int i, ret; 3631da177e4SLinus Torvalds 3641da177e4SLinus Torvalds if (!pdev) 3651da177e4SLinus Torvalds return -EINVAL; 3661da177e4SLinus Torvalds 3671da177e4SLinus Torvalds if (!pdev->dev.parent) 3681da177e4SLinus Torvalds pdev->dev.parent = &platform_bus; 3691da177e4SLinus Torvalds 3701da177e4SLinus Torvalds pdev->dev.bus = &platform_bus_type; 3711da177e4SLinus Torvalds 372689ae231SJean Delvare switch (pdev->id) { 373689ae231SJean Delvare default: 3741e0b2cf9SKay Sievers dev_set_name(&pdev->dev, "%s.%d", pdev->name, pdev->id); 375689ae231SJean Delvare break; 376689ae231SJean Delvare case PLATFORM_DEVID_NONE: 377acc0e90fSGreg Kroah-Hartman dev_set_name(&pdev->dev, "%s", pdev->name); 378689ae231SJean Delvare break; 379689ae231SJean Delvare case PLATFORM_DEVID_AUTO: 380689ae231SJean Delvare /* 381689ae231SJean Delvare * Automatically allocated device ID. We mark it as such so 382689ae231SJean Delvare * that we remember it must be freed, and we append a suffix 383689ae231SJean Delvare * to avoid namespace collision with explicit IDs. 384689ae231SJean Delvare */ 385689ae231SJean Delvare ret = ida_simple_get(&platform_devid_ida, 0, 0, GFP_KERNEL); 386689ae231SJean Delvare if (ret < 0) 3875da7f709SGreg Kroah-Hartman goto err_out; 388689ae231SJean Delvare pdev->id = ret; 389689ae231SJean Delvare pdev->id_auto = true; 390689ae231SJean Delvare dev_set_name(&pdev->dev, "%s.%d.auto", pdev->name, pdev->id); 391689ae231SJean Delvare break; 392689ae231SJean Delvare } 3931da177e4SLinus Torvalds 3941da177e4SLinus Torvalds for (i = 0; i < pdev->num_resources; i++) { 3955da7f709SGreg Kroah-Hartman struct resource *p, *r = &pdev->resource[i]; 3961da177e4SLinus Torvalds 3971da177e4SLinus Torvalds if (r->name == NULL) 3981e0b2cf9SKay Sievers r->name = dev_name(&pdev->dev); 3991da177e4SLinus Torvalds 4001da177e4SLinus Torvalds p = r->parent; 4011da177e4SLinus Torvalds if (!p) { 4020e6c861fSGreg Kroah-Hartman if (resource_type(r) == IORESOURCE_MEM) 4031da177e4SLinus Torvalds p = &iomem_resource; 4040e6c861fSGreg Kroah-Hartman else if (resource_type(r) == IORESOURCE_IO) 4051da177e4SLinus Torvalds p = &ioport_resource; 4061da177e4SLinus Torvalds } 4071da177e4SLinus Torvalds 4080e6c861fSGreg Kroah-Hartman if (p && insert_resource(p, r)) { 4098a18f428SChen Yu dev_err(&pdev->dev, "failed to claim resource %d: %pR\n", i, r); 4105da7f709SGreg Kroah-Hartman ret = -EBUSY; 4115da7f709SGreg Kroah-Hartman goto failed; 4125da7f709SGreg Kroah-Hartman } 4131da177e4SLinus Torvalds } 4141da177e4SLinus Torvalds 4151da177e4SLinus Torvalds pr_debug("Registering platform device '%s'. Parent at %s\n", 4161e0b2cf9SKay Sievers dev_name(&pdev->dev), dev_name(pdev->dev.parent)); 4171da177e4SLinus Torvalds 418e3915532SRussell King ret = device_add(&pdev->dev); 4198b2dcebaSGreg Kroah-Hartman if (ret == 0) 4208b2dcebaSGreg Kroah-Hartman return ret; 4218b2dcebaSGreg Kroah-Hartman 4225da7f709SGreg Kroah-Hartman failed: 4238b2dcebaSGreg Kroah-Hartman if (pdev->id_auto) { 4248b2dcebaSGreg Kroah-Hartman ida_simple_remove(&platform_devid_ida, pdev->id); 4258b2dcebaSGreg Kroah-Hartman pdev->id = PLATFORM_DEVID_AUTO; 4268b2dcebaSGreg Kroah-Hartman } 4278b2dcebaSGreg Kroah-Hartman 4288b2dcebaSGreg Kroah-Hartman while (--i >= 0) { 4298b2dcebaSGreg Kroah-Hartman struct resource *r = &pdev->resource[i]; 4307f5dcaf1SGrant Likely if (r->parent) 4318b2dcebaSGreg Kroah-Hartman release_resource(r); 4328b2dcebaSGreg Kroah-Hartman } 433c9f66169SMagnus Damm 4345da7f709SGreg Kroah-Hartman err_out: 4351da177e4SLinus Torvalds return ret; 4361da177e4SLinus Torvalds } 43737c12e74SRussell King EXPORT_SYMBOL_GPL(platform_device_add); 43837c12e74SRussell King 43937c12e74SRussell King /** 44093ce3061SDmitry Torokhov * platform_device_del - remove a platform-level device 44193ce3061SDmitry Torokhov * @pdev: platform device we're removing 44293ce3061SDmitry Torokhov * 44393ce3061SDmitry Torokhov * Note that this function will also release all memory- and port-based 4444a3ad20cSGreg Kroah-Hartman * resources owned by the device (@dev->resource). This function must 4454a3ad20cSGreg Kroah-Hartman * _only_ be externally called in error cases. All other usage is a bug. 44693ce3061SDmitry Torokhov */ 44793ce3061SDmitry Torokhov void platform_device_del(struct platform_device *pdev) 44893ce3061SDmitry Torokhov { 4498b2dcebaSGreg Kroah-Hartman int i; 45093ce3061SDmitry Torokhov 4518b2dcebaSGreg Kroah-Hartman if (pdev) { 452c90aab9cSJerome Marchand device_remove_properties(&pdev->dev); 453dc4c15d4SJean Delvare device_del(&pdev->dev); 4548b2dcebaSGreg Kroah-Hartman 4558b2dcebaSGreg Kroah-Hartman if (pdev->id_auto) { 4568b2dcebaSGreg Kroah-Hartman ida_simple_remove(&platform_devid_ida, pdev->id); 4578b2dcebaSGreg Kroah-Hartman pdev->id = PLATFORM_DEVID_AUTO; 4588b2dcebaSGreg Kroah-Hartman } 4598b2dcebaSGreg Kroah-Hartman 4608b2dcebaSGreg Kroah-Hartman for (i = 0; i < pdev->num_resources; i++) { 4618b2dcebaSGreg Kroah-Hartman struct resource *r = &pdev->resource[i]; 4627f5dcaf1SGrant Likely if (r->parent) 4638b2dcebaSGreg Kroah-Hartman release_resource(r); 4648b2dcebaSGreg Kroah-Hartman } 4658b2dcebaSGreg Kroah-Hartman } 46693ce3061SDmitry Torokhov } 46793ce3061SDmitry Torokhov EXPORT_SYMBOL_GPL(platform_device_del); 46893ce3061SDmitry Torokhov 46993ce3061SDmitry Torokhov /** 47037c12e74SRussell King * platform_device_register - add a platform-level device 47137c12e74SRussell King * @pdev: platform device we're adding 47237c12e74SRussell King */ 47337c12e74SRussell King int platform_device_register(struct platform_device *pdev) 47437c12e74SRussell King { 47537c12e74SRussell King device_initialize(&pdev->dev); 476a77ce816SKumar Gala arch_setup_pdev_archdata(pdev); 47737c12e74SRussell King return platform_device_add(pdev); 47837c12e74SRussell King } 479a96b2042SDmitry Torokhov EXPORT_SYMBOL_GPL(platform_device_register); 4801da177e4SLinus Torvalds 4811da177e4SLinus Torvalds /** 48293ce3061SDmitry Torokhov * platform_device_unregister - unregister a platform-level device 48393ce3061SDmitry Torokhov * @pdev: platform device we're unregistering 4841da177e4SLinus Torvalds * 48580682fa9SUwe Zeisberger * Unregistration is done in 2 steps. First we release all resources 4862d7b5a70SJean Delvare * and remove it from the subsystem, then we drop reference count by 48793ce3061SDmitry Torokhov * calling platform_device_put(). 4881da177e4SLinus Torvalds */ 4891da177e4SLinus Torvalds void platform_device_unregister(struct platform_device *pdev) 4901da177e4SLinus Torvalds { 49193ce3061SDmitry Torokhov platform_device_del(pdev); 49293ce3061SDmitry Torokhov platform_device_put(pdev); 4931da177e4SLinus Torvalds } 494a96b2042SDmitry Torokhov EXPORT_SYMBOL_GPL(platform_device_unregister); 4951da177e4SLinus Torvalds 4961da177e4SLinus Torvalds /** 49701dcc60aSUwe Kleine-König * platform_device_register_full - add a platform-level device with 49844f28bdeSUwe Kleine-König * resources and platform-specific data 49944f28bdeSUwe Kleine-König * 50001dcc60aSUwe Kleine-König * @pdevinfo: data used to create device 501d8bf2540SDmitry Baryshkov * 502f0eae0edSJani Nikula * Returns &struct platform_device pointer on success, or ERR_PTR() on error. 503d8bf2540SDmitry Baryshkov */ 50401dcc60aSUwe Kleine-König struct platform_device *platform_device_register_full( 5055a3072beSUwe Kleine-König const struct platform_device_info *pdevinfo) 506d8bf2540SDmitry Baryshkov { 50744f28bdeSUwe Kleine-König int ret = -ENOMEM; 508d8bf2540SDmitry Baryshkov struct platform_device *pdev; 509d8bf2540SDmitry Baryshkov 51001dcc60aSUwe Kleine-König pdev = platform_device_alloc(pdevinfo->name, pdevinfo->id); 51144f28bdeSUwe Kleine-König if (!pdev) 51201dcc60aSUwe Kleine-König goto err_alloc; 51301dcc60aSUwe Kleine-König 51401dcc60aSUwe Kleine-König pdev->dev.parent = pdevinfo->parent; 515ce793486SRafael J. Wysocki pdev->dev.fwnode = pdevinfo->fwnode; 51601dcc60aSUwe Kleine-König 51701dcc60aSUwe Kleine-König if (pdevinfo->dma_mask) { 51801dcc60aSUwe Kleine-König /* 51901dcc60aSUwe Kleine-König * This memory isn't freed when the device is put, 52001dcc60aSUwe Kleine-König * I don't have a nice idea for that though. Conceptually 52101dcc60aSUwe Kleine-König * dma_mask in struct device should not be a pointer. 52201dcc60aSUwe Kleine-König * See http://thread.gmane.org/gmane.linux.kernel.pci/9081 52301dcc60aSUwe Kleine-König */ 52401dcc60aSUwe Kleine-König pdev->dev.dma_mask = 52501dcc60aSUwe Kleine-König kmalloc(sizeof(*pdev->dev.dma_mask), GFP_KERNEL); 52601dcc60aSUwe Kleine-König if (!pdev->dev.dma_mask) 52744f28bdeSUwe Kleine-König goto err; 528d8bf2540SDmitry Baryshkov 52901dcc60aSUwe Kleine-König *pdev->dev.dma_mask = pdevinfo->dma_mask; 53001dcc60aSUwe Kleine-König pdev->dev.coherent_dma_mask = pdevinfo->dma_mask; 53101dcc60aSUwe Kleine-König } 532d8bf2540SDmitry Baryshkov 53301dcc60aSUwe Kleine-König ret = platform_device_add_resources(pdev, 53401dcc60aSUwe Kleine-König pdevinfo->res, pdevinfo->num_res); 53544f28bdeSUwe Kleine-König if (ret) 53644f28bdeSUwe Kleine-König goto err; 537d8bf2540SDmitry Baryshkov 53801dcc60aSUwe Kleine-König ret = platform_device_add_data(pdev, 53901dcc60aSUwe Kleine-König pdevinfo->data, pdevinfo->size_data); 54044f28bdeSUwe Kleine-König if (ret) 54144f28bdeSUwe Kleine-König goto err; 54244f28bdeSUwe Kleine-König 543f4d05266SHeikki Krogerus if (pdevinfo->properties) { 544f4d05266SHeikki Krogerus ret = platform_device_add_properties(pdev, 545f4d05266SHeikki Krogerus pdevinfo->properties); 54600bbc1d8SMika Westerberg if (ret) 54700bbc1d8SMika Westerberg goto err; 54800bbc1d8SMika Westerberg } 54900bbc1d8SMika Westerberg 55044f28bdeSUwe Kleine-König ret = platform_device_add(pdev); 55144f28bdeSUwe Kleine-König if (ret) { 55244f28bdeSUwe Kleine-König err: 5537b199811SRafael J. Wysocki ACPI_COMPANION_SET(&pdev->dev, NULL); 55401dcc60aSUwe Kleine-König kfree(pdev->dev.dma_mask); 55501dcc60aSUwe Kleine-König 55601dcc60aSUwe Kleine-König err_alloc: 55744f28bdeSUwe Kleine-König platform_device_put(pdev); 55844f28bdeSUwe Kleine-König return ERR_PTR(ret); 55944f28bdeSUwe Kleine-König } 560d8bf2540SDmitry Baryshkov 561d8bf2540SDmitry Baryshkov return pdev; 562d8bf2540SDmitry Baryshkov } 56301dcc60aSUwe Kleine-König EXPORT_SYMBOL_GPL(platform_device_register_full); 564d8bf2540SDmitry Baryshkov 56500d3dcddSRussell King static int platform_drv_probe(struct device *_dev) 56600d3dcddSRussell King { 56700d3dcddSRussell King struct platform_driver *drv = to_platform_driver(_dev->driver); 56800d3dcddSRussell King struct platform_device *dev = to_platform_device(_dev); 56994d76d5dSRafael J. Wysocki int ret; 57000d3dcddSRussell King 57186be408bSSylwester Nawrocki ret = of_clk_set_defaults(_dev->of_node, false); 57286be408bSSylwester Nawrocki if (ret < 0) 57386be408bSSylwester Nawrocki return ret; 57486be408bSSylwester Nawrocki 575cb518413SUlf Hansson ret = dev_pm_domain_attach(_dev, true); 57625cad69fSMartin Wilck if (ret != -EPROBE_DEFER) { 57725cad69fSMartin Wilck if (drv->probe) { 57894d76d5dSRafael J. Wysocki ret = drv->probe(dev); 5799383f4c6SJosh Cartwright if (ret) 580cb518413SUlf Hansson dev_pm_domain_detach(_dev, true); 58125cad69fSMartin Wilck } else { 58225cad69fSMartin Wilck /* don't fail if just dev_pm_domain_attach failed */ 58325cad69fSMartin Wilck ret = 0; 58425cad69fSMartin Wilck } 585cb518413SUlf Hansson } 58694d76d5dSRafael J. Wysocki 5873f9120b0SJohan Hovold if (drv->prevent_deferred_probe && ret == -EPROBE_DEFER) { 5883f9120b0SJohan Hovold dev_warn(_dev, "probe deferral not supported\n"); 5893f9120b0SJohan Hovold ret = -ENXIO; 5903f9120b0SJohan Hovold } 5913f9120b0SJohan Hovold 59294d76d5dSRafael J. Wysocki return ret; 59300d3dcddSRussell King } 59400d3dcddSRussell King 595c67334fbSDavid Brownell static int platform_drv_probe_fail(struct device *_dev) 596c67334fbSDavid Brownell { 597c67334fbSDavid Brownell return -ENXIO; 598c67334fbSDavid Brownell } 599c67334fbSDavid Brownell 60000d3dcddSRussell King static int platform_drv_remove(struct device *_dev) 60100d3dcddSRussell King { 60200d3dcddSRussell King struct platform_driver *drv = to_platform_driver(_dev->driver); 60300d3dcddSRussell King struct platform_device *dev = to_platform_device(_dev); 604b8b2c7d8SUwe Kleine-König int ret = 0; 60500d3dcddSRussell King 606b8b2c7d8SUwe Kleine-König if (drv->remove) 60794d76d5dSRafael J. Wysocki ret = drv->remove(dev); 608cb518413SUlf Hansson dev_pm_domain_detach(_dev, true); 60994d76d5dSRafael J. Wysocki 61094d76d5dSRafael J. Wysocki return ret; 61100d3dcddSRussell King } 61200d3dcddSRussell King 61300d3dcddSRussell King static void platform_drv_shutdown(struct device *_dev) 61400d3dcddSRussell King { 61500d3dcddSRussell King struct platform_driver *drv = to_platform_driver(_dev->driver); 61600d3dcddSRussell King struct platform_device *dev = to_platform_device(_dev); 61700d3dcddSRussell King 618b8b2c7d8SUwe Kleine-König if (drv->shutdown) 61900d3dcddSRussell King drv->shutdown(dev); 62000d3dcddSRussell King } 62100d3dcddSRussell King 62200d3dcddSRussell King /** 6239447057eSLibo Chen * __platform_driver_register - register a driver for platform-level devices 62400d3dcddSRussell King * @drv: platform driver structure 62508801f96SRandy Dunlap * @owner: owning module/driver 62600d3dcddSRussell King */ 6279447057eSLibo Chen int __platform_driver_register(struct platform_driver *drv, 6289447057eSLibo Chen struct module *owner) 62900d3dcddSRussell King { 6309447057eSLibo Chen drv->driver.owner = owner; 63100d3dcddSRussell King drv->driver.bus = &platform_bus_type; 63200d3dcddSRussell King drv->driver.probe = platform_drv_probe; 63300d3dcddSRussell King drv->driver.remove = platform_drv_remove; 63400d3dcddSRussell King drv->driver.shutdown = platform_drv_shutdown; 635783ea7d4SMagnus Damm 63600d3dcddSRussell King return driver_register(&drv->driver); 63700d3dcddSRussell King } 6389447057eSLibo Chen EXPORT_SYMBOL_GPL(__platform_driver_register); 63900d3dcddSRussell King 64000d3dcddSRussell King /** 6413c31f07aSBen Hutchings * platform_driver_unregister - unregister a driver for platform-level devices 64200d3dcddSRussell King * @drv: platform driver structure 64300d3dcddSRussell King */ 64400d3dcddSRussell King void platform_driver_unregister(struct platform_driver *drv) 64500d3dcddSRussell King { 64600d3dcddSRussell King driver_unregister(&drv->driver); 64700d3dcddSRussell King } 64800d3dcddSRussell King EXPORT_SYMBOL_GPL(platform_driver_unregister); 64900d3dcddSRussell King 650c67334fbSDavid Brownell /** 651c3b50dc2SWolfram Sang * __platform_driver_probe - register driver for non-hotpluggable device 652c67334fbSDavid Brownell * @drv: platform driver structure 6533f9120b0SJohan Hovold * @probe: the driver probe routine, probably from an __init section 654c3b50dc2SWolfram Sang * @module: module which will be the owner of the driver 655c67334fbSDavid Brownell * 656c67334fbSDavid Brownell * Use this instead of platform_driver_register() when you know the device 657c67334fbSDavid Brownell * is not hotpluggable and has already been registered, and you want to 658c67334fbSDavid Brownell * remove its run-once probe() infrastructure from memory after the driver 659c67334fbSDavid Brownell * has bound to the device. 660c67334fbSDavid Brownell * 661c67334fbSDavid Brownell * One typical use for this would be with drivers for controllers integrated 662c67334fbSDavid Brownell * into system-on-chip processors, where the controller devices have been 663c67334fbSDavid Brownell * configured as part of board setup. 664c67334fbSDavid Brownell * 6653f9120b0SJohan Hovold * Note that this is incompatible with deferred probing. 666647c86d0SFabio Porcedda * 667c67334fbSDavid Brownell * Returns zero if the driver registered and bound to a device, else returns 668c67334fbSDavid Brownell * a negative error code and with the driver not registered. 669c67334fbSDavid Brownell */ 670c3b50dc2SWolfram Sang int __init_or_module __platform_driver_probe(struct platform_driver *drv, 671c3b50dc2SWolfram Sang int (*probe)(struct platform_device *), struct module *module) 672c67334fbSDavid Brownell { 673c67334fbSDavid Brownell int retval, code; 674c67334fbSDavid Brownell 6755c36eb2aSDmitry Torokhov if (drv->driver.probe_type == PROBE_PREFER_ASYNCHRONOUS) { 6765c36eb2aSDmitry Torokhov pr_err("%s: drivers registered with %s can not be probed asynchronously\n", 6775c36eb2aSDmitry Torokhov drv->driver.name, __func__); 6785c36eb2aSDmitry Torokhov return -EINVAL; 6795c36eb2aSDmitry Torokhov } 6805c36eb2aSDmitry Torokhov 6815c36eb2aSDmitry Torokhov /* 6825c36eb2aSDmitry Torokhov * We have to run our probes synchronously because we check if 6835c36eb2aSDmitry Torokhov * we find any devices to bind to and exit with error if there 6845c36eb2aSDmitry Torokhov * are any. 6855c36eb2aSDmitry Torokhov */ 6865c36eb2aSDmitry Torokhov drv->driver.probe_type = PROBE_FORCE_SYNCHRONOUS; 6875c36eb2aSDmitry Torokhov 6883f9120b0SJohan Hovold /* 6893f9120b0SJohan Hovold * Prevent driver from requesting probe deferral to avoid further 6903f9120b0SJohan Hovold * futile probe attempts. 6913f9120b0SJohan Hovold */ 6923f9120b0SJohan Hovold drv->prevent_deferred_probe = true; 6933f9120b0SJohan Hovold 6941a6f2a75SDmitry Torokhov /* make sure driver won't have bind/unbind attributes */ 6951a6f2a75SDmitry Torokhov drv->driver.suppress_bind_attrs = true; 6961a6f2a75SDmitry Torokhov 697c67334fbSDavid Brownell /* temporary section violation during probe() */ 698c67334fbSDavid Brownell drv->probe = probe; 699c3b50dc2SWolfram Sang retval = code = __platform_driver_register(drv, module); 700c67334fbSDavid Brownell 7011a6f2a75SDmitry Torokhov /* 7021a6f2a75SDmitry Torokhov * Fixup that section violation, being paranoid about code scanning 703c67334fbSDavid Brownell * the list of drivers in order to probe new devices. Check to see 704c67334fbSDavid Brownell * if the probe was successful, and make sure any forced probes of 705c67334fbSDavid Brownell * new devices fail. 706c67334fbSDavid Brownell */ 707d79d3244SPatrick Pannuto spin_lock(&drv->driver.bus->p->klist_drivers.k_lock); 708c67334fbSDavid Brownell drv->probe = NULL; 709e5dd1278SGreg Kroah-Hartman if (code == 0 && list_empty(&drv->driver.p->klist_devices.k_list)) 710c67334fbSDavid Brownell retval = -ENODEV; 711c67334fbSDavid Brownell drv->driver.probe = platform_drv_probe_fail; 712d79d3244SPatrick Pannuto spin_unlock(&drv->driver.bus->p->klist_drivers.k_lock); 713c67334fbSDavid Brownell 714c67334fbSDavid Brownell if (code != retval) 715c67334fbSDavid Brownell platform_driver_unregister(drv); 716c67334fbSDavid Brownell return retval; 717c67334fbSDavid Brownell } 718c3b50dc2SWolfram Sang EXPORT_SYMBOL_GPL(__platform_driver_probe); 7191da177e4SLinus Torvalds 720ecdf6cebSDmitry Torokhov /** 721291f653aSWolfram Sang * __platform_create_bundle - register driver and create corresponding device 722ecdf6cebSDmitry Torokhov * @driver: platform driver structure 723ecdf6cebSDmitry Torokhov * @probe: the driver probe routine, probably from an __init section 724ecdf6cebSDmitry Torokhov * @res: set of resources that needs to be allocated for the device 725ecdf6cebSDmitry Torokhov * @n_res: number of resources 726ecdf6cebSDmitry Torokhov * @data: platform specific data for this platform device 727ecdf6cebSDmitry Torokhov * @size: size of platform specific data 728291f653aSWolfram Sang * @module: module which will be the owner of the driver 729ecdf6cebSDmitry Torokhov * 730ecdf6cebSDmitry Torokhov * Use this in legacy-style modules that probe hardware directly and 731ecdf6cebSDmitry Torokhov * register a single platform device and corresponding platform driver. 732f0eae0edSJani Nikula * 733f0eae0edSJani Nikula * Returns &struct platform_device pointer on success, or ERR_PTR() on error. 734ecdf6cebSDmitry Torokhov */ 735291f653aSWolfram Sang struct platform_device * __init_or_module __platform_create_bundle( 736ecdf6cebSDmitry Torokhov struct platform_driver *driver, 737ecdf6cebSDmitry Torokhov int (*probe)(struct platform_device *), 738ecdf6cebSDmitry Torokhov struct resource *res, unsigned int n_res, 739291f653aSWolfram Sang const void *data, size_t size, struct module *module) 740ecdf6cebSDmitry Torokhov { 741ecdf6cebSDmitry Torokhov struct platform_device *pdev; 742ecdf6cebSDmitry Torokhov int error; 743ecdf6cebSDmitry Torokhov 744ecdf6cebSDmitry Torokhov pdev = platform_device_alloc(driver->driver.name, -1); 745ecdf6cebSDmitry Torokhov if (!pdev) { 746ecdf6cebSDmitry Torokhov error = -ENOMEM; 747ecdf6cebSDmitry Torokhov goto err_out; 748ecdf6cebSDmitry Torokhov } 749ecdf6cebSDmitry Torokhov 750ecdf6cebSDmitry Torokhov error = platform_device_add_resources(pdev, res, n_res); 751ecdf6cebSDmitry Torokhov if (error) 752ecdf6cebSDmitry Torokhov goto err_pdev_put; 753ecdf6cebSDmitry Torokhov 754ecdf6cebSDmitry Torokhov error = platform_device_add_data(pdev, data, size); 755ecdf6cebSDmitry Torokhov if (error) 756ecdf6cebSDmitry Torokhov goto err_pdev_put; 757ecdf6cebSDmitry Torokhov 758ecdf6cebSDmitry Torokhov error = platform_device_add(pdev); 759ecdf6cebSDmitry Torokhov if (error) 760ecdf6cebSDmitry Torokhov goto err_pdev_put; 761ecdf6cebSDmitry Torokhov 762291f653aSWolfram Sang error = __platform_driver_probe(driver, probe, module); 763ecdf6cebSDmitry Torokhov if (error) 764ecdf6cebSDmitry Torokhov goto err_pdev_del; 765ecdf6cebSDmitry Torokhov 766ecdf6cebSDmitry Torokhov return pdev; 767ecdf6cebSDmitry Torokhov 768ecdf6cebSDmitry Torokhov err_pdev_del: 769ecdf6cebSDmitry Torokhov platform_device_del(pdev); 770ecdf6cebSDmitry Torokhov err_pdev_put: 771ecdf6cebSDmitry Torokhov platform_device_put(pdev); 772ecdf6cebSDmitry Torokhov err_out: 773ecdf6cebSDmitry Torokhov return ERR_PTR(error); 774ecdf6cebSDmitry Torokhov } 775291f653aSWolfram Sang EXPORT_SYMBOL_GPL(__platform_create_bundle); 776ecdf6cebSDmitry Torokhov 777dbe2256dSThierry Reding /** 778dbe2256dSThierry Reding * __platform_register_drivers - register an array of platform drivers 779dbe2256dSThierry Reding * @drivers: an array of drivers to register 780dbe2256dSThierry Reding * @count: the number of drivers to register 781dbe2256dSThierry Reding * @owner: module owning the drivers 782dbe2256dSThierry Reding * 783dbe2256dSThierry Reding * Registers platform drivers specified by an array. On failure to register a 784dbe2256dSThierry Reding * driver, all previously registered drivers will be unregistered. Callers of 785dbe2256dSThierry Reding * this API should use platform_unregister_drivers() to unregister drivers in 786dbe2256dSThierry Reding * the reverse order. 787dbe2256dSThierry Reding * 788dbe2256dSThierry Reding * Returns: 0 on success or a negative error code on failure. 789dbe2256dSThierry Reding */ 790dbe2256dSThierry Reding int __platform_register_drivers(struct platform_driver * const *drivers, 791dbe2256dSThierry Reding unsigned int count, struct module *owner) 792dbe2256dSThierry Reding { 793dbe2256dSThierry Reding unsigned int i; 794dbe2256dSThierry Reding int err; 795dbe2256dSThierry Reding 796dbe2256dSThierry Reding for (i = 0; i < count; i++) { 797dbe2256dSThierry Reding pr_debug("registering platform driver %ps\n", drivers[i]); 798dbe2256dSThierry Reding 799dbe2256dSThierry Reding err = __platform_driver_register(drivers[i], owner); 800dbe2256dSThierry Reding if (err < 0) { 801dbe2256dSThierry Reding pr_err("failed to register platform driver %ps: %d\n", 802dbe2256dSThierry Reding drivers[i], err); 803dbe2256dSThierry Reding goto error; 804dbe2256dSThierry Reding } 805dbe2256dSThierry Reding } 806dbe2256dSThierry Reding 807dbe2256dSThierry Reding return 0; 808dbe2256dSThierry Reding 809dbe2256dSThierry Reding error: 810dbe2256dSThierry Reding while (i--) { 811dbe2256dSThierry Reding pr_debug("unregistering platform driver %ps\n", drivers[i]); 812dbe2256dSThierry Reding platform_driver_unregister(drivers[i]); 813dbe2256dSThierry Reding } 814dbe2256dSThierry Reding 815dbe2256dSThierry Reding return err; 816dbe2256dSThierry Reding } 817dbe2256dSThierry Reding EXPORT_SYMBOL_GPL(__platform_register_drivers); 818dbe2256dSThierry Reding 819dbe2256dSThierry Reding /** 820dbe2256dSThierry Reding * platform_unregister_drivers - unregister an array of platform drivers 821dbe2256dSThierry Reding * @drivers: an array of drivers to unregister 822dbe2256dSThierry Reding * @count: the number of drivers to unregister 823dbe2256dSThierry Reding * 824dbe2256dSThierry Reding * Unegisters platform drivers specified by an array. This is typically used 825dbe2256dSThierry Reding * to complement an earlier call to platform_register_drivers(). Drivers are 826dbe2256dSThierry Reding * unregistered in the reverse order in which they were registered. 827dbe2256dSThierry Reding */ 828dbe2256dSThierry Reding void platform_unregister_drivers(struct platform_driver * const *drivers, 829dbe2256dSThierry Reding unsigned int count) 830dbe2256dSThierry Reding { 831dbe2256dSThierry Reding while (count--) { 832dbe2256dSThierry Reding pr_debug("unregistering platform driver %ps\n", drivers[count]); 833dbe2256dSThierry Reding platform_driver_unregister(drivers[count]); 834dbe2256dSThierry Reding } 835dbe2256dSThierry Reding } 836dbe2256dSThierry Reding EXPORT_SYMBOL_GPL(platform_unregister_drivers); 837dbe2256dSThierry Reding 838a0245f7aSDavid Brownell /* modalias support enables more hands-off userspace setup: 839a0245f7aSDavid Brownell * (a) environment variable lets new-style hotplug events work once system is 840a0245f7aSDavid Brownell * fully running: "modprobe $MODALIAS" 841a0245f7aSDavid Brownell * (b) sysfs attribute lets new-style coldplug recover from hotplug events 842a0245f7aSDavid Brownell * mishandled before system is fully running: "modprobe $(cat modalias)" 843a0245f7aSDavid Brownell */ 8444a3ad20cSGreg Kroah-Hartman static ssize_t modalias_show(struct device *dev, struct device_attribute *a, 8454a3ad20cSGreg Kroah-Hartman char *buf) 846a0245f7aSDavid Brownell { 847a0245f7aSDavid Brownell struct platform_device *pdev = to_platform_device(dev); 8488c4ff6d0SZhang Rui int len; 8498c4ff6d0SZhang Rui 8500634c295SRob Herring len = of_device_modalias(dev, buf, PAGE_SIZE); 851b9f73067SZhang Rui if (len != -ENODEV) 852b9f73067SZhang Rui return len; 853b9f73067SZhang Rui 8548c4ff6d0SZhang Rui len = acpi_device_modalias(dev, buf, PAGE_SIZE -1); 8558c4ff6d0SZhang Rui if (len != -ENODEV) 8568c4ff6d0SZhang Rui return len; 8578c4ff6d0SZhang Rui 8588c4ff6d0SZhang Rui len = snprintf(buf, PAGE_SIZE, "platform:%s\n", pdev->name); 859a0245f7aSDavid Brownell 860a0245f7aSDavid Brownell return (len >= PAGE_SIZE) ? (PAGE_SIZE - 1) : len; 861a0245f7aSDavid Brownell } 862d06262e5SGreg Kroah-Hartman static DEVICE_ATTR_RO(modalias); 863a0245f7aSDavid Brownell 8643d713e0eSKim Phillips static ssize_t driver_override_store(struct device *dev, 8653d713e0eSKim Phillips struct device_attribute *attr, 8663d713e0eSKim Phillips const char *buf, size_t count) 8673d713e0eSKim Phillips { 8683d713e0eSKim Phillips struct platform_device *pdev = to_platform_device(dev); 86962655397SAdrian Salido char *driver_override, *old, *cp; 8703d713e0eSKim Phillips 871bf563b01SNicolai Stange /* We need to keep extra room for a newline */ 872bf563b01SNicolai Stange if (count >= (PAGE_SIZE - 1)) 8733d713e0eSKim Phillips return -EINVAL; 8743d713e0eSKim Phillips 8753d713e0eSKim Phillips driver_override = kstrndup(buf, count, GFP_KERNEL); 8763d713e0eSKim Phillips if (!driver_override) 8773d713e0eSKim Phillips return -ENOMEM; 8783d713e0eSKim Phillips 8793d713e0eSKim Phillips cp = strchr(driver_override, '\n'); 8803d713e0eSKim Phillips if (cp) 8813d713e0eSKim Phillips *cp = '\0'; 8823d713e0eSKim Phillips 88362655397SAdrian Salido device_lock(dev); 88462655397SAdrian Salido old = pdev->driver_override; 8853d713e0eSKim Phillips if (strlen(driver_override)) { 8863d713e0eSKim Phillips pdev->driver_override = driver_override; 8873d713e0eSKim Phillips } else { 8883d713e0eSKim Phillips kfree(driver_override); 8893d713e0eSKim Phillips pdev->driver_override = NULL; 8903d713e0eSKim Phillips } 89162655397SAdrian Salido device_unlock(dev); 8923d713e0eSKim Phillips 8933d713e0eSKim Phillips kfree(old); 8943d713e0eSKim Phillips 8953d713e0eSKim Phillips return count; 8963d713e0eSKim Phillips } 8973d713e0eSKim Phillips 8983d713e0eSKim Phillips static ssize_t driver_override_show(struct device *dev, 8993d713e0eSKim Phillips struct device_attribute *attr, char *buf) 9003d713e0eSKim Phillips { 9013d713e0eSKim Phillips struct platform_device *pdev = to_platform_device(dev); 90262655397SAdrian Salido ssize_t len; 9033d713e0eSKim Phillips 90462655397SAdrian Salido device_lock(dev); 90562655397SAdrian Salido len = sprintf(buf, "%s\n", pdev->driver_override); 90662655397SAdrian Salido device_unlock(dev); 90762655397SAdrian Salido return len; 9083d713e0eSKim Phillips } 9093d713e0eSKim Phillips static DEVICE_ATTR_RW(driver_override); 9103d713e0eSKim Phillips 9113d713e0eSKim Phillips 912d06262e5SGreg Kroah-Hartman static struct attribute *platform_dev_attrs[] = { 913d06262e5SGreg Kroah-Hartman &dev_attr_modalias.attr, 9143d713e0eSKim Phillips &dev_attr_driver_override.attr, 915d06262e5SGreg Kroah-Hartman NULL, 916a0245f7aSDavid Brownell }; 917d06262e5SGreg Kroah-Hartman ATTRIBUTE_GROUPS(platform_dev); 918a0245f7aSDavid Brownell 9197eff2e7aSKay Sievers static int platform_uevent(struct device *dev, struct kobj_uevent_env *env) 920a0245f7aSDavid Brownell { 921a0245f7aSDavid Brownell struct platform_device *pdev = to_platform_device(dev); 922eca39301SGrant Likely int rc; 923eca39301SGrant Likely 924eca39301SGrant Likely /* Some devices have extra OF data and an OF-style MODALIAS */ 92507d57a32SGrant Likely rc = of_device_uevent_modalias(dev, env); 926eca39301SGrant Likely if (rc != -ENODEV) 927eca39301SGrant Likely return rc; 928a0245f7aSDavid Brownell 9298c4ff6d0SZhang Rui rc = acpi_device_uevent_modalias(dev, env); 9308c4ff6d0SZhang Rui if (rc != -ENODEV) 9318c4ff6d0SZhang Rui return rc; 9328c4ff6d0SZhang Rui 93357fee4a5SEric Miao add_uevent_var(env, "MODALIAS=%s%s", PLATFORM_MODULE_PREFIX, 9340a26813cSSebastian Andrzej Siewior pdev->name); 935a0245f7aSDavid Brownell return 0; 936a0245f7aSDavid Brownell } 937a0245f7aSDavid Brownell 93857fee4a5SEric Miao static const struct platform_device_id *platform_match_id( 939831fad2fSUwe Kleine-König const struct platform_device_id *id, 94057fee4a5SEric Miao struct platform_device *pdev) 94157fee4a5SEric Miao { 94257fee4a5SEric Miao while (id->name[0]) { 94357fee4a5SEric Miao if (strcmp(pdev->name, id->name) == 0) { 94457fee4a5SEric Miao pdev->id_entry = id; 94557fee4a5SEric Miao return id; 94657fee4a5SEric Miao } 94757fee4a5SEric Miao id++; 94857fee4a5SEric Miao } 94957fee4a5SEric Miao return NULL; 95057fee4a5SEric Miao } 95157fee4a5SEric Miao 9521da177e4SLinus Torvalds /** 9531da177e4SLinus Torvalds * platform_match - bind platform device to platform driver. 9541da177e4SLinus Torvalds * @dev: device. 9551da177e4SLinus Torvalds * @drv: driver. 9561da177e4SLinus Torvalds * 9571da177e4SLinus Torvalds * Platform device IDs are assumed to be encoded like this: 9584a3ad20cSGreg Kroah-Hartman * "<name><instance>", where <name> is a short description of the type of 9594a3ad20cSGreg Kroah-Hartman * device, like "pci" or "floppy", and <instance> is the enumerated 9604a3ad20cSGreg Kroah-Hartman * instance of the device, like '0' or '42'. Driver IDs are simply 9614a3ad20cSGreg Kroah-Hartman * "<name>". So, extract the <name> from the platform_device structure, 9624a3ad20cSGreg Kroah-Hartman * and compare it against the name of the driver. Return whether they match 9634a3ad20cSGreg Kroah-Hartman * or not. 9641da177e4SLinus Torvalds */ 9651da177e4SLinus Torvalds static int platform_match(struct device *dev, struct device_driver *drv) 9661da177e4SLinus Torvalds { 96771b3e0c1SEric Miao struct platform_device *pdev = to_platform_device(dev); 96857fee4a5SEric Miao struct platform_driver *pdrv = to_platform_driver(drv); 9691da177e4SLinus Torvalds 9703d713e0eSKim Phillips /* When driver_override is set, only bind to the matching driver */ 9713d713e0eSKim Phillips if (pdev->driver_override) 9723d713e0eSKim Phillips return !strcmp(pdev->driver_override, drv->name); 9733d713e0eSKim Phillips 97405212157SGrant Likely /* Attempt an OF style match first */ 97505212157SGrant Likely if (of_driver_match_device(dev, drv)) 97605212157SGrant Likely return 1; 97705212157SGrant Likely 97891e56878SMika Westerberg /* Then try ACPI style match */ 97991e56878SMika Westerberg if (acpi_driver_match_device(dev, drv)) 98091e56878SMika Westerberg return 1; 98191e56878SMika Westerberg 98205212157SGrant Likely /* Then try to match against the id table */ 98357fee4a5SEric Miao if (pdrv->id_table) 98457fee4a5SEric Miao return platform_match_id(pdrv->id_table, pdev) != NULL; 98557fee4a5SEric Miao 98657fee4a5SEric Miao /* fall-back to driver name match */ 9871e0b2cf9SKay Sievers return (strcmp(pdev->name, drv->name) == 0); 9881da177e4SLinus Torvalds } 9891da177e4SLinus Torvalds 99025e18499SRafael J. Wysocki #ifdef CONFIG_PM_SLEEP 99125e18499SRafael J. Wysocki 99225e18499SRafael J. Wysocki static int platform_legacy_suspend(struct device *dev, pm_message_t mesg) 9931da177e4SLinus Torvalds { 994783ea7d4SMagnus Damm struct platform_driver *pdrv = to_platform_driver(dev->driver); 995783ea7d4SMagnus Damm struct platform_device *pdev = to_platform_device(dev); 9961da177e4SLinus Torvalds int ret = 0; 9971da177e4SLinus Torvalds 998783ea7d4SMagnus Damm if (dev->driver && pdrv->suspend) 999783ea7d4SMagnus Damm ret = pdrv->suspend(pdev, mesg); 1000386415d8SDavid Brownell 1001386415d8SDavid Brownell return ret; 1002386415d8SDavid Brownell } 1003386415d8SDavid Brownell 100425e18499SRafael J. Wysocki static int platform_legacy_resume(struct device *dev) 10051da177e4SLinus Torvalds { 1006783ea7d4SMagnus Damm struct platform_driver *pdrv = to_platform_driver(dev->driver); 1007783ea7d4SMagnus Damm struct platform_device *pdev = to_platform_device(dev); 10081da177e4SLinus Torvalds int ret = 0; 10091da177e4SLinus Torvalds 1010783ea7d4SMagnus Damm if (dev->driver && pdrv->resume) 1011783ea7d4SMagnus Damm ret = pdrv->resume(pdev); 10129480e307SRussell King 10131da177e4SLinus Torvalds return ret; 10141da177e4SLinus Torvalds } 10151da177e4SLinus Torvalds 101669c9dd1eSRafael J. Wysocki #endif /* CONFIG_PM_SLEEP */ 10179d730229SMagnus Damm 101825e18499SRafael J. Wysocki #ifdef CONFIG_SUSPEND 101925e18499SRafael J. Wysocki 102069c9dd1eSRafael J. Wysocki int platform_pm_suspend(struct device *dev) 102125e18499SRafael J. Wysocki { 102225e18499SRafael J. Wysocki struct device_driver *drv = dev->driver; 102325e18499SRafael J. Wysocki int ret = 0; 102425e18499SRafael J. Wysocki 1025adf09493SRafael J. Wysocki if (!drv) 1026adf09493SRafael J. Wysocki return 0; 1027adf09493SRafael J. Wysocki 1028adf09493SRafael J. Wysocki if (drv->pm) { 102925e18499SRafael J. Wysocki if (drv->pm->suspend) 103025e18499SRafael J. Wysocki ret = drv->pm->suspend(dev); 103125e18499SRafael J. Wysocki } else { 103225e18499SRafael J. Wysocki ret = platform_legacy_suspend(dev, PMSG_SUSPEND); 103325e18499SRafael J. Wysocki } 103425e18499SRafael J. Wysocki 103525e18499SRafael J. Wysocki return ret; 103625e18499SRafael J. Wysocki } 103725e18499SRafael J. Wysocki 103869c9dd1eSRafael J. Wysocki int platform_pm_resume(struct device *dev) 103925e18499SRafael J. Wysocki { 104025e18499SRafael J. Wysocki struct device_driver *drv = dev->driver; 104125e18499SRafael J. Wysocki int ret = 0; 104225e18499SRafael J. Wysocki 1043adf09493SRafael J. Wysocki if (!drv) 1044adf09493SRafael J. Wysocki return 0; 1045adf09493SRafael J. Wysocki 1046adf09493SRafael J. Wysocki if (drv->pm) { 104725e18499SRafael J. Wysocki if (drv->pm->resume) 104825e18499SRafael J. Wysocki ret = drv->pm->resume(dev); 104925e18499SRafael J. Wysocki } else { 105025e18499SRafael J. Wysocki ret = platform_legacy_resume(dev); 105125e18499SRafael J. Wysocki } 105225e18499SRafael J. Wysocki 105325e18499SRafael J. Wysocki return ret; 105425e18499SRafael J. Wysocki } 105525e18499SRafael J. Wysocki 105669c9dd1eSRafael J. Wysocki #endif /* CONFIG_SUSPEND */ 105725e18499SRafael J. Wysocki 10581f112ceeSRafael J. Wysocki #ifdef CONFIG_HIBERNATE_CALLBACKS 105925e18499SRafael J. Wysocki 106069c9dd1eSRafael J. Wysocki int platform_pm_freeze(struct device *dev) 106125e18499SRafael J. Wysocki { 106225e18499SRafael J. Wysocki struct device_driver *drv = dev->driver; 106325e18499SRafael J. Wysocki int ret = 0; 106425e18499SRafael J. Wysocki 106525e18499SRafael J. Wysocki if (!drv) 106625e18499SRafael J. Wysocki return 0; 106725e18499SRafael J. Wysocki 106825e18499SRafael J. Wysocki if (drv->pm) { 106925e18499SRafael J. Wysocki if (drv->pm->freeze) 107025e18499SRafael J. Wysocki ret = drv->pm->freeze(dev); 107125e18499SRafael J. Wysocki } else { 107225e18499SRafael J. Wysocki ret = platform_legacy_suspend(dev, PMSG_FREEZE); 107325e18499SRafael J. Wysocki } 107425e18499SRafael J. Wysocki 107525e18499SRafael J. Wysocki return ret; 107625e18499SRafael J. Wysocki } 107725e18499SRafael J. Wysocki 107869c9dd1eSRafael J. Wysocki int platform_pm_thaw(struct device *dev) 107925e18499SRafael J. Wysocki { 108025e18499SRafael J. Wysocki struct device_driver *drv = dev->driver; 108125e18499SRafael J. Wysocki int ret = 0; 108225e18499SRafael J. Wysocki 1083adf09493SRafael J. Wysocki if (!drv) 1084adf09493SRafael J. Wysocki return 0; 1085adf09493SRafael J. Wysocki 1086adf09493SRafael J. Wysocki if (drv->pm) { 108725e18499SRafael J. Wysocki if (drv->pm->thaw) 108825e18499SRafael J. Wysocki ret = drv->pm->thaw(dev); 108925e18499SRafael J. Wysocki } else { 109025e18499SRafael J. Wysocki ret = platform_legacy_resume(dev); 109125e18499SRafael J. Wysocki } 109225e18499SRafael J. Wysocki 109325e18499SRafael J. Wysocki return ret; 109425e18499SRafael J. Wysocki } 109525e18499SRafael J. Wysocki 109669c9dd1eSRafael J. Wysocki int platform_pm_poweroff(struct device *dev) 109725e18499SRafael J. Wysocki { 109825e18499SRafael J. Wysocki struct device_driver *drv = dev->driver; 109925e18499SRafael J. Wysocki int ret = 0; 110025e18499SRafael J. Wysocki 1101adf09493SRafael J. Wysocki if (!drv) 1102adf09493SRafael J. Wysocki return 0; 1103adf09493SRafael J. Wysocki 1104adf09493SRafael J. Wysocki if (drv->pm) { 110525e18499SRafael J. Wysocki if (drv->pm->poweroff) 110625e18499SRafael J. Wysocki ret = drv->pm->poweroff(dev); 110725e18499SRafael J. Wysocki } else { 110825e18499SRafael J. Wysocki ret = platform_legacy_suspend(dev, PMSG_HIBERNATE); 110925e18499SRafael J. Wysocki } 111025e18499SRafael J. Wysocki 111125e18499SRafael J. Wysocki return ret; 111225e18499SRafael J. Wysocki } 111325e18499SRafael J. Wysocki 111469c9dd1eSRafael J. Wysocki int platform_pm_restore(struct device *dev) 111525e18499SRafael J. Wysocki { 111625e18499SRafael J. Wysocki struct device_driver *drv = dev->driver; 111725e18499SRafael J. Wysocki int ret = 0; 111825e18499SRafael J. Wysocki 1119adf09493SRafael J. Wysocki if (!drv) 1120adf09493SRafael J. Wysocki return 0; 1121adf09493SRafael J. Wysocki 1122adf09493SRafael J. Wysocki if (drv->pm) { 112325e18499SRafael J. Wysocki if (drv->pm->restore) 112425e18499SRafael J. Wysocki ret = drv->pm->restore(dev); 112525e18499SRafael J. Wysocki } else { 112625e18499SRafael J. Wysocki ret = platform_legacy_resume(dev); 112725e18499SRafael J. Wysocki } 112825e18499SRafael J. Wysocki 112925e18499SRafael J. Wysocki return ret; 113025e18499SRafael J. Wysocki } 113125e18499SRafael J. Wysocki 113269c9dd1eSRafael J. Wysocki #endif /* CONFIG_HIBERNATE_CALLBACKS */ 113325e18499SRafael J. Wysocki 1134d9ab7716SDmitry Torokhov static const struct dev_pm_ops platform_dev_pm_ops = { 11358b313a38SRafael J. Wysocki .runtime_suspend = pm_generic_runtime_suspend, 11368b313a38SRafael J. Wysocki .runtime_resume = pm_generic_runtime_resume, 113769c9dd1eSRafael J. Wysocki USE_PLATFORM_PM_SLEEP_OPS 113825e18499SRafael J. Wysocki }; 113925e18499SRafael J. Wysocki 11401da177e4SLinus Torvalds struct bus_type platform_bus_type = { 11411da177e4SLinus Torvalds .name = "platform", 1142d06262e5SGreg Kroah-Hartman .dev_groups = platform_dev_groups, 11431da177e4SLinus Torvalds .match = platform_match, 1144a0245f7aSDavid Brownell .uevent = platform_uevent, 11459d730229SMagnus Damm .pm = &platform_dev_pm_ops, 11461da177e4SLinus Torvalds }; 1147a96b2042SDmitry Torokhov EXPORT_SYMBOL_GPL(platform_bus_type); 11481da177e4SLinus Torvalds 11491da177e4SLinus Torvalds int __init platform_bus_init(void) 11501da177e4SLinus Torvalds { 1151fbfb1445SCornelia Huck int error; 1152fbfb1445SCornelia Huck 115313977091SMagnus Damm early_platform_cleanup(); 115413977091SMagnus Damm 1155fbfb1445SCornelia Huck error = device_register(&platform_bus); 1156fbfb1445SCornelia Huck if (error) 1157fbfb1445SCornelia Huck return error; 1158fbfb1445SCornelia Huck error = bus_register(&platform_bus_type); 1159fbfb1445SCornelia Huck if (error) 1160fbfb1445SCornelia Huck device_unregister(&platform_bus); 1161801d728cSPantelis Antoniou of_platform_register_reconfig_notifier(); 1162fbfb1445SCornelia Huck return error; 11631da177e4SLinus Torvalds } 11641da177e4SLinus Torvalds 11651da177e4SLinus Torvalds #ifndef ARCH_HAS_DMA_GET_REQUIRED_MASK 11661da177e4SLinus Torvalds u64 dma_get_required_mask(struct device *dev) 11671da177e4SLinus Torvalds { 11681da177e4SLinus Torvalds u32 low_totalram = ((max_pfn - 1) << PAGE_SHIFT); 11691da177e4SLinus Torvalds u32 high_totalram = ((max_pfn - 1) >> (32 - PAGE_SHIFT)); 11701da177e4SLinus Torvalds u64 mask; 11711da177e4SLinus Torvalds 11721da177e4SLinus Torvalds if (!high_totalram) { 11731da177e4SLinus Torvalds /* convert to mask just covering totalram */ 11741da177e4SLinus Torvalds low_totalram = (1 << (fls(low_totalram) - 1)); 11751da177e4SLinus Torvalds low_totalram += low_totalram - 1; 11761da177e4SLinus Torvalds mask = low_totalram; 11771da177e4SLinus Torvalds } else { 11781da177e4SLinus Torvalds high_totalram = (1 << (fls(high_totalram) - 1)); 11791da177e4SLinus Torvalds high_totalram += high_totalram - 1; 11801da177e4SLinus Torvalds mask = (((u64)high_totalram) << 32) + 0xffffffff; 11811da177e4SLinus Torvalds } 1182e88a0c2cSJames Bottomley return mask; 11831da177e4SLinus Torvalds } 11841da177e4SLinus Torvalds EXPORT_SYMBOL_GPL(dma_get_required_mask); 11851da177e4SLinus Torvalds #endif 118613977091SMagnus Damm 118713977091SMagnus Damm static __initdata LIST_HEAD(early_platform_driver_list); 118813977091SMagnus Damm static __initdata LIST_HEAD(early_platform_device_list); 118913977091SMagnus Damm 119013977091SMagnus Damm /** 11914d26e139SMagnus Damm * early_platform_driver_register - register early platform driver 1192d86c1302SRandy Dunlap * @epdrv: early_platform driver structure 119313977091SMagnus Damm * @buf: string passed from early_param() 11944d26e139SMagnus Damm * 11954d26e139SMagnus Damm * Helper function for early_platform_init() / early_platform_init_buffer() 119613977091SMagnus Damm */ 119713977091SMagnus Damm int __init early_platform_driver_register(struct early_platform_driver *epdrv, 119813977091SMagnus Damm char *buf) 119913977091SMagnus Damm { 1200c60e0504SMagnus Damm char *tmp; 120113977091SMagnus Damm int n; 120213977091SMagnus Damm 120313977091SMagnus Damm /* Simply add the driver to the end of the global list. 120413977091SMagnus Damm * Drivers will by default be put on the list in compiled-in order. 120513977091SMagnus Damm */ 120613977091SMagnus Damm if (!epdrv->list.next) { 120713977091SMagnus Damm INIT_LIST_HEAD(&epdrv->list); 120813977091SMagnus Damm list_add_tail(&epdrv->list, &early_platform_driver_list); 120913977091SMagnus Damm } 121013977091SMagnus Damm 121113977091SMagnus Damm /* If the user has specified device then make sure the driver 121213977091SMagnus Damm * gets prioritized. The driver of the last device specified on 121313977091SMagnus Damm * command line will be put first on the list. 121413977091SMagnus Damm */ 121513977091SMagnus Damm n = strlen(epdrv->pdrv->driver.name); 121613977091SMagnus Damm if (buf && !strncmp(buf, epdrv->pdrv->driver.name, n)) { 121713977091SMagnus Damm list_move(&epdrv->list, &early_platform_driver_list); 121813977091SMagnus Damm 1219c60e0504SMagnus Damm /* Allow passing parameters after device name */ 1220c60e0504SMagnus Damm if (buf[n] == '\0' || buf[n] == ',') 122113977091SMagnus Damm epdrv->requested_id = -1; 1222c60e0504SMagnus Damm else { 1223c60e0504SMagnus Damm epdrv->requested_id = simple_strtoul(&buf[n + 1], 1224c60e0504SMagnus Damm &tmp, 10); 1225c60e0504SMagnus Damm 1226c60e0504SMagnus Damm if (buf[n] != '.' || (tmp == &buf[n + 1])) { 122713977091SMagnus Damm epdrv->requested_id = EARLY_PLATFORM_ID_ERROR; 1228c60e0504SMagnus Damm n = 0; 1229c60e0504SMagnus Damm } else 1230c60e0504SMagnus Damm n += strcspn(&buf[n + 1], ",") + 1; 1231c60e0504SMagnus Damm } 1232c60e0504SMagnus Damm 1233c60e0504SMagnus Damm if (buf[n] == ',') 1234c60e0504SMagnus Damm n++; 1235c60e0504SMagnus Damm 1236c60e0504SMagnus Damm if (epdrv->bufsize) { 1237c60e0504SMagnus Damm memcpy(epdrv->buffer, &buf[n], 1238c60e0504SMagnus Damm min_t(int, epdrv->bufsize, strlen(&buf[n]) + 1)); 1239c60e0504SMagnus Damm epdrv->buffer[epdrv->bufsize - 1] = '\0'; 1240c60e0504SMagnus Damm } 124113977091SMagnus Damm } 124213977091SMagnus Damm 124313977091SMagnus Damm return 0; 124413977091SMagnus Damm } 124513977091SMagnus Damm 124613977091SMagnus Damm /** 12474d26e139SMagnus Damm * early_platform_add_devices - adds a number of early platform devices 124813977091SMagnus Damm * @devs: array of early platform devices to add 124913977091SMagnus Damm * @num: number of early platform devices in array 12504d26e139SMagnus Damm * 12514d26e139SMagnus Damm * Used by early architecture code to register early platform devices and 12524d26e139SMagnus Damm * their platform data. 125313977091SMagnus Damm */ 125413977091SMagnus Damm void __init early_platform_add_devices(struct platform_device **devs, int num) 125513977091SMagnus Damm { 125613977091SMagnus Damm struct device *dev; 125713977091SMagnus Damm int i; 125813977091SMagnus Damm 125913977091SMagnus Damm /* simply add the devices to list */ 126013977091SMagnus Damm for (i = 0; i < num; i++) { 126113977091SMagnus Damm dev = &devs[i]->dev; 126213977091SMagnus Damm 126313977091SMagnus Damm if (!dev->devres_head.next) { 1264bed2b42dSRafael J. Wysocki pm_runtime_early_init(dev); 126513977091SMagnus Damm INIT_LIST_HEAD(&dev->devres_head); 126613977091SMagnus Damm list_add_tail(&dev->devres_head, 126713977091SMagnus Damm &early_platform_device_list); 126813977091SMagnus Damm } 126913977091SMagnus Damm } 127013977091SMagnus Damm } 127113977091SMagnus Damm 127213977091SMagnus Damm /** 12734d26e139SMagnus Damm * early_platform_driver_register_all - register early platform drivers 127413977091SMagnus Damm * @class_str: string to identify early platform driver class 12754d26e139SMagnus Damm * 12764d26e139SMagnus Damm * Used by architecture code to register all early platform drivers 12774d26e139SMagnus Damm * for a certain class. If omitted then only early platform drivers 12784d26e139SMagnus Damm * with matching kernel command line class parameters will be registered. 127913977091SMagnus Damm */ 128013977091SMagnus Damm void __init early_platform_driver_register_all(char *class_str) 128113977091SMagnus Damm { 128213977091SMagnus Damm /* The "class_str" parameter may or may not be present on the kernel 128313977091SMagnus Damm * command line. If it is present then there may be more than one 128413977091SMagnus Damm * matching parameter. 128513977091SMagnus Damm * 128613977091SMagnus Damm * Since we register our early platform drivers using early_param() 128713977091SMagnus Damm * we need to make sure that they also get registered in the case 128813977091SMagnus Damm * when the parameter is missing from the kernel command line. 128913977091SMagnus Damm * 129013977091SMagnus Damm * We use parse_early_options() to make sure the early_param() gets 129113977091SMagnus Damm * called at least once. The early_param() may be called more than 129213977091SMagnus Damm * once since the name of the preferred device may be specified on 129313977091SMagnus Damm * the kernel command line. early_platform_driver_register() handles 129413977091SMagnus Damm * this case for us. 129513977091SMagnus Damm */ 129613977091SMagnus Damm parse_early_options(class_str); 129713977091SMagnus Damm } 129813977091SMagnus Damm 129913977091SMagnus Damm /** 13004d26e139SMagnus Damm * early_platform_match - find early platform device matching driver 1301d86c1302SRandy Dunlap * @epdrv: early platform driver structure 130213977091SMagnus Damm * @id: id to match against 130313977091SMagnus Damm */ 1304a8257910SHanjun Guo static struct platform_device * __init 130513977091SMagnus Damm early_platform_match(struct early_platform_driver *epdrv, int id) 130613977091SMagnus Damm { 130713977091SMagnus Damm struct platform_device *pd; 130813977091SMagnus Damm 130913977091SMagnus Damm list_for_each_entry(pd, &early_platform_device_list, dev.devres_head) 131013977091SMagnus Damm if (platform_match(&pd->dev, &epdrv->pdrv->driver)) 131113977091SMagnus Damm if (pd->id == id) 131213977091SMagnus Damm return pd; 131313977091SMagnus Damm 131413977091SMagnus Damm return NULL; 131513977091SMagnus Damm } 131613977091SMagnus Damm 131713977091SMagnus Damm /** 13184d26e139SMagnus Damm * early_platform_left - check if early platform driver has matching devices 1319d86c1302SRandy Dunlap * @epdrv: early platform driver structure 132013977091SMagnus Damm * @id: return true if id or above exists 132113977091SMagnus Damm */ 1322a8257910SHanjun Guo static int __init early_platform_left(struct early_platform_driver *epdrv, 132313977091SMagnus Damm int id) 132413977091SMagnus Damm { 132513977091SMagnus Damm struct platform_device *pd; 132613977091SMagnus Damm 132713977091SMagnus Damm list_for_each_entry(pd, &early_platform_device_list, dev.devres_head) 132813977091SMagnus Damm if (platform_match(&pd->dev, &epdrv->pdrv->driver)) 132913977091SMagnus Damm if (pd->id >= id) 133013977091SMagnus Damm return 1; 133113977091SMagnus Damm 133213977091SMagnus Damm return 0; 133313977091SMagnus Damm } 133413977091SMagnus Damm 133513977091SMagnus Damm /** 13364d26e139SMagnus Damm * early_platform_driver_probe_id - probe drivers matching class_str and id 133713977091SMagnus Damm * @class_str: string to identify early platform driver class 133813977091SMagnus Damm * @id: id to match against 133913977091SMagnus Damm * @nr_probe: number of platform devices to successfully probe before exiting 134013977091SMagnus Damm */ 134113977091SMagnus Damm static int __init early_platform_driver_probe_id(char *class_str, 134213977091SMagnus Damm int id, 134313977091SMagnus Damm int nr_probe) 134413977091SMagnus Damm { 134513977091SMagnus Damm struct early_platform_driver *epdrv; 134613977091SMagnus Damm struct platform_device *match; 134713977091SMagnus Damm int match_id; 134813977091SMagnus Damm int n = 0; 134913977091SMagnus Damm int left = 0; 135013977091SMagnus Damm 135113977091SMagnus Damm list_for_each_entry(epdrv, &early_platform_driver_list, list) { 135213977091SMagnus Damm /* only use drivers matching our class_str */ 135313977091SMagnus Damm if (strcmp(class_str, epdrv->class_str)) 135413977091SMagnus Damm continue; 135513977091SMagnus Damm 135613977091SMagnus Damm if (id == -2) { 135713977091SMagnus Damm match_id = epdrv->requested_id; 135813977091SMagnus Damm left = 1; 135913977091SMagnus Damm 136013977091SMagnus Damm } else { 136113977091SMagnus Damm match_id = id; 136213977091SMagnus Damm left += early_platform_left(epdrv, id); 136313977091SMagnus Damm 136413977091SMagnus Damm /* skip requested id */ 136513977091SMagnus Damm switch (epdrv->requested_id) { 136613977091SMagnus Damm case EARLY_PLATFORM_ID_ERROR: 136713977091SMagnus Damm case EARLY_PLATFORM_ID_UNSET: 136813977091SMagnus Damm break; 136913977091SMagnus Damm default: 137013977091SMagnus Damm if (epdrv->requested_id == id) 137113977091SMagnus Damm match_id = EARLY_PLATFORM_ID_UNSET; 137213977091SMagnus Damm } 137313977091SMagnus Damm } 137413977091SMagnus Damm 137513977091SMagnus Damm switch (match_id) { 137613977091SMagnus Damm case EARLY_PLATFORM_ID_ERROR: 13770258e182SFabio Porcedda pr_warn("%s: unable to parse %s parameter\n", 137813977091SMagnus Damm class_str, epdrv->pdrv->driver.name); 137913977091SMagnus Damm /* fall-through */ 138013977091SMagnus Damm case EARLY_PLATFORM_ID_UNSET: 138113977091SMagnus Damm match = NULL; 138213977091SMagnus Damm break; 138313977091SMagnus Damm default: 138413977091SMagnus Damm match = early_platform_match(epdrv, match_id); 138513977091SMagnus Damm } 138613977091SMagnus Damm 138713977091SMagnus Damm if (match) { 1388a636ee7fSPaul Mundt /* 1389a636ee7fSPaul Mundt * Set up a sensible init_name to enable 1390a636ee7fSPaul Mundt * dev_name() and others to be used before the 1391a636ee7fSPaul Mundt * rest of the driver core is initialized. 1392a636ee7fSPaul Mundt */ 139306fe53beSPaul Mundt if (!match->dev.init_name && slab_is_available()) { 1394a636ee7fSPaul Mundt if (match->id != -1) 1395bd05086bSPaul Mundt match->dev.init_name = 1396bd05086bSPaul Mundt kasprintf(GFP_KERNEL, "%s.%d", 1397bd05086bSPaul Mundt match->name, 1398bd05086bSPaul Mundt match->id); 1399a636ee7fSPaul Mundt else 1400bd05086bSPaul Mundt match->dev.init_name = 1401bd05086bSPaul Mundt kasprintf(GFP_KERNEL, "%s", 1402a636ee7fSPaul Mundt match->name); 1403a636ee7fSPaul Mundt 1404a636ee7fSPaul Mundt if (!match->dev.init_name) 1405a636ee7fSPaul Mundt return -ENOMEM; 1406a636ee7fSPaul Mundt } 1407bd05086bSPaul Mundt 140813977091SMagnus Damm if (epdrv->pdrv->probe(match)) 14090258e182SFabio Porcedda pr_warn("%s: unable to probe %s early.\n", 141013977091SMagnus Damm class_str, match->name); 141113977091SMagnus Damm else 141213977091SMagnus Damm n++; 141313977091SMagnus Damm } 141413977091SMagnus Damm 141513977091SMagnus Damm if (n >= nr_probe) 141613977091SMagnus Damm break; 141713977091SMagnus Damm } 141813977091SMagnus Damm 141913977091SMagnus Damm if (left) 142013977091SMagnus Damm return n; 142113977091SMagnus Damm else 142213977091SMagnus Damm return -ENODEV; 142313977091SMagnus Damm } 142413977091SMagnus Damm 142513977091SMagnus Damm /** 14264d26e139SMagnus Damm * early_platform_driver_probe - probe a class of registered drivers 142713977091SMagnus Damm * @class_str: string to identify early platform driver class 142813977091SMagnus Damm * @nr_probe: number of platform devices to successfully probe before exiting 142913977091SMagnus Damm * @user_only: only probe user specified early platform devices 14304d26e139SMagnus Damm * 14314d26e139SMagnus Damm * Used by architecture code to probe registered early platform drivers 14324d26e139SMagnus Damm * within a certain class. For probe to happen a registered early platform 14334d26e139SMagnus Damm * device matching a registered early platform driver is needed. 143413977091SMagnus Damm */ 143513977091SMagnus Damm int __init early_platform_driver_probe(char *class_str, 143613977091SMagnus Damm int nr_probe, 143713977091SMagnus Damm int user_only) 143813977091SMagnus Damm { 143913977091SMagnus Damm int k, n, i; 144013977091SMagnus Damm 144113977091SMagnus Damm n = 0; 144213977091SMagnus Damm for (i = -2; n < nr_probe; i++) { 144313977091SMagnus Damm k = early_platform_driver_probe_id(class_str, i, nr_probe - n); 144413977091SMagnus Damm 144513977091SMagnus Damm if (k < 0) 144613977091SMagnus Damm break; 144713977091SMagnus Damm 144813977091SMagnus Damm n += k; 144913977091SMagnus Damm 145013977091SMagnus Damm if (user_only) 145113977091SMagnus Damm break; 145213977091SMagnus Damm } 145313977091SMagnus Damm 145413977091SMagnus Damm return n; 145513977091SMagnus Damm } 145613977091SMagnus Damm 145713977091SMagnus Damm /** 145813977091SMagnus Damm * early_platform_cleanup - clean up early platform code 145913977091SMagnus Damm */ 146013977091SMagnus Damm void __init early_platform_cleanup(void) 146113977091SMagnus Damm { 146213977091SMagnus Damm struct platform_device *pd, *pd2; 146313977091SMagnus Damm 146413977091SMagnus Damm /* clean up the devres list used to chain devices */ 146513977091SMagnus Damm list_for_each_entry_safe(pd, pd2, &early_platform_device_list, 146613977091SMagnus Damm dev.devres_head) { 146713977091SMagnus Damm list_del(&pd->dev.devres_head); 146813977091SMagnus Damm memset(&pd->dev.devres_head, 0, sizeof(pd->dev.devres_head)); 146913977091SMagnus Damm } 147013977091SMagnus Damm } 147113977091SMagnus Damm 1472