Browse Source

Merge branch 'acpi-enumeration'

* acpi-enumeration:
  ACPI: remove unnecessary INIT_LIST_HEAD
  ACPI / platform: include missed header into acpi_platform.c
  platform / ACPI: Attach/detach ACPI PM during probe/remove/shutdown
  mmc: sdhci-acpi: add SDHCI ACPI driver
  ACPI: add SDHCI to ACPI platform devices
  ACPI / PNP: skip ACPI device nodes associated with physical nodes already
  i2c / ACPI: add ACPI enumeration support
  ACPI / platform: Initialize ACPI handles of platform devices in advance
  ACPI / driver core: Introduce struct acpi_dev_node and related macros
  ACPI: Allow ACPI handles of devices to be initialized in advance
  ACPI / resources: Use AE_CTRL_TERMINATE to terminate resources walks
  ACPI: Centralized processing of ACPI device resources
  ACPI / platform: Use common ACPI device resource parsing routines
  ACPI: Move device resources interpretation code from PNP to ACPI core
  ACPI / platform: use ACPI device name instead of _HID._UID
  ACPI: Add support for platform bus type
  ACPI / ia64: Export acpi_[un]register_gsi()
  ACPI / x86: Export acpi_[un]register_gsi()
  ACPI: Provide generic functions for matching ACPI device nodes
  driver core / ACPI: Move ACPI support to core device and driver types
Rafael J. Wysocki 12 years ago
parent
commit
bcacbdbdc8

+ 0 - 3
arch/ia64/include/asm/device.h

@@ -7,9 +7,6 @@
 #define _ASM_IA64_DEVICE_H
 
 struct dev_archdata {
-#ifdef CONFIG_ACPI
-	void	*acpi_handle;
-#endif
 #ifdef CONFIG_INTEL_IOMMU
 	void *iommu; /* hook for IOMMU specific extension */
 #endif

+ 2 - 0
arch/ia64/kernel/acpi.c

@@ -633,6 +633,7 @@ int acpi_register_gsi(struct device *dev, u32 gsi, int triggering, int polarity)
 				      ACPI_EDGE_SENSITIVE) ? IOSAPIC_EDGE :
 				     IOSAPIC_LEVEL);
 }
+EXPORT_SYMBOL_GPL(acpi_register_gsi);
 
 void acpi_unregister_gsi(u32 gsi)
 {
@@ -644,6 +645,7 @@ void acpi_unregister_gsi(u32 gsi)
 
 	iosapic_unregister_intr(gsi);
 }
