123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103 |
- /*
- * 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);
|