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/err.h> 17 #include <linux/kernel.h> 18 #include <linux/module.h> 19 #include <linux/platform_device.h> 20 21 #include "internal.h" 22 23 ACPI_MODULE_NAME("platform"); 24 25 /* 26 * The following ACPI IDs are known to be suitable for representing as 27 * platform devices. 28 */ 29 static const struct acpi_device_id acpi_platform_device_ids[] = { 30 31 { "PNP0D40" }, 32 33 /* Intel Smart Sound Technology */ 34 { "INT33C8" }, 35 { "80860F28" }, 36 { } 37 }; 38 39 /** 40 * acpi_create_platform_device - Create platform device for ACPI device node 41 * @adev: ACPI device node to create a platform device for. 42 * @id: ACPI device ID used to match @adev. 43 * 44 * Check if the given @adev can be represented as a platform device and, if 45 * that's the case, create and register a platform device, populate its common 46 * resources and returns a pointer to it. Otherwise, return %NULL. 47 * 48 * Name of the platform device will be the same as @adev's. 49 */ 50 int acpi_create_platform_device(struct acpi_device *adev, 51 const struct acpi_device_id *id) 52 { 53 struct platform_device *pdev = NULL; 54 struct acpi_device *acpi_parent; 55 struct platform_device_info pdevinfo; 56 struct resource_list_entry *rentry; 57 struct list_head resource_list; 58 struct resource *resources = NULL; 59 int count; 60 61 /* If the ACPI node already has a physical device attached, skip it. */ 62 if (adev->physical_node_count) 63 return 0; 64 65 INIT_LIST_HEAD(&resource_list); 66 count = acpi_dev_get_resources(adev, &resource_list, NULL, NULL); 67 if (count < 0) { 68 return 0; 69 } else if (count > 0) { 70 resources = kmalloc(count * sizeof(struct resource), 71 GFP_KERNEL); 72 if (!resources) { 73 dev_err(&adev->dev, "No memory for resources\n"); 74 acpi_dev_free_resource_list(&resource_list); 75 return -ENOMEM; 76 } 77 count = 0; 78 list_for_each_entry(rentry, &resource_list, node) 79 resources[count++] = rentry->res; 80 81 acpi_dev_free_resource_list(&resource_list); 82 } 83 84 memset(&pdevinfo, 0, sizeof(pdevinfo)); 85 /* 86 * If the ACPI node has a parent and that parent has a physical device 87 * attached to it, that physical device should be the parent of the 88 * platform device we are about to create. 89 */ 90 pdevinfo.parent = NULL; 91 acpi_parent = adev->parent; 92 if (acpi_parent) { 93 struct acpi_device_physical_node *entry; 94 struct list_head *list; 95 96 mutex_lock(&acpi_parent->physical_node_lock); 97 list = &acpi_parent->physical_node_list; 98 if (!list_empty(list)) { 99 entry = list_first_entry(list, 100 struct acpi_device_physical_node, 101 node); 102 pdevinfo.parent = entry->dev; 103 } 104 mutex_unlock(&acpi_parent->physical_node_lock); 105 } 106 pdevinfo.name = dev_name(&adev->dev); 107 pdevinfo.id = -1; 108 pdevinfo.res = resources; 109 pdevinfo.num_res = count; 110 pdevinfo.acpi_node.handle = adev->handle; 111 pdev = platform_device_register_full(&pdevinfo); 112 if (IS_ERR(pdev)) { 113 dev_err(&adev->dev, "platform device creation failed: %ld\n", 114 PTR_ERR(pdev)); 115 pdev = NULL; 116 } else { 117 dev_dbg(&adev->dev, "created platform device %s\n", 118 dev_name(&pdev->dev)); 119 } 120 121 kfree(resources); 122 return 1; 123 } 124 125 static struct acpi_scan_handler platform_handler = { 126 .ids = acpi_platform_device_ids, 127 .attach = acpi_create_platform_device, 128 }; 129 130 void __init acpi_platform_init(void) 131 { 132 acpi_scan_add_handler(&platform_handler); 133 } 134