dect
/
linux-2.6
Archived
13
0
Fork 0

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
This commit is contained in:
Rafael J. Wysocki 2012-11-29 21:41:25 +01:00
commit bcacbdbdc8
27 changed files with 1326 additions and 301 deletions

View File

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

View File

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

View File

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

View File

@ -574,6 +574,12 @@ int acpi_register_gsi(struct device *dev, u32 gsi, int trigger, int polarity)
return irq; 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) void __init acpi_set_irq_model_pic(void)
{ {

View File

@ -181,6 +181,12 @@ config ACPI_DOCK
This driver supports ACPI-controlled docking stations and removable This driver supports ACPI-controlled docking stations and removable
drive bays such as the IBM Ultrabay and the Dell Module Bay. 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 config ACPI_PROCESSOR
tristate "Processor" tristate "Processor"
select THERMAL select THERMAL

View File

@ -33,10 +33,12 @@ acpi-$(CONFIG_ACPI_SLEEP) += proc.o
# #
acpi-y += bus.o glue.o acpi-y += bus.o glue.o
acpi-y += scan.o acpi-y += scan.o
acpi-y += resource.o
acpi-y += processor_core.o acpi-y += processor_core.o
acpi-y += ec.o acpi-y += ec.o
acpi-$(CONFIG_ACPI_DOCK) += dock.o acpi-$(CONFIG_ACPI_DOCK) += dock.o
acpi-y += pci_root.o pci_link.o pci_irq.o pci_bind.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 += power.o
acpi-y += event.o acpi-y += event.o
acpi-y += sysfs.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_EC_DEBUGFS) += ec_sys.o
obj-$(CONFIG_ACPI_CUSTOM_METHOD)+= custom_method.o obj-$(CONFIG_ACPI_CUSTOM_METHOD)+= custom_method.o
obj-$(CONFIG_ACPI_BGRT) += bgrt.o obj-$(CONFIG_ACPI_BGRT) += bgrt.o
obj-$(CONFIG_ACPI_I2C) += acpi_i2c.o
# processor has its own "processor." module_param namespace # processor has its own "processor." module_param namespace
processor-y := processor_driver.o processor_throttling.o processor-y := processor_driver.o processor_throttling.o

103
drivers/acpi/acpi_i2c.c Normal file
View File

@ -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);

View File

@ -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;
}

View File

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

View File

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

View File

