1 /* 2 * ACPI support for platform bus type. 3 * 4 * Copyright (C) 2012, Intel Corporation 5 * Authors: Mika Westerberg <mika.westerberg@linux.intel.com> 6 * Mathias Nyman <mathias.nyman@linux.intel.com> 7 * Rafael J. Wysocki <rafael.j.wysocki@intel.com> 8 * 9 * This program is free software; you can redistribute it and/or modify 10 * it under the terms of the GNU General Public License version 2 as 11 * published by the Free Software Foundation. 12 */ 13 14 #include <linux/acpi.h> 15 #include <linux/device.h> 16 #include <linux/kernel.h> 17 #include <linux/module.h> 18 #include <linux/platform_device.h> 19 20 #include "internal.h" 21 22 ACPI_MODULE_NAME("platform"); 23 24 /** 25 * acpi_create_platform_device - Create platform device for ACPI device node 26 * @adev: ACPI device node to create a platform device for. 27 * 28 * Check if the given @adev can be represented as a platform device and, if 29 * that's the case, create and register a platform device, populate its common 30 * resources and returns a pointer to it. Otherwise, return %NULL. 31 * 32 * The platform device's name will be taken from the @adev's _HID and _UID. 33 */ 34 struct platform_device *acpi_create_platform_device(struct acpi_device *adev) 35 { 36 struct platform_device *pdev = NULL; 37 struct acpi_device *acpi_parent; 38 struct platform_device_info pdevinfo; 39 struct resource_list_entry *rentry; 40 struct list_head resource_list; 41 struct resource *resources; 42 int count; 43 44 /* If the ACPI node already has a physical device attached, skip it. */ 45 if (adev->physical_node_count) 46 return NULL; 47 48 INIT_LIST_HEAD(&resource_list); 49 count = acpi_dev_get_resources(adev, &resource_list, NULL, NULL); 50 if (count <= 0) 51 return NULL; 52 53 resources = kmalloc(count * sizeof(struct resource), GFP_KERNEL); 54 if (!resources) { 55 dev_err(&adev->dev, "No memory for resources\n"); 56 acpi_dev_free_resource_list(&resource_list); 57 return NULL; 58 } 59 count = 0; 60 list_for_each_entry(rentry, &resource_list, node) 61 resources[count++] = rentry->res; 62 63 acpi_dev_free_resource_list(&resource_list); 64 65 memset(&pdevinfo, 0, sizeof(pdevinfo)); 66 /* 67 * If the ACPI node has a parent and that parent has a physical device 68 * attached to it, that physical device should be the parent of the 69 * platform device we are about to create. 70 */ 71 pdevinfo.parent = NULL; 72 acpi_parent = adev->parent; 73 if (acpi_parent) { 74 struct acpi_device_physical_node *entry; 75 struct list_head *list; 76 77 mutex_lock(&acpi_parent->physical_node_lock); 78 list = &acpi_parent->physical_node_list; 79 if (!list_empty(list)) { 80 entry = list_first_entry(list, 81 struct acpi_device_physical_node, 82 node); 83 pdevinfo.parent = entry->dev; 84 } 85 mutex_unlock(&acpi_parent->physical_node_lock); 86 } 87 pdevinfo.name = dev_name(&adev->dev); 88 pdevinfo.id = -1; 89 pdevinfo.res = resources; 90 pdevinfo.num_res = count; 91 pdevinfo.acpi_node.handle = adev->handle; 92 pdev = platform_device_register_full(&pdevinfo); 93 if (IS_ERR(pdev)) { 94 dev_err(&adev->dev, "platform device creation failed: %ld\n", 95 PTR_ERR(pdev)); 96 pdev = NULL; 97 } else { 98 dev_dbg(&adev->dev, "created platform device %s\n", 99 dev_name(&pdev->dev)); 100 } 101 102 kfree(resources); 103 return pdev; 104 } 105