+EXPORT_SYMBOL_GPL(acpi_unregister_gsi);
 
 static int __init acpi_parse_fadt(struct acpi_table_header *table)
 {

+ 0 - 3
arch/x86/include/asm/device.h

@@ -2,9 +2,6 @@
 #define _ASM_X86_DEVICE_H
 
 struct dev_archdata {
-#ifdef CONFIG_ACPI
-	void	*acpi_handle;
-#endif
 #ifdef CONFIG_X86_DEV_DMA_OPS
 	struct dma_map_ops *dma_ops;
 #endif

+ 6 - 0
arch/x86/kernel/acpi/boot.c

@@ -574,6 +574,12 @@ int acpi_register_gsi(struct device *dev, u32 gsi, int trigger, int polarity)
 
 	return irq;
 }
+EXPORT_SYMBOL_GPL(acpi_register_gsi);
+
+void acpi_unregister_gsi(u32 gsi)
+{
+}
+EXPORT_SYMBOL_GPL(acpi_unregister_gsi);
 
 void __init acpi_set_irq_model_pic(void)
 {

+ 6 - 0
drivers/acpi/Kconfig

@@ -181,6 +181,12 @@ config ACPI_DOCK
 	  This driver supports ACPI-controlled docking stations and removable
 	  drive bays such as the IBM Ultrabay and the Dell Module Bay.
 
+config ACPI_I2C
+	def_tristate I2C
+	depends on I2C
+	help
+	  ACPI I2C enumeration support.
+
 config ACPI_PROCESSOR
 	tristate "Processor"
 	select THERMAL

+ 3 - 0
drivers/acpi/Makefile

@@ -33,10 +33,12 @@ acpi-$(CONFIG_ACPI_SLEEP)	+= proc.o
 #
 acpi-y				+= bus.o glue.o
 acpi-y				+= scan.o
+acpi-y				+= resource.o
 acpi-y				+= processor_core.o
 acpi-y				+= ec.o
 acpi-$(CONFIG_ACPI_DOCK)	+= dock.o
 acpi-y				+= pci_root.o pci_link.o pci_irq.o pci_bind.o
+acpi-y				+= acpi_platform.o
 acpi-y				+= power.o
 acpi-y				+= event.o
 acpi-y				+= sysfs.o
@@ -68,6 +70,7 @@ obj-$(CONFIG_ACPI_HED)		+= hed.o
 obj-$(CONFIG_ACPI_EC_DEBUGFS)	+= ec_sys.o
 obj-$(CONFIG_ACPI_CUSTOM_METHOD)+= custom_method.o
 obj-$(CONFIG_ACPI_BGRT)		+= bgrt.o
+obj-$(CONFIG_ACPI_I2C)		+= acpi_i2c.o
 
 # processor has its own "processor." module_param namespace
 processor-y			:= processor_driver.o processor_throttling.o

+ 103 - 0
drivers/acpi/acpi_i2c.c

@@ -0,0 +1,103 @@
+/*
+ * ACPI I2C enumeration support
+ *
+ * Copyright (C) 2012, Intel Corporation
+ * Author: Mika Westerberg <mika.westerberg@linux.intel.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/acpi.h>
+#include <linux/device.h>
+#include <linux/export.h>
+#include <linux/i2c.h>
+#include <linux/ioport.h>
+
+ACPI_MODULE_NAME("i2c");
+
+static int acpi_i2c_add_resource(struct acpi_resource *ares, void *data)
+{
+	struct i2c_board_info *info = data;
+
+	if (ares->type == ACPI_RESOURCE_TYPE_SERIAL_BUS) {
+		struct acpi_resource_i2c_serialbus *sb;
+
+		sb = &ares->data.i2c_serial_bus;
+		if (sb->type == ACPI_RESOURCE_SERIAL_TYPE_I2C) {
+			info->addr = sb->slave_address;
+			if (sb->access_mode == ACPI_I2C_10BIT_MODE)
+				info->flags |= I2C_CLIENT_TEN;
+		}
+	} else if (info->irq < 0) {
+		struct resource r;
+
+		if (acpi_dev_resource_interrupt(ares, 0, &r))
+			info->irq = r.start;
+	}
+
+	/* Tell the ACPI core to skip this resource */
+	return 1;
+}
+
+static acpi_status acpi_i2c_add_device(acpi_handle handle, u32 level,
+				       void *data, void **return_value)
+{
+	struct i2c_adapter *adapter = data;
+	struct list_head resource_list;
+	struct i2c_board_info info;
+	struct acpi_device *adev;
+	int ret;
+
+	if (acpi_bus_get_device(handle, &adev))
+		return AE_OK;
+	if (acpi_bus_get_status(adev) || !adev->status.present)
+		return AE_OK;
+
+	memset(&info, 0, sizeof(info));
+	info.acpi_node.handle = handle;
+	info.irq = -1;
+
+	INIT_LIST_HEAD(&resource_list);
+	ret = acpi_dev_get_resources(adev, &resource_list,
+				     acpi_i2c_add_resource, &info);
+	acpi_dev_free_resource_list(&resource_list);
+
+	if (ret < 0 || !info.addr)
+		return AE_OK;
+
+	strlcpy(info.type, dev_name(&adev->dev), sizeof(info.type));
+	if (!i2c_new_device(adapter, &info)) {
+		dev_err(&adapter->dev,
+			"failed to add I2C device %s from ACPI\n",
+			dev_name(&adev->dev));
+	}
+
+	return AE_OK;
+}
+
+/**
+ * acpi_i2c_register_devices - enumerate I2C slave devices behind adapter
+ * @adapter: pointer to adapter
+ *
+ * Enumerate all I2C slave devices behind this adapter by walking the ACPI
+ * namespace. When a device is found it will be added to the Linux device
+ * model and bound to the corresponding ACPI handle.
+ */
+void acpi_i2c_register_devices(struct i2c_adapter *adapter)
+{
+	acpi_handle handle;
+	acpi_status status;
+
+	handle = ACPI_HANDLE(&adapter->dev);
+	if (!handle)
+		return;
+
+	status = acpi_walk_namespace(ACPI_TYPE_DEVICE, handle, 1,
+				     acpi_i2c_add_device, NULL,
+				     adapter, NULL);
+	if (ACPI_FAILURE(status))
+		dev_warn(&adapter->dev, "failed to enumerate I2C slaves\n");
+}
+EXPORT_SYMBOL_GPL(acpi_i2c_register_devices);

+ 104 - 0
drivers/acpi/acpi_platform.c

@@ -0,0 +1,104 @@
+/*
+ * ACPI support for platform bus type.
+ *
+ * Copyright (C) 2012, Intel Corporation
+ * Authors: Mika Westerberg <mika.westerberg@linux.intel.com>
+ *          Mathias Nyman <mathias.nyman@linux.intel.com>
+ *          Rafael J. Wysocki <rafael.j.wysocki@intel.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/acpi.h>
+#include <linux/device.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+
+#include "internal.h"
+
+ACPI_MODULE_NAME("platform");
+
+/**
+ * acpi_create_platform_device - Create platform device for ACPI device node
+ * @adev: ACPI device node to create a platform device for.
+ *
+ * Check if the given @adev can be represented as a platform device and, if
+ * that's the case, create and register a platform device, populate its common
+ * resources and returns a pointer to it.  Otherwise, return %NULL.
+ *
+ * The platform device's name will be taken from the @adev's _HID and _UID.
+ */
+struct platform_device *acpi_create_platform_device(struct acpi_device *adev)
+{
+	struct platform_device *pdev = NULL;
+	struct acpi_device *acpi_parent;
+	struct platform_device_info pdevinfo;
+	struct resource_list_entry *rentry;
+	struct list_head resource_list;
+	struct resource *resources;
+	int count;
+
+	/* If the ACPI node already has a physical device attached, skip it. */
+	if (adev->physical_node_count)
+		return NULL;
+
+	INIT_LIST_HEAD(&resource_list);
+	count = acpi_dev_get_resources(adev, &resource_list, NULL, NULL);
+	if (count <= 0)
+		return NULL;
+
+	resources = kmalloc(count * sizeof(struct resource), GFP_KERNEL);
+	if (!resources) {
+		dev_err(&adev->dev, "No memory for resources\n");
+		acpi_dev_free_resource_list(&resource_list);
+		return NULL;
+	}
+	count = 0;
+	list_for_each_entry(rentry, &resource_list, node)
+		resources[count++] = rentry->res;
+
+	acpi_dev_free_resource_list(&resource_list);
+
+	memset(&pdevinfo, 0, sizeof(pdevinfo));
+	/*
+	 * If the ACPI node has a parent and that parent has a physical device
+	 * attached to it, that physical device should be the parent of the
+	 * platform device we are about to create.
+	 */
+	pdevinfo.parent = NULL;
+	acpi_parent = adev->parent;
+	if (acpi_parent) {
+		struct acpi_device_physical_node *entry;
+		struct list_head *list;
+
+		mutex_lock(&acpi_parent->physical_node_lock);
+		list = &acpi_parent->physical_node_list;
+		if (!list_empty(list)) {
+			entry = list_first_entry(list,
+					struct acpi_device_physical_node,
+					node);
+			pdevinfo.parent = entry->dev;
+		}
+		mutex_unlock(&acpi_parent->physical_node_lock);
+	}
+	pdevinfo.name = dev_name(&adev->dev);
+	pdevinfo.id = -1;
+	pdevinfo.res = resources;
+	pdevinfo.num_res = count;
+	pdevinfo.acpi_node.handle = adev->handle;
+	pdev = platform_device_register_full(&pdevinfo);
+	if (IS_ERR(pdev)) {
+		dev_err(&adev->dev, "platform device creation failed: %ld\n",
+			PTR_ERR(pdev));
+		pdev = NULL;
+	} else {
+		dev_dbg(&adev->dev, "created platform device %s\n",
+			dev_name(&pdev->dev));
+	}
+
+	kfree(resources);
+	return pdev;
+}

+ 39 - 17
drivers/acpi/glue.c

@@ -130,46 +130,59 @@ static int acpi_bind_one(struct device *dev, acpi_handle handle)
 {
 	struct acpi_device *acpi_dev;
 	acpi_status status;
-	struct acpi_device_physical_node *physical_node;
+	struct acpi_device_physical_node *physical_node, *pn;
 	char physical_node_name[sizeof(PHYSICAL_NODE_STRING) + 2];
 	int retval = -EINVAL;
 
-	if (dev->archdata.acpi_handle) {
-		dev_warn(dev, "Drivers changed 'acpi_handle'\n");
-		return -EINVAL;
+	if (ACPI_HANDLE(dev)) {
+		if (handle) {
+			dev_warn(dev, "ACPI handle is already set\n");
+			return -EINVAL;
+		} else {
+			handle = ACPI_HANDLE(dev);
+		}
 	}
+	if (!handle)
+		return -EINVAL;
 
 	get_device(dev);
 	status = acpi_bus_get_device(handle, &acpi_dev);
 	if (ACPI_FAILURE(status))
 		goto err;
 
-	physical_node = kzalloc(sizeof(struct acpi_device_physical_node),
-		GFP_KERNEL);
+	physical_node = kzalloc(sizeof(*physical_node), GFP_KERNEL);
 	if (!physical_node) {
 		retval = -ENOMEM;
 		goto err;
 	}
 
 	mutex_lock(&acpi_dev->physical_node_lock);
+
+	/* Sanity check. */
+	list_for_each_entry(pn, &acpi_dev->physical_node_list, node)
+		if (pn->dev == dev) {
+			dev_warn(dev, "Already associated with ACPI node\n");
+			goto err_free;
+		}
+
 	/* allocate physical node id according to physical_node_id_bitmap */
 	physical_node->node_id =
 		find_first_zero_bit(acpi_dev->physical_node_id_bitmap,
 		ACPI_MAX_PHYSICAL_NODE);
 	if (physical_node->node_id >= ACPI_MAX_PHYSICAL_NODE) {
 		retval = -ENOSPC;
-		mutex_unlock(&acpi_dev->physical_node_lock);
-		kfree(physical_node);
-		goto err;
+		goto err_free;
 	}
 
 	set_bit(physical_node->node_id, acpi_dev->physical_node_id_bitmap);
 	physical_node->dev = dev;
 	list_add_tail(&physical_node->node, &acpi_dev->physical_node_list);
 	acpi_dev->physical_node_count++;
+
 	mutex_unlock(&acpi_dev->physical_node_lock);
 
-	dev->archdata.acpi_handle = handle;
+	if (!ACPI_HANDLE(dev))
+		ACPI_HANDLE_SET(dev, acpi_dev->handle);
 
 	if (!physical_node->node_id)
 		strcpy(physical_node_name, PHYSICAL_NODE_STRING);
@@ -187,8 +200,14 @@ static int acpi_bind_one(struct device *dev, acpi_handle handle)
 	return 0;
 
  err:
+	ACPI_HANDLE_SET(dev, NULL);
 	put_device(dev);
 	return retval;
+
+ err_free:
+	mutex_unlock(&acpi_dev->physical_node_lock);
+	kfree(physical_node);
+	goto err;
 }
 
 static int acpi_unbind_one(struct device *dev)
@@ -198,11 +217,10 @@ static int acpi_unbind_one(struct device *dev)
 	acpi_status status;
 	struct list_head *node, *next;
 
-	if (!dev->archdata.acpi_handle)
+	if (!ACPI_HANDLE(dev))
 		return 0;
 
-	status = acpi_bus_get_device(dev->archdata.acpi_handle,
-		&acpi_dev);
+	status = acpi_bus_get_device(ACPI_HANDLE(dev), &acpi_dev);
 	if (ACPI_FAILURE(status))
 		goto err;
 
@@ -228,7 +246,7 @@ static int acpi_unbind_one(struct device *dev)
 
 		sysfs_remove_link(&acpi_dev->dev.kobj, physical_node_name);
 		sysfs_remove_link(&dev->kobj, "firmware_node");
-		dev->archdata.acpi_handle = NULL;
+		ACPI_HANDLE_SET(dev, NULL);
 		/* acpi_bind_one increase refcnt by one */
 		put_device(dev);
 		kfree(entry);
@@ -248,6 +266,10 @@ static int acpi_platform_notify(struct device *dev)
 	acpi_handle handle;
 	int ret = -EINVAL;
 
+	ret = acpi_bind_one(dev, NULL);
+	if (!ret)
+		goto out;
+
 	if (!dev->bus || !dev->parent) {
 		/* bridge devices genernally haven't bus or parent */
 		ret = acpi_find_bridge_device(dev, &handle);
@@ -261,16 +283,16 @@ static int acpi_platform_notify(struct device *dev)
 	}
 	if ((ret = type->find_device(dev, &handle)) != 0)
 		DBG("Can't get handler for %s\n", dev_name(dev));
-      end:
+ end:
 	if (!ret)
 		acpi_bind_one(dev, handle);
 
+ out:
 #if ACPI_GLUE_DEBUG
 	if (!ret) {
 		struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL };
 
-		acpi_get_name(dev->archdata.acpi_handle,
-			      ACPI_FULL_PATHNAME, &buffer);
+		acpi_get_name(dev->acpi_handle, ACPI_FULL_PATHNAME, &buffer);
 		DBG("Device %s -> %s\n", dev_name(dev), (char *)buffer.pointer);
 		kfree(buffer.pointer);
 	} else

+ 7 - 0
drivers/acpi/internal.h

@@ -93,4 +93,11 @@ static inline int suspend_nvs_save(void) { return 0; }
 static inline void suspend_nvs_restore(void) {}
 #endif
 
+/*--------------------------------------------------------------------------
+				Platform bus support
+  -------------------------------------------------------------------------- */
+struct platform_device;
+
+struct platform_device *acpi_create_platform_device(struct acpi_device *adev);
+
 #endif /* _ACPI_INTERNAL_H_ */

+ 0 - 5
drivers/acpi/pci_irq.c

@@ -495,11 +495,6 @@ int acpi_pci_irq_enable(struct pci_dev *dev)
 	return 0;
 }
 
