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> 291da177e4SLinus Torvalds 30a1bdc7aaSBen Dooks #include "base.h" 31bed2b42dSRafael J. Wysocki #include "power/power.h" 32a1bdc7aaSBen Dooks 33689ae231SJean Delvare /* For automatically allocated device IDs */ 34689ae231SJean Delvare static DEFINE_IDA(platform_devid_ida); 35689ae231SJean Delvare 361da177e4SLinus Torvalds struct device platform_bus = { 371e0b2cf9SKay Sievers .init_name = "platform", 381da177e4SLinus Torvalds }; 39a96b2042SDmitry Torokhov EXPORT_SYMBOL_GPL(platform_bus); 401da177e4SLinus Torvalds 411da177e4SLinus Torvalds /** 42a77ce816SKumar Gala * arch_setup_pdev_archdata - Allow manipulation of archdata before its used 437de636faSRandy Dunlap * @pdev: platform device 44a77ce816SKumar Gala * 45a77ce816SKumar Gala * This is called before platform_device_add() such that any pdev_archdata may 46a77ce816SKumar Gala * be setup before the platform_notifier is called. So if a user needs to 47a77ce816SKumar Gala * manipulate any relevant information in the pdev_archdata they can do: 48a77ce816SKumar Gala * 49b1d6d822SSebastian Andrzej Siewior * platform_device_alloc() 50a77ce816SKumar Gala * ... manipulate ... 51a77ce816SKumar Gala * platform_device_add() 52a77ce816SKumar Gala * 53a77ce816SKumar Gala * And if they don't care they can just call platform_device_register() and 54a77ce816SKumar Gala * everything will just work out. 55a77ce816SKumar Gala */ 56a77ce816SKumar Gala void __weak arch_setup_pdev_archdata(struct platform_device *pdev) 57a77ce816SKumar Gala { 58a77ce816SKumar Gala } 59a77ce816SKumar Gala 60a77ce816SKumar Gala /** 611da177e4SLinus Torvalds * platform_get_resource - get a resource for a device 621da177e4SLinus Torvalds * @dev: platform device 631da177e4SLinus Torvalds * @type: resource type 641da177e4SLinus Torvalds * @num: resource index 651da177e4SLinus Torvalds */ 664a3ad20cSGreg Kroah-Hartman struct resource *platform_get_resource(struct platform_device *dev, 674a3ad20cSGreg Kroah-Hartman unsigned int type, unsigned int num) 681da177e4SLinus Torvalds { 691da177e4SLinus Torvalds int i; 701da177e4SLinus Torvalds 711da177e4SLinus Torvalds for (i = 0; i < dev->num_resources; i++) { 721da177e4SLinus Torvalds struct resource *r = &dev->resource[i]; 731da177e4SLinus Torvalds 74c9f66169SMagnus Damm if (type == resource_type(r) && num-- == 0) 751da177e4SLinus Torvalds return r; 761da177e4SLinus Torvalds } 771da177e4SLinus Torvalds return NULL; 781da177e4SLinus Torvalds } 79a96b2042SDmitry Torokhov EXPORT_SYMBOL_GPL(platform_get_resource); 801da177e4SLinus Torvalds 811da177e4SLinus Torvalds /** 821da177e4SLinus Torvalds * platform_get_irq - get an IRQ for a device 831da177e4SLinus Torvalds * @dev: platform device 841da177e4SLinus Torvalds * @num: IRQ number index 851da177e4SLinus Torvalds */ 861da177e4SLinus Torvalds int platform_get_irq(struct platform_device *dev, unsigned int num) 871da177e4SLinus Torvalds { 885cf8f7dbSAndreas Larsson #ifdef CONFIG_SPARC 895cf8f7dbSAndreas Larsson /* sparc does not have irqs represented as IORESOURCE_IRQ resources */ 905cf8f7dbSAndreas Larsson if (!dev || num >= dev->archdata.num_irqs) 915cf8f7dbSAndreas Larsson return -ENXIO; 925cf8f7dbSAndreas Larsson return dev->archdata.irqs[num]; 935cf8f7dbSAndreas Larsson #else 949ec36cafSRob Herring struct resource *r; 95aff008adSGuenter Roeck if (IS_ENABLED(CONFIG_OF_IRQ) && dev->dev.of_node) { 96aff008adSGuenter Roeck int ret; 97aff008adSGuenter Roeck 98aff008adSGuenter Roeck ret = of_irq_get(dev->dev.of_node, num); 99aff008adSGuenter Roeck if (ret >= 0 || ret == -EPROBE_DEFER) 100aff008adSGuenter Roeck return ret; 101aff008adSGuenter Roeck } 1029ec36cafSRob Herring 1039ec36cafSRob Herring r = platform_get_resource(dev, IORESOURCE_IRQ, num); 1041da177e4SLinus Torvalds 105305b3228SDavid Vrabel return r ? r->start : -ENXIO; 1065cf8f7dbSAndreas Larsson #endif 1071da177e4SLinus Torvalds } 108a96b2042SDmitry Torokhov EXPORT_SYMBOL_GPL(platform_get_irq); 1091da177e4SLinus Torvalds 1101da177e4SLinus Torvalds /** 1111da177e4SLinus Torvalds * platform_get_resource_byname - get a resource for a device by name 1121da177e4SLinus Torvalds * @dev: platform device 1131da177e4SLinus Torvalds * @type: resource type 1141da177e4SLinus Torvalds * @name: resource name 1151da177e4SLinus Torvalds */ 1164a3ad20cSGreg Kroah-Hartman struct resource *platform_get_resource_byname(struct platform_device *dev, 117c0afe7baSLinus Walleij unsigned int type, 118c0afe7baSLinus Walleij const char *name) 1191da177e4SLinus Torvalds { 1201da177e4SLinus Torvalds int i; 1211da177e4SLinus Torvalds 1221da177e4SLinus Torvalds for (i = 0; i < dev->num_resources; i++) { 1231da177e4SLinus Torvalds struct resource *r = &dev->resource[i]; 1241da177e4SLinus Torvalds 1251b8cb929SPeter Ujfalusi if (unlikely(!r->name)) 1261b8cb929SPeter Ujfalusi continue; 1271b8cb929SPeter Ujfalusi 128c9f66169SMagnus Damm if (type == resource_type(r) && !strcmp(r->name, name)) 1291da177e4SLinus Torvalds return r; 1301da177e4SLinus Torvalds } 1311da177e4SLinus Torvalds return NULL; 1321da177e4SLinus Torvalds } 133a96b2042SDmitry Torokhov EXPORT_SYMBOL_GPL(platform_get_resource_byname); 1341da177e4SLinus Torvalds 1351da177e4SLinus Torvalds /** 136d6ff8551SWolfram Sang * platform_get_irq_byname - get an IRQ for a device by name 1371da177e4SLinus Torvalds * @dev: platform device 1381da177e4SLinus Torvalds * @name: IRQ name 1391da177e4SLinus Torvalds */ 140c0afe7baSLinus Walleij int platform_get_irq_byname(struct platform_device *dev, const char *name) 1411da177e4SLinus Torvalds { 142ad69674eSGrygorii Strashko struct resource *r; 1431da177e4SLinus Torvalds 144aff008adSGuenter Roeck if (IS_ENABLED(CONFIG_OF_IRQ) && dev->dev.of_node) { 145aff008adSGuenter Roeck int ret; 146aff008adSGuenter Roeck 147aff008adSGuenter Roeck ret = of_irq_get_byname(dev->dev.of_node, name); 148aff008adSGuenter Roeck if (ret >= 0 || ret == -EPROBE_DEFER) 149aff008adSGuenter Roeck return ret; 150aff008adSGuenter Roeck } 151ad69674eSGrygorii Strashko 152ad69674eSGrygorii Strashko r = platform_get_resource_byname(dev, IORESOURCE_IRQ, name); 153305b3228SDavid Vrabel return r ? r->start : -ENXIO; 1541da177e4SLinus Torvalds } 155a96b2042SDmitry Torokhov EXPORT_SYMBOL_GPL(platform_get_irq_byname); 1561da177e4SLinus Torvalds 1571da177e4SLinus Torvalds /** 1581da177e4SLinus Torvalds * platform_add_devices - add a numbers of platform devices 1591da177e4SLinus Torvalds * @devs: array of platform devices to add 1601da177e4SLinus Torvalds * @num: number of platform devices in array 1611da177e4SLinus Torvalds */ 1621da177e4SLinus Torvalds int platform_add_devices(struct platform_device **devs, int num) 1631da177e4SLinus Torvalds { 1641da177e4SLinus Torvalds int i, ret = 0; 1651da177e4SLinus Torvalds 1661da177e4SLinus Torvalds for (i = 0; i < num; i++) { 1671da177e4SLinus Torvalds ret = platform_device_register(devs[i]); 1681da177e4SLinus Torvalds if (ret) { 1691da177e4SLinus Torvalds while (--i >= 0) 1701da177e4SLinus Torvalds platform_device_unregister(devs[i]); 1711da177e4SLinus Torvalds break; 1721da177e4SLinus Torvalds } 1731da177e4SLinus Torvalds } 1741da177e4SLinus Torvalds 1751da177e4SLinus Torvalds return ret; 1761da177e4SLinus Torvalds } 177a96b2042SDmitry Torokhov EXPORT_SYMBOL_GPL(platform_add_devices); 1781da177e4SLinus Torvalds 17937c12e74SRussell King struct platform_object { 18037c12e74SRussell King struct platform_device pdev; 1811cec24c5SYann Droneaud char name[]; 18237c12e74SRussell King }; 18337c12e74SRussell King 1841da177e4SLinus Torvalds /** 1853c31f07aSBen Hutchings * platform_device_put - destroy a platform device 18637c12e74SRussell King * @pdev: platform device to free 18737c12e74SRussell King * 1884a3ad20cSGreg Kroah-Hartman * Free all memory associated with a platform device. This function must 1894a3ad20cSGreg Kroah-Hartman * _only_ be externally called in error cases. All other usage is a bug. 19037c12e74SRussell King */ 19137c12e74SRussell King void platform_device_put(struct platform_device *pdev) 19237c12e74SRussell King { 19337c12e74SRussell King if (pdev) 19437c12e74SRussell King put_device(&pdev->dev); 19537c12e74SRussell King } 19637c12e74SRussell King EXPORT_SYMBOL_GPL(platform_device_put); 19737c12e74SRussell King 19837c12e74SRussell King static void platform_device_release(struct device *dev) 19937c12e74SRussell King { 2004a3ad20cSGreg Kroah-Hartman struct platform_object *pa = container_of(dev, struct platform_object, 2014a3ad20cSGreg Kroah-Hartman pdev.dev); 20237c12e74SRussell King 2037096d042SGrant Likely of_device_node_put(&pa->pdev.dev); 20437c12e74SRussell King kfree(pa->pdev.dev.platform_data); 205e710d7d5SSamuel Ortiz kfree(pa->pdev.mfd_cell); 20637c12e74SRussell King kfree(pa->pdev.resource); 2073d713e0eSKim Phillips kfree(pa->pdev.driver_override); 20837c12e74SRussell King kfree(pa); 20937c12e74SRussell King } 21037c12e74SRussell King 21137c12e74SRussell King /** 2123c31f07aSBen Hutchings * platform_device_alloc - create a platform device 21337c12e74SRussell King * @name: base name of the device we're adding 21437c12e74SRussell King * @id: instance id 21537c12e74SRussell King * 21637c12e74SRussell King * Create a platform device object which can have other objects attached 21737c12e74SRussell King * to it, and which will have attached objects freed when it is released. 21837c12e74SRussell King */ 2191359555eSJean Delvare struct platform_device *platform_device_alloc(const char *name, int id) 22037c12e74SRussell King { 22137c12e74SRussell King struct platform_object *pa; 22237c12e74SRussell King 2231cec24c5SYann Droneaud pa = kzalloc(sizeof(*pa) + strlen(name) + 1, GFP_KERNEL); 22437c12e74SRussell King if (pa) { 22537c12e74SRussell King strcpy(pa->name, name); 22637c12e74SRussell King pa->pdev.name = pa->name; 22737c12e74SRussell King pa->pdev.id = id; 22837c12e74SRussell King device_initialize(&pa->pdev.dev); 22937c12e74SRussell King pa->pdev.dev.release = platform_device_release; 230a77ce816SKumar Gala arch_setup_pdev_archdata(&pa->pdev); 23137c12e74SRussell King } 23237c12e74SRussell King 23337c12e74SRussell King return pa ? &pa->pdev : NULL; 23437c12e74SRussell King } 23537c12e74SRussell King EXPORT_SYMBOL_GPL(platform_device_alloc); 23637c12e74SRussell King 23737c12e74SRussell King /** 2383c31f07aSBen Hutchings * platform_device_add_resources - add resources to a platform device 23937c12e74SRussell King * @pdev: platform device allocated by platform_device_alloc to add resources to 24037c12e74SRussell King * @res: set of resources that needs to be allocated for the device 24137c12e74SRussell King * @num: number of resources 24237c12e74SRussell King * 24337c12e74SRussell King * Add a copy of the resources to the platform device. The memory 2444a3ad20cSGreg Kroah-Hartman * associated with the resources will be freed when the platform device is 2454a3ad20cSGreg Kroah-Hartman * released. 24637c12e74SRussell King */ 2474a3ad20cSGreg Kroah-Hartman int platform_device_add_resources(struct platform_device *pdev, 2480b7f1a7eSGeert Uytterhoeven const struct resource *res, unsigned int num) 24937c12e74SRussell King { 250cea89623SUwe Kleine-König struct resource *r = NULL; 25137c12e74SRussell King 252cea89623SUwe Kleine-König if (res) { 2533e61dfd8SUwe Kleine-König r = kmemdup(res, sizeof(struct resource) * num, GFP_KERNEL); 254cea89623SUwe Kleine-König if (!r) 255cea89623SUwe Kleine-König return -ENOMEM; 256cea89623SUwe Kleine-König } 257cea89623SUwe Kleine-König 2584a03d6f7SUwe Kleine-König kfree(pdev->resource); 25937c12e74SRussell King pdev->resource = r; 26037c12e74SRussell King pdev->num_resources = num; 2613e61dfd8SUwe Kleine-König return 0; 26237c12e74SRussell King } 26337c12e74SRussell King EXPORT_SYMBOL_GPL(platform_device_add_resources); 26437c12e74SRussell King 26537c12e74SRussell King /** 2663c31f07aSBen Hutchings * platform_device_add_data - add platform-specific data to a platform device 26737c12e74SRussell King * @pdev: platform device allocated by platform_device_alloc to add resources to 26837c12e74SRussell King * @data: platform specific data for this platform device 26937c12e74SRussell King * @size: size of platform specific data 27037c12e74SRussell King * 2714a3ad20cSGreg Kroah-Hartman * Add a copy of platform specific data to the platform device's 2724a3ad20cSGreg Kroah-Hartman * platform_data pointer. The memory associated with the platform data 2734a3ad20cSGreg Kroah-Hartman * will be freed when the platform device is released. 27437c12e74SRussell King */ 2754a3ad20cSGreg Kroah-Hartman int platform_device_add_data(struct platform_device *pdev, const void *data, 2764a3ad20cSGreg Kroah-Hartman size_t size) 27737c12e74SRussell King { 27827a33f9eSUwe Kleine-König void *d = NULL; 27937c12e74SRussell King 28027a33f9eSUwe Kleine-König if (data) { 2815cfc64ceSAnton Vorontsov d = kmemdup(data, size, GFP_KERNEL); 28227a33f9eSUwe Kleine-König if (!d) 28327a33f9eSUwe Kleine-König return -ENOMEM; 28427a33f9eSUwe Kleine-König } 28527a33f9eSUwe Kleine-König 286251e031dSUwe Kleine-König kfree(pdev->dev.platform_data); 28737c12e74SRussell King pdev->dev.platform_data = d; 288daa41226SAndrew Morton return 0; 28937c12e74SRussell King } 29037c12e74SRussell King EXPORT_SYMBOL_GPL(platform_device_add_data); 29137c12e74SRussell King 29237c12e74SRussell King /** 29337c12e74SRussell King * platform_device_add - add a platform device to device hierarchy 29467be2dd1SMartin Waitz * @pdev: platform device we're adding 2951da177e4SLinus Torvalds * 29637c12e74SRussell King * This is part 2 of platform_device_register(), though may be called 29737c12e74SRussell King * separately _iff_ pdev was allocated by platform_device_alloc(). 2981da177e4SLinus Torvalds */ 29937c12e74SRussell King int platform_device_add(struct platform_device *pdev) 3001da177e4SLinus Torvalds { 301689ae231SJean Delvare int i, ret; 3021da177e4SLinus Torvalds 3031da177e4SLinus Torvalds if (!pdev) 3041da177e4SLinus Torvalds return -EINVAL; 3051da177e4SLinus Torvalds 3061da177e4SLinus Torvalds if (!pdev->dev.parent) 3071da177e4SLinus Torvalds pdev->dev.parent = &platform_bus; 3081da177e4SLinus Torvalds 3091da177e4SLinus Torvalds pdev->dev.bus = &platform_bus_type; 3101da177e4SLinus Torvalds 311689ae231SJean Delvare switch (pdev->id) { 312689ae231SJean Delvare default: 3131e0b2cf9SKay Sievers dev_set_name(&pdev->dev, "%s.%d", pdev->name, pdev->id); 314689ae231SJean Delvare break; 315689ae231SJean Delvare case PLATFORM_DEVID_NONE: 316acc0e90fSGreg Kroah-Hartman dev_set_name(&pdev->dev, "%s", pdev->name); 317689ae231SJean Delvare break; 318689ae231SJean Delvare case PLATFORM_DEVID_AUTO: 319689ae231SJean Delvare /* 320689ae231SJean Delvare * Automatically allocated device ID. We mark it as such so 321689ae231SJean Delvare * that we remember it must be freed, and we append a suffix 322689ae231SJean Delvare * to avoid namespace collision with explicit IDs. 323689ae231SJean Delvare */ 324689ae231SJean Delvare ret = ida_simple_get(&platform_devid_ida, 0, 0, GFP_KERNEL); 325689ae231SJean Delvare if (ret < 0) 326689ae231SJean Delvare goto err_out; 327689ae231SJean Delvare pdev->id = ret; 328689ae231SJean Delvare pdev->id_auto = true; 329689ae231SJean Delvare dev_set_name(&pdev->dev, "%s.%d.auto", pdev->name, pdev->id); 330689ae231SJean Delvare break; 331689ae231SJean Delvare } 3321da177e4SLinus Torvalds 3331da177e4SLinus Torvalds for (i = 0; i < pdev->num_resources; i++) { 3341da177e4SLinus Torvalds struct resource *p, *r = &pdev->resource[i]; 3351da177e4SLinus Torvalds 3361da177e4SLinus Torvalds if (r->name == NULL) 3371e0b2cf9SKay Sievers r->name = dev_name(&pdev->dev); 3381da177e4SLinus Torvalds 3391da177e4SLinus Torvalds p = r->parent; 3401da177e4SLinus Torvalds if (!p) { 341c9f66169SMagnus Damm if (resource_type(r) == IORESOURCE_MEM) 3421da177e4SLinus Torvalds p = &iomem_resource; 343c9f66169SMagnus Damm else if (resource_type(r) == IORESOURCE_IO) 3441da177e4SLinus Torvalds p = &ioport_resource; 3451da177e4SLinus Torvalds } 3461da177e4SLinus Torvalds 347d960bb4dSKumar Gala if (p && insert_resource(p, r)) { 3480258e182SFabio Porcedda dev_err(&pdev->dev, "failed to claim resource %d\n", i); 3491da177e4SLinus Torvalds ret = -EBUSY; 3501da177e4SLinus Torvalds goto failed; 3511da177e4SLinus Torvalds } 3521da177e4SLinus Torvalds } 3531da177e4SLinus Torvalds 3541da177e4SLinus Torvalds pr_debug("Registering platform device '%s'. Parent at %s\n", 3551e0b2cf9SKay Sievers dev_name(&pdev->dev), dev_name(pdev->dev.parent)); 3561da177e4SLinus Torvalds 357e3915532SRussell King ret = device_add(&pdev->dev); 3581da177e4SLinus Torvalds if (ret == 0) 3591da177e4SLinus Torvalds return ret; 3601da177e4SLinus Torvalds 3611da177e4SLinus Torvalds failed: 362689ae231SJean Delvare if (pdev->id_auto) { 363689ae231SJean Delvare ida_simple_remove(&platform_devid_ida, pdev->id); 364689ae231SJean Delvare pdev->id = PLATFORM_DEVID_AUTO; 365689ae231SJean Delvare } 366689ae231SJean Delvare 367c9f66169SMagnus Damm while (--i >= 0) { 368c9f66169SMagnus Damm struct resource *r = &pdev->resource[i]; 369c9f66169SMagnus Damm unsigned long type = resource_type(r); 370c9f66169SMagnus Damm 371c9f66169SMagnus Damm if (type == IORESOURCE_MEM || type == IORESOURCE_IO) 372c9f66169SMagnus Damm release_resource(r); 373c9f66169SMagnus Damm } 374c9f66169SMagnus Damm 375689ae231SJean Delvare err_out: 3761da177e4SLinus Torvalds return ret; 3771da177e4SLinus Torvalds } 37837c12e74SRussell King EXPORT_SYMBOL_GPL(platform_device_add); 37937c12e74SRussell King 38037c12e74SRussell King /** 38193ce3061SDmitry Torokhov * platform_device_del - remove a platform-level device 38293ce3061SDmitry Torokhov * @pdev: platform device we're removing 38393ce3061SDmitry Torokhov * 38493ce3061SDmitry Torokhov * Note that this function will also release all memory- and port-based 3854a3ad20cSGreg Kroah-Hartman * resources owned by the device (@dev->resource). This function must 3864a3ad20cSGreg Kroah-Hartman * _only_ be externally called in error cases. All other usage is a bug. 38793ce3061SDmitry Torokhov */ 38893ce3061SDmitry Torokhov void platform_device_del(struct platform_device *pdev) 38993ce3061SDmitry Torokhov { 39093ce3061SDmitry Torokhov int i; 39193ce3061SDmitry Torokhov 39293ce3061SDmitry Torokhov if (pdev) { 393dc4c15d4SJean Delvare device_del(&pdev->dev); 394dc4c15d4SJean Delvare 395689ae231SJean Delvare if (pdev->id_auto) { 396689ae231SJean Delvare ida_simple_remove(&platform_devid_ida, pdev->id); 397689ae231SJean Delvare pdev->id = PLATFORM_DEVID_AUTO; 398689ae231SJean Delvare } 399689ae231SJean Delvare 40093ce3061SDmitry Torokhov for (i = 0; i < pdev->num_resources; i++) { 40193ce3061SDmitry Torokhov struct resource *r = &pdev->resource[i]; 402c9f66169SMagnus Damm unsigned long type = resource_type(r); 403c9f66169SMagnus Damm 404c9f66169SMagnus Damm if (type == IORESOURCE_MEM || type == IORESOURCE_IO) 40593ce3061SDmitry Torokhov release_resource(r); 40693ce3061SDmitry Torokhov } 40793ce3061SDmitry Torokhov } 40893ce3061SDmitry Torokhov } 40993ce3061SDmitry Torokhov EXPORT_SYMBOL_GPL(platform_device_del); 41093ce3061SDmitry Torokhov 41193ce3061SDmitry Torokhov /** 41237c12e74SRussell King * platform_device_register - add a platform-level device 41337c12e74SRussell King * @pdev: platform device we're adding 41437c12e74SRussell King */ 41537c12e74SRussell King int platform_device_register(struct platform_device *pdev) 41637c12e74SRussell King { 41737c12e74SRussell King device_initialize(&pdev->dev); 418a77ce816SKumar Gala arch_setup_pdev_archdata(pdev); 41937c12e74SRussell King return platform_device_add(pdev); 42037c12e74SRussell King } 421a96b2042SDmitry Torokhov EXPORT_SYMBOL_GPL(platform_device_register); 4221da177e4SLinus Torvalds 4231da177e4SLinus Torvalds /** 42493ce3061SDmitry Torokhov * platform_device_unregister - unregister a platform-level device 42593ce3061SDmitry Torokhov * @pdev: platform device we're unregistering 4261da177e4SLinus Torvalds * 42780682fa9SUwe Zeisberger * Unregistration is done in 2 steps. First we release all resources 4282d7b5a70SJean Delvare * and remove it from the subsystem, then we drop reference count by 42993ce3061SDmitry Torokhov * calling platform_device_put(). 4301da177e4SLinus Torvalds */ 4311da177e4SLinus Torvalds void platform_device_unregister(struct platform_device *pdev) 4321da177e4SLinus Torvalds { 43393ce3061SDmitry Torokhov platform_device_del(pdev); 43493ce3061SDmitry Torokhov platform_device_put(pdev); 4351da177e4SLinus Torvalds } 436a96b2042SDmitry Torokhov EXPORT_SYMBOL_GPL(platform_device_unregister); 4371da177e4SLinus Torvalds 4381da177e4SLinus Torvalds /** 43901dcc60aSUwe Kleine-König * platform_device_register_full - add a platform-level device with 44044f28bdeSUwe Kleine-König * resources and platform-specific data 44144f28bdeSUwe Kleine-König * 44201dcc60aSUwe Kleine-König * @pdevinfo: data used to create device 443d8bf2540SDmitry Baryshkov * 444f0eae0edSJani Nikula * Returns &struct platform_device pointer on success, or ERR_PTR() on error. 445d8bf2540SDmitry Baryshkov */ 44601dcc60aSUwe Kleine-König struct platform_device *platform_device_register_full( 4475a3072beSUwe Kleine-König const struct platform_device_info *pdevinfo) 448d8bf2540SDmitry Baryshkov { 44944f28bdeSUwe Kleine-König int ret = -ENOMEM; 450d8bf2540SDmitry Baryshkov struct platform_device *pdev; 451d8bf2540SDmitry Baryshkov 45201dcc60aSUwe Kleine-König pdev = platform_device_alloc(pdevinfo->name, pdevinfo->id); 45344f28bdeSUwe Kleine-König if (!pdev) 45401dcc60aSUwe Kleine-König goto err_alloc; 45501dcc60aSUwe Kleine-König 45601dcc60aSUwe Kleine-König pdev->dev.parent = pdevinfo->parent; 4577b199811SRafael J. Wysocki ACPI_COMPANION_SET(&pdev->dev, pdevinfo->acpi_node.companion); 45801dcc60aSUwe Kleine-König 45901dcc60aSUwe Kleine-König if (pdevinfo->dma_mask) { 46001dcc60aSUwe Kleine-König /* 46101dcc60aSUwe Kleine-König * This memory isn't freed when the device is put, 46201dcc60aSUwe Kleine-König * I don't have a nice idea for that though. Conceptually 46301dcc60aSUwe Kleine-König * dma_mask in struct device should not be a pointer. 46401dcc60aSUwe Kleine-König * See http://thread.gmane.org/gmane.linux.kernel.pci/9081 46501dcc60aSUwe Kleine-König */ 46601dcc60aSUwe Kleine-König pdev->dev.dma_mask = 46701dcc60aSUwe Kleine-König kmalloc(sizeof(*pdev->dev.dma_mask), GFP_KERNEL); 46801dcc60aSUwe Kleine-König if (!pdev->dev.dma_mask) 46944f28bdeSUwe Kleine-König goto err; 470d8bf2540SDmitry Baryshkov 47101dcc60aSUwe Kleine-König *pdev->dev.dma_mask = pdevinfo->dma_mask; 47201dcc60aSUwe Kleine-König pdev->dev.coherent_dma_mask = pdevinfo->dma_mask; 47301dcc60aSUwe Kleine-König } 474d8bf2540SDmitry Baryshkov 47501dcc60aSUwe Kleine-König ret = platform_device_add_resources(pdev, 47601dcc60aSUwe Kleine-König pdevinfo->res, pdevinfo->num_res); 47744f28bdeSUwe Kleine-König if (ret) 47844f28bdeSUwe Kleine-König goto err; 479d8bf2540SDmitry Baryshkov 48001dcc60aSUwe Kleine-König ret = platform_device_add_data(pdev, 48101dcc60aSUwe Kleine-König pdevinfo->data, pdevinfo->size_data); 48244f28bdeSUwe Kleine-König if (ret) 48344f28bdeSUwe Kleine-König goto err; 48444f28bdeSUwe Kleine-König 48544f28bdeSUwe Kleine-König ret = platform_device_add(pdev); 48644f28bdeSUwe Kleine-König if (ret) { 48744f28bdeSUwe Kleine-König err: 4887b199811SRafael J. Wysocki ACPI_COMPANION_SET(&pdev->dev, NULL); 48901dcc60aSUwe Kleine-König kfree(pdev->dev.dma_mask); 49001dcc60aSUwe Kleine-König 49101dcc60aSUwe Kleine-König err_alloc: 49244f28bdeSUwe Kleine-König platform_device_put(pdev); 49344f28bdeSUwe Kleine-König return ERR_PTR(ret); 49444f28bdeSUwe Kleine-König } 495d8bf2540SDmitry Baryshkov 496d8bf2540SDmitry Baryshkov return pdev; 497d8bf2540SDmitry Baryshkov } 49801dcc60aSUwe Kleine-König EXPORT_SYMBOL_GPL(platform_device_register_full); 499d8bf2540SDmitry Baryshkov 50000d3dcddSRussell King static int platform_drv_probe(struct device *_dev) 50100d3dcddSRussell King { 50200d3dcddSRussell King struct platform_driver *drv = to_platform_driver(_dev->driver); 50300d3dcddSRussell King struct platform_device *dev = to_platform_device(_dev); 50494d76d5dSRafael J. Wysocki int ret; 50500d3dcddSRussell King 50686be408bSSylwester Nawrocki ret = of_clk_set_defaults(_dev->of_node, false); 50786be408bSSylwester Nawrocki if (ret < 0) 50886be408bSSylwester Nawrocki return ret; 50986be408bSSylwester Nawrocki 510cb518413SUlf Hansson ret = dev_pm_domain_attach(_dev, true); 511cb518413SUlf Hansson if (ret != -EPROBE_DEFER) { 51294d76d5dSRafael J. Wysocki ret = drv->probe(dev); 5139383f4c6SJosh Cartwright if (ret) 514cb518413SUlf Hansson dev_pm_domain_detach(_dev, true); 515cb518413SUlf Hansson } 51694d76d5dSRafael J. Wysocki 5173f9120b0SJohan Hovold if (drv->prevent_deferred_probe && ret == -EPROBE_DEFER) { 5183f9120b0SJohan Hovold dev_warn(_dev, "probe deferral not supported\n"); 5193f9120b0SJohan Hovold ret = -ENXIO; 5203f9120b0SJohan Hovold } 5213f9120b0SJohan Hovold 52294d76d5dSRafael J. Wysocki return ret; 52300d3dcddSRussell King } 52400d3dcddSRussell King 525c67334fbSDavid Brownell static int platform_drv_probe_fail(struct device *_dev) 526c67334fbSDavid Brownell { 527c67334fbSDavid Brownell return -ENXIO; 528c67334fbSDavid Brownell } 529c67334fbSDavid Brownell 53000d3dcddSRussell King static int platform_drv_remove(struct device *_dev) 53100d3dcddSRussell King { 53200d3dcddSRussell King struct platform_driver *drv = to_platform_driver(_dev->driver); 53300d3dcddSRussell King struct platform_device *dev = to_platform_device(_dev); 53494d76d5dSRafael J. Wysocki int ret; 53500d3dcddSRussell King 53694d76d5dSRafael J. Wysocki ret = drv->remove(dev); 537cb518413SUlf Hansson dev_pm_domain_detach(_dev, true); 53894d76d5dSRafael J. Wysocki 53994d76d5dSRafael J. Wysocki return ret; 54000d3dcddSRussell King } 54100d3dcddSRussell King 54200d3dcddSRussell King static void platform_drv_shutdown(struct device *_dev) 54300d3dcddSRussell King { 54400d3dcddSRussell King struct platform_driver *drv = to_platform_driver(_dev->driver); 54500d3dcddSRussell King struct platform_device *dev = to_platform_device(_dev); 54600d3dcddSRussell King 54700d3dcddSRussell King drv->shutdown(dev); 548cb518413SUlf Hansson dev_pm_domain_detach(_dev, true); 54900d3dcddSRussell King } 55000d3dcddSRussell King 55100d3dcddSRussell King /** 5529447057eSLibo Chen * __platform_driver_register - register a driver for platform-level devices 55300d3dcddSRussell King * @drv: platform driver structure 55408801f96SRandy Dunlap * @owner: owning module/driver 55500d3dcddSRussell King */ 5569447057eSLibo Chen int __platform_driver_register(struct platform_driver *drv, 5579447057eSLibo Chen struct module *owner) 55800d3dcddSRussell King { 5599447057eSLibo Chen drv->driver.owner = owner; 56000d3dcddSRussell King drv->driver.bus = &platform_bus_type; 56100d3dcddSRussell King if (drv->probe) 56200d3dcddSRussell King drv->driver.probe = platform_drv_probe; 56300d3dcddSRussell King if (drv->remove) 56400d3dcddSRussell King drv->driver.remove = platform_drv_remove; 56500d3dcddSRussell King if (drv->shutdown) 56600d3dcddSRussell King drv->driver.shutdown = platform_drv_shutdown; 567783ea7d4SMagnus Damm 56800d3dcddSRussell King return driver_register(&drv->driver); 56900d3dcddSRussell King } 5709447057eSLibo Chen EXPORT_SYMBOL_GPL(__platform_driver_register); 57100d3dcddSRussell King 57200d3dcddSRussell King /** 5733c31f07aSBen Hutchings * platform_driver_unregister - unregister a driver for platform-level devices 57400d3dcddSRussell King * @drv: platform driver structure 57500d3dcddSRussell King */ 57600d3dcddSRussell King void platform_driver_unregister(struct platform_driver *drv) 57700d3dcddSRussell King { 57800d3dcddSRussell King driver_unregister(&drv->driver); 57900d3dcddSRussell King } 58000d3dcddSRussell King EXPORT_SYMBOL_GPL(platform_driver_unregister); 58100d3dcddSRussell King 582c67334fbSDavid Brownell /** 583c67334fbSDavid Brownell * platform_driver_probe - register driver for non-hotpluggable device 584c67334fbSDavid Brownell * @drv: platform driver structure 5853f9120b0SJohan Hovold * @probe: the driver probe routine, probably from an __init section 586c67334fbSDavid Brownell * 587c67334fbSDavid Brownell * Use this instead of platform_driver_register() when you know the device 588c67334fbSDavid Brownell * is not hotpluggable and has already been registered, and you want to 589c67334fbSDavid Brownell * remove its run-once probe() infrastructure from memory after the driver 590c67334fbSDavid Brownell * has bound to the device. 591c67334fbSDavid Brownell * 592c67334fbSDavid Brownell * One typical use for this would be with drivers for controllers integrated 593c67334fbSDavid Brownell * into system-on-chip processors, where the controller devices have been 594c67334fbSDavid Brownell * configured as part of board setup. 595c67334fbSDavid Brownell * 5963f9120b0SJohan Hovold * Note that this is incompatible with deferred probing. 597647c86d0SFabio Porcedda * 598c67334fbSDavid Brownell * Returns zero if the driver registered and bound to a device, else returns 599c67334fbSDavid Brownell * a negative error code and with the driver not registered. 600c67334fbSDavid Brownell */ 601c63e0783SAndrew Morton int __init_or_module platform_driver_probe(struct platform_driver *drv, 602c67334fbSDavid Brownell int (*probe)(struct platform_device *)) 603c67334fbSDavid Brownell { 604c67334fbSDavid Brownell int retval, code; 605c67334fbSDavid Brownell 6063f9120b0SJohan Hovold /* 6073f9120b0SJohan Hovold * Prevent driver from requesting probe deferral to avoid further 6083f9120b0SJohan Hovold * futile probe attempts. 6093f9120b0SJohan Hovold */ 6103f9120b0SJohan Hovold drv->prevent_deferred_probe = true; 6113f9120b0SJohan Hovold 6121a6f2a75SDmitry Torokhov /* make sure driver won't have bind/unbind attributes */ 6131a6f2a75SDmitry Torokhov drv->driver.suppress_bind_attrs = true; 6141a6f2a75SDmitry Torokhov 615c67334fbSDavid Brownell /* temporary section violation during probe() */ 616c67334fbSDavid Brownell drv->probe = probe; 617c67334fbSDavid Brownell retval = code = platform_driver_register(drv); 618c67334fbSDavid Brownell 6191a6f2a75SDmitry Torokhov /* 6201a6f2a75SDmitry Torokhov * Fixup that section violation, being paranoid about code scanning 621c67334fbSDavid Brownell * the list of drivers in order to probe new devices. Check to see 622c67334fbSDavid Brownell * if the probe was successful, and make sure any forced probes of 623c67334fbSDavid Brownell * new devices fail. 624c67334fbSDavid Brownell */ 625d79d3244SPatrick Pannuto spin_lock(&drv->driver.bus->p->klist_drivers.k_lock); 626c67334fbSDavid Brownell drv->probe = NULL; 627e5dd1278SGreg Kroah-Hartman if (code == 0 && list_empty(&drv->driver.p->klist_devices.k_list)) 628c67334fbSDavid Brownell retval = -ENODEV; 629c67334fbSDavid Brownell drv->driver.probe = platform_drv_probe_fail; 630d79d3244SPatrick Pannuto spin_unlock(&drv->driver.bus->p->klist_drivers.k_lock); 631c67334fbSDavid Brownell 632c67334fbSDavid Brownell if (code != retval) 633c67334fbSDavid Brownell platform_driver_unregister(drv); 634c67334fbSDavid Brownell return retval; 635c67334fbSDavid Brownell } 636c67334fbSDavid Brownell EXPORT_SYMBOL_GPL(platform_driver_probe); 6371da177e4SLinus Torvalds 638ecdf6cebSDmitry Torokhov /** 639ecdf6cebSDmitry Torokhov * platform_create_bundle - register driver and create corresponding device 640ecdf6cebSDmitry Torokhov * @driver: platform driver structure 641ecdf6cebSDmitry Torokhov * @probe: the driver probe routine, probably from an __init section 642ecdf6cebSDmitry Torokhov * @res: set of resources that needs to be allocated for the device 643ecdf6cebSDmitry Torokhov * @n_res: number of resources 644ecdf6cebSDmitry Torokhov * @data: platform specific data for this platform device 645ecdf6cebSDmitry Torokhov * @size: size of platform specific data 646ecdf6cebSDmitry Torokhov * 647ecdf6cebSDmitry Torokhov * Use this in legacy-style modules that probe hardware directly and 648ecdf6cebSDmitry Torokhov * register a single platform device and corresponding platform driver. 649f0eae0edSJani Nikula * 650f0eae0edSJani Nikula * Returns &struct platform_device pointer on success, or ERR_PTR() on error. 651ecdf6cebSDmitry Torokhov */ 652ecdf6cebSDmitry Torokhov struct platform_device * __init_or_module platform_create_bundle( 653ecdf6cebSDmitry Torokhov struct platform_driver *driver, 654ecdf6cebSDmitry Torokhov int (*probe)(struct platform_device *), 655ecdf6cebSDmitry Torokhov struct resource *res, unsigned int n_res, 656ecdf6cebSDmitry Torokhov const void *data, size_t size) 657ecdf6cebSDmitry Torokhov { 658ecdf6cebSDmitry Torokhov struct platform_device *pdev; 659ecdf6cebSDmitry Torokhov int error; 660ecdf6cebSDmitry Torokhov 661ecdf6cebSDmitry Torokhov pdev = platform_device_alloc(driver->driver.name, -1); 662ecdf6cebSDmitry Torokhov if (!pdev) { 663ecdf6cebSDmitry Torokhov error = -ENOMEM; 664ecdf6cebSDmitry Torokhov goto err_out; 665ecdf6cebSDmitry Torokhov } 666ecdf6cebSDmitry Torokhov 667ecdf6cebSDmitry Torokhov error = platform_device_add_resources(pdev, res, n_res); 668ecdf6cebSDmitry Torokhov if (error) 669ecdf6cebSDmitry Torokhov goto err_pdev_put; 670ecdf6cebSDmitry Torokhov 671ecdf6cebSDmitry Torokhov error = platform_device_add_data(pdev, data, size); 672ecdf6cebSDmitry Torokhov if (error) 673ecdf6cebSDmitry Torokhov goto err_pdev_put; 674ecdf6cebSDmitry Torokhov 675ecdf6cebSDmitry Torokhov error = platform_device_add(pdev); 676ecdf6cebSDmitry Torokhov if (error) 677ecdf6cebSDmitry Torokhov goto err_pdev_put; 678ecdf6cebSDmitry Torokhov 679ecdf6cebSDmitry Torokhov error = platform_driver_probe(driver, probe); 680ecdf6cebSDmitry Torokhov if (error) 681ecdf6cebSDmitry Torokhov goto err_pdev_del; 682ecdf6cebSDmitry Torokhov 683ecdf6cebSDmitry Torokhov return pdev; 684ecdf6cebSDmitry Torokhov 685ecdf6cebSDmitry Torokhov err_pdev_del: 686ecdf6cebSDmitry Torokhov platform_device_del(pdev); 687ecdf6cebSDmitry Torokhov err_pdev_put: 688ecdf6cebSDmitry Torokhov platform_device_put(pdev); 689ecdf6cebSDmitry Torokhov err_out: 690ecdf6cebSDmitry Torokhov return ERR_PTR(error); 691ecdf6cebSDmitry Torokhov } 692ecdf6cebSDmitry Torokhov EXPORT_SYMBOL_GPL(platform_create_bundle); 693ecdf6cebSDmitry Torokhov 694a0245f7aSDavid Brownell /* modalias support enables more hands-off userspace setup: 695a0245f7aSDavid Brownell * (a) environment variable lets new-style hotplug events work once system is 696a0245f7aSDavid Brownell * fully running: "modprobe $MODALIAS" 697a0245f7aSDavid Brownell * (b) sysfs attribute lets new-style coldplug recover from hotplug events 698a0245f7aSDavid Brownell * mishandled before system is fully running: "modprobe $(cat modalias)" 699a0245f7aSDavid Brownell */ 7004a3ad20cSGreg Kroah-Hartman static ssize_t modalias_show(struct device *dev, struct device_attribute *a, 7014a3ad20cSGreg Kroah-Hartman char *buf) 702a0245f7aSDavid Brownell { 703a0245f7aSDavid Brownell struct platform_device *pdev = to_platform_device(dev); 7048c4ff6d0SZhang Rui int len; 7058c4ff6d0SZhang Rui 706b9f73067SZhang Rui len = of_device_get_modalias(dev, buf, PAGE_SIZE -1); 707b9f73067SZhang Rui if (len != -ENODEV) 708b9f73067SZhang Rui return len; 709b9f73067SZhang Rui 7108c4ff6d0SZhang Rui len = acpi_device_modalias(dev, buf, PAGE_SIZE -1); 7118c4ff6d0SZhang Rui if (len != -ENODEV) 7128c4ff6d0SZhang Rui return len; 7138c4ff6d0SZhang Rui 7148c4ff6d0SZhang Rui len = snprintf(buf, PAGE_SIZE, "platform:%s\n", pdev->name); 715a0245f7aSDavid Brownell 716a0245f7aSDavid Brownell return (len >= PAGE_SIZE) ? (PAGE_SIZE - 1) : len; 717a0245f7aSDavid Brownell } 718d06262e5SGreg Kroah-Hartman static DEVICE_ATTR_RO(modalias); 719a0245f7aSDavid Brownell 7203d713e0eSKim Phillips static ssize_t driver_override_store(struct device *dev, 7213d713e0eSKim Phillips struct device_attribute *attr, 7223d713e0eSKim Phillips const char *buf, size_t count) 7233d713e0eSKim Phillips { 7243d713e0eSKim Phillips struct platform_device *pdev = to_platform_device(dev); 7253d713e0eSKim Phillips char *driver_override, *old = pdev->driver_override, *cp; 7263d713e0eSKim Phillips 7273d713e0eSKim Phillips if (count > PATH_MAX) 7283d713e0eSKim Phillips return -EINVAL; 7293d713e0eSKim Phillips 7303d713e0eSKim Phillips driver_override = kstrndup(buf, count, GFP_KERNEL); 7313d713e0eSKim Phillips if (!driver_override) 7323d713e0eSKim Phillips return -ENOMEM; 7333d713e0eSKim Phillips 7343d713e0eSKim Phillips cp = strchr(driver_override, '\n'); 7353d713e0eSKim Phillips if (cp) 7363d713e0eSKim Phillips *cp = '\0'; 7373d713e0eSKim Phillips 7383d713e0eSKim Phillips if (strlen(driver_override)) { 7393d713e0eSKim Phillips pdev->driver_override = driver_override; 7403d713e0eSKim Phillips } else { 7413d713e0eSKim Phillips kfree(driver_override); 7423d713e0eSKim Phillips pdev->driver_override = NULL; 7433d713e0eSKim Phillips } 7443d713e0eSKim Phillips 7453d713e0eSKim Phillips kfree(old); 7463d713e0eSKim Phillips 7473d713e0eSKim Phillips return count; 7483d713e0eSKim Phillips } 7493d713e0eSKim Phillips 7503d713e0eSKim Phillips static ssize_t driver_override_show(struct device *dev, 7513d713e0eSKim Phillips struct device_attribute *attr, char *buf) 7523d713e0eSKim Phillips { 7533d713e0eSKim Phillips struct platform_device *pdev = to_platform_device(dev); 7543d713e0eSKim Phillips 7553d713e0eSKim Phillips return sprintf(buf, "%s\n", pdev->driver_override); 7563d713e0eSKim Phillips } 7573d713e0eSKim Phillips static DEVICE_ATTR_RW(driver_override); 7583d713e0eSKim Phillips 7593d713e0eSKim Phillips 760d06262e5SGreg Kroah-Hartman static struct attribute *platform_dev_attrs[] = { 761d06262e5SGreg Kroah-Hartman &dev_attr_modalias.attr, 7623d713e0eSKim Phillips &dev_attr_driver_override.attr, 763d06262e5SGreg Kroah-Hartman NULL, 764a0245f7aSDavid Brownell }; 765d06262e5SGreg Kroah-Hartman ATTRIBUTE_GROUPS(platform_dev); 766a0245f7aSDavid Brownell 7677eff2e7aSKay Sievers static int platform_uevent(struct device *dev, struct kobj_uevent_env *env) 768a0245f7aSDavid Brownell { 769a0245f7aSDavid Brownell struct platform_device *pdev = to_platform_device(dev); 770eca39301SGrant Likely int rc; 771eca39301SGrant Likely 772eca39301SGrant Likely /* Some devices have extra OF data and an OF-style MODALIAS */ 77307d57a32SGrant Likely rc = of_device_uevent_modalias(dev, env); 774eca39301SGrant Likely if (rc != -ENODEV) 775eca39301SGrant Likely return rc; 776a0245f7aSDavid Brownell 7778c4ff6d0SZhang Rui rc = acpi_device_uevent_modalias(dev, env); 7788c4ff6d0SZhang Rui if (rc != -ENODEV) 7798c4ff6d0SZhang Rui return rc; 7808c4ff6d0SZhang Rui 78157fee4a5SEric Miao add_uevent_var(env, "MODALIAS=%s%s", PLATFORM_MODULE_PREFIX, 7820a26813cSSebastian Andrzej Siewior pdev->name); 783a0245f7aSDavid Brownell return 0; 784a0245f7aSDavid Brownell } 785a0245f7aSDavid Brownell 78657fee4a5SEric Miao static const struct platform_device_id *platform_match_id( 787831fad2fSUwe Kleine-König const struct platform_device_id *id, 78857fee4a5SEric Miao struct platform_device *pdev) 78957fee4a5SEric Miao { 79057fee4a5SEric Miao while (id->name[0]) { 79157fee4a5SEric Miao if (strcmp(pdev->name, id->name) == 0) { 79257fee4a5SEric Miao pdev->id_entry = id; 79357fee4a5SEric Miao return id; 79457fee4a5SEric Miao } 79557fee4a5SEric Miao id++; 79657fee4a5SEric Miao } 79757fee4a5SEric Miao return NULL; 79857fee4a5SEric Miao } 79957fee4a5SEric Miao 8001da177e4SLinus Torvalds /** 8011da177e4SLinus Torvalds * platform_match - bind platform device to platform driver. 8021da177e4SLinus Torvalds * @dev: device. 8031da177e4SLinus Torvalds * @drv: driver. 8041da177e4SLinus Torvalds * 8051da177e4SLinus Torvalds * Platform device IDs are assumed to be encoded like this: 8064a3ad20cSGreg Kroah-Hartman * "<name><instance>", where <name> is a short description of the type of 8074a3ad20cSGreg Kroah-Hartman * device, like "pci" or "floppy", and <instance> is the enumerated 8084a3ad20cSGreg Kroah-Hartman * instance of the device, like '0' or '42'. Driver IDs are simply 8094a3ad20cSGreg Kroah-Hartman * "<name>". So, extract the <name> from the platform_device structure, 8104a3ad20cSGreg Kroah-Hartman * and compare it against the name of the driver. Return whether they match 8114a3ad20cSGreg Kroah-Hartman * or not. 8121da177e4SLinus Torvalds */ 8131da177e4SLinus Torvalds static int platform_match(struct device *dev, struct device_driver *drv) 8141da177e4SLinus Torvalds { 81571b3e0c1SEric Miao struct platform_device *pdev = to_platform_device(dev); 81657fee4a5SEric Miao struct platform_driver *pdrv = to_platform_driver(drv); 8171da177e4SLinus Torvalds 8183d713e0eSKim Phillips /* When driver_override is set, only bind to the matching driver */ 8193d713e0eSKim Phillips if (pdev->driver_override) 8203d713e0eSKim Phillips return !strcmp(pdev->driver_override, drv->name); 8213d713e0eSKim Phillips 82205212157SGrant Likely /* Attempt an OF style match first */ 82305212157SGrant Likely if (of_driver_match_device(dev, drv)) 82405212157SGrant Likely return 1; 82505212157SGrant Likely 82691e56878SMika Westerberg /* Then try ACPI style match */ 82791e56878SMika Westerberg if (acpi_driver_match_device(dev, drv)) 82891e56878SMika Westerberg return 1; 82991e56878SMika Westerberg 83005212157SGrant Likely /* Then try to match against the id table */ 83157fee4a5SEric Miao if (pdrv->id_table) 83257fee4a5SEric Miao return platform_match_id(pdrv->id_table, pdev) != NULL; 83357fee4a5SEric Miao 83457fee4a5SEric Miao /* fall-back to driver name match */ 8351e0b2cf9SKay Sievers return (strcmp(pdev->name, drv->name) == 0); 8361da177e4SLinus Torvalds } 8371da177e4SLinus Torvalds 83825e18499SRafael J. Wysocki #ifdef CONFIG_PM_SLEEP 83925e18499SRafael J. Wysocki 84025e18499SRafael J. Wysocki static int platform_legacy_suspend(struct device *dev, pm_message_t mesg) 8411da177e4SLinus Torvalds { 842783ea7d4SMagnus Damm struct platform_driver *pdrv = to_platform_driver(dev->driver); 843783ea7d4SMagnus Damm struct platform_device *pdev = to_platform_device(dev); 8441da177e4SLinus Torvalds int ret = 0; 8451da177e4SLinus Torvalds 846783ea7d4SMagnus Damm if (dev->driver && pdrv->suspend) 847783ea7d4SMagnus Damm ret = pdrv->suspend(pdev, mesg); 848386415d8SDavid Brownell 849386415d8SDavid Brownell return ret; 850386415d8SDavid Brownell } 851386415d8SDavid Brownell 85225e18499SRafael J. Wysocki static int platform_legacy_resume(struct device *dev) 8531da177e4SLinus Torvalds { 854783ea7d4SMagnus Damm struct platform_driver *pdrv = to_platform_driver(dev->driver); 855783ea7d4SMagnus Damm struct platform_device *pdev = to_platform_device(dev); 8561da177e4SLinus Torvalds int ret = 0; 8571da177e4SLinus Torvalds 858783ea7d4SMagnus Damm if (dev->driver && pdrv->resume) 859783ea7d4SMagnus Damm ret = pdrv->resume(pdev); 8609480e307SRussell King 8611da177e4SLinus Torvalds return ret; 8621da177e4SLinus Torvalds } 8631da177e4SLinus Torvalds 86469c9dd1eSRafael J. Wysocki #endif /* CONFIG_PM_SLEEP */ 8659d730229SMagnus Damm 86625e18499SRafael J. Wysocki #ifdef CONFIG_SUSPEND 86725e18499SRafael J. Wysocki 86869c9dd1eSRafael J. Wysocki int platform_pm_suspend(struct device *dev) 86925e18499SRafael J. Wysocki { 87025e18499SRafael J. Wysocki struct device_driver *drv = dev->driver; 87125e18499SRafael J. Wysocki int ret = 0; 87225e18499SRafael J. Wysocki 873adf09493SRafael J. Wysocki if (!drv) 874adf09493SRafael J. Wysocki return 0; 875adf09493SRafael J. Wysocki 876adf09493SRafael J. Wysocki if (drv->pm) { 87725e18499SRafael J. Wysocki if (drv->pm->suspend) 87825e18499SRafael J. Wysocki ret = drv->pm->suspend(dev); 87925e18499SRafael J. Wysocki } else { 88025e18499SRafael J. Wysocki ret = platform_legacy_suspend(dev, PMSG_SUSPEND); 88125e18499SRafael J. Wysocki } 88225e18499SRafael J. Wysocki 88325e18499SRafael J. Wysocki return ret; 88425e18499SRafael J. Wysocki } 88525e18499SRafael J. Wysocki 88669c9dd1eSRafael J. Wysocki int platform_pm_resume(struct device *dev) 88725e18499SRafael J. Wysocki { 88825e18499SRafael J. Wysocki struct device_driver *drv = dev->driver; 88925e18499SRafael J. Wysocki int ret = 0; 89025e18499SRafael J. Wysocki 891adf09493SRafael J. Wysocki if (!drv) 892adf09493SRafael J. Wysocki return 0; 893adf09493SRafael J. Wysocki 894adf09493SRafael J. Wysocki if (drv->pm) { 89525e18499SRafael J. Wysocki if (drv->pm->resume) 89625e18499SRafael J. Wysocki ret = drv->pm->resume(dev); 89725e18499SRafael J. Wysocki } else { 89825e18499SRafael J. Wysocki ret = platform_legacy_resume(dev); 89925e18499SRafael J. Wysocki } 90025e18499SRafael J. Wysocki 90125e18499SRafael J. Wysocki return ret; 90225e18499SRafael J. Wysocki } 90325e18499SRafael J. Wysocki 90469c9dd1eSRafael J. Wysocki #endif /* CONFIG_SUSPEND */ 90525e18499SRafael J. Wysocki 9061f112ceeSRafael J. Wysocki #ifdef CONFIG_HIBERNATE_CALLBACKS 90725e18499SRafael J. Wysocki 90869c9dd1eSRafael J. Wysocki int platform_pm_freeze(struct device *dev) 90925e18499SRafael J. Wysocki { 91025e18499SRafael J. Wysocki struct device_driver *drv = dev->driver; 91125e18499SRafael J. Wysocki int ret = 0; 91225e18499SRafael J. Wysocki 91325e18499SRafael J. Wysocki if (!drv) 91425e18499SRafael J. Wysocki return 0; 91525e18499SRafael J. Wysocki 91625e18499SRafael J. Wysocki if (drv->pm) { 91725e18499SRafael J. Wysocki if (drv->pm->freeze) 91825e18499SRafael J. Wysocki ret = drv->pm->freeze(dev); 91925e18499SRafael J. Wysocki } else { 92025e18499SRafael J. Wysocki ret = platform_legacy_suspend(dev, PMSG_FREEZE); 92125e18499SRafael J. Wysocki } 92225e18499SRafael J. Wysocki 92325e18499SRafael J. Wysocki return ret; 92425e18499SRafael J. Wysocki } 92525e18499SRafael J. Wysocki 92669c9dd1eSRafael J. Wysocki int platform_pm_thaw(struct device *dev) 92725e18499SRafael J. Wysocki { 92825e18499SRafael J. Wysocki struct device_driver *drv = dev->driver; 92925e18499SRafael J. Wysocki int ret = 0; 93025e18499SRafael J. Wysocki 931adf09493SRafael J. Wysocki if (!drv) 932adf09493SRafael J. Wysocki return 0; 933adf09493SRafael J. Wysocki 934adf09493SRafael J. Wysocki if (drv->pm) { 93525e18499SRafael J. Wysocki if (drv->pm->thaw) 93625e18499SRafael J. Wysocki ret = drv->pm->thaw(dev); 93725e18499SRafael J. Wysocki } else { 93825e18499SRafael J. Wysocki ret = platform_legacy_resume(dev); 93925e18499SRafael J. Wysocki } 94025e18499SRafael J. Wysocki 94125e18499SRafael J. Wysocki return ret; 94225e18499SRafael J. Wysocki } 94325e18499SRafael J. Wysocki 94469c9dd1eSRafael J. Wysocki int platform_pm_poweroff(struct device *dev) 94525e18499SRafael J. Wysocki { 94625e18499SRafael J. Wysocki struct device_driver *drv = dev->driver; 94725e18499SRafael J. Wysocki int ret = 0; 94825e18499SRafael J. Wysocki 949adf09493SRafael J. Wysocki if (!drv) 950adf09493SRafael J. Wysocki return 0; 951adf09493SRafael J. Wysocki 952adf09493SRafael J. Wysocki if (drv->pm) { 95325e18499SRafael J. Wysocki if (drv->pm->poweroff) 95425e18499SRafael J. Wysocki ret = drv->pm->poweroff(dev); 95525e18499SRafael J. Wysocki } else { 95625e18499SRafael J. Wysocki ret = platform_legacy_suspend(dev, PMSG_HIBERNATE); 95725e18499SRafael J. Wysocki } 95825e18499SRafael J. Wysocki 95925e18499SRafael J. Wysocki return ret; 96025e18499SRafael J. Wysocki } 96125e18499SRafael J. Wysocki 96269c9dd1eSRafael J. Wysocki int platform_pm_restore(struct device *dev) 96325e18499SRafael J. Wysocki { 96425e18499SRafael J. Wysocki struct device_driver *drv = dev->driver; 96525e18499SRafael J. Wysocki int ret = 0; 96625e18499SRafael J. Wysocki 967adf09493SRafael J. Wysocki if (!drv) 968adf09493SRafael J. Wysocki return 0; 969adf09493SRafael J. Wysocki 970adf09493SRafael J. Wysocki if (drv->pm) { 97125e18499SRafael J. Wysocki if (drv->pm->restore) 97225e18499SRafael J. Wysocki ret = drv->pm->restore(dev); 97325e18499SRafael J. Wysocki } else { 97425e18499SRafael J. Wysocki ret = platform_legacy_resume(dev); 97525e18499SRafael J. Wysocki } 97625e18499SRafael J. Wysocki 97725e18499SRafael J. Wysocki return ret; 97825e18499SRafael J. Wysocki } 97925e18499SRafael J. Wysocki 98069c9dd1eSRafael J. Wysocki #endif /* CONFIG_HIBERNATE_CALLBACKS */ 98125e18499SRafael J. Wysocki 982d9ab7716SDmitry Torokhov static const struct dev_pm_ops platform_dev_pm_ops = { 9838b313a38SRafael J. Wysocki .runtime_suspend = pm_generic_runtime_suspend, 9848b313a38SRafael J. Wysocki .runtime_resume = pm_generic_runtime_resume, 98569c9dd1eSRafael J. Wysocki USE_PLATFORM_PM_SLEEP_OPS 98625e18499SRafael J. Wysocki }; 98725e18499SRafael J. Wysocki 9881da177e4SLinus Torvalds struct bus_type platform_bus_type = { 9891da177e4SLinus Torvalds .name = "platform", 990d06262e5SGreg Kroah-Hartman .dev_groups = platform_dev_groups, 9911da177e4SLinus Torvalds .match = platform_match, 992a0245f7aSDavid Brownell .uevent = platform_uevent, 9939d730229SMagnus Damm .pm = &platform_dev_pm_ops, 9941da177e4SLinus Torvalds }; 995a96b2042SDmitry Torokhov EXPORT_SYMBOL_GPL(platform_bus_type); 9961da177e4SLinus Torvalds 9971da177e4SLinus Torvalds int __init platform_bus_init(void) 9981da177e4SLinus Torvalds { 999fbfb1445SCornelia Huck int error; 1000fbfb1445SCornelia Huck 100113977091SMagnus Damm early_platform_cleanup(); 100213977091SMagnus Damm 1003fbfb1445SCornelia Huck error = device_register(&platform_bus); 1004fbfb1445SCornelia Huck if (error) 1005fbfb1445SCornelia Huck return error; 1006fbfb1445SCornelia Huck error = bus_register(&platform_bus_type); 1007fbfb1445SCornelia Huck if (error) 1008fbfb1445SCornelia Huck device_unregister(&platform_bus); 1009fbfb1445SCornelia Huck return error; 10101da177e4SLinus Torvalds } 10111da177e4SLinus Torvalds 10121da177e4SLinus Torvalds #ifndef ARCH_HAS_DMA_GET_REQUIRED_MASK 10131da177e4SLinus Torvalds u64 dma_get_required_mask(struct device *dev) 10141da177e4SLinus Torvalds { 10151da177e4SLinus Torvalds u32 low_totalram = ((max_pfn - 1) << PAGE_SHIFT); 10161da177e4SLinus Torvalds u32 high_totalram = ((max_pfn - 1) >> (32 - PAGE_SHIFT)); 10171da177e4SLinus Torvalds u64 mask; 10181da177e4SLinus Torvalds 10191da177e4SLinus Torvalds if (!high_totalram) { 10201da177e4SLinus Torvalds /* convert to mask just covering totalram */ 10211da177e4SLinus Torvalds low_totalram = (1 << (fls(low_totalram) - 1)); 10221da177e4SLinus Torvalds low_totalram += low_totalram - 1; 10231da177e4SLinus Torvalds mask = low_totalram; 10241da177e4SLinus Torvalds } else { 10251da177e4SLinus Torvalds high_totalram = (1 << (fls(high_totalram) - 1)); 10261da177e4SLinus Torvalds high_totalram += high_totalram - 1; 10271da177e4SLinus Torvalds mask = (((u64)high_totalram) << 32) + 0xffffffff; 10281da177e4SLinus Torvalds } 1029e88a0c2cSJames Bottomley return mask; 10301da177e4SLinus Torvalds } 10311da177e4SLinus Torvalds EXPORT_SYMBOL_GPL(dma_get_required_mask); 10321da177e4SLinus Torvalds #endif 103313977091SMagnus Damm 103413977091SMagnus Damm static __initdata LIST_HEAD(early_platform_driver_list); 103513977091SMagnus Damm static __initdata LIST_HEAD(early_platform_device_list); 103613977091SMagnus Damm 103713977091SMagnus Damm /** 10384d26e139SMagnus Damm * early_platform_driver_register - register early platform driver 1039d86c1302SRandy Dunlap * @epdrv: early_platform driver structure 104013977091SMagnus Damm * @buf: string passed from early_param() 10414d26e139SMagnus Damm * 10424d26e139SMagnus Damm * Helper function for early_platform_init() / early_platform_init_buffer() 104313977091SMagnus Damm */ 104413977091SMagnus Damm int __init early_platform_driver_register(struct early_platform_driver *epdrv, 104513977091SMagnus Damm char *buf) 104613977091SMagnus Damm { 1047c60e0504SMagnus Damm char *tmp; 104813977091SMagnus Damm int n; 104913977091SMagnus Damm 105013977091SMagnus Damm /* Simply add the driver to the end of the global list. 105113977091SMagnus Damm * Drivers will by default be put on the list in compiled-in order. 105213977091SMagnus Damm */ 105313977091SMagnus Damm if (!epdrv->list.next) { 105413977091SMagnus Damm INIT_LIST_HEAD(&epdrv->list); 105513977091SMagnus Damm list_add_tail(&epdrv->list, &early_platform_driver_list); 105613977091SMagnus Damm } 105713977091SMagnus Damm 105813977091SMagnus Damm /* If the user has specified device then make sure the driver 105913977091SMagnus Damm * gets prioritized. The driver of the last device specified on 106013977091SMagnus Damm * command line will be put first on the list. 106113977091SMagnus Damm */ 106213977091SMagnus Damm n = strlen(epdrv->pdrv->driver.name); 106313977091SMagnus Damm if (buf && !strncmp(buf, epdrv->pdrv->driver.name, n)) { 106413977091SMagnus Damm list_move(&epdrv->list, &early_platform_driver_list); 106513977091SMagnus Damm 1066c60e0504SMagnus Damm /* Allow passing parameters after device name */ 1067c60e0504SMagnus Damm if (buf[n] == '\0' || buf[n] == ',') 106813977091SMagnus Damm epdrv->requested_id = -1; 1069c60e0504SMagnus Damm else { 1070c60e0504SMagnus Damm epdrv->requested_id = simple_strtoul(&buf[n + 1], 1071c60e0504SMagnus Damm &tmp, 10); 1072c60e0504SMagnus Damm 1073c60e0504SMagnus Damm if (buf[n] != '.' || (tmp == &buf[n + 1])) { 107413977091SMagnus Damm epdrv->requested_id = EARLY_PLATFORM_ID_ERROR; 1075c60e0504SMagnus Damm n = 0; 1076c60e0504SMagnus Damm } else 1077c60e0504SMagnus Damm n += strcspn(&buf[n + 1], ",") + 1; 1078c60e0504SMagnus Damm } 1079c60e0504SMagnus Damm 1080c60e0504SMagnus Damm if (buf[n] == ',') 1081c60e0504SMagnus Damm n++; 1082c60e0504SMagnus Damm 1083c60e0504SMagnus Damm if (epdrv->bufsize) { 1084c60e0504SMagnus Damm memcpy(epdrv->buffer, &buf[n], 1085c60e0504SMagnus Damm min_t(int, epdrv->bufsize, strlen(&buf[n]) + 1)); 1086c60e0504SMagnus Damm epdrv->buffer[epdrv->bufsize - 1] = '\0'; 1087c60e0504SMagnus Damm } 108813977091SMagnus Damm } 108913977091SMagnus Damm 109013977091SMagnus Damm return 0; 109113977091SMagnus Damm } 109213977091SMagnus Damm 109313977091SMagnus Damm /** 10944d26e139SMagnus Damm * early_platform_add_devices - adds a number of early platform devices 109513977091SMagnus Damm * @devs: array of early platform devices to add 109613977091SMagnus Damm * @num: number of early platform devices in array 10974d26e139SMagnus Damm * 10984d26e139SMagnus Damm * Used by early architecture code to register early platform devices and 10994d26e139SMagnus Damm * their platform data. 110013977091SMagnus Damm */ 110113977091SMagnus Damm void __init early_platform_add_devices(struct platform_device **devs, int num) 110213977091SMagnus Damm { 110313977091SMagnus Damm struct device *dev; 110413977091SMagnus Damm int i; 110513977091SMagnus Damm 110613977091SMagnus Damm /* simply add the devices to list */ 110713977091SMagnus Damm for (i = 0; i < num; i++) { 110813977091SMagnus Damm dev = &devs[i]->dev; 110913977091SMagnus Damm 111013977091SMagnus Damm if (!dev->devres_head.next) { 1111bed2b42dSRafael J. Wysocki pm_runtime_early_init(dev); 111213977091SMagnus Damm INIT_LIST_HEAD(&dev->devres_head); 111313977091SMagnus Damm list_add_tail(&dev->devres_head, 111413977091SMagnus Damm &early_platform_device_list); 111513977091SMagnus Damm } 111613977091SMagnus Damm } 111713977091SMagnus Damm } 111813977091SMagnus Damm 111913977091SMagnus Damm /** 11204d26e139SMagnus Damm * early_platform_driver_register_all - register early platform drivers 112113977091SMagnus Damm * @class_str: string to identify early platform driver class 11224d26e139SMagnus Damm * 11234d26e139SMagnus Damm * Used by architecture code to register all early platform drivers 11244d26e139SMagnus Damm * for a certain class. If omitted then only early platform drivers 11254d26e139SMagnus Damm * with matching kernel command line class parameters will be registered. 112613977091SMagnus Damm */ 112713977091SMagnus Damm void __init early_platform_driver_register_all(char *class_str) 112813977091SMagnus Damm { 112913977091SMagnus Damm /* The "class_str" parameter may or may not be present on the kernel 113013977091SMagnus Damm * command line. If it is present then there may be more than one 113113977091SMagnus Damm * matching parameter. 113213977091SMagnus Damm * 113313977091SMagnus Damm * Since we register our early platform drivers using early_param() 113413977091SMagnus Damm * we need to make sure that they also get registered in the case 113513977091SMagnus Damm * when the parameter is missing from the kernel command line. 113613977091SMagnus Damm * 113713977091SMagnus Damm * We use parse_early_options() to make sure the early_param() gets 113813977091SMagnus Damm * called at least once. The early_param() may be called more than 113913977091SMagnus Damm * once since the name of the preferred device may be specified on 114013977091SMagnus Damm * the kernel command line. early_platform_driver_register() handles 114113977091SMagnus Damm * this case for us. 114213977091SMagnus Damm */ 114313977091SMagnus Damm parse_early_options(class_str); 114413977091SMagnus Damm } 114513977091SMagnus Damm 114613977091SMagnus Damm /** 11474d26e139SMagnus Damm * early_platform_match - find early platform device matching driver 1148d86c1302SRandy Dunlap * @epdrv: early platform driver structure 114913977091SMagnus Damm * @id: id to match against 115013977091SMagnus Damm */ 1151a8257910SHanjun Guo static struct platform_device * __init 115213977091SMagnus Damm early_platform_match(struct early_platform_driver *epdrv, int id) 115313977091SMagnus Damm { 115413977091SMagnus Damm struct platform_device *pd; 115513977091SMagnus Damm 115613977091SMagnus Damm list_for_each_entry(pd, &early_platform_device_list, dev.devres_head) 115713977091SMagnus Damm if (platform_match(&pd->dev, &epdrv->pdrv->driver)) 115813977091SMagnus Damm if (pd->id == id) 115913977091SMagnus Damm return pd; 116013977091SMagnus Damm 116113977091SMagnus Damm return NULL; 116213977091SMagnus Damm } 116313977091SMagnus Damm 116413977091SMagnus Damm /** 11654d26e139SMagnus Damm * early_platform_left - check if early platform driver has matching devices 1166d86c1302SRandy Dunlap * @epdrv: early platform driver structure 116713977091SMagnus Damm * @id: return true if id or above exists 116813977091SMagnus Damm */ 1169a8257910SHanjun Guo static int __init early_platform_left(struct early_platform_driver *epdrv, 117013977091SMagnus Damm int id) 117113977091SMagnus Damm { 117213977091SMagnus Damm struct platform_device *pd; 117313977091SMagnus Damm 117413977091SMagnus Damm list_for_each_entry(pd, &early_platform_device_list, dev.devres_head) 117513977091SMagnus Damm if (platform_match(&pd->dev, &epdrv->pdrv->driver)) 117613977091SMagnus Damm if (pd->id >= id) 117713977091SMagnus Damm return 1; 117813977091SMagnus Damm 117913977091SMagnus Damm return 0; 118013977091SMagnus Damm } 118113977091SMagnus Damm 118213977091SMagnus Damm /** 11834d26e139SMagnus Damm * early_platform_driver_probe_id - probe drivers matching class_str and id 118413977091SMagnus Damm * @class_str: string to identify early platform driver class 118513977091SMagnus Damm * @id: id to match against 118613977091SMagnus Damm * @nr_probe: number of platform devices to successfully probe before exiting 118713977091SMagnus Damm */ 118813977091SMagnus Damm static int __init early_platform_driver_probe_id(char *class_str, 118913977091SMagnus Damm int id, 119013977091SMagnus Damm int nr_probe) 119113977091SMagnus Damm { 119213977091SMagnus Damm struct early_platform_driver *epdrv; 119313977091SMagnus Damm struct platform_device *match; 119413977091SMagnus Damm int match_id; 119513977091SMagnus Damm int n = 0; 119613977091SMagnus Damm int left = 0; 119713977091SMagnus Damm 119813977091SMagnus Damm list_for_each_entry(epdrv, &early_platform_driver_list, list) { 119913977091SMagnus Damm /* only use drivers matching our class_str */ 120013977091SMagnus Damm if (strcmp(class_str, epdrv->class_str)) 120113977091SMagnus Damm continue; 120213977091SMagnus Damm 120313977091SMagnus Damm if (id == -2) { 120413977091SMagnus Damm match_id = epdrv->requested_id; 120513977091SMagnus Damm left = 1; 120613977091SMagnus Damm 120713977091SMagnus Damm } else { 120813977091SMagnus Damm match_id = id; 120913977091SMagnus Damm left += early_platform_left(epdrv, id); 121013977091SMagnus Damm 121113977091SMagnus Damm /* skip requested id */ 121213977091SMagnus Damm switch (epdrv->requested_id) { 121313977091SMagnus Damm case EARLY_PLATFORM_ID_ERROR: 121413977091SMagnus Damm case EARLY_PLATFORM_ID_UNSET: 121513977091SMagnus Damm break; 121613977091SMagnus Damm default: 121713977091SMagnus Damm if (epdrv->requested_id == id) 121813977091SMagnus Damm match_id = EARLY_PLATFORM_ID_UNSET; 121913977091SMagnus Damm } 122013977091SMagnus Damm } 122113977091SMagnus Damm 122213977091SMagnus Damm switch (match_id) { 122313977091SMagnus Damm case EARLY_PLATFORM_ID_ERROR: 12240258e182SFabio Porcedda pr_warn("%s: unable to parse %s parameter\n", 122513977091SMagnus Damm class_str, epdrv->pdrv->driver.name); 122613977091SMagnus Damm /* fall-through */ 122713977091SMagnus Damm case EARLY_PLATFORM_ID_UNSET: 122813977091SMagnus Damm match = NULL; 122913977091SMagnus Damm break; 123013977091SMagnus Damm default: 123113977091SMagnus Damm match = early_platform_match(epdrv, match_id); 123213977091SMagnus Damm } 123313977091SMagnus Damm 123413977091SMagnus Damm if (match) { 1235a636ee7fSPaul Mundt /* 1236a636ee7fSPaul Mundt * Set up a sensible init_name to enable 1237a636ee7fSPaul Mundt * dev_name() and others to be used before the 1238a636ee7fSPaul Mundt * rest of the driver core is initialized. 1239a636ee7fSPaul Mundt */ 124006fe53beSPaul Mundt if (!match->dev.init_name && slab_is_available()) { 1241a636ee7fSPaul Mundt if (match->id != -1) 1242bd05086bSPaul Mundt match->dev.init_name = 1243bd05086bSPaul Mundt kasprintf(GFP_KERNEL, "%s.%d", 1244bd05086bSPaul Mundt match->name, 1245bd05086bSPaul Mundt match->id); 1246a636ee7fSPaul Mundt else 1247bd05086bSPaul Mundt match->dev.init_name = 1248bd05086bSPaul Mundt kasprintf(GFP_KERNEL, "%s", 1249a636ee7fSPaul Mundt match->name); 1250a636ee7fSPaul Mundt 1251a636ee7fSPaul Mundt if (!match->dev.init_name) 1252a636ee7fSPaul Mundt return -ENOMEM; 1253a636ee7fSPaul Mundt } 1254bd05086bSPaul Mundt 125513977091SMagnus Damm if (epdrv->pdrv->probe(match)) 12560258e182SFabio Porcedda pr_warn("%s: unable to probe %s early.\n", 125713977091SMagnus Damm class_str, match->name); 125813977091SMagnus Damm else 125913977091SMagnus Damm n++; 126013977091SMagnus Damm } 126113977091SMagnus Damm 126213977091SMagnus Damm if (n >= nr_probe) 126313977091SMagnus Damm break; 126413977091SMagnus Damm } 126513977091SMagnus Damm 126613977091SMagnus Damm if (left) 126713977091SMagnus Damm return n; 126813977091SMagnus Damm else 126913977091SMagnus Damm return -ENODEV; 127013977091SMagnus Damm } 127113977091SMagnus Damm 127213977091SMagnus Damm /** 12734d26e139SMagnus Damm * early_platform_driver_probe - probe a class of registered drivers 127413977091SMagnus Damm * @class_str: string to identify early platform driver class 127513977091SMagnus Damm * @nr_probe: number of platform devices to successfully probe before exiting 127613977091SMagnus Damm * @user_only: only probe user specified early platform devices 12774d26e139SMagnus Damm * 12784d26e139SMagnus Damm * Used by architecture code to probe registered early platform drivers 12794d26e139SMagnus Damm * within a certain class. For probe to happen a registered early platform 12804d26e139SMagnus Damm * device matching a registered early platform driver is needed. 128113977091SMagnus Damm */ 128213977091SMagnus Damm int __init early_platform_driver_probe(char *class_str, 128313977091SMagnus Damm int nr_probe, 128413977091SMagnus Damm int user_only) 128513977091SMagnus Damm { 128613977091SMagnus Damm int k, n, i; 128713977091SMagnus Damm 128813977091SMagnus Damm n = 0; 128913977091SMagnus Damm for (i = -2; n < nr_probe; i++) { 129013977091SMagnus Damm k = early_platform_driver_probe_id(class_str, i, nr_probe - n); 129113977091SMagnus Damm 129213977091SMagnus Damm if (k < 0) 129313977091SMagnus Damm break; 129413977091SMagnus Damm 129513977091SMagnus Damm n += k; 129613977091SMagnus Damm 129713977091SMagnus Damm if (user_only) 129813977091SMagnus Damm break; 129913977091SMagnus Damm } 130013977091SMagnus Damm 130113977091SMagnus Damm return n; 130213977091SMagnus Damm } 130313977091SMagnus Damm 130413977091SMagnus Damm /** 130513977091SMagnus Damm * early_platform_cleanup - clean up early platform code 130613977091SMagnus Damm */ 130713977091SMagnus Damm void __init early_platform_cleanup(void) 130813977091SMagnus Damm { 130913977091SMagnus Damm struct platform_device *pd, *pd2; 131013977091SMagnus Damm 131113977091SMagnus Damm /* clean up the devres list used to chain devices */ 131213977091SMagnus Damm list_for_each_entry_safe(pd, pd2, &early_platform_device_list, 131313977091SMagnus Damm dev.devres_head) { 131413977091SMagnus Damm list_del(&pd->dev.devres_head); 131513977091SMagnus Damm memset(&pd->dev.devres_head, 0, sizeof(pd->dev.devres_head)); 131613977091SMagnus Damm } 131713977091SMagnus Damm } 131813977091SMagnus Damm 1319