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