-/* FIXME: implement x86/x86_64 version */
-void __attribute__ ((weak)) acpi_unregister_gsi(u32 i)
-{
-}
-
 void acpi_pci_irq_disable(struct pci_dev *dev)
 {
 	struct acpi_prt_entry *entry;

+ 526 - 0
drivers/acpi/resource.c

@@ -0,0 +1,526 @@
+/*
+ * drivers/acpi/resource.c - ACPI device resources interpretation.
+ *
+ * Copyright (C) 2012, Intel Corp.
+ * Author: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
+ *
+ * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License version 2 as published
+ *  by the Free Software Foundation.
+ *
+ *  This program is distributed in the hope that it will be useful, but
+ *  WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ *  General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License along
+ *  with this program; if not, write to the Free Software Foundation, Inc.,
+ *  59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
+ *
+ * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ */
+
+#include <linux/acpi.h>
+#include <linux/device.h>
+#include <linux/export.h>
+#include <linux/ioport.h>
+#include <linux/slab.h>
+
+#ifdef CONFIG_X86
+#define valid_IRQ(i) (((i) != 0) && ((i) != 2))
+#else
+#define valid_IRQ(i) (true)
+#endif
+
+static unsigned long acpi_dev_memresource_flags(u64 len, u8 write_protect,
+						bool window)
+{
+	unsigned long flags = IORESOURCE_MEM;
+
+	if (len == 0)
+		flags |= IORESOURCE_DISABLED;
+
+	if (write_protect == ACPI_READ_WRITE_MEMORY)
+		flags |= IORESOURCE_MEM_WRITEABLE;
+
+	if (window)
+		flags |= IORESOURCE_WINDOW;
+
+	return flags;
+}
+
+static void acpi_dev_get_memresource(struct resource *res, u64 start, u64 len,
+				     u8 write_protect)
+{
+	res->start = start;
+	res->end = start + len - 1;
+	res->flags = acpi_dev_memresource_flags(len, write_protect, false);
+}
+
+/**
+ * acpi_dev_resource_memory - Extract ACPI memory resource information.
+ * @ares: Input ACPI resource object.
+ * @res: Output generic resource object.
+ *
+ * Check if the given ACPI resource object represents a memory resource and
+ * if that's the case, use the information in it to populate the generic
+ * resource object pointed to by @res.
+ */
+bool acpi_dev_resource_memory(struct acpi_resource *ares, struct resource *res)
+{
+	struct acpi_resource_memory24 *memory24;
+	struct acpi_resource_memory32 *memory32;
+	struct acpi_resource_fixed_memory32 *fixed_memory32;
+
+	switch (ares->type) {
+	case ACPI_RESOURCE_TYPE_MEMORY24:
+		memory24 = &ares->data.memory24;
+		acpi_dev_get_memresource(res, memory24->minimum,
+					 memory24->address_length,
+					 memory24->write_protect);
+		break;
+	case ACPI_RESOURCE_TYPE_MEMORY32:
+		memory32 = &ares->data.memory32;
+		acpi_dev_get_memresource(res, memory32->minimum,
+					 memory32->address_length,
+					 memory32->write_protect);
+		break;
+	case ACPI_RESOURCE_TYPE_FIXED_MEMORY32:
+		fixed_memory32 = &ares->data.fixed_memory32;
+		acpi_dev_get_memresource(res, fixed_memory32->address,
+					 fixed_memory32->address_length,
+					 fixed_memory32->write_protect);
+		break;
+	default:
+		return false;
+	}
+	return true;
+}
+EXPORT_SYMBOL_GPL(acpi_dev_resource_memory);
+
+static unsigned int acpi_dev_ioresource_flags(u64 start, u64 end, u8 io_decode,
+					      bool window)
+{
+	int flags = IORESOURCE_IO;
+
+	if (io_decode == ACPI_DECODE_16)
+		flags |= IORESOURCE_IO_16BIT_ADDR;
+
+	if (start > end || end >= 0x10003)
+		flags |= IORESOURCE_DISABLED;
+
+	if (window)
+		flags |= IORESOURCE_WINDOW;
+
+	return flags;
+}
+
+static void acpi_dev_get_ioresource(struct resource *res, u64 start, u64 len,
+				    u8 io_decode)
+{
+	u64 end = start + len - 1;
+
+	res->start = start;
+	res->end = end;
+	res->flags = acpi_dev_ioresource_flags(start, end, io_decode, false);
+}
+
+/**
+ * acpi_dev_resource_io - Extract ACPI I/O resource information.
+ * @ares: Input ACPI resource object.
+ * @res: Output generic resource object.
+ *
+ * Check if the given ACPI resource object represents an I/O resource and
+ * if that's the case, use the information in it to populate the generic
+ * resource object pointed to by @res.
+ */
+bool acpi_dev_resource_io(struct acpi_resource *ares, struct resource *res)
+{
+	struct acpi_resource_io *io;
+	struct acpi_resource_fixed_io *fixed_io;
+
+	switch (ares->type) {
+	case ACPI_RESOURCE_TYPE_IO:
+		io = &ares->data.io;
+		acpi_dev_get_ioresource(res, io->minimum,
+					io->address_length,
+					io->io_decode);
+		break;
+	case ACPI_RESOURCE_TYPE_FIXED_IO:
+		fixed_io = &ares->data.fixed_io;
+		acpi_dev_get_ioresource(res, fixed_io->address,
+					fixed_io->address_length,
+					ACPI_DECODE_10);
+		break;
+	default:
+		return false;
+	}
+	return true;
+}
+EXPORT_SYMBOL_GPL(acpi_dev_resource_io);
+
+/**
+ * acpi_dev_resource_address_space - Extract ACPI address space information.
+ * @ares: Input ACPI resource object.
+ * @res: Output generic resource object.
+ *
+ * Check if the given ACPI resource object represents an address space resource
+ * and if that's the case, use the information in it to populate the generic
+ * resource object pointed to by @res.
+ */
+bool acpi_dev_resource_address_space(struct acpi_resource *ares,
+				     struct resource *res)
+{
+	acpi_status status;
+	struct acpi_resource_address64 addr;
+	bool window;
+	u64 len;
+	u8 io_decode;
+
+	switch (ares->type) {
+	case ACPI_RESOURCE_TYPE_ADDRESS16:
+	case ACPI_RESOURCE_TYPE_ADDRESS32:
+	case ACPI_RESOURCE_TYPE_ADDRESS64:
+		break;
+	default:
+		return false;
+	}
+
+	status = acpi_resource_to_address64(ares, &addr);
+	if (ACPI_FAILURE(status))
+		return true;
+
+	res->start = addr.minimum;
+	res->end = addr.maximum;
+	window = addr.producer_consumer == ACPI_PRODUCER;
+
+	switch(addr.resource_type) {
+	case ACPI_MEMORY_RANGE:
+		len = addr.maximum - addr.minimum + 1;
+		res->flags = acpi_dev_memresource_flags(len,
+						addr.info.mem.write_protect,
+						window);
+		break;
+	case ACPI_IO_RANGE:
+		io_decode = addr.granularity == 0xfff ?
+				ACPI_DECODE_10 : ACPI_DECODE_16;
+		res->flags = acpi_dev_ioresource_flags(addr.minimum,
+						       addr.maximum,
+						       io_decode, window);
+		break;
+	case ACPI_BUS_NUMBER_RANGE:
+		res->flags = IORESOURCE_BUS;
+		break;
+	default:
+		res->flags = 0;
+	}
+
+	return true;
+}
+EXPORT_SYMBOL_GPL(acpi_dev_resource_address_space);
+
+/**
+ * acpi_dev_resource_ext_address_space - Extract ACPI address space information.
+ * @ares: Input ACPI resource object.
+ * @res: Output generic resource object.
+ *
+ * Check if the given ACPI resource object represents an extended address space
+ * resource and if that's the case, use the information in it to populate the
+ * generic resource object pointed to by @res.
+ */
+bool acpi_dev_resource_ext_address_space(struct acpi_resource *ares,
+					 struct resource *res)
+{
+	struct acpi_resource_extended_address64 *ext_addr;
+	bool window;
+	u64 len;
+	u8 io_decode;
+
+	if (ares->type != ACPI_RESOURCE_TYPE_EXTENDED_ADDRESS64)
+		return false;
+
+	ext_addr = &ares->data.ext_address64;
+
+	res->start = ext_addr->minimum;
+	res->end = ext_addr->maximum;
+	window = ext_addr->producer_consumer == ACPI_PRODUCER;
+
+	switch(ext_addr->resource_type) {
+	case ACPI_MEMORY_RANGE:
+		len = ext_addr->maximum - ext_addr->minimum + 1;
+		res->flags = acpi_dev_memresource_flags(len,
+					ext_addr->info.mem.write_protect,
+					window);
+		break;
+	case ACPI_IO_RANGE:
+		io_decode = ext_addr->granularity == 0xfff ?
+				ACPI_DECODE_10 : ACPI_DECODE_16;
+		res->flags = acpi_dev_ioresource_flags(ext_addr->minimum,
+						       ext_addr->maximum,
+						       io_decode, window);
+		break;
+	case ACPI_BUS_NUMBER_RANGE:
+		res->flags = IORESOURCE_BUS;
+		break;
+	default:
+		res->flags = 0;
+	}
+
+	return true;
+}
+EXPORT_SYMBOL_GPL(acpi_dev_resource_ext_address_space);
+
+/**
+ * acpi_dev_irq_flags - Determine IRQ resource flags.
+ * @triggering: Triggering type as provided by ACPI.
+ * @polarity: Interrupt polarity as provided by ACPI.
+ * @shareable: Whether or not the interrupt is shareable.
+ */
+unsigned long acpi_dev_irq_flags(u8 triggering, u8 polarity, u8 shareable)
+{
+	unsigned long flags;
+
+	if (triggering == ACPI_LEVEL_SENSITIVE)
+		flags = polarity == ACPI_ACTIVE_LOW ?
+			IORESOURCE_IRQ_LOWLEVEL : IORESOURCE_IRQ_HIGHLEVEL;
+	else
+		flags = polarity == ACPI_ACTIVE_LOW ?
+			IORESOURCE_IRQ_LOWEDGE : IORESOURCE_IRQ_HIGHEDGE;
+
+	if (shareable == ACPI_SHARED)
+		flags |= IORESOURCE_IRQ_SHAREABLE;
+
+	return flags | IORESOURCE_IRQ;
+}
+EXPORT_SYMBOL_GPL(acpi_dev_irq_flags);
+
+static void acpi_dev_irqresource_disabled(struct resource *res, u32 gsi)
+{
+	res->start = gsi;
+	res->end = gsi;
+	res->flags = IORESOURCE_IRQ | IORESOURCE_DISABLED;
+}
+
+static void acpi_dev_get_irqresource(struct resource *res, u32 gsi,
+				     u8 triggering, u8 polarity, u8 shareable)
+{
+	int irq, p, t;
+
+	if (!valid_IRQ(gsi)) {
+		acpi_dev_irqresource_disabled(res, gsi);
+		return;
+	}
+
+	/*
+	 * In IO-APIC mode, use overrided attribute. Two reasons:
+	 * 1. BIOS bug in DSDT
+	 * 2. BIOS uses IO-APIC mode Interrupt Source Override
+	 */
+	if (!acpi_get_override_irq(gsi, &t, &p)) {
+		u8 trig = t ? ACPI_LEVEL_SENSITIVE : ACPI_EDGE_SENSITIVE;
+		u8 pol = p ? ACPI_ACTIVE_LOW : ACPI_ACTIVE_HIGH;
+
+		if (triggering != trig || polarity != pol) {
+			pr_warning("ACPI: IRQ %d override to %s, %s\n", gsi,
+				   t ? "edge" : "level", p ? "low" : "high");
+			triggering = trig;
+			polarity = pol;
+		}
+	}
+
+	res->flags = acpi_dev_irq_flags(triggering, polarity, shareable);
+	irq = acpi_register_gsi(NULL, gsi, triggering, polarity);
+	if (irq >= 0) {
+		res->start = irq;
+		res->end = irq;
+	} else {
+		acpi_dev_irqresource_disabled(res, gsi);
+	}
+}
+
+/**
+ * acpi_dev_resource_interrupt - Extract ACPI interrupt resource information.
+ * @ares: Input ACPI resource object.
+ * @index: Index into the array of GSIs represented by the resource.
+ * @res: Output generic resource object.
+ *
+ * Check if the given ACPI resource object represents an interrupt resource
+ * and @index does not exceed the resource's interrupt count (true is returned
+ * in that case regardless of the results of the other checks)).  If that's the
+ * case, register the GSI corresponding to @index from the array of interrupts
+ * represented by the resource and populate the generic resource object pointed
+ * to by @res accordingly.  If the registration of the GSI is not successful,
+ * IORESOURCE_DISABLED will be set it that object's flags.
+ */
+bool acpi_dev_resource_interrupt(struct acpi_resource *ares, int index,
+				 struct resource *res)
+{
+	struct acpi_resource_irq *irq;
+	struct acpi_resource_extended_irq *ext_irq;
+
+	switch (ares->type) {
+	case ACPI_RESOURCE_TYPE_IRQ:
+		/*
+		 * Per spec, only one interrupt per descriptor is allowed in
+		 * _CRS, but some firmware violates this, so parse them all.
+		 */
+		irq = &ares->data.irq;
+		if (index >= irq->interrupt_count) {
+			acpi_dev_irqresource_disabled(res, 0);
+			return false;
+		}
+		acpi_dev_get_irqresource(res, irq->interrupts[index],
+					 irq->triggering, irq->polarity,
+					 irq->sharable);
+		break;
+	case ACPI_RESOURCE_TYPE_EXTENDED_IRQ:
+		ext_irq = &ares->data.extended_irq;
+		if (index >= ext_irq->interrupt_count) {
+			acpi_dev_irqresource_disabled(res, 0);
+			return false;
+		}
+		acpi_dev_get_irqresource(res, ext_irq->interrupts[index],
+					 ext_irq->triggering, ext_irq->polarity,
+					 ext_irq->sharable);
+		break;
+	default:
+		return false;
+	}
+
+	return true;
+}
+EXPORT_SYMBOL_GPL(acpi_dev_resource_interrupt);
+
+/**
+ * acpi_dev_free_resource_list - Free resource from %acpi_dev_get_resources().
+ * @list: The head of the resource list to free.
+ */
+void acpi_dev_free_resource_list(struct list_head *list)
+{
+	struct resource_list_entry *rentry, *re;
+
+	list_for_each_entry_safe(rentry, re, list, node) {
+		list_del(&rentry->node);
+		kfree(rentry);
+	}
+}
+EXPORT_SYMBOL_GPL(acpi_dev_free_resource_list);
+
+struct res_proc_context {
+	struct list_head *list;
+	int (*preproc)(struct acpi_resource *, void *);
+	void *preproc_data;
+	int count;
+	int error;
+};
+
+static acpi_status acpi_dev_new_resource_entry(struct resource *r,
+					       struct res_proc_context *c)
+{
+	struct resource_list_entry *rentry;
+
+	rentry = kmalloc(sizeof(*rentry), GFP_KERNEL);
+	if (!rentry) {
+		c->error = -ENOMEM;
+		return AE_NO_MEMORY;
+	}
+	rentry->res = *r;
+	list_add_tail(&rentry->node, c->list);
+	c->count++;
+	return AE_OK;
+}
+
+static acpi_status acpi_dev_process_resource(struct acpi_resource *ares,
+					     void *context)
+{
+	struct res_proc_context *c = context;
+	struct resource r;
+	int i;
+
+	if (c->preproc) {
+		int ret;
+
+		ret = c->preproc(ares, c->preproc_data);
+		if (ret < 0) {
+			c->error = ret;
+			return AE_CTRL_TERMINATE;
+		} else if (ret > 0) {
+			return AE_OK;
+		}
+	}
+
+	memset(&r, 0, sizeof(r));
+
+	if (acpi_dev_resource_memory(ares, &r)
+	    || acpi_dev_resource_io(ares, &r)
+	    || acpi_dev_resource_address_space(ares, &r)
+	    || acpi_dev_resource_ext_address_space(ares, &r))
+		return acpi_dev_new_resource_entry(&r, c);
+
+	for (i = 0; acpi_dev_resource_interrupt(ares, i, &r); i++) {
+		acpi_status status;
+
+		status = acpi_dev_new_resource_entry(&r, c);
+		if (ACPI_FAILURE(status))
+			return status;
+	}
+
+	return AE_OK;
+}
+
+/**
+ * acpi_dev_get_resources - Get current resources of a device.
+ * @adev: ACPI device node to get the resources for.
+ * @list: Head of the resultant list of resources (must be empty).
+ * @preproc: The caller's preprocessing routine.
+ * @preproc_data: Pointer passed to the caller's preprocessing routine.
+ *
+ * Evaluate the _CRS method for the given device node and process its output by
+ * (1) executing the @preproc() rountine provided by the caller, passing the
+ * resource pointer and @preproc_data to it as arguments, for each ACPI resource
+ * returned and (2) converting all of the returned ACPI resources into struct
+ * resource objects if possible.  If the return value of @preproc() in step (1)
+ * is different from 0, step (2) is not applied to the given ACPI resource and
+ * if that value is negative, the whole processing is aborted and that value is
+ * returned as the final error code.
+ *
+ * The resultant struct resource objects are put on the list pointed to by
+ * @list, that must be empty initially, as members of struct resource_list_entry
+ * objects.  Callers of this routine should use %acpi_dev_free_resource_list() to
+ * free that list.
+ *
+ * The number of resources in the output list is returned on success, an error
+ * code reflecting the error condition is returned otherwise.
+ */
+int acpi_dev_get_resources(struct acpi_device *adev, struct list_head *list,
+			   int (*preproc)(struct acpi_resource *, void *),
+			   void *preproc_data)
+{
+	struct res_proc_context c;
+	acpi_handle not_used;
+	acpi_status status;
+
+	if (!adev || !adev->handle || !list_empty(list))
+		return -EINVAL;
+
+	status = acpi_get_handle(adev->handle, METHOD_NAME__CRS, &not_used);
+	if (ACPI_FAILURE(status))
+		return 0;
+
+	c.list = list;
+	c.preproc = preproc;
+	c.preproc_data = preproc_data;
+	c.count = 0;
+	c.error = 0;
+	status = acpi_walk_resources(adev->handle, METHOD_NAME__CRS,
+				     acpi_dev_process_resource, &c);
+	if (ACPI_FAILURE(status)) {
+		acpi_dev_free_resource_list(list);
+		return c.error ? c.error : -EIO;
+	}
+
+	return c.count;
+}
+EXPORT_SYMBOL_GPL(acpi_dev_get_resources);

+ 52 - 6
drivers/acpi/scan.c

@@ -29,6 +29,17 @@ extern struct acpi_device *acpi_root;
 
 static const char *dummy_hid = "device";
 
+/*
+ * The following ACPI IDs are known to be suitable for representing as
+ * platform devices.
+ */
+static const struct acpi_device_id acpi_platform_device_ids[] = {
+
+	{ "PNP0D40" },
+
+	{ }
+};
+
 static LIST_HEAD(acpi_device_list);
 static LIST_HEAD(acpi_bus_id_list);
 DEFINE_MUTEX(acpi_device_lock);
@@ -340,8 +351,8 @@ static void acpi_device_remove_files(struct acpi_device *dev)
 			ACPI Bus operations
    -------------------------------------------------------------------------- */
 
-int acpi_match_device_ids(struct acpi_device *device,
-			  const struct acpi_device_id *ids)
+static const struct acpi_device_id *__acpi_match_device(
+	struct acpi_device *device, const struct acpi_device_id *ids)
 {
 	const struct acpi_device_id *id;
 	struct acpi_hardware_id *hwid;
@@ -351,14 +362,44 @@ int acpi_match_device_ids(struct acpi_device *device,
 	 * driver for it.
 	 */
 	if (!device->status.present)
-		return -ENODEV;
+		return NULL;
 
 	for (id = ids; id->id[0]; id++)
 		list_for_each_entry(hwid, &device->pnp.ids, list)
 			if (!strcmp((char *) id->id, hwid->id))
-				return 0;
+				return id;
+
+	return NULL;
+}
+
+/**
+ * acpi_match_device - Match a struct device against a given list of ACPI IDs
+ * @ids: Array of struct acpi_device_id object to match against.
+ * @dev: The device structure to match.
+ *
+ * Check if @dev has a valid ACPI handle and if there is a struct acpi_device
+ * object for that handle and use that object to match against a given list of
+ * device IDs.
+ *
+ * Return a pointer to the first matching ID on success or %NULL on failure.
+ */
+const struct acpi_device_id *acpi_match_device(const struct acpi_device_id *ids,
+					       const struct device *dev)
+{
+	struct acpi_device *adev;
+
+	if (!ids || !ACPI_HANDLE(dev)
+	    || ACPI_FAILURE(acpi_bus_get_device(ACPI_HANDLE(dev), &adev)))
+		return NULL;
 
-	return -ENOENT;
+	return __acpi_match_device(adev, ids);
+}
+EXPORT_SYMBOL_GPL(acpi_match_device);
+
+int acpi_match_device_ids(struct acpi_device *device,
+			  const struct acpi_device_id *ids)
+{
+	return __acpi_match_device(device, ids) ? 0 : -ENOENT;
 }
 EXPORT_SYMBOL(acpi_match_device_ids);
 
@@ -1490,8 +1531,13 @@ static acpi_status acpi_bus_check_add(acpi_handle handle, u32 lvl,
 	 */
 	device = NULL;
 	acpi_bus_get_device(handle, &device);
-	if (ops->acpi_op_add && !device)
+	if (ops->acpi_op_add && !device) {
 		acpi_add_single_object(&device, handle, type, sta, ops);
+		/* Is the device a known good platform device? */
+		if (device
+		    && !acpi_match_device_ids(device, acpi_platform_device_ids))
+			acpi_create_platform_device(device);
+	}
 
 	if (!device)
 		return AE_CTRL_DEPTH;

+ 24 - 2
drivers/base/platform.c

@@ -21,6 +21,7 @@
 #include <linux/slab.h>
 #include <linux/pm_runtime.h>
 #include <linux/idr.h>
+#include <linux/acpi.h>
 
 #include "base.h"
 #include "power/power.h"
@@ -436,6 +437,7 @@ struct platform_device *platform_device_register_full(
 		goto err_alloc;
 
 	pdev->dev.parent = pdevinfo->parent;
+	ACPI_HANDLE_SET(&pdev->dev, pdevinfo->acpi_node.handle);
 
 	if (pdevinfo->dma_mask) {
 		/*
@@ -466,6 +468,7 @@ struct platform_device *platform_device_register_full(
 	ret = platform_device_add(pdev);
 	if (ret) {
 err:
+		ACPI_HANDLE_SET(&pdev->dev, NULL);
 		kfree(pdev->dev.dma_mask);
 
 err_alloc:
@@ -481,8 +484,16 @@ static int platform_drv_probe(struct device *_dev)
 {
 	struct platform_driver *drv = to_platform_driver(_dev->driver);
 	struct platform_device *dev = to_platform_device(_dev);
+	int ret;
 
-	return drv->probe(dev);
+	if (ACPI_HANDLE(_dev))
+		acpi_dev_pm_attach(_dev, true);
+
+	ret = drv->probe(dev);
+	if (ret && ACPI_HANDLE(_dev))
+		acpi_dev_pm_detach(_dev, true);
+
+	return ret;
 }
 
 static int platform_drv_probe_fail(struct device *_dev)
@@ -494,8 +505,13 @@ static int platform_drv_remove(struct device *_dev)
 {
 	struct platform_driver *drv = to_platform_driver(_dev->driver);
 	struct platform_device *dev = to_platform_device(_dev);
+	int ret;
+
+	ret = drv->remove(dev);
+	if (ACPI_HANDLE(_dev))
+		acpi_dev_pm_detach(_dev, true);
 
-	return drv->remove(dev);
+	return ret;
 }
 
 static void platform_drv_shutdown(struct device *_dev)
@@ -504,6 +520,8 @@ static void platform_drv_shutdown(struct device *_dev)
 	struct platform_device *dev = to_platform_device(_dev);
 
 	drv->shutdown(dev);
+	if (ACPI_HANDLE(_dev))
+		acpi_dev_pm_detach(_dev, true);
 }
 
 /**
@@ -709,6 +727,10 @@ static int platform_match(struct device *dev, struct device_driver *drv)
 	if (of_driver_match_device(dev, drv))
 		return 1;
 
+	/* Then try ACPI style match */
+	if (acpi_driver_match_device(dev, drv))
+		return 1;
+
 	/* Then try to match against the id table */
 	if (pdrv->id_table)
 		return platform_match_id(pdrv->id_table, pdev) != NULL;

+ 6 - 0
drivers/i2c/i2c-core.c

@@ -39,6 +39,7 @@
 #include <linux/irqflags.h>
 #include <linux/rwsem.h>
 #include <linux/pm_runtime.h>
+#include <linux/acpi.h>
 #include <asm/uaccess.h>
 
 #include "i2c-core.h"
@@ -78,6 +79,10 @@ static int i2c_device_match(struct device *dev, struct device_driver *drv)
 	if (of_driver_match_device(dev, drv))
 		return 1;
 
+	/* Then ACPI style match */
+	if (acpi_driver_match_device(dev, drv))
+		return 1;
+
 	driver = to_i2c_driver(drv);
 	/* match on an id table if there is one */
 	if (driver->id_table)
@@ -539,6 +544,7 @@ i2c_new_device(struct i2c_adapter *adap, struct i2c_board_info const *info)
 	client->dev.bus = &i2c_bus_type;
 	client->dev.type = &i2c_client_type;
 	client->dev.of_node = info->of_node;
+	ACPI_HANDLE_SET(&client->dev, info->acpi_node.handle);
 
 	/* For 10-bit clients, add an arbitrary offset to avoid collisions */
 	dev_set_name(&client->dev, "%d-%04x", i2c_adapter_id(adap),

+ 12 - 0
drivers/mmc/host/Kconfig

@@ -81,6 +81,18 @@ config MMC_RICOH_MMC
 
 	  If unsure, say Y.
 
+config MMC_SDHCI_ACPI
+	tristate "SDHCI support for ACPI enumerated SDHCI controllers"
+	depends on MMC_SDHCI && ACPI
+	help
+	  This selects support for ACPI enumerated SDHCI controllers,
+	  identified by ACPI Compatibility ID PNP0D40 or specific
+	  ACPI Hardware IDs.
+
+	  If you have a controller with this interface, say Y or M here.
+
+	  If unsure, say N.
+
 config MMC_SDHCI_PLTFM
 	tristate "SDHCI platform and OF driver helper"
 	depends on MMC_SDHCI

+ 1 - 0
drivers/mmc/host/Makefile

@@ -9,6 +9,7 @@ obj-$(CONFIG_MMC_MXS)		+= mxs-mmc.o
 obj-$(CONFIG_MMC_SDHCI)		+= sdhci.o
 obj-$(CONFIG_MMC_SDHCI_PCI)	+= sdhci-pci.o
 obj-$(subst m,y,$(CONFIG_MMC_SDHCI_PCI))	+= sdhci-pci-data.o
+obj-$(CONFIG_MMC_SDHCI_ACPI)	+= sdhci-acpi.o
 obj-$(CONFIG_MMC_SDHCI_PXAV3)	+= sdhci-pxav3.o
 obj-$(CONFIG_MMC_SDHCI_PXAV2)	+= sdhci-pxav2.o
 obj-$(CONFIG_MMC_SDHCI_S3C)	+= sdhci-s3c.o

+ 304 - 0
drivers/mmc/host/sdhci-acpi.c

@@ -0,0 +1,304 @@
+/*
+ * Secure Digital Host Controller Interface ACPI driver.
+ *
+ * Copyright (c) 2012, Intel Corporation.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ */
+
+#include <linux/init.h>
+#include <linux/export.h>
+#include <linux/module.h>
+#include <linux/device.h>
+#include <linux/platform_device.h>
+#include <linux/ioport.h>
+#include <linux/io.h>
+#include <linux/dma-mapping.h>
+#include <linux/compiler.h>
+#include <linux/stddef.h>
+#include <linux/bitops.h>
+#include <linux/types.h>
+#include <linux/err.h>
+#include <linux/interrupt.h>
+#include <linux/acpi.h>
+#include <linux/pm.h>
+#include <linux/pm_runtime.h>
+
+#include <linux/mmc/host.h>
+#include <linux/mmc/pm.h>
+#include <linux/mmc/sdhci.h>
+
+#include "sdhci.h"
+
+enum {
+	SDHCI_ACPI_SD_CD	= BIT(0),
+	SDHCI_ACPI_RUNTIME_PM	= BIT(1),
+};
+
+struct sdhci_acpi_chip {
+	const struct	sdhci_ops *ops;
+	unsigned int	quirks;
+	unsigned int	quirks2;
+	unsigned long	caps;
+	unsigned int	caps2;
+	mmc_pm_flag_t	pm_caps;
+};
+
+struct sdhci_acpi_slot {
+	const struct	sdhci_acpi_chip *chip;
+	unsigned int	quirks;
+	unsigned int	quirks2;
+	unsigned long	caps;
+	unsigned int	caps2;
+	mmc_pm_flag_t	pm_caps;
+	unsigned int	flags;
+};
+
+struct sdhci_acpi_host {
+	struct sdhci_host		*host;
+	const struct sdhci_acpi_slot	*slot;
+	struct platform_device		*pdev;
+	bool				use_runtime_pm;
+};
+
+static inline bool sdhci_acpi_flag(struct sdhci_acpi_host *c, unsigned int flag)
+{
+	return c->slot && (c->slot->flags & flag);
+}
+
+static int sdhci_acpi_enable_dma(struct sdhci_host *host)
+{
+	return 0;
+}
+
+static const struct sdhci_ops sdhci_acpi_ops_dflt = {
+	.enable_dma = sdhci_acpi_enable_dma,
+};
+
+static const struct acpi_device_id sdhci_acpi_ids[] = {
+	{ "PNP0D40" },
+	{ },
+};
+MODULE_DEVICE_TABLE(acpi, sdhci_acpi_ids);
+
+static const struct sdhci_acpi_slot *sdhci_acpi_get_slot(const char *hid)
+{
+	const struct acpi_device_id *id;
+
+	for (id = sdhci_acpi_ids; id->id[0]; id++)
+		if (!strcmp(id->id, hid))
+			return (const struct sdhci_acpi_slot *)id->driver_data;
+	return NULL;
+}
+
+static int __devinit sdhci_acpi_probe(struct platform_device *pdev)
+{
+	struct device *dev = &pdev->dev;
+	acpi_handle handle = ACPI_HANDLE(dev);
+	struct acpi_device *device;
+	struct sdhci_acpi_host *c;
+	struct sdhci_host *host;
+	struct resource *iomem;
+	resource_size_t len;
+	const char *hid;
+	int err;
+
+	if (acpi_bus_get_device(handle, &device))
+		return -ENODEV;
+
+	if (acpi_bus_get_status(device) || !device->status.present)
+		return -ENODEV;
+
+	hid = acpi_device_hid(device);
+
+	iomem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	if (!iomem)
+		return -ENOMEM;
+
+	len = resource_size(iomem);
+	if (len < 0x100)
+		dev_err(dev, "Invalid iomem size!\n");
+
+	if (!devm_request_mem_region(dev, iomem->start, len, dev_name(dev)))
+		return -ENOMEM;
+
+	host = sdhci_alloc_host(dev, sizeof(struct sdhci_acpi_host));
+	if (IS_ERR(host))
+		return PTR_ERR(host);
+
+	c = sdhci_priv(host);
+	c->host = host;
+	c->slot = sdhci_acpi_get_slot(hid);
+	c->pdev = pdev;
+	c->use_runtime_pm = sdhci_acpi_flag(c, SDHCI_ACPI_RUNTIME_PM);
+
+	platform_set_drvdata(pdev, c);
+
+	host->hw_name	= "ACPI";
+	host->ops	= &sdhci_acpi_ops_dflt;
+	host->irq	= platform_get_irq(pdev, 0);
+
+	host->ioaddr = devm_ioremap_nocache(dev, iomem->start,
+					    resource_size(iomem));
+	if (host->ioaddr == NULL) {
+		err = -ENOMEM;
+		goto err_free;
+	}
+
+	if (!dev->dma_mask) {
+		u64 dma_mask;
+
+		if (sdhci_readl(host, SDHCI_CAPABILITIES) & SDHCI_CAN_64BIT) {
+			/* 64-bit DMA is not supported at present */
+			dma_mask = DMA_BIT_MASK(32);
+		} else {
+			dma_mask = DMA_BIT_MASK(32);
+		}
+
+		dev->dma_mask = &dev->coherent_dma_mask;
+		dev->coherent_dma_mask = dma_mask;
+	}
+
+	if (c->slot) {
+		if (c->slot->chip) {
+			host->ops            = c->slot->chip->ops;
+			host->quirks        |= c->slot->chip->quirks;
+			host->quirks2       |= c->slot->chip->quirks2;
+			host->mmc->caps     |= c->slot->chip->caps;
+			host->mmc->caps2    |= c->slot->chip->caps2;
+			host->mmc->pm_caps  |= c->slot->chip->pm_caps;
+		}
+		host->quirks        |= c->slot->quirks;
+		host->quirks2       |= c->slot->quirks2;
+		host->mmc->caps     |= c->slot->caps;
+		host->mmc->caps2    |= c->slot->caps2;
+		host->mmc->pm_caps  |= c->slot->pm_caps;
+	}
+
+	err = sdhci_add_host(host);
+	if (err)
+		goto err_free;
+
+	if (c->use_runtime_pm) {
+		pm_suspend_ignore_children(dev, 1);
+		pm_runtime_set_autosuspend_delay(dev, 50);
+		pm_runtime_use_autosuspend(dev);
+		pm_runtime_enable(dev);
+	}
+
+	return 0;
+
+err_free:
+	platform_set_drvdata(pdev, NULL);
+	sdhci_free_host(c->host);
+	return err;
+}
+
+static int __devexit sdhci_acpi_remove(struct platform_device *pdev)
+{
+	struct sdhci_acpi_host *c = platform_get_drvdata(pdev);
+	struct device *dev = &pdev->dev;
+	int dead;
+
+	if (c->use_runtime_pm) {
+		pm_runtime_get_sync(dev);
+		pm_runtime_disable(dev);
+		pm_runtime_put_noidle(dev);
+	}
+
+	dead = (sdhci_readl(c->host, SDHCI_INT_STATUS) == ~0);
+	sdhci_remove_host(c->host, dead);
+	platform_set_drvdata(pdev, NULL);
+	sdhci_free_host(c->host);
+
+	return 0;
+}
+
+#ifdef CONFIG_PM_SLEEP
+
+static int sdhci_acpi_suspend(struct device *dev)
+{
+	struct sdhci_acpi_host *c = dev_get_drvdata(dev);
+
+	return sdhci_suspend_host(c->host);
+}
+
+static int sdhci_acpi_resume(struct device *dev)
+{
+	struct sdhci_acpi_host *c = dev_get_drvdata(dev);
+
+	return sdhci_resume_host(c->host);
+}
+
+#else
+
+#define sdhci_acpi_suspend	NULL
+#define sdhci_acpi_resume	NULL
+
+#endif
+
+#ifdef CONFIG_PM_RUNTIME
+
+static int sdhci_acpi_runtime_suspend(struct device *dev)
+{
+	struct sdhci_acpi_host *c = dev_get_drvdata(dev);
+
+	return sdhci_runtime_suspend_host(c->host);
+}
+
+static int sdhci_acpi_runtime_resume(struct device *dev)
+{
+	struct sdhci_acpi_host *c = dev_get_drvdata(dev);
+
+	return sdhci_runtime_resume_host(c->host);
+}
+
+static int sdhci_acpi_runtime_idle(struct device *dev)
+{
+	return 0;
+}
+
+#else
+
+#define sdhci_acpi_runtime_suspend	NULL
+#define sdhci_acpi_runtime_resume	NULL
+#define sdhci_acpi_runtime_idle		NULL
+
+#endif
+
+static const struct dev_pm_ops sdhci_acpi_pm_ops = {
+	.suspend		= sdhci_acpi_suspend,
+	.resume			= sdhci_acpi_resume,
+	.runtime_suspend	= sdhci_acpi_runtime_suspend,
+	.runtime_resume		= sdhci_acpi_runtime_resume,
+	.runtime_idle		= sdhci_acpi_runtime_idle,
+};
+
+static struct platform_driver sdhci_acpi_driver = {
+	.driver = {
+		.name			= "sdhci-acpi",
+		.owner			= THIS_MODULE,
+		.acpi_match_table	= sdhci_acpi_ids,
+		.pm			= &sdhci_acpi_pm_ops,
+	},
+	.probe	= sdhci_acpi_probe,
+	.remove	= __devexit_p(sdhci_acpi_remove),
+};
+
+module_platform_driver(sdhci_acpi_driver);
+
+MODULE_DESCRIPTION("Secure Digital Host Controller Interface ACPI driver");
+MODULE_AUTHOR("Adrian Hunter");
+MODULE_LICENSE("GPL v2");

+ 2 - 0
drivers/pnp/base.h

@@ -159,6 +159,8 @@ struct pnp_resource {
 
 void pnp_free_resource(struct pnp_resource *pnp_res);
 
+struct pnp_resource *pnp_add_resource(struct pnp_dev *dev,
+				      struct resource *res);
 struct pnp_resource *pnp_add_irq_resource(struct pnp_dev *dev, int irq,
 					  int flags);
 struct pnp_resource *pnp_add_dma_resource(struct pnp_dev *dev, int dma,

+ 4 - 0
drivers/pnp/pnpacpi/core.c

@@ -242,6 +242,10 @@ static int __init pnpacpi_add_device(struct acpi_device *device)
 	char *pnpid;
 	struct acpi_hardware_id *id;
 
+	/* Skip devices that are already bound */
+	if (device->physical_node_count)
+		return 0;
+
 	/*
 	 * If a PnPacpi device is not present , the device
 	 * driver should not be loaded.

+ 32 - 264
drivers/pnp/pnpacpi/rsparser.c

@@ -28,37 +28,6 @@
 #include "../base.h"
 #include "pnpacpi.h"
 
-#ifdef CONFIG_IA64
-#define valid_IRQ(i) (1)
-#else
-#define valid_IRQ(i) (((i) != 0) && ((i) != 2))
-#endif
-
-/*
- * Allocated Resources
- */
-static int irq_flags(int triggering, int polarity, int shareable)
-{
-	int flags;
-
-	if (triggering == ACPI_LEVEL_SENSITIVE) {
-		if (polarity == ACPI_ACTIVE_LOW)
-			flags = IORESOURCE_IRQ_LOWLEVEL;
-		else
-			flags = IORESOURCE_IRQ_HIGHLEVEL;
-	} else {
-		if (polarity == ACPI_ACTIVE_LOW)
-			flags = IORESOURCE_IRQ_LOWEDGE;
-		else
-			flags = IORESOURCE_IRQ_HIGHEDGE;
-	}
-
-	if (shareable == ACPI_SHARED)
-		flags |= IORESOURCE_IRQ_SHAREABLE;
-
-	return flags;
-}
-
 static void decode_irq_flags(struct pnp_dev *dev, int flags, int *triggering,
 			     int *polarity, int *shareable)
 {
@@ -94,45 +63,6 @@ static void decode_irq_flags(struct pnp_dev *dev, int flags, int *triggering,
 		*shareable = ACPI_EXCLUSIVE;
 }
 
-static void pnpacpi_parse_allocated_irqresource(struct pnp_dev *dev,
-						u32 gsi, int triggering,
-						int polarity, int shareable)
-{
-	int irq, flags;
-	int p, t;
-
-	if (!valid_IRQ(gsi)) {
-		pnp_add_irq_resource(dev, gsi, IORESOURCE_DISABLED);
-		return;
-	}
-
-	/*
-	 * in IO-APIC mode, use overrided attribute. Two reasons:
-	 * 1. BIOS bug in DSDT
-	 * 2. BIOS uses IO-APIC mode Interrupt Source Override
-	 */
-	if (!acpi_get_override_irq(gsi, &t, &p)) {
-		t = t ? ACPI_LEVEL_SENSITIVE : ACPI_EDGE_SENSITIVE;
-		p = p ? ACPI_ACTIVE_LOW : ACPI_ACTIVE_HIGH;
-
-		if (triggering != t || polarity != p) {
-			dev_warn(&dev->dev, "IRQ %d override to %s, %s\n",
-				gsi, t ? "edge":"level", p ? "low":"high");
-			triggering = t;
-			polarity = p;
-		}
-	}
-
-	flags = irq_flags(triggering, polarity, shareable);
-	irq = acpi_register_gsi(&dev->dev, gsi, triggering, polarity);
-	if (irq >= 0)
-		pcibios_penalize_isa_irq(irq, 1);
-	else
-		flags |= IORESOURCE_DISABLED;
-
-	pnp_add_irq_resource(dev, irq, flags);
-}
-
 static int dma_flags(struct pnp_dev *dev, int type, int bus_master,
 		     int transfer)
 {
@@ -177,21 +107,16 @@ static int dma_flags(struct pnp_dev *dev, int type, int bus_master,
 	return flags;
 }
 
-static void pnpacpi_parse_allocated_ioresource(struct pnp_dev *dev, u64 start,
-					       u64 len, int io_decode,
-					       int window)
-{
-	int flags = 0;
-	u64 end = start + len - 1;
+/*
+ * Allocated Resources
+ */
 
-	if (io_decode == ACPI_DECODE_16)
-		flags |= IORESOURCE_IO_16BIT_ADDR;
-	if (len == 0 || end >= 0x10003)
-		flags |= IORESOURCE_DISABLED;
-	if (window)
-		flags |= IORESOURCE_WINDOW;
+static void pnpacpi_add_irqresource(struct pnp_dev *dev, struct resource *r)
+{
+	if (!(r->flags & IORESOURCE_DISABLED))
+		pcibios_penalize_isa_irq(r->start, 1);
 
-	pnp_add_io_resource(dev, start, end, flags);
+	pnp_add_resource(dev, r);
 }
 
 /*
@@ -249,130 +174,49 @@ static void pnpacpi_parse_allocated_vendor(struct pnp_dev *dev,
 	}
 }
 
-static void pnpacpi_parse_allocated_memresource(struct pnp_dev *dev,
-						u64 start, u64 len,
-						int write_protect, int window)
-{
-	int flags = 0;
-	u64 end = start + len - 1;
-
-	if (len == 0)
-		flags |= IORESOURCE_DISABLED;
-	if (write_protect == ACPI_READ_WRITE_MEMORY)
-		flags |= IORESOURCE_MEM_WRITEABLE;
-	if (window)
-		flags |= IORESOURCE_WINDOW;
-
-	pnp_add_mem_resource(dev, start, end, flags);
-}
-
-static void pnpacpi_parse_allocated_busresource(struct pnp_dev *dev,
-						u64 start, u64 len)
-{
-	u64 end = start + len - 1;
-
-	pnp_add_bus_resource(dev, start, end);
-}
-
-static void pnpacpi_parse_allocated_address_space(struct pnp_dev *dev,
-						  struct acpi_resource *res)
-{
-	struct acpi_resource_address64 addr, *p = &addr;
-	acpi_status status;
-	int window;
-	u64 len;
-
-	status = acpi_resource_to_address64(res, p);
-	if (!ACPI_SUCCESS(status)) {
-		dev_warn(&dev->dev, "failed to convert resource type %d\n",
-			 res->type);
-		return;
-	}
-
-	/* Windows apparently computes length rather than using _LEN */
-	len = p->maximum - p->minimum + 1;
-	window = (p->producer_consumer == ACPI_PRODUCER) ? 1 : 0;
-
-	if (p->resource_type == ACPI_MEMORY_RANGE)
-		pnpacpi_parse_allocated_memresource(dev, p->minimum, len,
-			p->info.mem.write_protect, window);
-	else if (p->resource_type == ACPI_IO_RANGE)
-		pnpacpi_parse_allocated_ioresource(dev, p->minimum, len,
-			p->granularity == 0xfff ? ACPI_DECODE_10 :
-				ACPI_DECODE_16, window);
-	else if (p->resource_type == ACPI_BUS_NUMBER_RANGE)
-		pnpacpi_parse_allocated_busresource(dev, p->minimum, len);
-}
-
-static void pnpacpi_parse_allocated_ext_address_space(struct pnp_dev *dev,
-						      struct acpi_resource *res)
-{
-	struct acpi_resource_extended_address64 *p = &res->data.ext_address64;
-	int window;
-	u64 len;
-
-	/* Windows apparently computes length rather than using _LEN */
-	len = p->maximum - p->minimum + 1;
-	window = (p->producer_consumer == ACPI_PRODUCER) ? 1 : 0;
-
-	if (p->resource_type == ACPI_MEMORY_RANGE)
-		pnpacpi_parse_allocated_memresource(dev, p->minimum, len,
-			p->info.mem.write_protect, window);
-	else if (p->resource_type == ACPI_IO_RANGE)
-		pnpacpi_parse_allocated_ioresource(dev, p->minimum, len,
-			p->granularity == 0xfff ? ACPI_DECODE_10 :
-				ACPI_DECODE_16, window);
-	else if (p->resource_type == ACPI_BUS_NUMBER_RANGE)
-		pnpacpi_parse_allocated_busresource(dev, p->minimum, len);
-}
-
 static acpi_status pnpacpi_allocated_resource(struct acpi_resource *res,
 					      void *data)
 {
 	struct pnp_dev *dev = data;
-	struct acpi_resource_irq *irq;
 	struct acpi_resource_dma *dma;
-	struct acpi_resource_io *io;
-	struct acpi_resource_fixed_io *fixed_io;
 	struct acpi_resource_vendor_typed *vendor_typed;
-	struct acpi_resource_memory24 *memory24;
-	struct acpi_resource_memory32 *memory32;
-	struct acpi_resource_fixed_memory32 *fixed_memory32;
-	struct acpi_resource_extended_irq *extended_irq;
+	struct resource r;
 	int i, flags;
 
-	switch (res->type) {
-	case ACPI_RESOURCE_TYPE_IRQ:
-		/*
-		 * Per spec, only one interrupt per descriptor is allowed in
-		 * _CRS, but some firmware violates this, so parse them all.
-		 */
-		irq = &res->data.irq;
-		if (irq->interrupt_count == 0)
-			pnp_add_irq_resource(dev, 0, IORESOURCE_DISABLED);
-		else {
-			for (i = 0; i < irq->interrupt_count; i++) {
-				pnpacpi_parse_allocated_irqresource(dev,
-					irq->interrupts[i],
-					irq->triggering,
-					irq->polarity,
-				    irq->sharable);
-			}
+	if (acpi_dev_resource_memory(res, &r)
+	    || acpi_dev_resource_io(res, &r)
+	    || acpi_dev_resource_address_space(res, &r)
+	    || acpi_dev_resource_ext_address_space(res, &r)) {
+		pnp_add_resource(dev, &r);
+		return AE_OK;
+	}
 
+	r.flags = 0;
+	if (acpi_dev_resource_interrupt(res, 0, &r)) {
+		pnpacpi_add_irqresource(dev, &r);
+		for (i = 1; acpi_dev_resource_interrupt(res, i, &r); i++)
+			pnpacpi_add_irqresource(dev, &r);
+
+		if (i > 1) {
 			/*
 			 * The IRQ encoder puts a single interrupt in each
 			 * descriptor, so if a _CRS descriptor has more than
 			 * one interrupt, we won't be able to re-encode it.
 			 */
-			if (pnp_can_write(dev) && irq->interrupt_count > 1) {
+			if (pnp_can_write(dev)) {
 				dev_warn(&dev->dev, "multiple interrupts in "
 					 "_CRS descriptor; configuration can't "
 					 "be changed\n");
 				dev->capabilities &= ~PNP_WRITE;
 			}
 		}
-		break;
+		return AE_OK;
+	} else if (r.flags & IORESOURCE_DISABLED) {
+		pnp_add_irq_resource(dev, 0, IORESOURCE_DISABLED);
+		return AE_OK;
+	}
 
+	switch (res->type) {
 	case ACPI_RESOURCE_TYPE_DMA:
 		dma = &res->data.dma;
 		if (dma->channel_count > 0 && dma->channels[0] != (u8) -1)
@@ -383,26 +227,10 @@ static acpi_status pnpacpi_allocated_resource(struct acpi_resource *res,
 		pnp_add_dma_resource(dev, dma->channels[0], flags);
 		break;
 
-	case ACPI_RESOURCE_TYPE_IO:
-		io = &res->data.io;
-		pnpacpi_parse_allocated_ioresource(dev,
-			io->minimum,
-			io->address_length,
-			io->io_decode, 0);
-		break;
-
 	case ACPI_RESOURCE_TYPE_START_DEPENDENT:
 	case ACPI_RESOURCE_TYPE_END_DEPENDENT:
 		break;
 
-	case ACPI_RESOURCE_TYPE_FIXED_IO:
-		fixed_io = &res->data.fixed_io;
-		pnpacpi_parse_allocated_ioresource(dev,
-			fixed_io->address,
-			fixed_io->address_length,
-			ACPI_DECODE_10, 0);
-		break;
-
 	case ACPI_RESOURCE_TYPE_VENDOR:
 		vendor_typed = &res->data.vendor_typed;
 		pnpacpi_parse_allocated_vendor(dev, vendor_typed);
@@ -411,66 +239,6 @@ static acpi_status pnpacpi_allocated_resource(struct acpi_resource *res,
 	case ACPI_RESOURCE_TYPE_END_TAG:
 		break;
 
-	case ACPI_RESOURCE_TYPE_MEMORY24:
-		memory24 = &res->data.memory24;
-		pnpacpi_parse_allocated_memresource(dev,
-			memory24->minimum,
-			memory24->address_length,
-			memory24->write_protect, 0);
-		break;
-	case ACPI_RESOURCE_TYPE_MEMORY32:
-		memory32 = &res->data.memory32;
-		pnpacpi_parse_allocated_memresource(dev,
-			memory32->minimum,
-			memory32->address_length,
-			memory32->write_protect, 0);
-		break;
-	case ACPI_RESOURCE_TYPE_FIXED_MEMORY32:
-		fixed_memory32 = &res->data.fixed_memory32;
-		pnpacpi_parse_allocated_memresource(dev,
-			fixed_memory32->address,
-			fixed_memory32->address_length,
-			fixed_memory32->write_protect, 0);
-		break;
-	case ACPI_RESOURCE_TYPE_ADDRESS16:
-	case ACPI_RESOURCE_TYPE_ADDRESS32:
-	case ACPI_RESOURCE_TYPE_ADDRESS64:
-		pnpacpi_parse_allocated_address_space(dev, res);
-		break;
-
-	case ACPI_RESOURCE_TYPE_EXTENDED_ADDRESS64:
-		pnpacpi_parse_allocated_ext_address_space(dev, res);
-		break;
-
-	case ACPI_RESOURCE_TYPE_EXTENDED_IRQ:
-		extended_irq = &res->data.extended_irq;
-
-		if (extended_irq->interrupt_count == 0)
-			pnp_add_irq_resource(dev, 0, IORESOURCE_DISABLED);
-		else {
-			for (i = 0; i < extended_irq->interrupt_count; i++) {
-				pnpacpi_parse_allocated_irqresource(dev,
-					extended_irq->interrupts[i],
-					extended_irq->triggering,
-					extended_irq->polarity,
-					extended_irq->sharable);
-			}
-
-			/*
-			 * The IRQ encoder puts a single interrupt in each
-			 * descriptor, so if a _CRS descriptor has more than
-			 * one interrupt, we won't be able to re-encode it.
-			 */
-			if (pnp_can_write(dev) &&
-			    extended_irq->interrupt_count > 1) {
-				dev_warn(&dev->dev, "multiple interrupts in "
-					 "_CRS descriptor; configuration can't "
-					 "be changed\n");
-				dev->capabilities &= ~PNP_WRITE;
-			}
-		}
-		break;
-
 	case ACPI_RESOURCE_TYPE_GENERIC_REGISTER:
 		break;
 
@@ -531,7 +299,7 @@ static __init void pnpacpi_parse_irq_option(struct pnp_dev *dev,
 		if (p->interrupts[i])
 			__set_bit(p->interrupts[i], map.bits);
 
-	flags = irq_flags(p->triggering, p->polarity, p->sharable);
+	flags = acpi_dev_irq_flags(p->triggering, p->polarity, p->sharable);
 	pnp_register_irq_resource(dev, option_flags, &map, flags);
 }
 
@@ -555,7 +323,7 @@ static __init void pnpacpi_parse_ext_irq_option(struct pnp_dev *dev,
 		}
 	}
 
-	flags = irq_flags(p->triggering, p->polarity, p->sharable);
+	flags = acpi_dev_irq_flags(p->triggering, p->polarity, p->sharable);
 	pnp_register_irq_resource(dev, option_flags, &map, flags);
 }
 

+ 16 - 0
drivers/pnp/resource.c

@@ -503,6 +503,22 @@ static struct pnp_resource *pnp_new_resource(struct pnp_dev *dev)
 	return pnp_res;
 }
 
+struct pnp_resource *pnp_add_resource(struct pnp_dev *dev,
+				      struct resource *res)
+{
+	struct pnp_resource *pnp_res;
+
+	pnp_res = pnp_new_resource(dev);
+	if (!pnp_res) {
+		dev_err(&dev->dev, "can't add resource %pR\n", res);
+		return NULL;
+	}
+
+	pnp_res->res = *res;
+	dev_dbg(&dev->dev, "%pR\n", res);
+	return pnp_res;
+}
+
 struct pnp_resource *pnp_add_irq_resource(struct pnp_dev *dev, int irq,
 					  int flags)
 {

+ 1 - 1
include/acpi/acpi_bus.h

@@ -412,7 +412,7 @@ acpi_handle acpi_get_child(acpi_handle, u64);
 int acpi_is_root_bridge(acpi_handle);
 acpi_handle acpi_get_pci_rootbridge_handle(unsigned int, unsigned int);
 struct acpi_pci_root *acpi_pci_find_root(acpi_handle handle);
-#define DEVICE_ACPI_HANDLE(dev) ((acpi_handle)((dev)->archdata.acpi_handle))
+#define DEVICE_ACPI_HANDLE(dev) ((acpi_handle)ACPI_HANDLE(dev))
 
 int acpi_enable_wakeup_device_power(struct acpi_device *dev, int state);
 int acpi_disable_wakeup_device_power(struct acpi_device *dev);

+ 48 - 0
include/linux/acpi.h

@@ -27,6 +27,7 @@
 
 #include <linux/errno.h>
 #include <linux/ioport.h>	/* for struct resource */
+#include <linux/device.h>
 
 #ifdef	CONFIG_ACPI
 
@@ -251,6 +252,26 @@ extern int pnpacpi_disabled;
 
 #define PXM_INVAL	(-1)
 
+bool acpi_dev_resource_memory(struct acpi_resource *ares, struct resource *res);
+bool acpi_dev_resource_io(struct acpi_resource *ares, struct resource *res);
+bool acpi_dev_resource_address_space(struct acpi_resource *ares,
+				     struct resource *res);
+bool acpi_dev_resource_ext_address_space(struct acpi_resource *ares,
+					 struct resource *res);
+unsigned long acpi_dev_irq_flags(u8 triggering, u8 polarity, u8 shareable);
+bool acpi_dev_resource_interrupt(struct acpi_resource *ares, int index,
+				 struct resource *res);
+
+struct resource_list_entry {
+	struct list_head node;
+	struct resource res;
+};
+
+void acpi_dev_free_resource_list(struct list_head *list);
+int acpi_dev_get_resources(struct acpi_device *adev, struct list_head *list,
+			   int (*preproc)(struct acpi_resource *, void *),
+			   void *preproc_data);
+
 int acpi_check_resource_conflict(const struct resource *res);
 
 int acpi_check_region(resource_size_t start, resource_size_t n,
@@ -365,6 +386,17 @@ extern int acpi_nvs_register(__u64 start, __u64 size);
 extern int acpi_nvs_for_each_region(int (*func)(__u64, __u64, void *),
 				    void *data);
 
+const struct acpi_device_id *acpi_match_device(const struct acpi_device_id *ids,
+					       const struct device *dev);
+
+static inline bool acpi_driver_match_device(struct device *dev,
+					    const struct device_driver *drv)
+{
+	return !!acpi_match_device(drv->acpi_match_table, dev);
+}
+
+#define ACPI_PTR(_ptr)	(_ptr)
+
 #else	/* !CONFIG_ACPI */
 
 #define acpi_disabled 1
@@ -419,6 +451,22 @@ static inline int acpi_nvs_for_each_region(int (*func)(__u64, __u64, void *),
 	return 0;
 }
 
+struct acpi_device_id;
+
+static inline const struct acpi_device_id *acpi_match_device(
+	const struct acpi_device_id *ids, const struct device *dev)
+{
+	return NULL;
+}
+
+static inline bool acpi_driver_match_device(struct device *dev,
+					    const struct device_driver *drv)
+{
+	return false;
+}
+
+#define ACPI_PTR(_ptr)	(NULL)
+
 #endif	/* !CONFIG_ACPI */
 
 #ifdef CONFIG_ACPI

+ 18 - 0
include/linux/device.h

@@ -190,6 +190,7 @@ extern struct klist *bus_get_device_klist(struct bus_type *bus);
  * @mod_name:	Used for built-in modules.
  * @suppress_bind_attrs: Disables bind/unbind via sysfs.
  * @of_match_table: The open firmware table.
+ * @acpi_match_table: The ACPI match table.
  * @probe:	Called to query the existence of a specific device,
  *		whether this driver can work with it, and bind the driver
  *		to a specific device.
@@ -223,6 +224,7 @@ struct device_driver {
 	bool suppress_bind_attrs;	/* disables bind/unbind via sysfs */
 
 	const struct of_device_id	*of_match_table;
+	const struct acpi_device_id	*acpi_match_table;
 
 	int (*probe) (struct device *dev);
 	int (*remove) (struct device *dev);
@@ -576,6 +578,12 @@ struct device_dma_parameters {
 	unsigned long segment_boundary_mask;
 };
 
+struct acpi_dev_node {
+#ifdef CONFIG_ACPI
+	void	*handle;
+#endif
+};
+
 /**
  * struct device - The basic device structure
  * @parent:	The device's "parent" device, the device to which it is attached.
@@ -616,6 +624,7 @@ struct device_dma_parameters {
  * @dma_mem:	Internal for coherent mem override.
  * @archdata:	For arch-specific additions.
  * @of_node:	Associated device tree node.
+ * @acpi_node:	Associated ACPI device node.
  * @devt:	For creating the sysfs "dev".
  * @id:		device instance
  * @devres_lock: Spinlock to protect the resource of the device.
@@ -680,6 +689,7 @@ struct device {
 	struct dev_archdata	archdata;
 
 	struct device_node	*of_node; /* associated device tree node */
+	struct acpi_dev_node	acpi_node; /* associated ACPI device node */
 
 	dev_t			devt;	/* dev_t, creates the sysfs "dev" */
 	u32			id;	/* device instance */
@@ -700,6 +710,14 @@ static inline struct device *kobj_to_dev(struct kobject *kobj)
 	return container_of(kobj, struct device, kobj);
 }
 
+#ifdef CONFIG_ACPI
+#define ACPI_HANDLE(dev)	((dev)->acpi_node.handle)
+#define ACPI_HANDLE_SET(dev, _handle_)	(dev)->acpi_node.handle = (_handle_)
+#else
+#define ACPI_HANDLE(dev)	(NULL)
+#define ACPI_HANDLE_SET(dev, _handle_)	do { } while (0)
+#endif
+
 /* Get the wakeup routines, which depend on struct device */
 #include <linux/pm_wakeup.h>
 

+ 9 - 0
include/linux/i2c.h

@@ -259,6 +259,7 @@ static inline void i2c_set_clientdata(struct i2c_client *dev, void *data)
  * @platform_data: stored in i2c_client.dev.platform_data
  * @archdata: copied into i2c_client.dev.archdata
  * @of_node: pointer to OpenFirmware device node
+ * @acpi_node: ACPI device node
  * @irq: stored in i2c_client.irq
  *
  * I2C doesn't actually support hardware probing, although controllers and
@@ -279,6 +280,7 @@ struct i2c_board_info {
 	void		*platform_data;
 	struct dev_archdata	*archdata;
 	struct device_node *of_node;
+	struct acpi_dev_node acpi_node;
 	int		irq;
 };
 
@@ -501,4 +503,11 @@ static inline int i2c_adapter_id(struct i2c_adapter *adap)
 			i2c_del_driver)
 
 #endif /* I2C */
+
+#if IS_ENABLED(CONFIG_ACPI_I2C)
+extern void acpi_i2c_register_devices(struct i2c_adapter *adap);
+#else
+static inline void acpi_i2c_register_devices(struct i2c_adapter *adap) {}
+#endif
+
 #endif /* _LINUX_I2C_H */

+ 1 - 0
include/linux/platform_device.h

@@ -55,6 +55,7 @@ extern int platform_add_devices(struct platform_device **, int);
 
 struct platform_device_info {
 		struct device *parent;
+		struct acpi_dev_node acpi_node;
 
 		const char *name;
 		int id;