@ -495,11 +495,6 @@ int acpi_pci_irq_enable(struct pci_dev *dev)
return 0; 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) void acpi_pci_irq_disable(struct pci_dev *dev)
{ {
struct acpi_prt_entry *entry; struct acpi_prt_entry *entry;

526
drivers/acpi/resource.c Normal file
View File

@ -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);

View File

@ -29,6 +29,17 @@ extern struct acpi_device *acpi_root;
static const char *dummy_hid = "device"; 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_device_list);
static LIST_HEAD(acpi_bus_id_list); static LIST_HEAD(acpi_bus_id_list);
DEFINE_MUTEX(acpi_device_lock); DEFINE_MUTEX(acpi_device_lock);
@ -340,8 +351,8 @@ static void acpi_device_remove_files(struct acpi_device *dev)
ACPI Bus operations ACPI Bus operations
-------------------------------------------------------------------------- */ -------------------------------------------------------------------------- */
int acpi_match_device_ids(struct acpi_device *device, static const struct acpi_device_id *__acpi_match_device(
const struct acpi_device_id *ids) struct acpi_device *device, const struct acpi_device_id *ids)
{ {
const struct acpi_device_id *id; const struct acpi_device_id *id;
struct acpi_hardware_id *hwid; struct acpi_hardware_id *hwid;
@ -351,14 +362,44 @@ int acpi_match_device_ids(struct acpi_device *device,
* driver for it. * driver for it.
*/ */
if (!device->status.present) if (!device->status.present)
return -ENODEV; return NULL;
for (id = ids; id->id[0]; id++) for (id = ids; id->id[0]; id++)
list_for_each_entry(hwid, &device->pnp.ids, list) list_for_each_entry(hwid, &device->pnp.ids, list)
if (!strcmp((char *) id->id, hwid->id)) if (!strcmp((char *) id->id, hwid->id))
return 0; return id;
return -ENOENT; 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 __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); EXPORT_SYMBOL(acpi_match_device_ids);
@ -1490,8 +1531,13 @@ static acpi_status acpi_bus_check_add(acpi_handle handle, u32 lvl,
*/ */
device = NULL; device = NULL;
acpi_bus_get_device(handle, &device); 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); 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) if (!device)
return AE_CTRL_DEPTH; return AE_CTRL_DEPTH;

View File

@ -21,6 +21,7 @@
#include <linux/slab.h> #include <linux/slab.h>
#include <linux/pm_runtime.h> #include <linux/pm_runtime.h>
#include <linux/idr.h> #include <linux/idr.h>
#include <linux/acpi.h>
#include "base.h" #include "base.h"
#include "power/power.h" #include "power/power.h"
@ -436,6 +437,7 @@ struct platform_device *platform_device_register_full(
goto err_alloc; goto err_alloc;
pdev->dev.parent = pdevinfo->parent; pdev->dev.parent = pdevinfo->parent;
ACPI_HANDLE_SET(&pdev->dev, pdevinfo->acpi_node.handle);
if (pdevinfo->dma_mask) { if (pdevinfo->dma_mask) {
/* /*
@ -466,6 +468,7 @@ struct platform_device *platform_device_register_full(
ret = platform_device_add(pdev); ret = platform_device_add(pdev);
if (ret) { if (ret) {
err: err:
ACPI_HANDLE_SET(&pdev->dev, NULL);
kfree(pdev->dev.dma_mask); kfree(pdev->dev.dma_mask);
err_alloc: 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_driver *drv = to_platform_driver(_dev->driver);
struct platform_device *dev = to_platform_device(_dev); 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) 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_driver *drv = to_platform_driver(_dev->driver);
struct platform_device *dev = to_platform_device(_dev); struct platform_device *dev = to_platform_device(_dev);
int ret;
return drv->remove(dev); ret = drv->remove(dev);
if (ACPI_HANDLE(_dev))
acpi_dev_pm_detach(_dev, true);
return ret;
} }
static void platform_drv_shutdown(struct device *_dev) 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); struct platform_device *dev = to_platform_device(_dev);
drv->shutdown(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)) if (of_driver_match_device(dev, drv))
return 1; return 1;
/* Then try ACPI style match */
if (acpi_driver_match_device(dev, drv))
return 1;
/* Then try to match against the id table */ /* Then try to match against the id table */
if (pdrv->id_table) if (pdrv->id_table)
return platform_match_id(pdrv->id_table, pdev) != NULL; return platform_match_id(pdrv->id_table, pdev) != NULL;

View File

@ -39,6 +39,7 @@
#include <linux/irqflags.h> #include <linux/irqflags.h>
#include <linux/rwsem.h> #include <linux/rwsem.h>
#include <linux/pm_runtime.h> #include <linux/pm_runtime.h>
#include <linux/acpi.h>
#include <asm/uaccess.h> #include <asm/uaccess.h>
#include "i2c-core.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)) if (of_driver_match_device(dev, drv))
return 1; return 1;
/* Then ACPI style match */
if (acpi_driver_match_device(dev, drv))
return 1;
driver = to_i2c_driver(drv); driver = to_i2c_driver(drv);
/* match on an id table if there is one */ /* match on an id table if there is one */
if (driver->id_table) 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.bus = &i2c_bus_type;
client->dev.type = &i2c_client_type; client->dev.type = &i2c_client_type;
client->dev.of_node = info->of_node; 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 */ /* For 10-bit clients, add an arbitrary offset to avoid collisions */
dev_set_name(&client->dev, "%d-%04x", i2c_adapter_id(adap), dev_set_name(&client->dev, "%d-%04x", i2c_adapter_id(adap),

View File

@ -81,6 +81,18 @@ config MMC_RICOH_MMC
If unsure, say Y. 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 config MMC_SDHCI_PLTFM
tristate "SDHCI platform and OF driver helper" tristate "SDHCI platform and OF driver helper"
depends on MMC_SDHCI depends on MMC_SDHCI

View File

@ -9,6 +9,7 @@ obj-$(CONFIG_MMC_MXS) += mxs-mmc.o
obj-$(CONFIG_MMC_SDHCI) += sdhci.o obj-$(CONFIG_MMC_SDHCI) += sdhci.o
obj-$(CONFIG_MMC_SDHCI_PCI) += sdhci-pci.o obj-$(CONFIG_MMC_SDHCI_PCI) += sdhci-pci.o
obj-$(subst m,y,$(CONFIG_MMC_SDHCI_PCI)) += sdhci-pci-data.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_PXAV3) += sdhci-pxav3.o
obj-$(CONFIG_MMC_SDHCI_PXAV2) += sdhci-pxav2.o obj-$(CONFIG_MMC_SDHCI_PXAV2) += sdhci-pxav2.o
obj-$(CONFIG_MMC_SDHCI_S3C) += sdhci-s3c.o obj-$(CONFIG_MMC_SDHCI_S3C) += sdhci-s3c.o

View File

@ -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");

View File

@ -159,6 +159,8 @@ struct pnp_resource {
void pnp_free_resource(struct pnp_resource *pnp_res); 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, struct pnp_resource *pnp_add_irq_resource(struct pnp_dev *dev, int irq,
int flags); int flags);
struct pnp_resource *pnp_add_dma_resource(struct pnp_dev *dev, int dma, struct pnp_resource *pnp_add_dma_resource(struct pnp_dev *dev, int dma,

View File

@ -242,6 +242,10 @@ static int __init pnpacpi_add_device(struct acpi_device *device)
char *pnpid; char *pnpid;
struct acpi_hardware_id *id; 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 * If a PnPacpi device is not present , the device
* driver should not be loaded. * driver should not be loaded.

View File

@ -28,37 +28,6 @@
#include "../base.h" #include "../base.h"
#include "pnpacpi.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, static void decode_irq_flags(struct pnp_dev *dev, int flags, int *triggering,
int *polarity, int *shareable) int *polarity, int *shareable)
{ {
@ -94,45 +63,6 @@ static void decode_irq_flags(struct pnp_dev *dev, int flags, int *triggering,
*shareable = ACPI_EXCLUSIVE; *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, static int dma_flags(struct pnp_dev *dev, int type, int bus_master,
int transfer) int transfer)
{ {
@ -177,21 +107,16 @@ static int dma_flags(struct pnp_dev *dev, int type, int bus_master,
return flags; return flags;
} }
static void pnpacpi_parse_allocated_ioresource(struct pnp_dev *dev, u64 start, /*
u64 len, int io_decode, * Allocated Resources
int window) */
static void pnpacpi_add_irqresource(struct pnp_dev *dev, struct resource *r)
{ {
int flags = 0; if (!(r->flags & IORESOURCE_DISABLED))
u64 end = start + len - 1; pcibios_penalize_isa_irq(r->start, 1);
if (io_decode == ACPI_DECODE_16) pnp_add_resource(dev, r);
flags |= IORESOURCE_IO_16BIT_ADDR;
if (len == 0 || end >= 0x10003)
flags |= IORESOURCE_DISABLED;
if (window)
flags |= IORESOURCE_WINDOW;
pnp_add_io_resource(dev, start, end, flags);
} }
/* /*
@ -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, static acpi_status pnpacpi_allocated_resource(struct acpi_resource *res,
void *data) void *data)
{ {
struct pnp_dev *dev = data; struct pnp_dev *dev = data;
struct acpi_resource_irq *irq;
struct acpi_resource_dma *dma; 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_vendor_typed *vendor_typed;
struct acpi_resource_memory24 *memory24; struct resource r;
struct acpi_resource_memory32 *memory32;
struct acpi_resource_fixed_memory32 *fixed_memory32;
struct acpi_resource_extended_irq *extended_irq;
int i, flags; int i, flags;
switch (res->type) { if (acpi_dev_resource_memory(res, &r)
case ACPI_RESOURCE_TYPE_IRQ: || acpi_dev_resource_io(res, &r)
/* || acpi_dev_resource_address_space(res, &r)
* Per spec, only one interrupt per descriptor is allowed in || acpi_dev_resource_ext_address_space(res, &r)) {
* _CRS, but some firmware violates this, so parse them all. pnp_add_resource(dev, &r);
*/ return AE_OK;
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);
}
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 * The IRQ encoder puts a single interrupt in each
* descriptor, so if a _CRS descriptor has more than * descriptor, so if a _CRS descriptor has more than
* one interrupt, we won't be able to re-encode it. * 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 " dev_warn(&dev->dev, "multiple interrupts in "
"_CRS descriptor; configuration can't " "_CRS descriptor; configuration can't "
"be changed\n"); "be changed\n");
dev->capabilities &= ~PNP_WRITE; 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: case ACPI_RESOURCE_TYPE_DMA:
dma = &res->data.dma; dma = &res->data.dma;
if (dma->channel_count > 0 && dma->channels[0] != (u8) -1) 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); pnp_add_dma_resource(dev, dma->channels[0], flags);
break; 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_START_DEPENDENT:
case ACPI_RESOURCE_TYPE_END_DEPENDENT: case ACPI_RESOURCE_TYPE_END_DEPENDENT:
break; 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: case ACPI_RESOURCE_TYPE_VENDOR:
vendor_typed = &res->data.vendor_typed; vendor_typed = &res->data.vendor_typed;
pnpacpi_parse_allocated_vendor(dev, 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: case ACPI_RESOURCE_TYPE_END_TAG:
break; 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: case ACPI_RESOURCE_TYPE_GENERIC_REGISTER:
break; break;
@ -531,7 +299,7 @@ static __init void pnpacpi_parse_irq_option(struct pnp_dev *dev,
if (p->interrupts[i]) if (p->interrupts[i])
__set_bit(p->interrupts[i], map.bits); __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); 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); pnp_register_irq_resource(dev, option_flags, &map, flags);
} }

View File

@ -503,6 +503,22 @@ static struct pnp_resource *pnp_new_resource(struct pnp_dev *dev)
return pnp_res; 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, struct pnp_resource *pnp_add_irq_resource(struct pnp_dev *dev, int irq,
int flags) int flags)
{ {

View File

@ -412,7 +412,7 @@ acpi_handle acpi_get_child(acpi_handle, u64);
int acpi_is_root_bridge(acpi_handle); int acpi_is_root_bridge(acpi_handle);
acpi_handle acpi_get_pci_rootbridge_handle(unsigned int, unsigned int); acpi_handle acpi_get_pci_rootbridge_handle(unsigned int, unsigned int);
struct acpi_pci_root *acpi_pci_find_root(acpi_handle handle); 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_enable_wakeup_device_power(struct acpi_device *dev, int state);
int acpi_disable_wakeup_device_power(struct acpi_device *dev); int acpi_disable_wakeup_device_power(struct acpi_device *dev);

View File

@ -27,6 +27,7 @@
#include <linux/errno.h> #include <linux/errno.h>
#include <linux/ioport.h> /* for struct resource */ #include <linux/ioport.h> /* for struct resource */
#include <linux/device.h>
#ifdef CONFIG_ACPI #ifdef CONFIG_ACPI
@ -251,6 +252,26 @@ extern int pnpacpi_disabled;
#define PXM_INVAL (-1) #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_resource_conflict(const struct resource *res);
int acpi_check_region(resource_size_t start, resource_size_t n, 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 *), extern int acpi_nvs_for_each_region(int (*func)(__u64, __u64, void *),
void *data); 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 */ #else /* !CONFIG_ACPI */
#define acpi_disabled 1 #define acpi_disabled 1
@ -419,6 +451,22 @@ static inline int acpi_nvs_for_each_region(int (*func)(__u64, __u64, void *),
return 0; 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 */ #endif /* !CONFIG_ACPI */
#ifdef CONFIG_ACPI #ifdef CONFIG_ACPI

View File

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

View File

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

View File

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