acpi_platform.c 4.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173
  1. // SPDX-License-Identifier: GPL-2.0-only
  2. /*
  3. * ACPI support for platform bus type.
  4. *
  5. * Copyright (C) 2012, Intel Corporation
  6. * Authors: Mika Westerberg <mika.westerberg@linux.intel.com>
  7. * Mathias Nyman <mathias.nyman@linux.intel.com>
  8. * Rafael J. Wysocki <rafael.j.wysocki@intel.com>
  9. */
  10. #include <linux/acpi.h>
  11. #include <linux/device.h>
  12. #include <linux/err.h>
  13. #include <linux/kernel.h>
  14. #include <linux/module.h>
  15. #include <linux/dma-mapping.h>
  16. #include <linux/pci.h>
  17. #include <linux/platform_device.h>
  18. #include "internal.h"
  19. static const struct acpi_device_id forbidden_id_list[] = {
  20. {"PNP0000", 0}, /* PIC */
  21. {"PNP0100", 0}, /* Timer */
  22. {"PNP0200", 0}, /* AT DMA Controller */
  23. {"ACPI0009", 0}, /* IOxAPIC */
  24. {"ACPI000A", 0}, /* IOAPIC */
  25. {"SMB0001", 0}, /* ACPI SMBUS virtual device */
  26. {"", 0},
  27. };
  28. static struct platform_device *acpi_platform_device_find_by_companion(struct acpi_device *adev)
  29. {
  30. struct device *dev;
  31. dev = bus_find_device_by_acpi_dev(&platform_bus_type, adev);
  32. return dev ? to_platform_device(dev) : NULL;
  33. }
  34. static int acpi_platform_device_remove_notify(struct notifier_block *nb,
  35. unsigned long value, void *arg)
  36. {
  37. struct acpi_device *adev = arg;
  38. struct platform_device *pdev;
  39. switch (value) {
  40. case ACPI_RECONFIG_DEVICE_ADD:
  41. /* Nothing to do here */
  42. break;
  43. case ACPI_RECONFIG_DEVICE_REMOVE:
  44. if (!acpi_device_enumerated(adev))
  45. break;
  46. pdev = acpi_platform_device_find_by_companion(adev);
  47. if (!pdev)
  48. break;
  49. platform_device_unregister(pdev);
  50. put_device(&pdev->dev);
  51. break;
  52. }
  53. return NOTIFY_OK;
  54. }
  55. static struct notifier_block acpi_platform_notifier = {
  56. .notifier_call = acpi_platform_device_remove_notify,
  57. };
  58. static void acpi_platform_fill_resource(struct acpi_device *adev,
  59. const struct resource *src, struct resource *dest)
  60. {
  61. struct device *parent;
  62. *dest = *src;
  63. /*
  64. * If the device has parent we need to take its resources into
  65. * account as well because this device might consume part of those.
  66. */
  67. parent = acpi_get_first_physical_node(adev->parent);
  68. if (parent && dev_is_pci(parent))
  69. dest->parent = pci_find_resource(to_pci_dev(parent), dest);
  70. }
  71. /**
  72. * acpi_create_platform_device - Create platform device for ACPI device node
  73. * @adev: ACPI device node to create a platform device for.
  74. * @properties: Optional collection of build-in properties.
  75. *
  76. * Check if the given @adev can be represented as a platform device and, if
  77. * that's the case, create and register a platform device, populate its common
  78. * resources and returns a pointer to it. Otherwise, return %NULL.
  79. *
  80. * Name of the platform device will be the same as @adev's.
  81. */
  82. struct platform_device *acpi_create_platform_device(struct acpi_device *adev,
  83. struct property_entry *properties)
  84. {
  85. struct platform_device *pdev = NULL;
  86. struct platform_device_info pdevinfo;
  87. struct resource_entry *rentry;
  88. struct list_head resource_list;
  89. struct resource *resources = NULL;
  90. int count;
  91. /* If the ACPI node already has a physical device attached, skip it. */
  92. if (adev->physical_node_count)
  93. return NULL;
  94. if (!acpi_match_device_ids(adev, forbidden_id_list))
  95. return ERR_PTR(-EINVAL);
  96. INIT_LIST_HEAD(&resource_list);
  97. count = acpi_dev_get_resources(adev, &resource_list, NULL, NULL);
  98. if (count < 0) {
  99. return NULL;
  100. } else if (count > 0) {
  101. resources = kcalloc(count, sizeof(struct resource),
  102. GFP_KERNEL);
  103. if (!resources) {
  104. dev_err(&adev->dev, "No memory for resources\n");
  105. acpi_dev_free_resource_list(&resource_list);
  106. return ERR_PTR(-ENOMEM);
  107. }
  108. count = 0;
  109. list_for_each_entry(rentry, &resource_list, node)
  110. acpi_platform_fill_resource(adev, rentry->res,
  111. &resources[count++]);
  112. acpi_dev_free_resource_list(&resource_list);
  113. }
  114. memset(&pdevinfo, 0, sizeof(pdevinfo));
  115. /*
  116. * If the ACPI node has a parent and that parent has a physical device
  117. * attached to it, that physical device should be the parent of the
  118. * platform device we are about to create.
  119. */
  120. pdevinfo.parent = adev->parent ?
  121. acpi_get_first_physical_node(adev->parent) : NULL;
  122. pdevinfo.name = dev_name(&adev->dev);
  123. pdevinfo.id = -1;
  124. pdevinfo.res = resources;
  125. pdevinfo.num_res = count;
  126. pdevinfo.fwnode = acpi_fwnode_handle(adev);
  127. pdevinfo.properties = properties;
  128. if (acpi_dma_supported(adev))
  129. pdevinfo.dma_mask = DMA_BIT_MASK(32);
  130. else
  131. pdevinfo.dma_mask = 0;
  132. pdev = platform_device_register_full(&pdevinfo);
  133. if (IS_ERR(pdev))
  134. dev_err(&adev->dev, "platform device creation failed: %ld\n",
  135. PTR_ERR(pdev));
  136. else {
  137. set_dev_node(&pdev->dev, acpi_get_node(adev->handle));
  138. dev_dbg(&adev->dev, "created platform device %s\n",
  139. dev_name(&pdev->dev));
  140. }
  141. kfree(resources);
  142. return pdev;
  143. }
  144. EXPORT_SYMBOL_GPL(acpi_create_platform_device);
  145. void __init acpi_platform_init(void)
  146. {
  147. acpi_reconfig_notifier_register(&acpi_platform_notifier);
  148. }