2012-11-15 11:00:12

by Mika Westerberg

[permalink] [raw]
Subject: [PATCH v2 0/3] ACPI 5 support for GPIO, SPI and I2C

Hi,

This is a second revision of the ACPI 5 patches originally introduced here:

https://lkml.org/lkml/2012/11/3/17

The series enables ACPI 5 enumeration of SPI and I2C devices and adds GPIO
translation support for the GPIO resources.

One can then enable ACPI support in a SPI or I2C driver adding something
like:

#ifdef CONFIG_ACPI
static struct acpi_device_id mydrv_acpi_match[] = {
{ "SPI0001", 0 },
...
{ }
};
MODULE_DEVICE_TABLE(acpi, mydrv_acpi_match);
#endif

static struct spi_driver mydrv = {
...
.driver = {
.acpi_match_table = ACPI_PTR(mydrv_acpi_match),
},
};

to the existing driver. If more complex configuration is needed, like
getting GPIOs, calling some method, etc. there is dev->acpi_handle for
that.

Changes to the original version:
[gpio]
- CONFIG_GPIO_ACPI instead of CONFIG_ACPI_GPIO
- removed redundant test in acpi_gpiochip_find()

[spi and i2c]
- switched to use ACPI centralized _CRS evaluation framework
introduced by Rafael
- dropped request_module() call
- dropped the acpi_enumerate_spi/i2c_device()
- added required includes and dropped <linux/acpi.h> from
acpi_i2c.h

The series applies on top of Rafael's
git://git.kernel.org/pub/scm/linux/kernel/git/rafael/linux-pm.git linux-next

There is a dependency to linux-pm.git/linux-next so I think it would be
better if these will be merged via that tree.

Mathias Nyman (1):
gpio / ACPI: add ACPI support

Mika Westerberg (2):
spi / ACPI: add ACPI enumeration support
i2c / ACPI: add ACPI enumeration support

drivers/acpi/Kconfig | 6 ++
drivers/acpi/Makefile | 1 +
drivers/acpi/acpi_i2c.c | 212 +++++++++++++++++++++++++++++++++++++++++++
drivers/gpio/Kconfig | 4 +
drivers/gpio/Makefile | 1 +
drivers/gpio/gpiolib-acpi.c | 56 ++++++++++++
drivers/i2c/i2c-core.c | 10 ++
drivers/spi/spi.c | 201 +++++++++++++++++++++++++++++++++++++++-
include/linux/acpi_gpio.h | 19 ++++
include/linux/acpi_i2c.h | 27 ++++++
10 files changed, 536 insertions(+), 1 deletion(-)
create mode 100644 drivers/acpi/acpi_i2c.c
create mode 100644 drivers/gpio/gpiolib-acpi.c
create mode 100644 include/linux/acpi_gpio.h
create mode 100644 include/linux/acpi_i2c.h

--
1.7.10.4


2012-11-15 11:00:28

by Mika Westerberg

[permalink] [raw]
Subject: [PATCH v2 3/3] i2c / ACPI: add ACPI enumeration support

ACPI 5 introduced I2cSerialBus resource that makes it possible to enumerate
and configure the I2C slave devices behind the I2C controller. This patch
adds helper functions to support I2C slave enumeration.

An ACPI enabled I2C controller driver only needs to call acpi_i2c_register_devices()
in order to get its slave devices enumerated, created and bound to the
corresponding ACPI handle.

Signed-off-by: Mika Westerberg <[email protected]>
---
drivers/acpi/Kconfig | 6 ++
drivers/acpi/Makefile | 1 +
drivers/acpi/acpi_i2c.c | 212 ++++++++++++++++++++++++++++++++++++++++++++++
drivers/i2c/i2c-core.c | 10 +++
include/linux/acpi_i2c.h | 27 ++++++
5 files changed, 256 insertions(+)
create mode 100644 drivers/acpi/acpi_i2c.c
create mode 100644 include/linux/acpi_i2c.h

diff --git a/drivers/acpi/Kconfig b/drivers/acpi/Kconfig
index 119d58d..0300bf6 100644
--- a/drivers/acpi/Kconfig
+++ b/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
diff --git a/drivers/acpi/Makefile b/drivers/acpi/Makefile
index 7289828..2a4502b 100644
--- a/drivers/acpi/Makefile
+++ b/drivers/acpi/Makefile
@@ -70,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
diff --git a/drivers/acpi/acpi_i2c.c b/drivers/acpi/acpi_i2c.c
new file mode 100644
index 0000000..5bf2dad
--- /dev/null
+++ b/drivers/acpi/acpi_i2c.c
@@ -0,0 +1,212 @@
+/*
+ * ACPI I2C enumeration support
+ *
+ * Copyright (C) 2012, Intel Corporation
+ * Author: Mika Westerberg <[email protected]>
+ *
+ * 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/err.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 acpi_resource_i2c_serialbus *sb;
+ struct i2c_board_info *info = data;
+
+ if (ares->type != ACPI_RESOURCE_TYPE_SERIAL_BUS)
+ return 0;
+
+ sb = &ares->data.i2c_serial_bus;
+ if (sb->type != ACPI_RESOURCE_SERIAL_TYPE_I2C)
+ return 0;
+
+ info->addr = sb->slave_address;
+ if (sb->access_mode == ACPI_I2C_10BIT_MODE)
+ info->flags |= I2C_CLIENT_TEN;
+
+ 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 resource_list_entry *rentry;
+ 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));
+
+ INIT_LIST_HEAD(&resource_list);
+ ret = acpi_dev_get_resources(adev, &resource_list,
+ acpi_i2c_add_resource, &info);
+ if (ret < 0)
+ return AE_OK;
+
+ list_for_each_entry(rentry, &resource_list, node) {
+ struct resource *r = &rentry->res;
+
+ if (resource_type(r) == IORESOURCE_IRQ) {
+ info.irq = r->start;
+ break;
+ }
+ }
+
+ acpi_dev_free_resource_list(&resource_list);
+
+ if (!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 = adapter->dev.acpi_handle;
+ 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);
+
+struct acpi_i2c_find {
+ acpi_handle handle;
+ u16 addr;
+ bool found;
+};
+
+static int acpi_i2c_find_child_address(struct acpi_resource *ares, void *data)
+{
+ struct acpi_resource_i2c_serialbus *sb;
+ struct acpi_i2c_find *i2c_find = data;
+
+ if (ares->type != ACPI_RESOURCE_TYPE_SERIAL_BUS)
+ return 1;
+
+ sb = &ares->data.i2c_serial_bus;
+ if (sb->type != ACPI_RESOURCE_SERIAL_TYPE_I2C)
+ return 1;
+
+ if (sb->slave_address == i2c_find->addr)
+ i2c_find->found = true;
+
+ return 1;
+}
+
+static acpi_status acpi_i2c_find_child(acpi_handle handle, u32 level,
+ void *data, void **return_value)
+{
+ struct acpi_i2c_find *i2c_find = data;
+ struct list_head resource_list;
+ 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;
+
+ INIT_LIST_HEAD(&resource_list);
+ ret = acpi_dev_get_resources(adev, &resource_list,
+ acpi_i2c_find_child_address, i2c_find);
+ if (ret < 0)
+ return AE_OK;
+
+ acpi_dev_free_resource_list(&resource_list);
+
+ if (i2c_find->found) {
+ i2c_find->handle = handle;
+ return AE_CTRL_TERMINATE;
+ }
+ return AE_OK;
+}
+
+static int acpi_i2c_find_device(struct device *dev, acpi_handle *handle)
+{
+ struct acpi_i2c_find i2c_find;
+ struct i2c_adapter *adapter;
+ struct i2c_client *client;
+ acpi_handle parent;
+ acpi_status status;
+
+ client = i2c_verify_client(dev);
+ if (!client)
+ return -ENODEV;
+
+ adapter = client->adapter;
+ if (!adapter)
+ return -ENODEV;
+
+ parent = adapter->dev.acpi_handle;
+ if (!parent)
+ return -ENODEV;
+
+ memset(&i2c_find, 0, sizeof(i2c_find));
+ i2c_find.addr = client->addr;
+
+ status = acpi_walk_namespace(ACPI_TYPE_DEVICE, parent, 1,
+ acpi_i2c_find_child, NULL,
+ &i2c_find, NULL);
+ if (ACPI_FAILURE(status) || !i2c_find.handle)
+ return -ENODEV;
+
+ *handle = i2c_find.handle;
+ return 0;
+}
+
+static struct acpi_bus_type acpi_i2c_bus = {
+ .bus = &i2c_bus_type,
+ .find_device = acpi_i2c_find_device,
+};
+
+void acpi_i2c_bus_register(void)
+{
+ register_acpi_bus_type(&acpi_i2c_bus);
+}
+EXPORT_SYMBOL_GPL(acpi_i2c_bus_register);
+
+void acpi_i2c_bus_unregister(void)
+{
+ unregister_acpi_bus_type(&acpi_i2c_bus);
+}
+EXPORT_SYMBOL_GPL(acpi_i2c_bus_unregister);
diff --git a/drivers/i2c/i2c-core.c b/drivers/i2c/i2c-core.c
index a7edf98..7385de2f 100644
--- a/drivers/i2c/i2c-core.c
+++ b/drivers/i2c/i2c-core.c
@@ -39,6 +39,8 @@
#include <linux/irqflags.h>
#include <linux/rwsem.h>
#include <linux/pm_runtime.h>
+#include <linux/acpi.h>
+#include <linux/acpi_i2c.h>
#include <asm/uaccess.h>

#include "i2c-core.h"
@@ -78,6 +80,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)
@@ -1298,6 +1304,8 @@ static int __init i2c_init(void)
retval = i2c_add_driver(&dummy_driver);
if (retval)
goto class_err;
+
+ acpi_i2c_bus_register();
return 0;

class_err:
@@ -1311,6 +1319,8 @@ bus_err:

static void __exit i2c_exit(void)
{
+ acpi_i2c_bus_unregister();
+
i2c_del_driver(&dummy_driver);
#ifdef CONFIG_I2C_COMPAT
class_compat_unregister(i2c_adapter_compat_class);
diff --git a/include/linux/acpi_i2c.h b/include/linux/acpi_i2c.h
new file mode 100644
index 0000000..cf2233f
--- /dev/null
+++ b/include/linux/acpi_i2c.h
@@ -0,0 +1,27 @@
+/*
+ * ACPI I2C enumeration support
+ *
+ * Copyright (C) 2012, Intel Corporation
+ * Author: Mika Westerberg <[email protected]>
+ *
+ * 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.
+ */
+
+#ifndef LINUX_ACPI_I2C_H
+#define LINUX_ACPI_I2C_H
+
+struct i2c_adapter;
+
+#if IS_ENABLED(CONFIG_ACPI_I2C)
+extern void acpi_i2c_register_devices(struct i2c_adapter *adap);
+extern void acpi_i2c_bus_register(void);
+extern void acpi_i2c_bus_unregister(void);
+#else
+static inline void acpi_i2c_register_devices(struct i2c_adapter *adap) {}
+static inline void acpi_i2c_bus_register(void) {}
+static inline void acpi_i2c_bus_unregister(void) {}
+#endif /* IS_ENABLED(CONFIG_ACPI_I2C) */
+
+#endif /* LINUX_ACPI_I2C_H */
--
1.7.10.4

2012-11-15 11:00:27

by Mika Westerberg

[permalink] [raw]
Subject: [PATCH v2 2/3] spi / ACPI: add ACPI enumeration support

ACPI 5 introduced SPISerialBus resource that allows us to enumerate and
configure the SPI slave devices behind the SPI controller. This patch adds
support for this to the SPI core.

In addition we bind ACPI nodes to SPI devices. This makes it possible for
the slave drivers to get the ACPI handle for further configuration.

Signed-off-by: Mika Westerberg <[email protected]>
---
drivers/spi/spi.c | 201 ++++++++++++++++++++++++++++++++++++++++++++++++++++-
1 file changed, 200 insertions(+), 1 deletion(-)

diff --git a/drivers/spi/spi.c b/drivers/spi/spi.c
index 84c2861..e39a484 100644
--- a/drivers/spi/spi.c
+++ b/drivers/spi/spi.c
@@ -35,6 +35,8 @@
#include <linux/sched.h>
#include <linux/delay.h>
#include <linux/kthread.h>
+#include <linux/ioport.h>
+#include <linux/acpi.h>

static void spidev_release(struct device *dev)
{
@@ -93,6 +95,10 @@ static int spi_match_device(struct device *dev, struct device_driver *drv)
if (of_driver_match_device(dev, drv))
return 1;

+ /* Then try ACPI */
+ if (acpi_driver_match_device(dev, drv))
+ return 1;
+
if (sdrv->id_table)
return !!spi_match_id(sdrv->id_table, spi);

@@ -888,6 +894,196 @@ static void of_register_spi_devices(struct spi_master *master)
static void of_register_spi_devices(struct spi_master *master) { }
#endif

+#ifdef CONFIG_ACPI
+static int acpi_spi_add_resource(struct acpi_resource *ares, void *data)
+{
+ struct acpi_resource_spi_serialbus *sb;
+ struct spi_device *spi = data;
+
+ if (ares->type != ACPI_RESOURCE_TYPE_SERIAL_BUS)
+ return 0;
+
+ sb = &ares->data.spi_serial_bus;
+ if (sb->type != ACPI_RESOURCE_SERIAL_TYPE_SPI)
+ return 0;
+
+ spi->chip_select = sb->device_selection;
+ spi->max_speed_hz = sb->connection_speed;
+
+ if (sb->clock_phase == ACPI_SPI_SECOND_PHASE)
+ spi->mode |= SPI_CPHA;
+ if (sb->clock_polarity == ACPI_SPI_START_HIGH)
+ spi->mode |= SPI_CPOL;
+ if (sb->device_polarity == ACPI_SPI_ACTIVE_HIGH)
+ spi->mode |= SPI_CS_HIGH;
+
+ return 1;
+}
+
+static acpi_status acpi_spi_add_device(acpi_handle handle, u32 level,
+ void *data, void **return_value)
+{
+ struct spi_master *master = data;
+ struct resource_list_entry *rentry;
+ struct list_head resource_list;
+ struct acpi_device *adev;
+ struct spi_device *spi;
+ int ret;
+
+ if (acpi_bus_get_device(handle, &adev))
+ return AE_OK;
+ if (acpi_bus_get_status(adev) || !adev->status.present)
+ return AE_OK;
+
+ spi = spi_alloc_device(master);
+ if (!spi) {
+ dev_err(&master->dev, "failed to allocate SPI device for %s\n",
+ dev_name(&adev->dev));
+ return AE_NO_MEMORY;
+ }
+
+ INIT_LIST_HEAD(&resource_list);
+ ret = acpi_dev_get_resources(adev, &resource_list,
+ acpi_spi_add_resource, spi);
+ if (ret < 0)
+ goto fail_put_dev;
+
+ list_for_each_entry(rentry, &resource_list, node) {
+ struct resource *r = &rentry->res;
+
+ if (resource_type(r) == IORESOURCE_IRQ) {
+ spi->irq = r->start;
+ break;
+ }
+ }
+
+ acpi_dev_free_resource_list(&resource_list);
+
+ if (!spi->max_speed_hz)
+ goto fail_put_dev;
+
+ strlcpy(spi->modalias, dev_name(&adev->dev), sizeof(spi->modalias));
+ if (spi_add_device(spi)) {
+ dev_err(&master->dev, "failed to add SPI device %s from ACPI\n",
+ dev_name(&adev->dev));
+ goto fail_put_dev;
+ }
+
+ return AE_OK;
+
+fail_put_dev:
+ spi_dev_put(spi);
+
+ return AE_OK;
+}
+
+static void acpi_register_spi_devices(struct spi_master *master)
+{
+ acpi_status status;
+ acpi_handle handle;
+
+ handle = master->dev.acpi_handle;
+ if (!handle)
+ return;
+
+ status = acpi_walk_namespace(ACPI_TYPE_DEVICE, handle, 1,
+ acpi_spi_add_device, NULL,
+ master, NULL);
+ if (ACPI_FAILURE(status))
+ dev_warn(&master->dev, "failed to enumerate SPI slaves\n");
+}
+
+struct acpi_spi_find {
+ acpi_handle handle;
+ u16 chip_select;
+ bool found;
+};
+
+static int acpi_spi_find_child_address(struct acpi_resource *ares, void *data)
+{
+ struct acpi_resource_spi_serialbus *sb;
+ struct acpi_spi_find *spi_find = data;
+
+ if (ares->type != ACPI_RESOURCE_TYPE_SERIAL_BUS)
+ return 1;
+
+ sb = &ares->data.spi_serial_bus;
+ if (sb->type != ACPI_RESOURCE_SERIAL_TYPE_SPI)
+ return 1;
+
+ if (sb->device_selection == spi_find->chip_select)
+ spi_find->found = true;
+
+ return 1;
+}
+
+static acpi_status acpi_spi_find_child(acpi_handle handle, u32 level,
+ void *data, void **return_value)
+{
+ struct acpi_spi_find *spi_find = data;
+ struct list_head resource_list;
+ 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;
+
+ INIT_LIST_HEAD(&resource_list);
+ ret = acpi_dev_get_resources(adev, &resource_list,
+ acpi_spi_find_child_address, spi_find);
+ if (ret < 0)
+ return AE_OK;
+
+ acpi_dev_free_resource_list(&resource_list);
+
+ if (spi_find->found) {
+ spi_find->handle = handle;
+ return AE_CTRL_TERMINATE;
+ }
+ return AE_OK;
+}
+
+static int acpi_spi_find_device(struct device *dev, acpi_handle *handle)
+{
+ struct spi_device *spi = to_spi_device(dev);
+ struct spi_master *master = spi->master;
+ struct acpi_spi_find spi_find;
+ acpi_handle parent;
+ acpi_status status;
+
+ parent = master->dev.acpi_handle;
+ if (!parent)
+ return -ENODEV;
+
+ memset(&spi_find, 0, sizeof(spi_find));
+ spi_find.chip_select = spi->chip_select;
+
+ status = acpi_walk_namespace(ACPI_TYPE_DEVICE, parent, 1,
+ acpi_spi_find_child, NULL,
+ &spi_find, NULL);
+ if (ACPI_FAILURE(status) || !spi_find.handle)
+ return -ENODEV;
+
+ *handle = spi_find.handle;
+ return 0;
+}
+
+static struct acpi_bus_type acpi_spi_bus = {
+ .bus = &spi_bus_type,
+ .find_device = acpi_spi_find_device,
+};
+
+static void acpi_spi_bus_register(void)
+{
+ register_acpi_bus_type(&acpi_spi_bus);
+}
+#else
+static inline void acpi_register_spi_devices(struct spi_master *master) {}
+static inline void acpi_spi_bus_register(void) {}
+#endif /* CONFIG_ACPI */
+
static void spi_master_release(struct device *dev)
{
struct spi_master *master;
@@ -1023,8 +1219,9 @@ int spi_register_master(struct spi_master *master)
spi_match_master_to_boardinfo(master, &bi->board_info);
mutex_unlock(&board_lock);

- /* Register devices from the device tree */
+ /* Register devices from the device tree and ACPI */
of_register_spi_devices(master);
+ acpi_register_spi_devices(master);
done:
return status;
}
@@ -1550,6 +1747,8 @@ static int __init spi_init(void)
status = class_register(&spi_master_class);
if (status < 0)
goto err2;
+
+ acpi_spi_bus_register();
return 0;

err2:
--
1.7.10.4

2012-11-15 11:01:09

by Mika Westerberg

[permalink] [raw]
Subject: [PATCH v2 1/3] gpio / ACPI: add ACPI support

From: Mathias Nyman <[email protected]>

Add support for translating ACPI GPIO pin numbers to Linux GPIO API pins.
Needs a gpio controller driver with the acpi handler hook set.

Drivers can use acpi_get_gpio() to translate ACPI5 GpioIO and GpioInt
resources to Linux GPIO's.

Signed-off-by: Mathias Nyman <[email protected]>
Signed-off-by: Mika Westerberg <[email protected]>
---
drivers/gpio/Kconfig | 4 ++++
drivers/gpio/Makefile | 1 +
drivers/gpio/gpiolib-acpi.c | 56 +++++++++++++++++++++++++++++++++++++++++++
include/linux/acpi_gpio.h | 19 +++++++++++++++
4 files changed, 80 insertions(+)
create mode 100644 drivers/gpio/gpiolib-acpi.c
create mode 100644 include/linux/acpi_gpio.h

diff --git a/drivers/gpio/Kconfig b/drivers/gpio/Kconfig
index f11d8e3..5c9b384 100644
--- a/drivers/gpio/Kconfig
+++ b/drivers/gpio/Kconfig
@@ -49,6 +49,10 @@ config OF_GPIO
def_bool y
depends on OF

+config GPIO_ACPI
+ def_bool y
+ depends on ACPI
+
config DEBUG_GPIO
bool "Debug GPIO calls"
depends on DEBUG_KERNEL
diff --git a/drivers/gpio/Makefile b/drivers/gpio/Makefile
index 9aeed67..420dbac 100644
--- a/drivers/gpio/Makefile
+++ b/drivers/gpio/Makefile
@@ -4,6 +4,7 @@ ccflags-$(CONFIG_DEBUG_GPIO) += -DDEBUG

obj-$(CONFIG_GPIOLIB) += gpiolib.o devres.o
obj-$(CONFIG_OF_GPIO) += gpiolib-of.o
+obj-$(CONFIG_GPIO_ACPI) += gpiolib-acpi.o

# Device drivers. Generally keep list sorted alphabetically
obj-$(CONFIG_GPIO_GENERIC) += gpio-generic.o
diff --git a/drivers/gpio/gpiolib-acpi.c b/drivers/gpio/gpiolib-acpi.c
new file mode 100644
index 0000000..8ef9831
--- /dev/null
+++ b/drivers/gpio/gpiolib-acpi.c
@@ -0,0 +1,56 @@
+/*
+ * ACPI helpers for GPIO API
+ *
+ * Copyright (C) 2012, Intel Corporation
+ * Authors: Mathias Nyman <[email protected]>
+ * Mika Westerberg <[email protected]>
+ *
+ * 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/errno.h>
+#include <linux/gpio.h>
+#include <linux/export.h>
+#include <linux/acpi_gpio.h>
+#include <linux/acpi.h>
+
+static int acpi_gpiochip_find(struct gpio_chip *gc, void *data)
+{
+ acpi_handle handle = data;
+
+ if (!gc->dev)
+ return false;
+
+ return gc->dev->acpi_handle == handle;
+}
+
+/**
+ * acpi_get_gpio() - Translate ACPI GPIO pin to GPIO number usable with GPIO API
+ * @path: ACPI GPIO controller full path name, (e.g. "\\_SB.GPO1")
+ * @pin: ACPI GPIO pin number (0-based, controller-relative)
+ *
+ * Returns GPIO number to use with Linux generic GPIO API, or errno error value
+ */
+
+int acpi_get_gpio(char *path, int pin)
+{
+ struct gpio_chip *chip;
+ acpi_handle handle;
+ acpi_status status;
+
+ status = acpi_get_handle(NULL, path, &handle);
+ if (ACPI_FAILURE(status))
+ return -ENODEV;
+
+ chip = gpiochip_find(handle, acpi_gpiochip_find);
+ if (!chip)
+ return -ENODEV;
+
+ if (!gpio_is_valid(chip->base + pin))
+ return -EINVAL;
+
+ return chip->base + pin;
+}
+EXPORT_SYMBOL_GPL(acpi_get_gpio);
diff --git a/include/linux/acpi_gpio.h b/include/linux/acpi_gpio.h
new file mode 100644
index 0000000..91615a3
--- /dev/null
+++ b/include/linux/acpi_gpio.h
@@ -0,0 +1,19 @@
+#ifndef _LINUX_ACPI_GPIO_H_
+#define _LINUX_ACPI_GPIO_H_
+
+#include <linux/errno.h>
+
+#ifdef CONFIG_GPIO_ACPI
+
+int acpi_get_gpio(char *path, int pin);
+
+#else /* CONFIG_GPIO_ACPI */
+
+static inline int acpi_get_gpio(char *path, int pin)
+{
+ return -ENODEV;
+}
+
+#endif /* CONFIG_GPIO_ACPI */
+
+#endif /* _LINUX_ACPI_GPIO_H_ */
--
1.7.10.4

2012-11-16 01:30:02

by Rafael J. Wysocki

[permalink] [raw]
Subject: Re: [PATCH v2 1/3] gpio / ACPI: add ACPI support

On Thursday, November 15, 2012 01:03:15 PM Mika Westerberg wrote:
> From: Mathias Nyman <[email protected]>
>
> Add support for translating ACPI GPIO pin numbers to Linux GPIO API pins.
> Needs a gpio controller driver with the acpi handler hook set.
>
> Drivers can use acpi_get_gpio() to translate ACPI5 GpioIO and GpioInt
> resources to Linux GPIO's.
>
> Signed-off-by: Mathias Nyman <[email protected]>
> Signed-off-by: Mika Westerberg <[email protected]>
> ---
> drivers/gpio/Kconfig | 4 ++++
> drivers/gpio/Makefile | 1 +
> drivers/gpio/gpiolib-acpi.c | 56 +++++++++++++++++++++++++++++++++++++++++++
> include/linux/acpi_gpio.h | 19 +++++++++++++++
> 4 files changed, 80 insertions(+)
> create mode 100644 drivers/gpio/gpiolib-acpi.c
> create mode 100644 include/linux/acpi_gpio.h
>
> diff --git a/drivers/gpio/Kconfig b/drivers/gpio/Kconfig
> index f11d8e3..5c9b384 100644
> --- a/drivers/gpio/Kconfig
> +++ b/drivers/gpio/Kconfig
> @@ -49,6 +49,10 @@ config OF_GPIO
> def_bool y
> depends on OF
>
> +config GPIO_ACPI
> + def_bool y
> + depends on ACPI
> +
> config DEBUG_GPIO
> bool "Debug GPIO calls"
> depends on DEBUG_KERNEL
> diff --git a/drivers/gpio/Makefile b/drivers/gpio/Makefile
> index 9aeed67..420dbac 100644
> --- a/drivers/gpio/Makefile
> +++ b/drivers/gpio/Makefile
> @@ -4,6 +4,7 @@ ccflags-$(CONFIG_DEBUG_GPIO) += -DDEBUG
>
> obj-$(CONFIG_GPIOLIB) += gpiolib.o devres.o
> obj-$(CONFIG_OF_GPIO) += gpiolib-of.o
> +obj-$(CONFIG_GPIO_ACPI) += gpiolib-acpi.o
>
> # Device drivers. Generally keep list sorted alphabetically
> obj-$(CONFIG_GPIO_GENERIC) += gpio-generic.o
> diff --git a/drivers/gpio/gpiolib-acpi.c b/drivers/gpio/gpiolib-acpi.c
> new file mode 100644
> index 0000000..8ef9831
> --- /dev/null
> +++ b/drivers/gpio/gpiolib-acpi.c
> @@ -0,0 +1,56 @@
> +/*
> + * ACPI helpers for GPIO API
> + *
> + * Copyright (C) 2012, Intel Corporation
> + * Authors: Mathias Nyman <[email protected]>
> + * Mika Westerberg <[email protected]>
> + *
> + * 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/errno.h>
> +#include <linux/gpio.h>
> +#include <linux/export.h>
> +#include <linux/acpi_gpio.h>
> +#include <linux/acpi.h>
> +
> +static int acpi_gpiochip_find(struct gpio_chip *gc, void *data)
> +{
> + acpi_handle handle = data;
> +
> + if (!gc->dev)
> + return false;
> +
> + return gc->dev->acpi_handle == handle;

I'd prefer DEVICE_ACPI_HANDLE() to be used in such places, we may want to
replace it with something else in the future or make it work differently.

> +}
> +
> +/**
> + * acpi_get_gpio() - Translate ACPI GPIO pin to GPIO number usable with GPIO API
> + * @path: ACPI GPIO controller full path name, (e.g. "\\_SB.GPO1")
> + * @pin: ACPI GPIO pin number (0-based, controller-relative)
> + *
> + * Returns GPIO number to use with Linux generic GPIO API, or errno error value
> + */
> +
> +int acpi_get_gpio(char *path, int pin)
> +{
> + struct gpio_chip *chip;
> + acpi_handle handle;
> + acpi_status status;
> +
> + status = acpi_get_handle(NULL, path, &handle);
> + if (ACPI_FAILURE(status))
> + return -ENODEV;
> +
> + chip = gpiochip_find(handle, acpi_gpiochip_find);
> + if (!chip)
> + return -ENODEV;
> +
> + if (!gpio_is_valid(chip->base + pin))
> + return -EINVAL;
> +
> + return chip->base + pin;
> +}
> +EXPORT_SYMBOL_GPL(acpi_get_gpio);
> diff --git a/include/linux/acpi_gpio.h b/include/linux/acpi_gpio.h
> new file mode 100644
> index 0000000..91615a3
> --- /dev/null
> +++ b/include/linux/acpi_gpio.h
> @@ -0,0 +1,19 @@
> +#ifndef _LINUX_ACPI_GPIO_H_
> +#define _LINUX_ACPI_GPIO_H_
> +
> +#include <linux/errno.h>
> +
> +#ifdef CONFIG_GPIO_ACPI
> +
> +int acpi_get_gpio(char *path, int pin);
> +
> +#else /* CONFIG_GPIO_ACPI */
> +
> +static inline int acpi_get_gpio(char *path, int pin)
> +{
> + return -ENODEV;
> +}
> +
> +#endif /* CONFIG_GPIO_ACPI */
> +
> +#endif /* _LINUX_ACPI_GPIO_H_ */
>
--
I speak only for myself.
Rafael J. Wysocki, Intel Open Source Technology Center.

2012-11-16 06:51:40

by Mika Westerberg

[permalink] [raw]
Subject: Re: [PATCH v2 1/3] gpio / ACPI: add ACPI support

On Fri, Nov 16, 2012 at 02:34:22AM +0100, Rafael J. Wysocki wrote:
> On Thursday, November 15, 2012 01:03:15 PM Mika Westerberg wrote:
> > From: Mathias Nyman <[email protected]>
> >
> > Add support for translating ACPI GPIO pin numbers to Linux GPIO API pins.
> > Needs a gpio controller driver with the acpi handler hook set.
> >
> > Drivers can use acpi_get_gpio() to translate ACPI5 GpioIO and GpioInt
> > resources to Linux GPIO's.
> >
> > Signed-off-by: Mathias Nyman <[email protected]>
> > Signed-off-by: Mika Westerberg <[email protected]>
> > ---
> > drivers/gpio/Kconfig | 4 ++++
> > drivers/gpio/Makefile | 1 +
> > drivers/gpio/gpiolib-acpi.c | 56 +++++++++++++++++++++++++++++++++++++++++++
> > include/linux/acpi_gpio.h | 19 +++++++++++++++
> > 4 files changed, 80 insertions(+)
> > create mode 100644 drivers/gpio/gpiolib-acpi.c
> > create mode 100644 include/linux/acpi_gpio.h
> >
> > diff --git a/drivers/gpio/Kconfig b/drivers/gpio/Kconfig
> > index f11d8e3..5c9b384 100644
> > --- a/drivers/gpio/Kconfig
> > +++ b/drivers/gpio/Kconfig
> > @@ -49,6 +49,10 @@ config OF_GPIO
> > def_bool y
> > depends on OF
> >
> > +config GPIO_ACPI
> > + def_bool y
> > + depends on ACPI
> > +
> > config DEBUG_GPIO
> > bool "Debug GPIO calls"
> > depends on DEBUG_KERNEL
> > diff --git a/drivers/gpio/Makefile b/drivers/gpio/Makefile
> > index 9aeed67..420dbac 100644
> > --- a/drivers/gpio/Makefile
> > +++ b/drivers/gpio/Makefile
> > @@ -4,6 +4,7 @@ ccflags-$(CONFIG_DEBUG_GPIO) += -DDEBUG
> >
> > obj-$(CONFIG_GPIOLIB) += gpiolib.o devres.o
> > obj-$(CONFIG_OF_GPIO) += gpiolib-of.o
> > +obj-$(CONFIG_GPIO_ACPI) += gpiolib-acpi.o
> >
> > # Device drivers. Generally keep list sorted alphabetically
> > obj-$(CONFIG_GPIO_GENERIC) += gpio-generic.o
> > diff --git a/drivers/gpio/gpiolib-acpi.c b/drivers/gpio/gpiolib-acpi.c
> > new file mode 100644
> > index 0000000..8ef9831
> > --- /dev/null
> > +++ b/drivers/gpio/gpiolib-acpi.c
> > @@ -0,0 +1,56 @@
> > +/*
> > + * ACPI helpers for GPIO API
> > + *
> > + * Copyright (C) 2012, Intel Corporation
> > + * Authors: Mathias Nyman <[email protected]>
> > + * Mika Westerberg <[email protected]>
> > + *
> > + * 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/errno.h>
> > +#include <linux/gpio.h>
> > +#include <linux/export.h>
> > +#include <linux/acpi_gpio.h>
> > +#include <linux/acpi.h>
> > +
> > +static int acpi_gpiochip_find(struct gpio_chip *gc, void *data)
> > +{
> > + acpi_handle handle = data;
> > +
> > + if (!gc->dev)
> > + return false;
> > +
> > + return gc->dev->acpi_handle == handle;
>
> I'd prefer DEVICE_ACPI_HANDLE() to be used in such places, we may want to
> replace it with something else in the future or make it work differently.

Sure but then we need to make it available for drivers as well when
!CONFIG_ACPI. Something like below is needed.

diff --git a/include/acpi/acpi_bus.h b/include/acpi/acpi_bus.h
index 2dca46f..01a26f9 100644
--- a/include/acpi/acpi_bus.h
+++ b/include/acpi/acpi_bus.h
@@ -416,7 +416,6 @@ 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)->acpi_handle))

int acpi_enable_wakeup_device_power(struct acpi_device *dev, int state);
int acpi_disable_wakeup_device_power(struct acpi_device *dev);
diff --git a/include/linux/acpi.h b/include/linux/acpi.h
index b4c9984..c4c58ff 100644
--- a/include/linux/acpi.h
+++ b/include/linux/acpi.h
@@ -28,6 +28,8 @@
#include <linux/ioport.h> /* for struct resource */
#include <linux/device.h>

+#define DEVICE_ACPI_HANDLE(dev) ((acpi_handle)((dev)->acpi_handle))
+
#ifdef CONFIG_ACPI

#ifndef _LINUX

2012-11-16 08:02:44

by Mika Westerberg

[permalink] [raw]
Subject: Re: [PATCH v2 1/3] gpio / ACPI: add ACPI support

On Fri, Nov 16, 2012 at 08:54:48AM +0200, Mika Westerberg wrote:
> On Fri, Nov 16, 2012 at 02:34:22AM +0100, Rafael J. Wysocki wrote:
> > On Thursday, November 15, 2012 01:03:15 PM Mika Westerberg wrote:
> > > From: Mathias Nyman <[email protected]>
> > >
> > > Add support for translating ACPI GPIO pin numbers to Linux GPIO API pins.
> > > Needs a gpio controller driver with the acpi handler hook set.
> > >
> > > Drivers can use acpi_get_gpio() to translate ACPI5 GpioIO and GpioInt
> > > resources to Linux GPIO's.
> > >
> > > Signed-off-by: Mathias Nyman <[email protected]>
> > > Signed-off-by: Mika Westerberg <[email protected]>
> > > ---
> > > drivers/gpio/Kconfig | 4 ++++
> > > drivers/gpio/Makefile | 1 +
> > > drivers/gpio/gpiolib-acpi.c | 56 +++++++++++++++++++++++++++++++++++++++++++
> > > include/linux/acpi_gpio.h | 19 +++++++++++++++
> > > 4 files changed, 80 insertions(+)
> > > create mode 100644 drivers/gpio/gpiolib-acpi.c
> > > create mode 100644 include/linux/acpi_gpio.h
> > >
> > > diff --git a/drivers/gpio/Kconfig b/drivers/gpio/Kconfig
> > > index f11d8e3..5c9b384 100644
> > > --- a/drivers/gpio/Kconfig
> > > +++ b/drivers/gpio/Kconfig
> > > @@ -49,6 +49,10 @@ config OF_GPIO
> > > def_bool y
> > > depends on OF
> > >
> > > +config GPIO_ACPI
> > > + def_bool y
> > > + depends on ACPI
> > > +
> > > config DEBUG_GPIO
> > > bool "Debug GPIO calls"
> > > depends on DEBUG_KERNEL
> > > diff --git a/drivers/gpio/Makefile b/drivers/gpio/Makefile
> > > index 9aeed67..420dbac 100644
> > > --- a/drivers/gpio/Makefile
> > > +++ b/drivers/gpio/Makefile
> > > @@ -4,6 +4,7 @@ ccflags-$(CONFIG_DEBUG_GPIO) += -DDEBUG
> > >
> > > obj-$(CONFIG_GPIOLIB) += gpiolib.o devres.o
> > > obj-$(CONFIG_OF_GPIO) += gpiolib-of.o
> > > +obj-$(CONFIG_GPIO_ACPI) += gpiolib-acpi.o
> > >
> > > # Device drivers. Generally keep list sorted alphabetically
> > > obj-$(CONFIG_GPIO_GENERIC) += gpio-generic.o
> > > diff --git a/drivers/gpio/gpiolib-acpi.c b/drivers/gpio/gpiolib-acpi.c
> > > new file mode 100644
> > > index 0000000..8ef9831
> > > --- /dev/null
> > > +++ b/drivers/gpio/gpiolib-acpi.c
> > > @@ -0,0 +1,56 @@
> > > +/*
> > > + * ACPI helpers for GPIO API
> > > + *
> > > + * Copyright (C) 2012, Intel Corporation
> > > + * Authors: Mathias Nyman <[email protected]>
> > > + * Mika Westerberg <[email protected]>
> > > + *
> > > + * 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/errno.h>
> > > +#include <linux/gpio.h>
> > > +#include <linux/export.h>
> > > +#include <linux/acpi_gpio.h>
> > > +#include <linux/acpi.h>
> > > +
> > > +static int acpi_gpiochip_find(struct gpio_chip *gc, void *data)
> > > +{
> > > + acpi_handle handle = data;
> > > +
> > > + if (!gc->dev)
> > > + return false;
> > > +
> > > + return gc->dev->acpi_handle == handle;
> >
> > I'd prefer DEVICE_ACPI_HANDLE() to be used in such places, we may want to
> > replace it with something else in the future or make it work differently.
>
> Sure but then we need to make it available for drivers as well when
> !CONFIG_ACPI. Something like below is needed.

One more thing, sometimes we want to assign the handle like in the case of
SPI controller driver we set the master->dev.acpi_handle. In that case we
can't use DEVICE_ACPI_HANDLE() as is. Should we just do something like:

master->dev.acpi_handle = pdev->dev.acpi_handle;

or should we introduce some new macro that supports this?

2012-11-16 08:13:13

by Mika Westerberg

[permalink] [raw]
Subject: Re: [PATCH v2 1/3] gpio / ACPI: add ACPI support

On Fri, Nov 16, 2012 at 10:05:49AM +0200, Mika Westerberg wrote:
>
> One more thing, sometimes we want to assign the handle like in the case of
> SPI controller driver we set the master->dev.acpi_handle. In that case we
> can't use DEVICE_ACPI_HANDLE() as is. Should we just do something like:
>
> master->dev.acpi_handle = pdev->dev.acpi_handle;
>
> or should we introduce some new macro that supports this?

Or we could just drop the cast from the macro and use the same.

#define DEVICE_ACPI_HANDLE(dev) ((dev)->acpi_handle)

2012-11-16 09:57:44

by Rafael J. Wysocki

[permalink] [raw]
Subject: Re: [PATCH v2 1/3] gpio / ACPI: add ACPI support

On Friday, November 16, 2012 10:12:46 AM Mika Westerberg wrote:
> On Fri, Nov 16, 2012 at 10:05:49AM +0200, Mika Westerberg wrote:
> >
> > One more thing, sometimes we want to assign the handle like in the case of
> > SPI controller driver we set the master->dev.acpi_handle. In that case we
> > can't use DEVICE_ACPI_HANDLE() as is. Should we just do something like:
> >
> > master->dev.acpi_handle = pdev->dev.acpi_handle;
> >
> > or should we introduce some new macro that supports this?
>
> Or we could just drop the cast from the macro and use the same.
>
> #define DEVICE_ACPI_HANDLE(dev) ((dev)->acpi_handle)

Well, I'm not sure. Perhaps it's better to add a new macro, like
ACPI_HANDLE(dev), defined as above and use it going forward (we can then
phase out the old one gradually).

However, let's leave the patches in this series as they are for now, we can
add that macro in a separate patch later.

Thanks,
Rafael


--
I speak only for myself.
Rafael J. Wysocki, Intel Open Source Technology Center.

2012-11-16 09:59:34

by Rafael J. Wysocki

[permalink] [raw]
Subject: Re: [PATCH v2 1/3] gpio / ACPI: add ACPI support

On Thursday, November 15, 2012 01:03:15 PM Mika Westerberg wrote:
> From: Mathias Nyman <[email protected]>
>
> Add support for translating ACPI GPIO pin numbers to Linux GPIO API pins.
> Needs a gpio controller driver with the acpi handler hook set.
>
> Drivers can use acpi_get_gpio() to translate ACPI5 GpioIO and GpioInt
> resources to Linux GPIO's.
>
> Signed-off-by: Mathias Nyman <[email protected]>
> Signed-off-by: Mika Westerberg <[email protected]>

I wonder if anyone has objections or comments?

Linus, Grant, are you OK with this patch?

Rafael


> ---
> drivers/gpio/Kconfig | 4 ++++
> drivers/gpio/Makefile | 1 +
> drivers/gpio/gpiolib-acpi.c | 56 +++++++++++++++++++++++++++++++++++++++++++
> include/linux/acpi_gpio.h | 19 +++++++++++++++
> 4 files changed, 80 insertions(+)
> create mode 100644 drivers/gpio/gpiolib-acpi.c
> create mode 100644 include/linux/acpi_gpio.h
>
> diff --git a/drivers/gpio/Kconfig b/drivers/gpio/Kconfig
> index f11d8e3..5c9b384 100644
> --- a/drivers/gpio/Kconfig
> +++ b/drivers/gpio/Kconfig
> @@ -49,6 +49,10 @@ config OF_GPIO
> def_bool y
> depends on OF
>
> +config GPIO_ACPI
> + def_bool y
> + depends on ACPI
> +
> config DEBUG_GPIO
> bool "Debug GPIO calls"
> depends on DEBUG_KERNEL
> diff --git a/drivers/gpio/Makefile b/drivers/gpio/Makefile
> index 9aeed67..420dbac 100644
> --- a/drivers/gpio/Makefile
> +++ b/drivers/gpio/Makefile
> @@ -4,6 +4,7 @@ ccflags-$(CONFIG_DEBUG_GPIO) += -DDEBUG
>
> obj-$(CONFIG_GPIOLIB) += gpiolib.o devres.o
> obj-$(CONFIG_OF_GPIO) += gpiolib-of.o
> +obj-$(CONFIG_GPIO_ACPI) += gpiolib-acpi.o
>
> # Device drivers. Generally keep list sorted alphabetically
> obj-$(CONFIG_GPIO_GENERIC) += gpio-generic.o
> diff --git a/drivers/gpio/gpiolib-acpi.c b/drivers/gpio/gpiolib-acpi.c
> new file mode 100644
> index 0000000..8ef9831
> --- /dev/null
> +++ b/drivers/gpio/gpiolib-acpi.c
> @@ -0,0 +1,56 @@
> +/*
> + * ACPI helpers for GPIO API
> + *
> + * Copyright (C) 2012, Intel Corporation
> + * Authors: Mathias Nyman <[email protected]>
> + * Mika Westerberg <[email protected]>
> + *
> + * 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/errno.h>
> +#include <linux/gpio.h>
> +#include <linux/export.h>
> +#include <linux/acpi_gpio.h>
> +#include <linux/acpi.h>
> +
> +static int acpi_gpiochip_find(struct gpio_chip *gc, void *data)
> +{
> + acpi_handle handle = data;
> +
> + if (!gc->dev)
> + return false;
> +
> + return gc->dev->acpi_handle == handle;
> +}
> +
> +/**
> + * acpi_get_gpio() - Translate ACPI GPIO pin to GPIO number usable with GPIO API
> + * @path: ACPI GPIO controller full path name, (e.g. "\\_SB.GPO1")
> + * @pin: ACPI GPIO pin number (0-based, controller-relative)
> + *
> + * Returns GPIO number to use with Linux generic GPIO API, or errno error value
> + */
> +
> +int acpi_get_gpio(char *path, int pin)
> +{
> + struct gpio_chip *chip;
> + acpi_handle handle;
> + acpi_status status;
> +
> + status = acpi_get_handle(NULL, path, &handle);
> + if (ACPI_FAILURE(status))
> + return -ENODEV;
> +
> + chip = gpiochip_find(handle, acpi_gpiochip_find);
> + if (!chip)
> + return -ENODEV;
> +
> + if (!gpio_is_valid(chip->base + pin))
> + return -EINVAL;
> +
> + return chip->base + pin;
> +}
> +EXPORT_SYMBOL_GPL(acpi_get_gpio);
> diff --git a/include/linux/acpi_gpio.h b/include/linux/acpi_gpio.h
> new file mode 100644
> index 0000000..91615a3
> --- /dev/null
> +++ b/include/linux/acpi_gpio.h
> @@ -0,0 +1,19 @@
> +#ifndef _LINUX_ACPI_GPIO_H_
> +#define _LINUX_ACPI_GPIO_H_
> +
> +#include <linux/errno.h>
> +
> +#ifdef CONFIG_GPIO_ACPI
> +
> +int acpi_get_gpio(char *path, int pin);
> +
> +#else /* CONFIG_GPIO_ACPI */
> +
> +static inline int acpi_get_gpio(char *path, int pin)
> +{
> + return -ENODEV;
> +}
> +
> +#endif /* CONFIG_GPIO_ACPI */
> +
> +#endif /* _LINUX_ACPI_GPIO_H_ */
>
--
I speak only for myself.
Rafael J. Wysocki, Intel Open Source Technology Center.

2012-11-16 10:02:27

by Rafael J. Wysocki

[permalink] [raw]
Subject: Re: [PATCH v2 2/3] spi / ACPI: add ACPI enumeration support

On Thursday, November 15, 2012 01:03:16 PM Mika Westerberg wrote:
> ACPI 5 introduced SPISerialBus resource that allows us to enumerate and
> configure the SPI slave devices behind the SPI controller. This patch adds
> support for this to the SPI core.
>
> In addition we bind ACPI nodes to SPI devices. This makes it possible for
> the slave drivers to get the ACPI handle for further configuration.
>
> Signed-off-by: Mika Westerberg <[email protected]>

Does anyone has objections or comments? Do we need to change anything
in this patch?

Grant? Linus? Bjorn?

Rafael


> ---
> drivers/spi/spi.c | 201 ++++++++++++++++++++++++++++++++++++++++++++++++++++-
> 1 file changed, 200 insertions(+), 1 deletion(-)
>
> diff --git a/drivers/spi/spi.c b/drivers/spi/spi.c
> index 84c2861..e39a484 100644
> --- a/drivers/spi/spi.c
> +++ b/drivers/spi/spi.c
> @@ -35,6 +35,8 @@
> #include <linux/sched.h>
> #include <linux/delay.h>
> #include <linux/kthread.h>
> +#include <linux/ioport.h>
> +#include <linux/acpi.h>
>
> static void spidev_release(struct device *dev)
> {
> @@ -93,6 +95,10 @@ static int spi_match_device(struct device *dev, struct device_driver *drv)
> if (of_driver_match_device(dev, drv))
> return 1;
>
> + /* Then try ACPI */
> + if (acpi_driver_match_device(dev, drv))
> + return 1;
> +
> if (sdrv->id_table)
> return !!spi_match_id(sdrv->id_table, spi);
>
> @@ -888,6 +894,196 @@ static void of_register_spi_devices(struct spi_master *master)
> static void of_register_spi_devices(struct spi_master *master) { }
> #endif
>
> +#ifdef CONFIG_ACPI
> +static int acpi_spi_add_resource(struct acpi_resource *ares, void *data)
> +{
> + struct acpi_resource_spi_serialbus *sb;
> + struct spi_device *spi = data;
> +
> + if (ares->type != ACPI_RESOURCE_TYPE_SERIAL_BUS)
> + return 0;
> +
> + sb = &ares->data.spi_serial_bus;
> + if (sb->type != ACPI_RESOURCE_SERIAL_TYPE_SPI)
> + return 0;
> +
> + spi->chip_select = sb->device_selection;
> + spi->max_speed_hz = sb->connection_speed;
> +
> + if (sb->clock_phase == ACPI_SPI_SECOND_PHASE)
> + spi->mode |= SPI_CPHA;
> + if (sb->clock_polarity == ACPI_SPI_START_HIGH)
> + spi->mode |= SPI_CPOL;
> + if (sb->device_polarity == ACPI_SPI_ACTIVE_HIGH)
> + spi->mode |= SPI_CS_HIGH;
> +
> + return 1;
> +}
> +
> +static acpi_status acpi_spi_add_device(acpi_handle handle, u32 level,
> + void *data, void **return_value)
> +{
> + struct spi_master *master = data;
> + struct resource_list_entry *rentry;
> + struct list_head resource_list;
> + struct acpi_device *adev;
> + struct spi_device *spi;
> + int ret;
> +
> + if (acpi_bus_get_device(handle, &adev))
> + return AE_OK;
> + if (acpi_bus_get_status(adev) || !adev->status.present)
> + return AE_OK;
> +
> + spi = spi_alloc_device(master);
> + if (!spi) {
> + dev_err(&master->dev, "failed to allocate SPI device for %s\n",
> + dev_name(&adev->dev));
> + return AE_NO_MEMORY;
> + }
> +
> + INIT_LIST_HEAD(&resource_list);
> + ret = acpi_dev_get_resources(adev, &resource_list,
> + acpi_spi_add_resource, spi);
> + if (ret < 0)
> + goto fail_put_dev;
> +
> + list_for_each_entry(rentry, &resource_list, node) {
> + struct resource *r = &rentry->res;
> +
> + if (resource_type(r) == IORESOURCE_IRQ) {
> + spi->irq = r->start;
> + break;
> + }
> + }
> +
> + acpi_dev_free_resource_list(&resource_list);
> +
> + if (!spi->max_speed_hz)
> + goto fail_put_dev;
> +
> + strlcpy(spi->modalias, dev_name(&adev->dev), sizeof(spi->modalias));
> + if (spi_add_device(spi)) {
> + dev_err(&master->dev, "failed to add SPI device %s from ACPI\n",
> + dev_name(&adev->dev));
> + goto fail_put_dev;
> + }
> +
> + return AE_OK;
> +
> +fail_put_dev:
> + spi_dev_put(spi);
> +
> + return AE_OK;
> +}
> +
> +static void acpi_register_spi_devices(struct spi_master *master)
> +{
> + acpi_status status;
> + acpi_handle handle;
> +
> + handle = master->dev.acpi_handle;
> + if (!handle)
> + return;
> +
> + status = acpi_walk_namespace(ACPI_TYPE_DEVICE, handle, 1,
> + acpi_spi_add_device, NULL,
> + master, NULL);
> + if (ACPI_FAILURE(status))
> + dev_warn(&master->dev, "failed to enumerate SPI slaves\n");
> +}
> +
> +struct acpi_spi_find {
> + acpi_handle handle;
> + u16 chip_select;
> + bool found;
> +};
> +
> +static int acpi_spi_find_child_address(struct acpi_resource *ares, void *data)
> +{
> + struct acpi_resource_spi_serialbus *sb;
> + struct acpi_spi_find *spi_find = data;
> +
> + if (ares->type != ACPI_RESOURCE_TYPE_SERIAL_BUS)
> + return 1;
> +
> + sb = &ares->data.spi_serial_bus;
> + if (sb->type != ACPI_RESOURCE_SERIAL_TYPE_SPI)
> + return 1;
> +
> + if (sb->device_selection == spi_find->chip_select)
> + spi_find->found = true;
> +
> + return 1;
> +}
> +
> +static acpi_status acpi_spi_find_child(acpi_handle handle, u32 level,
> + void *data, void **return_value)
> +{
> + struct acpi_spi_find *spi_find = data;
> + struct list_head resource_list;
> + 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;
> +
> + INIT_LIST_HEAD(&resource_list);
> + ret = acpi_dev_get_resources(adev, &resource_list,
> + acpi_spi_find_child_address, spi_find);
> + if (ret < 0)
> + return AE_OK;
> +
> + acpi_dev_free_resource_list(&resource_list);
> +
> + if (spi_find->found) {
> + spi_find->handle = handle;
> + return AE_CTRL_TERMINATE;
> + }
> + return AE_OK;
> +}
> +
> +static int acpi_spi_find_device(struct device *dev, acpi_handle *handle)
> +{
> + struct spi_device *spi = to_spi_device(dev);
> + struct spi_master *master = spi->master;
> + struct acpi_spi_find spi_find;
> + acpi_handle parent;
> + acpi_status status;
> +
> + parent = master->dev.acpi_handle;
> + if (!parent)
> + return -ENODEV;
> +
> + memset(&spi_find, 0, sizeof(spi_find));
> + spi_find.chip_select = spi->chip_select;
> +
> + status = acpi_walk_namespace(ACPI_TYPE_DEVICE, parent, 1,
> + acpi_spi_find_child, NULL,
> + &spi_find, NULL);
> + if (ACPI_FAILURE(status) || !spi_find.handle)
> + return -ENODEV;
> +
> + *handle = spi_find.handle;
> + return 0;
> +}
> +
> +static struct acpi_bus_type acpi_spi_bus = {
> + .bus = &spi_bus_type,
> + .find_device = acpi_spi_find_device,
> +};
> +
> +static void acpi_spi_bus_register(void)
> +{
> + register_acpi_bus_type(&acpi_spi_bus);
> +}
> +#else
> +static inline void acpi_register_spi_devices(struct spi_master *master) {}
> +static inline void acpi_spi_bus_register(void) {}
> +#endif /* CONFIG_ACPI */
> +
> static void spi_master_release(struct device *dev)
> {
> struct spi_master *master;
> @@ -1023,8 +1219,9 @@ int spi_register_master(struct spi_master *master)
> spi_match_master_to_boardinfo(master, &bi->board_info);
> mutex_unlock(&board_lock);
>
> - /* Register devices from the device tree */
> + /* Register devices from the device tree and ACPI */
> of_register_spi_devices(master);
> + acpi_register_spi_devices(master);
> done:
> return status;
> }
> @@ -1550,6 +1747,8 @@ static int __init spi_init(void)
> status = class_register(&spi_master_class);
> if (status < 0)
> goto err2;
> +
> + acpi_spi_bus_register();
> return 0;
>
> err2:
>
--
I speak only for myself.
Rafael J. Wysocki, Intel Open Source Technology Center.

2012-11-16 10:04:43

by Rafael J. Wysocki

[permalink] [raw]
Subject: Re: [PATCH v2 3/3] i2c / ACPI: add ACPI enumeration support

On Thursday, November 15, 2012 01:03:17 PM Mika Westerberg wrote:
> ACPI 5 introduced I2cSerialBus resource that makes it possible to enumerate
> and configure the I2C slave devices behind the I2C controller. This patch
> adds helper functions to support I2C slave enumeration.
>
> An ACPI enabled I2C controller driver only needs to call acpi_i2c_register_devices()
> in order to get its slave devices enumerated, created and bound to the
> corresponding ACPI handle.
>
> Signed-off-by: Mika Westerberg <[email protected]>

Are there any objections against this patch or comments?

Worfram? Jean? Ben?

Rafael


> ---
> drivers/acpi/Kconfig | 6 ++
> drivers/acpi/Makefile | 1 +
> drivers/acpi/acpi_i2c.c | 212 ++++++++++++++++++++++++++++++++++++++++++++++
> drivers/i2c/i2c-core.c | 10 +++
> include/linux/acpi_i2c.h | 27 ++++++
> 5 files changed, 256 insertions(+)
> create mode 100644 drivers/acpi/acpi_i2c.c
> create mode 100644 include/linux/acpi_i2c.h
>
> diff --git a/drivers/acpi/Kconfig b/drivers/acpi/Kconfig
> index 119d58d..0300bf6 100644
> --- a/drivers/acpi/Kconfig
> +++ b/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
> diff --git a/drivers/acpi/Makefile b/drivers/acpi/Makefile
> index 7289828..2a4502b 100644
> --- a/drivers/acpi/Makefile
> +++ b/drivers/acpi/Makefile
> @@ -70,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
> diff --git a/drivers/acpi/acpi_i2c.c b/drivers/acpi/acpi_i2c.c
> new file mode 100644
> index 0000000..5bf2dad
> --- /dev/null
> +++ b/drivers/acpi/acpi_i2c.c
> @@ -0,0 +1,212 @@
> +/*
> + * ACPI I2C enumeration support
> + *
> + * Copyright (C) 2012, Intel Corporation
> + * Author: Mika Westerberg <[email protected]>
> + *
> + * 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/err.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 acpi_resource_i2c_serialbus *sb;
> + struct i2c_board_info *info = data;
> +
> + if (ares->type != ACPI_RESOURCE_TYPE_SERIAL_BUS)
> + return 0;
> +
> + sb = &ares->data.i2c_serial_bus;
> + if (sb->type != ACPI_RESOURCE_SERIAL_TYPE_I2C)
> + return 0;
> +
> + info->addr = sb->slave_address;
> + if (sb->access_mode == ACPI_I2C_10BIT_MODE)
> + info->flags |= I2C_CLIENT_TEN;
> +
> + 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 resource_list_entry *rentry;
> + 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));
> +
> + INIT_LIST_HEAD(&resource_list);
> + ret = acpi_dev_get_resources(adev, &resource_list,
> + acpi_i2c_add_resource, &info);
> + if (ret < 0)
> + return AE_OK;
> +
> + list_for_each_entry(rentry, &resource_list, node) {
> + struct resource *r = &rentry->res;
> +
> + if (resource_type(r) == IORESOURCE_IRQ) {
> + info.irq = r->start;
> + break;
> + }
> + }
> +
> + acpi_dev_free_resource_list(&resource_list);
> +
> + if (!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 = adapter->dev.acpi_handle;
> + 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);
> +
> +struct acpi_i2c_find {
> + acpi_handle handle;
> + u16 addr;
> + bool found;
> +};
> +
> +static int acpi_i2c_find_child_address(struct acpi_resource *ares, void *data)
> +{
> + struct acpi_resource_i2c_serialbus *sb;
> + struct acpi_i2c_find *i2c_find = data;
> +
> + if (ares->type != ACPI_RESOURCE_TYPE_SERIAL_BUS)
> + return 1;
> +
> + sb = &ares->data.i2c_serial_bus;
> + if (sb->type != ACPI_RESOURCE_SERIAL_TYPE_I2C)
> + return 1;
> +
> + if (sb->slave_address == i2c_find->addr)
> + i2c_find->found = true;
> +
> + return 1;
> +}
> +
> +static acpi_status acpi_i2c_find_child(acpi_handle handle, u32 level,
> + void *data, void **return_value)
> +{
> + struct acpi_i2c_find *i2c_find = data;
> + struct list_head resource_list;
> + 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;
> +
> + INIT_LIST_HEAD(&resource_list);
> + ret = acpi_dev_get_resources(adev, &resource_list,
> + acpi_i2c_find_child_address, i2c_find);
> + if (ret < 0)
> + return AE_OK;
> +
> + acpi_dev_free_resource_list(&resource_list);
> +
> + if (i2c_find->found) {
> + i2c_find->handle = handle;
> + return AE_CTRL_TERMINATE;
> + }
> + return AE_OK;
> +}
> +
> +static int acpi_i2c_find_device(struct device *dev, acpi_handle *handle)
> +{
> + struct acpi_i2c_find i2c_find;
> + struct i2c_adapter *adapter;
> + struct i2c_client *client;
> + acpi_handle parent;
> + acpi_status status;
> +
> + client = i2c_verify_client(dev);
> + if (!client)
> + return -ENODEV;
> +
> + adapter = client->adapter;
> + if (!adapter)
> + return -ENODEV;
> +
> + parent = adapter->dev.acpi_handle;
> + if (!parent)
> + return -ENODEV;
> +
> + memset(&i2c_find, 0, sizeof(i2c_find));
> + i2c_find.addr = client->addr;
> +
> + status = acpi_walk_namespace(ACPI_TYPE_DEVICE, parent, 1,
> + acpi_i2c_find_child, NULL,
> + &i2c_find, NULL);
> + if (ACPI_FAILURE(status) || !i2c_find.handle)
> + return -ENODEV;
> +
> + *handle = i2c_find.handle;
> + return 0;
> +}
> +
> +static struct acpi_bus_type acpi_i2c_bus = {
> + .bus = &i2c_bus_type,
> + .find_device = acpi_i2c_find_device,
> +};
> +
> +void acpi_i2c_bus_register(void)
> +{
> + register_acpi_bus_type(&acpi_i2c_bus);
> +}
> +EXPORT_SYMBOL_GPL(acpi_i2c_bus_register);
> +
> +void acpi_i2c_bus_unregister(void)
> +{
> + unregister_acpi_bus_type(&acpi_i2c_bus);
> +}
> +EXPORT_SYMBOL_GPL(acpi_i2c_bus_unregister);
> diff --git a/drivers/i2c/i2c-core.c b/drivers/i2c/i2c-core.c
> index a7edf98..7385de2f 100644
> --- a/drivers/i2c/i2c-core.c
> +++ b/drivers/i2c/i2c-core.c
> @@ -39,6 +39,8 @@
> #include <linux/irqflags.h>
> #include <linux/rwsem.h>
> #include <linux/pm_runtime.h>
> +#include <linux/acpi.h>
> +#include <linux/acpi_i2c.h>
> #include <asm/uaccess.h>
>
> #include "i2c-core.h"
> @@ -78,6 +80,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)
> @@ -1298,6 +1304,8 @@ static int __init i2c_init(void)
> retval = i2c_add_driver(&dummy_driver);
> if (retval)
> goto class_err;
> +
> + acpi_i2c_bus_register();
> return 0;
>
> class_err:
> @@ -1311,6 +1319,8 @@ bus_err:
>
> static void __exit i2c_exit(void)
> {
> + acpi_i2c_bus_unregister();
> +
> i2c_del_driver(&dummy_driver);
> #ifdef CONFIG_I2C_COMPAT
> class_compat_unregister(i2c_adapter_compat_class);
> diff --git a/include/linux/acpi_i2c.h b/include/linux/acpi_i2c.h
> new file mode 100644
> index 0000000..cf2233f
> --- /dev/null
> +++ b/include/linux/acpi_i2c.h
> @@ -0,0 +1,27 @@
> +/*
> + * ACPI I2C enumeration support
> + *
> + * Copyright (C) 2012, Intel Corporation
> + * Author: Mika Westerberg <[email protected]>
> + *
> + * 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.
> + */
> +
> +#ifndef LINUX_ACPI_I2C_H
> +#define LINUX_ACPI_I2C_H
> +
> +struct i2c_adapter;
> +
> +#if IS_ENABLED(CONFIG_ACPI_I2C)
> +extern void acpi_i2c_register_devices(struct i2c_adapter *adap);
> +extern void acpi_i2c_bus_register(void);
> +extern void acpi_i2c_bus_unregister(void);
> +#else
> +static inline void acpi_i2c_register_devices(struct i2c_adapter *adap) {}
> +static inline void acpi_i2c_bus_register(void) {}
> +static inline void acpi_i2c_bus_unregister(void) {}
> +#endif /* IS_ENABLED(CONFIG_ACPI_I2C) */
> +
> +#endif /* LINUX_ACPI_I2C_H */
>
--
I speak only for myself.
Rafael J. Wysocki, Intel Open Source Technology Center.

2012-11-16 12:46:41

by Mika Westerberg

[permalink] [raw]
Subject: Re: [PATCH v2 1/3] gpio / ACPI: add ACPI support

On Fri, Nov 16, 2012 at 11:02:05AM +0100, Rafael J. Wysocki wrote:
> On Friday, November 16, 2012 10:12:46 AM Mika Westerberg wrote:
> > On Fri, Nov 16, 2012 at 10:05:49AM +0200, Mika Westerberg wrote:
> > >
> > > One more thing, sometimes we want to assign the handle like in the case of
> > > SPI controller driver we set the master->dev.acpi_handle. In that case we
> > > can't use DEVICE_ACPI_HANDLE() as is. Should we just do something like:
> > >
> > > master->dev.acpi_handle = pdev->dev.acpi_handle;
> > >
> > > or should we introduce some new macro that supports this?
> >
> > Or we could just drop the cast from the macro and use the same.
> >
> > #define DEVICE_ACPI_HANDLE(dev) ((dev)->acpi_handle)
>
> Well, I'm not sure. Perhaps it's better to add a new macro, like
> ACPI_HANDLE(dev), defined as above and use it going forward (we can then
> phase out the old one gradually).

Yeah, that sounds good.

> However, let's leave the patches in this series as they are for now, we can
> add that macro in a separate patch later.

OK.

2012-11-16 13:04:29

by Jean Delvare

[permalink] [raw]
Subject: Re: [PATCH v2 3/3] i2c / ACPI: add ACPI enumeration support

Hi Rafael,

On Fri, 16 Nov 2012 11:09:03 +0100, Rafael J. Wysocki wrote:
> On Thursday, November 15, 2012 01:03:17 PM Mika Westerberg wrote:
> > ACPI 5 introduced I2cSerialBus resource that makes it possible to enumerate
> > and configure the I2C slave devices behind the I2C controller. This patch
> > adds helper functions to support I2C slave enumeration.
> >
> > An ACPI enabled I2C controller driver only needs to call acpi_i2c_register_devices()
> > in order to get its slave devices enumerated, created and bound to the
> > corresponding ACPI handle.
> >
> > Signed-off-by: Mika Westerberg <[email protected]>
>
> Are there any objections against this patch or comments?
>
> Worfram? Jean? Ben?

I am no longer maintaining the i2c subsystem and will not have the time
to look deeply into this. All I can say is that I very happy to see
this finally happen. Maybe with ACPI 5.0 we will finally be done with
resource conflicts plaguing many systems for several years now.

I took a quick look, and the only thing which seems suspicious is this
function:

> +static int acpi_i2c_find_child_address(struct acpi_resource *ares, void *data)
> +{
> + struct acpi_resource_i2c_serialbus *sb;
> + struct acpi_i2c_find *i2c_find = data;
> +
> + if (ares->type != ACPI_RESOURCE_TYPE_SERIAL_BUS)
> + return 1;
> +
> + sb = &ares->data.i2c_serial_bus;
> + if (sb->type != ACPI_RESOURCE_SERIAL_TYPE_I2C)
> + return 1;
> +
> + if (sb->slave_address == i2c_find->addr)

The 7-bit and 10-bit address maps overlap, so the above isn't enough.
You must compare the addresses _and_ sb->access_mode with
i2c_find->access_mode (which needs to be added and filled properly.)

> + i2c_find->found = true;
> +
> + return 1;
> +}

Plus, it seems odd that this function always returns 1.

--
Jean Delvare

2012-11-16 13:17:34

by Rafael J. Wysocki

[permalink] [raw]
Subject: Re: [PATCH v2 3/3] i2c / ACPI: add ACPI enumeration support

On Friday, November 16, 2012 02:03:57 PM Jean Delvare wrote:
> Hi Rafael,
>
> On Fri, 16 Nov 2012 11:09:03 +0100, Rafael J. Wysocki wrote:
> > On Thursday, November 15, 2012 01:03:17 PM Mika Westerberg wrote:
> > > ACPI 5 introduced I2cSerialBus resource that makes it possible to enumerate
> > > and configure the I2C slave devices behind the I2C controller. This patch
> > > adds helper functions to support I2C slave enumeration.
> > >
> > > An ACPI enabled I2C controller driver only needs to call acpi_i2c_register_devices()
> > > in order to get its slave devices enumerated, created and bound to the
> > > corresponding ACPI handle.
> > >
> > > Signed-off-by: Mika Westerberg <[email protected]>
> >
> > Are there any objections against this patch or comments?
> >
> > Worfram? Jean? Ben?
>
> I am no longer maintaining the i2c subsystem and will not have the time
> to look deeply into this. All I can say is that I very happy to see
> this finally happen. Maybe with ACPI 5.0 we will finally be done with
> resource conflicts plaguing many systems for several years now.
>
> I took a quick look, and the only thing which seems suspicious is this
> function:
>
> > +static int acpi_i2c_find_child_address(struct acpi_resource *ares, void *data)
> > +{
> > + struct acpi_resource_i2c_serialbus *sb;
> > + struct acpi_i2c_find *i2c_find = data;
> > +
> > + if (ares->type != ACPI_RESOURCE_TYPE_SERIAL_BUS)
> > + return 1;
> > +
> > + sb = &ares->data.i2c_serial_bus;
> > + if (sb->type != ACPI_RESOURCE_SERIAL_TYPE_I2C)
> > + return 1;
> > +
> > + if (sb->slave_address == i2c_find->addr)
>
> The 7-bit and 10-bit address maps overlap, so the above isn't enough.
> You must compare the addresses _and_ sb->access_mode with
> i2c_find->access_mode (which needs to be added and filled properly.)
>
> > + i2c_find->found = true;
> > +
> > + return 1;
> > +}
>
> Plus, it seems odd that this function always returns 1.

Yes, this is a bug I think. Mika?


--
I speak only for myself.
Rafael J. Wysocki, Intel Open Source Technology Center.

2012-11-16 13:43:15

by Jean Delvare

[permalink] [raw]
Subject: Re: [PATCH v2 3/3] i2c / ACPI: add ACPI enumeration support

On Fri, 16 Nov 2012 14:21:54 +0100, Rafael J. Wysocki wrote:
> On Friday, November 16, 2012 02:03:57 PM Jean Delvare wrote:
> > Hi Rafael,
> >
> > On Fri, 16 Nov 2012 11:09:03 +0100, Rafael J. Wysocki wrote:
> > > On Thursday, November 15, 2012 01:03:17 PM Mika Westerberg wrote:
> > > > ACPI 5 introduced I2cSerialBus resource that makes it possible to enumerate
> > > > and configure the I2C slave devices behind the I2C controller. This patch
> > > > adds helper functions to support I2C slave enumeration.
> > > >
> > > > An ACPI enabled I2C controller driver only needs to call acpi_i2c_register_devices()
> > > > in order to get its slave devices enumerated, created and bound to the
> > > > corresponding ACPI handle.
> > > >
> > > > Signed-off-by: Mika Westerberg <[email protected]>
> > >
> > > Are there any objections against this patch or comments?
> > >
> > > Worfram? Jean? Ben?
> >
> > I am no longer maintaining the i2c subsystem and will not have the time
> > to look deeply into this. All I can say is that I very happy to see
> > this finally happen. Maybe with ACPI 5.0 we will finally be done with
> > resource conflicts plaguing many systems for several years now.
> >
> > I took a quick look, and the only thing which seems suspicious is this
> > function:
> >
> > > +static int acpi_i2c_find_child_address(struct acpi_resource *ares, void *data)
> > > +{
> > > + struct acpi_resource_i2c_serialbus *sb;
> > > + struct acpi_i2c_find *i2c_find = data;
> > > +
> > > + if (ares->type != ACPI_RESOURCE_TYPE_SERIAL_BUS)
> > > + return 1;
> > > +
> > > + sb = &ares->data.i2c_serial_bus;
> > > + if (sb->type != ACPI_RESOURCE_SERIAL_TYPE_I2C)
> > > + return 1;
> > > +
> > > + if (sb->slave_address == i2c_find->addr)
> >
> > The 7-bit and 10-bit address maps overlap, so the above isn't enough.
> > You must compare the addresses _and_ sb->access_mode with
> > i2c_find->access_mode (which needs to be added and filled properly.)
> >
> > > + i2c_find->found = true;
> > > +
> > > + return 1;
> > > +}
> >
> > Plus, it seems odd that this function always returns 1.
>
> Yes, this is a bug I think. Mika?

The equivalent function for SPI devices does the same, so if this is a
bug, it must be fixed there too. If this is not a bug then it is
questionable why these functions return something in the first place.

But then again I didn't look into the design, so I may be missing
something.

--
Jean Delvare

2012-11-16 14:14:22

by Mika Westerberg

[permalink] [raw]
Subject: Re: [PATCH v2 3/3] i2c / ACPI: add ACPI enumeration support

On Fri, Nov 16, 2012 at 02:42:56PM +0100, Jean Delvare wrote:
> On Fri, 16 Nov 2012 14:21:54 +0100, Rafael J. Wysocki wrote:
> > On Friday, November 16, 2012 02:03:57 PM Jean Delvare wrote:
> > > Hi Rafael,
> > >
> > > On Fri, 16 Nov 2012 11:09:03 +0100, Rafael J. Wysocki wrote:
> > > > On Thursday, November 15, 2012 01:03:17 PM Mika Westerberg wrote:
> > > > > ACPI 5 introduced I2cSerialBus resource that makes it possible to enumerate
> > > > > and configure the I2C slave devices behind the I2C controller. This patch
> > > > > adds helper functions to support I2C slave enumeration.
> > > > >
> > > > > An ACPI enabled I2C controller driver only needs to call acpi_i2c_register_devices()
> > > > > in order to get its slave devices enumerated, created and bound to the
> > > > > corresponding ACPI handle.
> > > > >
> > > > > Signed-off-by: Mika Westerberg <[email protected]>
> > > >
> > > > Are there any objections against this patch or comments?
> > > >
> > > > Worfram? Jean? Ben?
> > >
> > > I am no longer maintaining the i2c subsystem and will not have the time
> > > to look deeply into this. All I can say is that I very happy to see
> > > this finally happen. Maybe with ACPI 5.0 we will finally be done with
> > > resource conflicts plaguing many systems for several years now.
> > >
> > > I took a quick look, and the only thing which seems suspicious is this
> > > function:
> > >
> > > > +static int acpi_i2c_find_child_address(struct acpi_resource *ares, void *data)
> > > > +{
> > > > + struct acpi_resource_i2c_serialbus *sb;
> > > > + struct acpi_i2c_find *i2c_find = data;
> > > > +
> > > > + if (ares->type != ACPI_RESOURCE_TYPE_SERIAL_BUS)
> > > > + return 1;
> > > > +
> > > > + sb = &ares->data.i2c_serial_bus;
> > > > + if (sb->type != ACPI_RESOURCE_SERIAL_TYPE_I2C)
> > > > + return 1;
> > > > +
> > > > + if (sb->slave_address == i2c_find->addr)
> > >
> > > The 7-bit and 10-bit address maps overlap, so the above isn't enough.
> > > You must compare the addresses _and_ sb->access_mode with
> > > i2c_find->access_mode (which needs to be added and filled properly.)

Ok. I wasn't sure about that and given that 10-bit addresses are not that
common I tought that we can just compare the addr to zero. I'll add the
check.

> > >
> > > > + i2c_find->found = true;
> > > > +
> > > > + return 1;
> > > > +}
> > >
> > > Plus, it seems odd that this function always returns 1.
> >
> > Yes, this is a bug I think. Mika?
>
> The equivalent function for SPI devices does the same, so if this is a
> bug, it must be fixed there too. If this is not a bug then it is
> questionable why these functions return something in the first place.
>
> But then again I didn't look into the design, so I may be missing
> something.

It is not a bug, it just means that we don't want the ACPI core to fill in
normal resources (we only want to peek the ACPI resources and find the
corresponding I2CSerialBus() resource).

2012-11-16 15:20:26

by Mika Westerberg

[permalink] [raw]
Subject: Re: [PATCH v2 3/3] i2c / ACPI: add ACPI enumeration support

On Fri, Nov 16, 2012 at 04:17:29PM +0200, Mika Westerberg wrote:
> > > > > +static int acpi_i2c_find_child_address(struct acpi_resource *ares, void *data)
> > > > > +{
> > > > > + struct acpi_resource_i2c_serialbus *sb;
> > > > > + struct acpi_i2c_find *i2c_find = data;
> > > > > +
> > > > > + if (ares->type != ACPI_RESOURCE_TYPE_SERIAL_BUS)
> > > > > + return 1;
> > > > > +
> > > > > + sb = &ares->data.i2c_serial_bus;
> > > > > + if (sb->type != ACPI_RESOURCE_SERIAL_TYPE_I2C)
> > > > > + return 1;
> > > > > +
> > > > > + if (sb->slave_address == i2c_find->addr)
> > > >
> > > > The 7-bit and 10-bit address maps overlap, so the above isn't enough.
> > > > You must compare the addresses _and_ sb->access_mode with
> > > > i2c_find->access_mode (which needs to be added and filled properly.)
>
> Ok. I wasn't sure about that and given that 10-bit addresses are not that
> common I tought that we can just compare the addr to zero. I'll add the
> check.

Here's the updated version where we handle 10-bit addresses properly
(hopefully).

From: Mika Westerberg <[email protected]>
Date: Mon, 10 Sep 2012 12:12:32 +0300
Subject: [PATCH] i2c / ACPI: add ACPI enumeration support

ACPI 5 introduced I2cSerialBus resource that makes it possible to enumerate
and configure the I2C slave devices behind the I2C controller. This patch
adds helper functions to support I2C slave enumeration.

An ACPI enabled I2C controller driver only needs to call acpi_i2c_register_devices()
in order to get its slave devices enumerated, created and bound to the
corresponding ACPI handle.

Signed-off-by: Mika Westerberg <[email protected]>
---
drivers/acpi/Kconfig | 6 ++
drivers/acpi/Makefile | 1 +
drivers/acpi/acpi_i2c.c | 216 ++++++++++++++++++++++++++++++++++++++++++++++
drivers/i2c/i2c-core.c | 10 +++
include/linux/acpi_i2c.h | 27 ++++++
5 files changed, 260 insertions(+)
create mode 100644 drivers/acpi/acpi_i2c.c
create mode 100644 include/linux/acpi_i2c.h

diff --git a/drivers/acpi/Kconfig b/drivers/acpi/Kconfig
index 119d58d..0300bf6 100644
--- a/drivers/acpi/Kconfig
+++ b/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
diff --git a/drivers/acpi/Makefile b/drivers/acpi/Makefile
index 7289828..2a4502b 100644
--- a/drivers/acpi/Makefile
+++ b/drivers/acpi/Makefile
@@ -70,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
diff --git a/drivers/acpi/acpi_i2c.c b/drivers/acpi/acpi_i2c.c
new file mode 100644
index 0000000..8c8d7e8
--- /dev/null
+++ b/drivers/acpi/acpi_i2c.c
@@ -0,0 +1,216 @@
+/*
+ * ACPI I2C enumeration support
+ *
+ * Copyright (C) 2012, Intel Corporation
+ * Author: Mika Westerberg <[email protected]>
+ *
+ * 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/err.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 acpi_resource_i2c_serialbus *sb;
+ struct i2c_board_info *info = data;
+
+ if (ares->type != ACPI_RESOURCE_TYPE_SERIAL_BUS)
+ return 0;
+
+ sb = &ares->data.i2c_serial_bus;
+ if (sb->type != ACPI_RESOURCE_SERIAL_TYPE_I2C)
+ return 0;
+
+ info->addr = sb->slave_address;
+ if (sb->access_mode == ACPI_I2C_10BIT_MODE)
+ info->flags |= I2C_CLIENT_TEN;
+
+ 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 resource_list_entry *rentry;
+ 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));
+
+ INIT_LIST_HEAD(&resource_list);
+ ret = acpi_dev_get_resources(adev, &resource_list,
+ acpi_i2c_add_resource, &info);
+ if (ret < 0)
+ return AE_OK;
+
+ list_for_each_entry(rentry, &resource_list, node) {
+ struct resource *r = &rentry->res;
+
+ if (resource_type(r) == IORESOURCE_IRQ) {
+ info.irq = r->start;
+ break;
+ }
+ }
+
+ acpi_dev_free_resource_list(&resource_list);
+
+ if (!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 = adapter->dev.acpi_handle;
+ 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);
+
+struct acpi_i2c_find {
+ acpi_handle handle;
+ u16 addr;
+ u8 access_mode;
+ bool found;
+};
+
+static int acpi_i2c_find_child_address(struct acpi_resource *ares, void *data)
+{
+ struct acpi_resource_i2c_serialbus *sb;
+ struct acpi_i2c_find *i2c_find = data;
+
+ if (ares->type != ACPI_RESOURCE_TYPE_SERIAL_BUS)
+ return 1;
+
+ sb = &ares->data.i2c_serial_bus;
+ if (sb->type != ACPI_RESOURCE_SERIAL_TYPE_I2C)
+ return 1;
+
+ if (sb->slave_address == i2c_find->addr &&
+ sb->access_mode == i2c_find->access_mode)
+ i2c_find->found = true;
+
+ return 1;
+}
+
+static acpi_status acpi_i2c_find_child(acpi_handle handle, u32 level,
+ void *data, void **return_value)
+{
+ struct acpi_i2c_find *i2c_find = data;
+ struct list_head resource_list;
+ 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;
+
+ INIT_LIST_HEAD(&resource_list);
+ ret = acpi_dev_get_resources(adev, &resource_list,
+ acpi_i2c_find_child_address, i2c_find);
+ if (ret < 0)
+ return AE_OK;
+
+ acpi_dev_free_resource_list(&resource_list);
+
+ if (i2c_find->found) {
+ i2c_find->handle = handle;
+ return AE_CTRL_TERMINATE;
+ }
+ return AE_OK;
+}
+
+static int acpi_i2c_find_device(struct device *dev, acpi_handle *handle)
+{
+ struct acpi_i2c_find i2c_find;
+ struct i2c_adapter *adapter;
+ struct i2c_client *client;
+ acpi_handle parent;
+ acpi_status status;
+
+ client = i2c_verify_client(dev);
+ if (!client)
+ return -ENODEV;
+
+ adapter = client->adapter;
+ if (!adapter)
+ return -ENODEV;
+
+ parent = adapter->dev.acpi_handle;
+ if (!parent)
+ return -ENODEV;
+
+ memset(&i2c_find, 0, sizeof(i2c_find));
+ i2c_find.addr = client->addr;
+ if (client->flags & I2C_CLIENT_TEN)
+ i2c_find.access_mode = ACPI_I2C_10BIT_MODE;
+
+ status = acpi_walk_namespace(ACPI_TYPE_DEVICE, parent, 1,
+ acpi_i2c_find_child, NULL,
+ &i2c_find, NULL);
+ if (ACPI_FAILURE(status) || !i2c_find.handle)
+ return -ENODEV;
+
+ *handle = i2c_find.handle;
+ return 0;
+}
+
+static struct acpi_bus_type acpi_i2c_bus = {
+ .bus = &i2c_bus_type,
+ .find_device = acpi_i2c_find_device,
+};
+
+void acpi_i2c_bus_register(void)
+{
+ register_acpi_bus_type(&acpi_i2c_bus);
+}
+EXPORT_SYMBOL_GPL(acpi_i2c_bus_register);
+
+void acpi_i2c_bus_unregister(void)
+{
+ unregister_acpi_bus_type(&acpi_i2c_bus);
+}
+EXPORT_SYMBOL_GPL(acpi_i2c_bus_unregister);
diff --git a/drivers/i2c/i2c-core.c b/drivers/i2c/i2c-core.c
index a7edf98..7385de2f 100644
--- a/drivers/i2c/i2c-core.c
+++ b/drivers/i2c/i2c-core.c
@@ -39,6 +39,8 @@
#include <linux/irqflags.h>
#include <linux/rwsem.h>
#include <linux/pm_runtime.h>
+#include <linux/acpi.h>
+#include <linux/acpi_i2c.h>
#include <asm/uaccess.h>

#include "i2c-core.h"
@@ -78,6 +80,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)
@@ -1298,6 +1304,8 @@ static int __init i2c_init(void)
retval = i2c_add_driver(&dummy_driver);
if (retval)
goto class_err;
+
+ acpi_i2c_bus_register();
return 0;

class_err:
@@ -1311,6 +1319,8 @@ bus_err:

static void __exit i2c_exit(void)
{
+ acpi_i2c_bus_unregister();
+
i2c_del_driver(&dummy_driver);
#ifdef CONFIG_I2C_COMPAT
class_compat_unregister(i2c_adapter_compat_class);
diff --git a/include/linux/acpi_i2c.h b/include/linux/acpi_i2c.h
new file mode 100644
index 0000000..cf2233f
--- /dev/null
+++ b/include/linux/acpi_i2c.h
@@ -0,0 +1,27 @@
+/*
+ * ACPI I2C enumeration support
+ *
+ * Copyright (C) 2012, Intel Corporation
+ * Author: Mika Westerberg <[email protected]>
+ *
+ * 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.
+ */
+
+#ifndef LINUX_ACPI_I2C_H
+#define LINUX_ACPI_I2C_H
+
+struct i2c_adapter;
+
+#if IS_ENABLED(CONFIG_ACPI_I2C)
+extern void acpi_i2c_register_devices(struct i2c_adapter *adap);
+extern void acpi_i2c_bus_register(void);
+extern void acpi_i2c_bus_unregister(void);
+#else
+static inline void acpi_i2c_register_devices(struct i2c_adapter *adap) {}
+static inline void acpi_i2c_bus_register(void) {}
+static inline void acpi_i2c_bus_unregister(void) {}
+#endif /* IS_ENABLED(CONFIG_ACPI_I2C) */
+
+#endif /* LINUX_ACPI_I2C_H */
--
1.7.10.4

2012-11-16 16:48:21

by Jean Delvare

[permalink] [raw]
Subject: Re: [PATCH v2 3/3] i2c / ACPI: add ACPI enumeration support

Hi Mika,

On Fri, 16 Nov 2012 17:23:32 +0200, Mika Westerberg wrote:
> Here's the updated version where we handle 10-bit addresses properly
> (hopefully).
> (...)
> +static int acpi_i2c_find_device(struct device *dev, acpi_handle *handle)
> +{
> (...)
> + memset(&i2c_find, 0, sizeof(i2c_find));
> + i2c_find.addr = client->addr;
> + if (client->flags & I2C_CLIENT_TEN)
> + i2c_find.access_mode = ACPI_I2C_10BIT_MODE;

This works because you are lucky and ACPI_I2C_7BIT_MODE has value 0,
but for correctness I'd rather add:

else
i2c_find.access_mode = ACPI_I2C_7BIT_MODE;

Other than this the new code looks OK WRT this issue, thanks.

--
Jean Delvare

2012-11-16 17:25:21

by Mika Westerberg

[permalink] [raw]
Subject: [PATCH v2 3/3 UPDATED] i2c / ACPI: add ACPI enumeration support

On Fri, Nov 16, 2012 at 05:47:53PM +0100, Jean Delvare wrote:
> Hi Mika,
>
> On Fri, 16 Nov 2012 17:23:32 +0200, Mika Westerberg wrote:
> > Here's the updated version where we handle 10-bit addresses properly
> > (hopefully).
> > (...)
> > +static int acpi_i2c_find_device(struct device *dev, acpi_handle *handle)
> > +{
> > (...)
> > + memset(&i2c_find, 0, sizeof(i2c_find));
> > + i2c_find.addr = client->addr;
> > + if (client->flags & I2C_CLIENT_TEN)
> > + i2c_find.access_mode = ACPI_I2C_10BIT_MODE;
>
> This works because you are lucky and ACPI_I2C_7BIT_MODE has value 0,
> but for correctness I'd rather add:
>
> else
> i2c_find.access_mode = ACPI_I2C_7BIT_MODE;

Right, sorry about that. The patch below should address this as well.

From: Mika Westerberg <[email protected]>
Date: Mon, 10 Sep 2012 12:12:32 +0300
Subject: [PATCH] i2c / ACPI: add ACPI enumeration support

ACPI 5 introduced I2cSerialBus resource that makes it possible to enumerate
and configure the I2C slave devices behind the I2C controller. This patch
adds helper functions to support I2C slave enumeration.

An ACPI enabled I2C controller driver only needs to call acpi_i2c_register_devices()
in order to get its slave devices enumerated, created and bound to the
corresponding ACPI handle.

Signed-off-by: Mika Westerberg <[email protected]>
---
drivers/acpi/Kconfig | 6 ++
drivers/acpi/Makefile | 1 +
drivers/acpi/acpi_i2c.c | 216 ++++++++++++++++++++++++++++++++++++++++++++++
drivers/i2c/i2c-core.c | 10 +++
include/linux/acpi_i2c.h | 27 ++++++
5 files changed, 260 insertions(+)
create mode 100644 drivers/acpi/acpi_i2c.c
create mode 100644 include/linux/acpi_i2c.h

diff --git a/drivers/acpi/Kconfig b/drivers/acpi/Kconfig
index 119d58d..0300bf6 100644
--- a/drivers/acpi/Kconfig
+++ b/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
diff --git a/drivers/acpi/Makefile b/drivers/acpi/Makefile
index 7289828..2a4502b 100644
--- a/drivers/acpi/Makefile
+++ b/drivers/acpi/Makefile
@@ -70,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
diff --git a/drivers/acpi/acpi_i2c.c b/drivers/acpi/acpi_i2c.c
new file mode 100644
index 0000000..5783d93
--- /dev/null
+++ b/drivers/acpi/acpi_i2c.c
@@ -0,0 +1,216 @@
+/*
+ * ACPI I2C enumeration support
+ *
+ * Copyright (C) 2012, Intel Corporation
+ * Author: Mika Westerberg <[email protected]>
+ *
+ * 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/err.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 acpi_resource_i2c_serialbus *sb;
+ struct i2c_board_info *info = data;
+
+ if (ares->type != ACPI_RESOURCE_TYPE_SERIAL_BUS)
+ return 0;
+
+ sb = &ares->data.i2c_serial_bus;
+ if (sb->type != ACPI_RESOURCE_SERIAL_TYPE_I2C)
+ return 0;
+
+ info->addr = sb->slave_address;
+ if (sb->access_mode == ACPI_I2C_10BIT_MODE)
+ info->flags |= I2C_CLIENT_TEN;
+
+ 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 resource_list_entry *rentry;
+ 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));
+
+ INIT_LIST_HEAD(&resource_list);
+ ret = acpi_dev_get_resources(adev, &resource_list,
+ acpi_i2c_add_resource, &info);
+ if (ret < 0)
+ return AE_OK;
+
+ list_for_each_entry(rentry, &resource_list, node) {
+ struct resource *r = &rentry->res;
+
+ if (resource_type(r) == IORESOURCE_IRQ) {
+ info.irq = r->start;
+ break;
+ }
+ }
+
+ acpi_dev_free_resource_list(&resource_list);
+
+ if (!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 = adapter->dev.acpi_handle;
+ 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);
+
+struct acpi_i2c_find {
+ acpi_handle handle;
+ u16 addr;
+ u8 access_mode;
+ bool found;
+};
+
+static int acpi_i2c_find_child_address(struct acpi_resource *ares, void *data)
+{
+ struct acpi_resource_i2c_serialbus *sb;
+ struct acpi_i2c_find *i2c_find = data;
+
+ if (ares->type != ACPI_RESOURCE_TYPE_SERIAL_BUS)
+ return 1;
+
+ sb = &ares->data.i2c_serial_bus;
+ if (sb->type != ACPI_RESOURCE_SERIAL_TYPE_I2C)
+ return 1;
+
+ if (sb->slave_address == i2c_find->addr &&
+ sb->access_mode == i2c_find->access_mode)
+ i2c_find->found = true;
+
+ return 1;
+}
+
+static acpi_status acpi_i2c_find_child(acpi_handle handle, u32 level,
+ void *data, void **return_value)
+{
+ struct acpi_i2c_find *i2c_find = data;
+ struct list_head resource_list;
+ 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;
+
+ INIT_LIST_HEAD(&resource_list);
+ ret = acpi_dev_get_resources(adev, &resource_list,
+ acpi_i2c_find_child_address, i2c_find);
+ if (ret < 0)
+ return AE_OK;
+
+ acpi_dev_free_resource_list(&resource_list);
+
+ if (i2c_find->found) {
+ i2c_find->handle = handle;
+ return AE_CTRL_TERMINATE;
+ }
+ return AE_OK;
+}
+
+static int acpi_i2c_find_device(struct device *dev, acpi_handle *handle)
+{
+ struct acpi_i2c_find i2c_find;
+ struct i2c_adapter *adapter;
+ struct i2c_client *client;
+ acpi_handle parent;
+ acpi_status status;
+
+ client = i2c_verify_client(dev);
+ if (!client)
+ return -ENODEV;
+
+ adapter = client->adapter;
+ if (!adapter)
+ return -ENODEV;
+
+ parent = adapter->dev.acpi_handle;
+ if (!parent)
+ return -ENODEV;
+
+ memset(&i2c_find, 0, sizeof(i2c_find));
+ i2c_find.addr = client->addr;
+ i2c_find.access_mode = client->flags & I2C_CLIENT_TEN ?
+ ACPI_I2C_10BIT_MODE : ACPI_I2C_7BIT_MODE;
+
+ status = acpi_walk_namespace(ACPI_TYPE_DEVICE, parent, 1,
+ acpi_i2c_find_child, NULL,
+ &i2c_find, NULL);
+ if (ACPI_FAILURE(status) || !i2c_find.handle)
+ return -ENODEV;
+
+ *handle = i2c_find.handle;
+ return 0;
+}
+
+static struct acpi_bus_type acpi_i2c_bus = {
+ .bus = &i2c_bus_type,
+ .find_device = acpi_i2c_find_device,
+};
+
+void acpi_i2c_bus_register(void)
+{
+ register_acpi_bus_type(&acpi_i2c_bus);
+}
+EXPORT_SYMBOL_GPL(acpi_i2c_bus_register);
+
+void acpi_i2c_bus_unregister(void)
+{
+ unregister_acpi_bus_type(&acpi_i2c_bus);
+}
+EXPORT_SYMBOL_GPL(acpi_i2c_bus_unregister);
diff --git a/drivers/i2c/i2c-core.c b/drivers/i2c/i2c-core.c
index a7edf98..7385de2f 100644
--- a/drivers/i2c/i2c-core.c
+++ b/drivers/i2c/i2c-core.c
@@ -39,6 +39,8 @@
#include <linux/irqflags.h>
#include <linux/rwsem.h>
#include <linux/pm_runtime.h>
+#include <linux/acpi.h>
+#include <linux/acpi_i2c.h>
#include <asm/uaccess.h>

#include "i2c-core.h"
@@ -78,6 +80,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)
@@ -1298,6 +1304,8 @@ static int __init i2c_init(void)
retval = i2c_add_driver(&dummy_driver);
if (retval)
goto class_err;
+
+ acpi_i2c_bus_register();
return 0;

class_err:
@@ -1311,6 +1319,8 @@ bus_err:

static void __exit i2c_exit(void)
{
+ acpi_i2c_bus_unregister();
+
i2c_del_driver(&dummy_driver);
#ifdef CONFIG_I2C_COMPAT
class_compat_unregister(i2c_adapter_compat_class);
diff --git a/include/linux/acpi_i2c.h b/include/linux/acpi_i2c.h
new file mode 100644
index 0000000..cf2233f
--- /dev/null
+++ b/include/linux/acpi_i2c.h
@@ -0,0 +1,27 @@
+/*
+ * ACPI I2C enumeration support
+ *
+ * Copyright (C) 2012, Intel Corporation
+ * Author: Mika Westerberg <[email protected]>
+ *
+ * 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.
+ */
+
+#ifndef LINUX_ACPI_I2C_H
+#define LINUX_ACPI_I2C_H
+
+struct i2c_adapter;
+
+#if IS_ENABLED(CONFIG_ACPI_I2C)
+extern void acpi_i2c_register_devices(struct i2c_adapter *adap);
+extern void acpi_i2c_bus_register(void);
+extern void acpi_i2c_bus_unregister(void);
+#else
+static inline void acpi_i2c_register_devices(struct i2c_adapter *adap) {}
+static inline void acpi_i2c_bus_register(void) {}
+static inline void acpi_i2c_bus_unregister(void) {}
+#endif /* IS_ENABLED(CONFIG_ACPI_I2C) */
+
+#endif /* LINUX_ACPI_I2C_H */
--
1.7.10.4

2012-11-16 18:13:12

by Jean Delvare

[permalink] [raw]
Subject: Re: [PATCH v2 3/3 UPDATED] i2c / ACPI: add ACPI enumeration support

On Fri, 16 Nov 2012 19:28:28 +0200, Mika Westerberg wrote:
> On Fri, Nov 16, 2012 at 05:47:53PM +0100, Jean Delvare wrote:
> > Hi Mika,
> >
> > On Fri, 16 Nov 2012 17:23:32 +0200, Mika Westerberg wrote:
> > > Here's the updated version where we handle 10-bit addresses properly
> > > (hopefully).
> > > (...)
> > > +static int acpi_i2c_find_device(struct device *dev, acpi_handle *handle)
> > > +{
> > > (...)
> > > + memset(&i2c_find, 0, sizeof(i2c_find));
> > > + i2c_find.addr = client->addr;
> > > + if (client->flags & I2C_CLIENT_TEN)
> > > + i2c_find.access_mode = ACPI_I2C_10BIT_MODE;
> >
> > This works because you are lucky and ACPI_I2C_7BIT_MODE has value 0,
> > but for correctness I'd rather add:
> >
> > else
> > i2c_find.access_mode = ACPI_I2C_7BIT_MODE;
>
> Right, sorry about that. The patch below should address this as well.
> (...)

Yes, looks good.

--
Jean Delvare

2012-11-16 19:58:16

by Rafael J. Wysocki

[permalink] [raw]
Subject: Re: [PATCH v2 3/3] i2c / ACPI: add ACPI enumeration support

On Friday, November 16, 2012 04:17:29 PM Mika Westerberg wrote:
> On Fri, Nov 16, 2012 at 02:42:56PM +0100, Jean Delvare wrote:
> > On Fri, 16 Nov 2012 14:21:54 +0100, Rafael J. Wysocki wrote:
> > > On Friday, November 16, 2012 02:03:57 PM Jean Delvare wrote:
> > > > Hi Rafael,
> > > >
> > > > On Fri, 16 Nov 2012 11:09:03 +0100, Rafael J. Wysocki wrote:
> > > > > On Thursday, November 15, 2012 01:03:17 PM Mika Westerberg wrote:
> > > > > > ACPI 5 introduced I2cSerialBus resource that makes it possible to enumerate
> > > > > > and configure the I2C slave devices behind the I2C controller. This patch
> > > > > > adds helper functions to support I2C slave enumeration.
> > > > > >
> > > > > > An ACPI enabled I2C controller driver only needs to call acpi_i2c_register_devices()
> > > > > > in order to get its slave devices enumerated, created and bound to the
> > > > > > corresponding ACPI handle.
> > > > > >
> > > > > > Signed-off-by: Mika Westerberg <[email protected]>
> > > > >
> > > > > Are there any objections against this patch or comments?
> > > > >
> > > > > Worfram? Jean? Ben?
> > > >
> > > > I am no longer maintaining the i2c subsystem and will not have the time
> > > > to look deeply into this. All I can say is that I very happy to see
> > > > this finally happen. Maybe with ACPI 5.0 we will finally be done with
> > > > resource conflicts plaguing many systems for several years now.
> > > >
> > > > I took a quick look, and the only thing which seems suspicious is this
> > > > function:
> > > >
> > > > > +static int acpi_i2c_find_child_address(struct acpi_resource *ares, void *data)
> > > > > +{
> > > > > + struct acpi_resource_i2c_serialbus *sb;
> > > > > + struct acpi_i2c_find *i2c_find = data;
> > > > > +
> > > > > + if (ares->type != ACPI_RESOURCE_TYPE_SERIAL_BUS)
> > > > > + return 1;
> > > > > +
> > > > > + sb = &ares->data.i2c_serial_bus;
> > > > > + if (sb->type != ACPI_RESOURCE_SERIAL_TYPE_I2C)
> > > > > + return 1;
> > > > > +
> > > > > + if (sb->slave_address == i2c_find->addr)
> > > >
> > > > The 7-bit and 10-bit address maps overlap, so the above isn't enough.
> > > > You must compare the addresses _and_ sb->access_mode with
> > > > i2c_find->access_mode (which needs to be added and filled properly.)
>
> Ok. I wasn't sure about that and given that 10-bit addresses are not that
> common I tought that we can just compare the addr to zero. I'll add the
> check.
>
> > > >
> > > > > + i2c_find->found = true;
> > > > > +
> > > > > + return 1;
> > > > > +}
> > > >
> > > > Plus, it seems odd that this function always returns 1.
> > >
> > > Yes, this is a bug I think. Mika?
> >
> > The equivalent function for SPI devices does the same, so if this is a
> > bug, it must be fixed there too. If this is not a bug then it is
> > questionable why these functions return something in the first place.
> >
> > But then again I didn't look into the design, so I may be missing
> > something.
>
> It is not a bug, it just means that we don't want the ACPI core to fill in
> normal resources (we only want to peek the ACPI resources and find the
> corresponding I2CSerialBus() resource).

Ah, that's what's called by acpi_dev_get_resources(). But what about writing
it this way:

static int acpi_i2c_find_child_address(struct acpi_resource *ares, void *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) {
struct acpi_i2c_find *i2c_find = data;

if (sb->slave_address == i2c_find->addr)
i2c_find->found = true;
}
}

/* Tell the ACPI core to skip this resource. */
return 1;
}

Seems easier to follow. :-)

Thanks,
Rafael


--
I speak only for myself.
Rafael J. Wysocki, Intel Open Source Technology Center.

2012-11-16 20:06:27

by Mika Westerberg

[permalink] [raw]
Subject: Re: [PATCH v2 3/3] i2c / ACPI: add ACPI enumeration support

On Fri, Nov 16, 2012 at 09:02:36PM +0100, Rafael J. Wysocki wrote:
> Ah, that's what's called by acpi_dev_get_resources(). But what about writing
> it this way:
>
> static int acpi_i2c_find_child_address(struct acpi_resource *ares, void *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) {
> struct acpi_i2c_find *i2c_find = data;
>
> if (sb->slave_address == i2c_find->addr)
> i2c_find->found = true;
> }
> }
>
> /* Tell the ACPI core to skip this resource. */
> return 1;
> }

Not a problem at all, I'll do it like above and also with the SPI case.
I'll wait til tomorrow for more comments and post v3 unless there are
objections.

2012-11-16 20:14:14

by Rafael J. Wysocki

[permalink] [raw]
Subject: Re: [PATCH v2 3/3] i2c / ACPI: add ACPI enumeration support

On Friday, November 16, 2012 10:09:34 PM Mika Westerberg wrote:
> On Fri, Nov 16, 2012 at 09:02:36PM +0100, Rafael J. Wysocki wrote:
> > Ah, that's what's called by acpi_dev_get_resources(). But what about writing
> > it this way:
> >
> > static int acpi_i2c_find_child_address(struct acpi_resource *ares, void *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) {
> > struct acpi_i2c_find *i2c_find = data;
> >
> > if (sb->slave_address == i2c_find->addr)
> > i2c_find->found = true;
> > }
> > }
> >
> > /* Tell the ACPI core to skip this resource. */
> > return 1;
> > }
>
> Not a problem at all, I'll do it like above and also with the SPI case.
> I'll wait til tomorrow for more comments and post v3 unless there are
> objections.

OK, thanks!


--
I speak only for myself.
Rafael J. Wysocki, Intel Open Source Technology Center.

2012-11-17 06:47:07

by Bjorn Helgaas

[permalink] [raw]
Subject: Re: [PATCH v2 3/3 UPDATED] i2c / ACPI: add ACPI enumeration support

On Fri, Nov 16, 2012 at 10:28 AM, Mika Westerberg
<[email protected]> wrote:
> ...
> From: Mika Westerberg <[email protected]>
> Date: Mon, 10 Sep 2012 12:12:32 +0300
> Subject: [PATCH] i2c / ACPI: add ACPI enumeration support
>
> ACPI 5 introduced I2cSerialBus resource that makes it possible to enumerate
> and configure the I2C slave devices behind the I2C controller. This patch
> adds helper functions to support I2C slave enumeration.
>
> An ACPI enabled I2C controller driver only needs to call acpi_i2c_register_devices()
> in order to get its slave devices enumerated, created and bound to the
> corresponding ACPI handle.

I must admit I don't understand the strategy here. Likely it's only
because I haven't been paying enough attention, but I'll ask anyway in
case anybody else is similarly confused.

The callchain when we enumerate these slave devices looks like this:

acpi_i2c_register_devices(struct i2c_adapter *)
acpi_walk_namespace(adapter->dev.acpi_handle, acpi_i2c_add_device)
acpi_i2c_add_device
acpi_bus_get_device
acpi_bus_get_status
acpi_dev_get_resources(..., acpi_i2c_add_resource, ...)
<find IRQ, addr>
acpi_dev_free_resources
i2c_new_device
client = kzalloc
client->dev = ...
device_register(&client->dev)

Is the ACPI namespace in question something like the following?

Device { # i2C master, i.e., the i2c_adapter
_HID PNPmmmm
Device { # I2C slave 1, i.e., a client
_HID PNPsss1
_CRS
SerialBus/I2C addr addr1, mode mode1
IRQ irq1
}
Device { # I2C slave 2
_HID PNPsss2
_CRS
SerialBus/I2C addr addr2, mode mode2
IRQ irq2
}
}

_CRS is a device configuration method, so I would expect that it
exists within the scope of a Device() object. The way I'm used to
this working is for a driver to specify "I know about PNPsss1
devices."

But it looks like acpi_i2c_register() walks the namespace below an i2c
master device, registering a new i2c device (a slave) for every ACPI
device node with a _CRS method that contains a SERIAL_BUS/TYPE_I2C
descriptor. It seems like you're basically claiming those devices
nodes based on the contents of their _CRS, not based on their PNP IDs,
which seems strange to me.

We have to be able to hook device enumeration into udev so we can
autoload drivers. It's obvious how to do that with _HID and _CID --
we just emit a uevent saying "we found a new device with PNP IDs
x,y,z". I don't see how to do anything similar based on the _CRS
contents. Again, probably I'm completely missing the point here, and
I'm sorry to be dense.

I guess this isn't really "enumeration" -- the ACPI core has
previously walked this namespace and built acpi_devices for the
Device() nodes, and I think it emits uevents at that time. So this is
more of a "claim" than an "enumerate." But the Device() node for the
I2C slave still exists, and it has _HID/_CID, doesn't it? Do we use
that _HID anywhere?

In any event, after acpi_i2c_register(), I think we have a set of
i2c_client devices (with the above namespace, I assume we'd have two
of them). I guess acpi_i2c_find_device() is useful now -- it looks
like it takes a "struct device *" (e.g., &client->dev from a struct
i2c_client), and and gives you back the acpi_handle corresponding to
it?

Here's the callchain of that path:

acpi_i2c_find_device(struct device *) # acpi_i2c_bus.find_device
i2c_verify_client(dev)
acpi_walk_namespace
acpi_i2c_find_child
acpi_bus_get_device
acpi_bus_get_status
acpi_dev_get_resources(..., acpi_i2c_find_child_address, ...)
acpi_i2c_find_child_address
found if (SERIAL_BUS && SERIAL_TYPE_I2C && slave_address == xx)
acpi_dev_free_resource_list
*handle = handle

That seems like an awful lot of work to do just to map a struct device
* back to the acpi_handle. But I don't have any suggestion; just that
observation.

Bjorn

2012-11-17 08:00:47

by Mika Westerberg

[permalink] [raw]
Subject: Re: [PATCH v2 3/3 UPDATED] i2c / ACPI: add ACPI enumeration support

On Fri, Nov 16, 2012 at 11:46:40PM -0700, Bjorn Helgaas wrote:
> On Fri, Nov 16, 2012 at 10:28 AM, Mika Westerberg
> <[email protected]> wrote:
> > ...
> > From: Mika Westerberg <[email protected]>
> > Date: Mon, 10 Sep 2012 12:12:32 +0300
> > Subject: [PATCH] i2c / ACPI: add ACPI enumeration support
> >
> > ACPI 5 introduced I2cSerialBus resource that makes it possible to enumerate
> > and configure the I2C slave devices behind the I2C controller. This patch
> > adds helper functions to support I2C slave enumeration.
> >
> > An ACPI enabled I2C controller driver only needs to call acpi_i2c_register_devices()
> > in order to get its slave devices enumerated, created and bound to the
> > corresponding ACPI handle.
>
> I must admit I don't understand the strategy here. Likely it's only
> because I haven't been paying enough attention, but I'll ask anyway in
> case anybody else is similarly confused.
>
> The callchain when we enumerate these slave devices looks like this:
>
> acpi_i2c_register_devices(struct i2c_adapter *)
> acpi_walk_namespace(adapter->dev.acpi_handle, acpi_i2c_add_device)
> acpi_i2c_add_device
> acpi_bus_get_device
> acpi_bus_get_status
> acpi_dev_get_resources(..., acpi_i2c_add_resource, ...)
> <find IRQ, addr>
> acpi_dev_free_resources
> i2c_new_device
> client = kzalloc
> client->dev = ...
> device_register(&client->dev)
>
> Is the ACPI namespace in question something like the following?
>
> Device { # i2C master, i.e., the i2c_adapter
> _HID PNPmmmm
> Device { # I2C slave 1, i.e., a client
> _HID PNPsss1
> _CRS
> SerialBus/I2C addr addr1, mode mode1
> IRQ irq1
> }
> Device { # I2C slave 2
> _HID PNPsss2
> _CRS
> SerialBus/I2C addr addr2, mode mode2
> IRQ irq2
> }
> }

Yes.

> _CRS is a device configuration method, so I would expect that it
> exists within the scope of a Device() object. The way I'm used to
> this working is for a driver to specify "I know about PNPsss1
> devices."

Yes.

> But it looks like acpi_i2c_register() walks the namespace below an i2c
> master device, registering a new i2c device (a slave) for every ACPI
> device node with a _CRS method that contains a SERIAL_BUS/TYPE_I2C
> descriptor. It seems like you're basically claiming those devices
> nodes based on the contents of their _CRS, not based on their PNP IDs,
> which seems strange to me.

Yes, if we only matched the PNP IDs we would get bunch of PNP devices which
certainly doesn't help us to reuse the existing I2C drivers. So instead of
creating a new glue driver for ACPI or PNP device we added this enumeration
method that then creates the I2C devices, just like DT does.

> We have to be able to hook device enumeration into udev so we can
> autoload drivers. It's obvious how to do that with _HID and _CID --
> we just emit a uevent saying "we found a new device with PNP IDs
> x,y,z". I don't see how to do anything similar based on the _CRS
> contents. Again, probably I'm completely missing the point here, and
> I'm sorry to be dense.

If you remember the concrete example, I gave you few mails back, it shows
how we are planning to the matching in an existing (or new driver). So we
match with _HID and _CID but that matching is done in the core of each bus
in question (platform, I2C and SPI).

> I guess this isn't really "enumeration" -- the ACPI core has
> previously walked this namespace and built acpi_devices for the
> Device() nodes, and I think it emits uevents at that time. So this is
> more of a "claim" than an "enumerate." But the Device() node for the
> I2C slave still exists, and it has _HID/_CID, doesn't it? Do we use
> that _HID anywhere?

The matching is done using those _HID and _CIDs in the ACPI namespace, we
just now allow any driver to match any device using and not limit it to
ACPI device drivers (this is done with the help of drv->acpi_match_table).

> In any event, after acpi_i2c_register(), I think we have a set of
> i2c_client devices (with the above namespace, I assume we'd have two
> of them). I guess acpi_i2c_find_device() is useful now -- it looks
> like it takes a "struct device *" (e.g., &client->dev from a struct
> i2c_client), and and gives you back the acpi_handle corresponding to
> it?
>
> Here's the callchain of that path:
>
> acpi_i2c_find_device(struct device *) # acpi_i2c_bus.find_device
> i2c_verify_client(dev)
> acpi_walk_namespace
> acpi_i2c_find_child
> acpi_bus_get_device
> acpi_bus_get_status
> acpi_dev_get_resources(..., acpi_i2c_find_child_address, ...)
> acpi_i2c_find_child_address
> found if (SERIAL_BUS && SERIAL_TYPE_I2C && slave_address == xx)
> acpi_dev_free_resource_list
> *handle = handle
>
> That seems like an awful lot of work to do just to map a struct device
> * back to the acpi_handle. But I don't have any suggestion; just that
> observation.

We had similar discussion internally about not using that
drivers/acpi/glue.c but we decided to use it for now, even if it really
backwards and makes things hard (like you observed as well). A much better
way would be just to assign the handle once we make the device but it
seemed not to be that simple after all.

2012-11-17 09:52:32

by Mika Westerberg

[permalink] [raw]
Subject: Re: [PATCH v2 3/3 UPDATED] i2c / ACPI: add ACPI enumeration support

On Sat, Nov 17, 2012 at 10:03:54AM +0200, Mika Westerberg wrote:
> On Fri, Nov 16, 2012 at 11:46:40PM -0700, Bjorn Helgaas wrote:
> > On Fri, Nov 16, 2012 at 10:28 AM, Mika Westerberg
> > <[email protected]> wrote:
> > > ...
> > > From: Mika Westerberg <[email protected]>
> > > Date: Mon, 10 Sep 2012 12:12:32 +0300
> > > Subject: [PATCH] i2c / ACPI: add ACPI enumeration support
> > >
> > > ACPI 5 introduced I2cSerialBus resource that makes it possible to enumerate
> > > and configure the I2C slave devices behind the I2C controller. This patch
> > > adds helper functions to support I2C slave enumeration.
> > >
> > > An ACPI enabled I2C controller driver only needs to call acpi_i2c_register_devices()
> > > in order to get its slave devices enumerated, created and bound to the
> > > corresponding ACPI handle.
> >
> > I must admit I don't understand the strategy here. Likely it's only
> > because I haven't been paying enough attention, but I'll ask anyway in
> > case anybody else is similarly confused.
> >
> > The callchain when we enumerate these slave devices looks like this:
> >
> > acpi_i2c_register_devices(struct i2c_adapter *)
> > acpi_walk_namespace(adapter->dev.acpi_handle, acpi_i2c_add_device)
> > acpi_i2c_add_device
> > acpi_bus_get_device
> > acpi_bus_get_status
> > acpi_dev_get_resources(..., acpi_i2c_add_resource, ...)
> > <find IRQ, addr>
> > acpi_dev_free_resources
> > i2c_new_device
> > client = kzalloc
> > client->dev = ...
> > device_register(&client->dev)
> >
> > Is the ACPI namespace in question something like the following?
> >
> > Device { # i2C master, i.e., the i2c_adapter
> > _HID PNPmmmm
> > Device { # I2C slave 1, i.e., a client
> > _HID PNPsss1
> > _CRS
> > SerialBus/I2C addr addr1, mode mode1
> > IRQ irq1
> > }
> > Device { # I2C slave 2
> > _HID PNPsss2
> > _CRS
> > SerialBus/I2C addr addr2, mode mode2
> > IRQ irq2
> > }
> > }
>
> Yes.
>
> > _CRS is a device configuration method, so I would expect that it
> > exists within the scope of a Device() object. The way I'm used to
> > this working is for a driver to specify "I know about PNPsss1
> > devices."
>
> Yes.
>
> > But it looks like acpi_i2c_register() walks the namespace below an i2c
> > master device, registering a new i2c device (a slave) for every ACPI
> > device node with a _CRS method that contains a SERIAL_BUS/TYPE_I2C
> > descriptor. It seems like you're basically claiming those devices
> > nodes based on the contents of their _CRS, not based on their PNP IDs,
> > which seems strange to me.
>
> Yes, if we only matched the PNP IDs we would get bunch of PNP devices which
> certainly doesn't help us to reuse the existing I2C drivers. So instead of
> creating a new glue driver for ACPI or PNP device we added this enumeration
> method that then creates the I2C devices, just like DT does.

In other words, what this whole thing is trying to achieve is something
along the lines of:

- Instead of making PNP or ACPI devices out of every device in the
ACPI namespace we use the resources returned by the _CRS
method for a given device as a hint of what type of device it is.

- If we find I2CSerialBus() we assume it is an I2C device and
create i2c_device (and i2c_client) and register this to the I2C
core.

- If we find SPISerialBus() we assume it is a SPI device and create
corresponding spidevice and register it to the SPI core.

- Devices that don't have a bus are represented as platform devices
(based on the table in drivers/acpi/scan.c). The reason for this
is that most of the SoC devices have already platform driver so
we can easily reuse the existing drivers.

The implementation follows the Device Tree as much as possible so that
adding support for DT and ACPI to a driver would be similar and thus easy
for people who know either method.

An alternative would be to create PNP or ACPI glue drivers for each device
that then create the corresponding real device like platform or I2C which
means that we need add much more lines of unnecessary code to the kernel
compared to adding the ACPI/PNP IDs to the driver which takes only few
lines of code.

We still allow more complex configuration with the means of
dev->acpi_handle. So for example if driver needs to call _DSM in order to
retrieve some parameters for the device it can do so with the help of
dev->acpi_handle.

2012-11-17 10:07:39

by Rafael J. Wysocki

[permalink] [raw]
Subject: Re: [PATCH v2 2/3] spi / ACPI: add ACPI enumeration support

On Thursday, November 15, 2012 01:03:16 PM Mika Westerberg wrote:
> ACPI 5 introduced SPISerialBus resource that allows us to enumerate and
> configure the SPI slave devices behind the SPI controller. This patch adds
> support for this to the SPI core.
>
> In addition we bind ACPI nodes to SPI devices. This makes it possible for
> the slave drivers to get the ACPI handle for further configuration.
>
> Signed-off-by: Mika Westerberg <[email protected]>
> ---
> drivers/spi/spi.c | 201 ++++++++++++++++++++++++++++++++++++++++++++++++++++-
> 1 file changed, 200 insertions(+), 1 deletion(-)
>
> diff --git a/drivers/spi/spi.c b/drivers/spi/spi.c
> index 84c2861..e39a484 100644
> --- a/drivers/spi/spi.c
> +++ b/drivers/spi/spi.c
> @@ -35,6 +35,8 @@
> #include <linux/sched.h>
> #include <linux/delay.h>
> #include <linux/kthread.h>
> +#include <linux/ioport.h>
> +#include <linux/acpi.h>
>
> static void spidev_release(struct device *dev)
> {
> @@ -93,6 +95,10 @@ static int spi_match_device(struct device *dev, struct device_driver *drv)
> if (of_driver_match_device(dev, drv))
> return 1;
>
> + /* Then try ACPI */
> + if (acpi_driver_match_device(dev, drv))
> + return 1;
> +
> if (sdrv->id_table)
> return !!spi_match_id(sdrv->id_table, spi);
>
> @@ -888,6 +894,196 @@ static void of_register_spi_devices(struct spi_master *master)
> static void of_register_spi_devices(struct spi_master *master) { }
> #endif
>
> +#ifdef CONFIG_ACPI
> +static int acpi_spi_add_resource(struct acpi_resource *ares, void *data)
> +{
> + struct acpi_resource_spi_serialbus *sb;
> + struct spi_device *spi = data;
> +
> + if (ares->type != ACPI_RESOURCE_TYPE_SERIAL_BUS)
> + return 0;
> +
> + sb = &ares->data.spi_serial_bus;
> + if (sb->type != ACPI_RESOURCE_SERIAL_TYPE_SPI)
> + return 0;
> +
> + spi->chip_select = sb->device_selection;
> + spi->max_speed_hz = sb->connection_speed;
> +
> + if (sb->clock_phase == ACPI_SPI_SECOND_PHASE)
> + spi->mode |= SPI_CPHA;
> + if (sb->clock_polarity == ACPI_SPI_START_HIGH)
> + spi->mode |= SPI_CPOL;
> + if (sb->device_polarity == ACPI_SPI_ACTIVE_HIGH)
> + spi->mode |= SPI_CS_HIGH;
> +
> + return 1;
> +}
> +
> +static acpi_status acpi_spi_add_device(acpi_handle handle, u32 level,
> + void *data, void **return_value)
> +{
> + struct spi_master *master = data;
> + struct resource_list_entry *rentry;
> + struct list_head resource_list;
> + struct acpi_device *adev;
> + struct spi_device *spi;
> + int ret;
> +
> + if (acpi_bus_get_device(handle, &adev))
> + return AE_OK;
> + if (acpi_bus_get_status(adev) || !adev->status.present)
> + return AE_OK;
> +
> + spi = spi_alloc_device(master);
> + if (!spi) {
> + dev_err(&master->dev, "failed to allocate SPI device for %s\n",
> + dev_name(&adev->dev));
> + return AE_NO_MEMORY;
> + }
> +
> + INIT_LIST_HEAD(&resource_list);
> + ret = acpi_dev_get_resources(adev, &resource_list,
> + acpi_spi_add_resource, spi);
> + if (ret < 0)
> + goto fail_put_dev;
> +
> + list_for_each_entry(rentry, &resource_list, node) {
> + struct resource *r = &rentry->res;
> +
> + if (resource_type(r) == IORESOURCE_IRQ) {
> + spi->irq = r->start;
> + break;
> + }
> + }
> +
> + acpi_dev_free_resource_list(&resource_list);

A potential problem is lurking here, or rather two of them.

Suppose there are multiple IRQ resources for this device. The code
above will cause GSIs to be registered for all of them, but we'll
use only one eventually. Moreover, we'll use the last one, but
perhaps we should use the first one instead?

Maybe a better approach would be to make acpi_spi_add_resource()
call acpi_dev_resource_interrupt(ares, 0, &r) directly and then skip all of
the remaining IRQ resources if it finds one?

For example set spi->irq to -1 initially, assign it if an IRQ
resource is found and skip all of the remaining IRQ resources if
it is non-negative?

Rafael


--
I speak only for myself.
Rafael J. Wysocki, Intel Open Source Technology Center.

2012-11-17 10:15:52

by Mika Westerberg

[permalink] [raw]
Subject: Re: [PATCH v2 2/3] spi / ACPI: add ACPI enumeration support

On Sat, Nov 17, 2012 at 11:11:59AM +0100, Rafael J. Wysocki wrote:
> > +static acpi_status acpi_spi_add_device(acpi_handle handle, u32 level,
> > + void *data, void **return_value)
> > +{
> > + struct spi_master *master = data;
> > + struct resource_list_entry *rentry;
> > + struct list_head resource_list;
> > + struct acpi_device *adev;
> > + struct spi_device *spi;
> > + int ret;
> > +
> > + if (acpi_bus_get_device(handle, &adev))
> > + return AE_OK;
> > + if (acpi_bus_get_status(adev) || !adev->status.present)
> > + return AE_OK;
> > +
> > + spi = spi_alloc_device(master);
> > + if (!spi) {
> > + dev_err(&master->dev, "failed to allocate SPI device for %s\n",
> > + dev_name(&adev->dev));
> > + return AE_NO_MEMORY;
> > + }
> > +
> > + INIT_LIST_HEAD(&resource_list);
> > + ret = acpi_dev_get_resources(adev, &resource_list,
> > + acpi_spi_add_resource, spi);
> > + if (ret < 0)
> > + goto fail_put_dev;
> > +
> > + list_for_each_entry(rentry, &resource_list, node) {
> > + struct resource *r = &rentry->res;
> > +
> > + if (resource_type(r) == IORESOURCE_IRQ) {
> > + spi->irq = r->start;
> > + break;
> > + }
> > + }
> > +
> > + acpi_dev_free_resource_list(&resource_list);
>
> A potential problem is lurking here, or rather two of them.
>
> Suppose there are multiple IRQ resources for this device. The code
> above will cause GSIs to be registered for all of them, but we'll
> use only one eventually. Moreover, we'll use the last one, but
> perhaps we should use the first one instead?

Indeed we should use the first one.

> Maybe a better approach would be to make acpi_spi_add_resource()
> call acpi_dev_resource_interrupt(ares, 0, &r) directly and then skip all of
> the remaining IRQ resources if it finds one?
>
> For example set spi->irq to -1 initially, assign it if an IRQ
> resource is found and skip all of the remaining IRQ resources if
> it is non-negative?

OK, will do. Thanks.

2012-11-17 11:20:25

by Rafael J. Wysocki

[permalink] [raw]
Subject: Re: [PATCH v2 3/3 UPDATED] i2c / ACPI: add ACPI enumeration support

On Saturday, November 17, 2012 10:03:54 AM Mika Westerberg wrote:
> On Fri, Nov 16, 2012 at 11:46:40PM -0700, Bjorn Helgaas wrote:

[...]

> > In any event, after acpi_i2c_register(), I think we have a set of
> > i2c_client devices (with the above namespace, I assume we'd have two
> > of them). I guess acpi_i2c_find_device() is useful now -- it looks
> > like it takes a "struct device *" (e.g., &client->dev from a struct
> > i2c_client), and and gives you back the acpi_handle corresponding to
> > it?
> >
> > Here's the callchain of that path:
> >
> > acpi_i2c_find_device(struct device *) # acpi_i2c_bus.find_device
> > i2c_verify_client(dev)
> > acpi_walk_namespace
> > acpi_i2c_find_child
> > acpi_bus_get_device
> > acpi_bus_get_status
> > acpi_dev_get_resources(..., acpi_i2c_find_child_address, ...)
> > acpi_i2c_find_child_address
> > found if (SERIAL_BUS && SERIAL_TYPE_I2C && slave_address == xx)
> > acpi_dev_free_resource_list
> > *handle = handle
> >
> > That seems like an awful lot of work to do just to map a struct device
> > * back to the acpi_handle. But I don't have any suggestion; just that
> > observation.
>
> We had similar discussion internally about not using that
> drivers/acpi/glue.c but we decided to use it for now, even if it really
> backwards and makes things hard (like you observed as well). A much better
> way would be just to assign the handle once we make the device but it
> seemed not to be that simple after all.

The problem basically is that acpi_bind_one() creates the "physical_node"
and "firmware_node" sysfs files, so both directories of the device nodes
involved need to exist at this point. Moreover, we want it to be called
before a driver is probed, so that the driver's .probe() routine can use
the information available from ACPI. This means it needs to be called
from device_add() and more-or-less where platform_notify() is called.

That's the reason why we decided to use the code in glue.c for the time
being. If you see a better way to do that, however, I'll be happy to
implement it. :-)

Well, maybe there is one. Perhaps we can make acpi_platform_notify()
call acpi_bind_one() upfront and only if that fails, do the whole
type->find_device() dance? Of course, acpi_bind_one() would need to
be modified slightly too, like in the patch below.

If we did that, acpi_i2c_add_device() would only need to assign acpi_handle
as appropriate before calling i2c_new_device() (and analogously for SPI).

What do you think?

Rafael


---
drivers/acpi/glue.c | 40 +++++++++++++++++++++++++++++++---------
1 file changed, 31 insertions(+), 9 deletions(-)

Index: linux/drivers/acpi/glue.c
===================================================================
--- linux.orig/drivers/acpi/glue.c
+++ linux/drivers/acpi/glue.c
@@ -135,8 +135,12 @@ static int acpi_bind_one(struct device *
int retval = -EINVAL;

if (dev->acpi_handle) {
- dev_warn(dev, "Drivers changed 'acpi_handle'\n");
- return -EINVAL;
+ if (handle) {
+ dev_warn(dev, "ACPI handle is already set\n");
+ return -EINVAL;
+ } else {
+ handle = dev->acpi_handle;
+ }
}

get_device(dev);
@@ -144,32 +148,40 @@ static int acpi_bind_one(struct device *
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(physical_node, &acpi_dev->physical_node_list, node)
+ if (physical_node->dev == dev) {
+ dev_warn(dev, "Already associated with ACPI node\n");
+ retval = -EINVAL;
+ 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->acpi_handle = handle;
+ if (!dev->acpi_handle)
+ dev->acpi_handle = handle;

if (!physical_node->node_id)
strcpy(physical_node_name, PHYSICAL_NODE_STRING);
@@ -189,6 +201,11 @@ static int acpi_bind_one(struct device *
err:
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)
@@ -247,6 +264,10 @@ static int acpi_platform_notify(struct d
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);
@@ -260,10 +281,11 @@ static int acpi_platform_notify(struct d
}
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 };


--
I speak only for myself.
Rafael J. Wysocki, Intel Open Source Technology Center.

2012-11-18 15:52:32

by Mika Westerberg

[permalink] [raw]
Subject: Re: [PATCH v2 3/3 UPDATED] i2c / ACPI: add ACPI enumeration support

On Sat, Nov 17, 2012 at 12:24:45PM +0100, Rafael J. Wysocki wrote:
> Well, maybe there is one. Perhaps we can make acpi_platform_notify()
> call acpi_bind_one() upfront and only if that fails, do the whole
> type->find_device() dance? Of course, acpi_bind_one() would need to
> be modified slightly too, like in the patch below.
>
> If we did that, acpi_i2c_add_device() would only need to assign acpi_handle
> as appropriate before calling i2c_new_device() (and analogously for SPI).
>
> What do you think?

This is certainly better than the thing we use currently. It makes adding
I2C and SPI support much shorter and simpler. If others don't object I
would suggest that we switch to use this method.

2012-11-18 21:11:03

by Rafael J. Wysocki

[permalink] [raw]
Subject: [PATCH 2/2] ACPI / platform: Initialize ACPI handles of platform devices in advance

From: Rafael J. Wysocki <[email protected]>

The current platform device creation and registration code in
acpi_create_platform_device() is quite convoluted. This function
takes an ACPI device node as an argument and eventually calls
platform_device_register_resndata() to create and register a
platform device object on the basis of the information contained
in that code. However, it doesn't associate the new platform
device with the ACPI node directly, but instead it relies on
acpi_platform_notify(), called from within device_add(), to find
that ACPI node again with the help of acpi_platform_find_device()
and acpi_platform_match() and then attach the new platform device
to it. This causes an additional ACPI namespace walk to happen and
is clearly suboptimal.

Use the observation that it is now possible to initialize the ACPI
handle of a device before calling device_add() for it to make this
code more straightforward. Namely, add a new field to struct
platform_device_info allowing us to pass the ACPI handle of interest
to platform_device_register_full(), which will then use it to
initialize the new device's ACPI handle before registering it.
This will cause acpi_platform_notify() to use the ACPI handle from
the device structure directly instead of using the .find_device()
routine provided by the device's bus type. In consequence,
acpi_platform_bus, acpi_platform_find_device(), and
acpi_platform_match() are not necessary any more, so remove them.

Signed-off-by: Rafael J. Wysocki <[email protected]>
---
drivers/acpi/acpi_platform.c | 76 +++++-----------------------------------
drivers/base/platform.c | 2 +
include/linux/platform_device.h | 1
3 files changed, 13 insertions(+), 66 deletions(-)

Index: linux/include/linux/platform_device.h
===================================================================
--- linux.orig/include/linux/platform_device.h
+++ linux/include/linux/platform_device.h
@@ -55,6 +55,7 @@ extern int platform_add_devices(struct p

struct platform_device_info {
struct device *parent;
+ void *acpi_handle;

const char *name;
int id;
Index: linux/drivers/acpi/acpi_platform.c
===================================================================
--- linux.orig/drivers/acpi/acpi_platform.c
+++ linux/drivers/acpi/acpi_platform.c
@@ -33,7 +33,7 @@ struct platform_device *acpi_create_plat
{
struct platform_device *pdev = NULL;
struct acpi_device *acpi_parent;
- struct device *parent = NULL;
+ struct platform_device_info pdevinfo;
struct resource_list_entry *rentry;
struct list_head resource_list;
struct resource *resources;
@@ -60,11 +60,13 @@ struct platform_device *acpi_create_plat

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;
@@ -76,12 +78,16 @@ struct platform_device *acpi_create_plat
entry = list_first_entry(list,
struct acpi_device_physical_node,
node);
- parent = entry->dev;
+ pdevinfo.parent = entry->dev;
}
mutex_unlock(&acpi_parent->physical_node_lock);
}
- pdev = platform_device_register_resndata(parent, dev_name(&adev->dev),
- -1, resources, count, NULL, 0);
+ pdevinfo.name = dev_name(&adev->dev);
+ pdevinfo.id = -1;
+ pdevinfo.res = resources;
+ pdevinfo.num_res = count;
+ pdevinfo.acpi_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));
@@ -94,65 +100,3 @@ struct platform_device *acpi_create_plat
kfree(resources);
return pdev;
}
-
-static acpi_status acpi_platform_match(acpi_handle handle, u32 depth,
- void *data, void **return_value)
-{
- struct platform_device *pdev = data;
- struct acpi_device *adev;
- acpi_status status;
-
- status = acpi_bus_get_device(handle, &adev);
- if (ACPI_FAILURE(status))
- return status;
-
- /* Skip ACPI devices that have physical device attached */
- if (adev->physical_node_count)
- return AE_OK;
-
- if (!strcmp(dev_name(&pdev->dev), dev_name(&adev->dev))) {
- *(acpi_handle *)return_value = handle;
- return AE_CTRL_TERMINATE;
- }
-
- return AE_OK;
-}
-
-static int acpi_platform_find_device(struct device *dev, acpi_handle *handle)
-{
- struct platform_device *pdev = to_platform_device(dev);
- char *name, *tmp, *hid;
-
- /*
- * The platform device is named using the ACPI device name
- * _HID:INSTANCE so we strip the INSTANCE out in order to find the
- * correct device using its _HID.
- */
- name = kstrdup(dev_name(dev), GFP_KERNEL);
- if (!name)
- return -ENOMEM;
-
- tmp = name;
- hid = strsep(&tmp, ":");
- if (!hid) {
- kfree(name);
- return -ENODEV;
- }
-
- *handle = NULL;
- acpi_get_devices(hid, acpi_platform_match, pdev, handle);
-
- kfree(name);
- return *handle ? 0 : -ENODEV;
-}
-
-static struct acpi_bus_type acpi_platform_bus = {
- .bus = &platform_bus_type,
- .find_device = acpi_platform_find_device,
-};
-
-static int __init acpi_platform_init(void)
-{
- return register_acpi_bus_type(&acpi_platform_bus);
-}
-arch_initcall(acpi_platform_init);
Index: linux/drivers/base/platform.c
===================================================================
--- linux.orig/drivers/base/platform.c
+++ linux/drivers/base/platform.c
@@ -437,6 +437,7 @@ struct platform_device *platform_device_
goto err_alloc;

pdev->dev.parent = pdevinfo->parent;
+ pdev->dev.acpi_handle = pdevinfo->acpi_handle;

if (pdevinfo->dma_mask) {
/*
@@ -467,6 +468,7 @@ struct platform_device *platform_device_
ret = platform_device_add(pdev);
if (ret) {
err:
+ pdev->dev.acpi_handle = NULL;
kfree(pdev->dev.dma_mask);

err_alloc:

2012-11-18 21:11:25

by Rafael J. Wysocki

[permalink] [raw]
Subject: [PATCH 1/2] ACPI: Allow ACPI handles of devices to be initialized in advance

From: Rafael J. Wysocki <[email protected]>

Currently, the ACPI handles of devices are initialized from within
device_add(), by acpi_bind_one() called from acpi_platform_notify()
which first uses the .find_device() routine provided by the device's
bus type to find the matching device node in the ACPI namespace.
This is a source of some computational overhead and, moreover, the
correctness of the result depends on the implementation of
.find_device() which is known to fail occasionally for some bus types
(e.g. PCI). In some cases, however, the corresponding ACPI device
node is known already before calling device_add() for the given
struct device object and the whole .find_device() dance in
acpi_platform_notify() is then simply unnecessary.

For this reason, make it possible to initialize the ACPI handles of
devices before calling device_add() for them. Modify
acpi_platform_notify() to call acpi_bind_one() in advance to check
the device's existing ACPI handle and skip the .find_device()
search if that is successful. Change acpi_bind_one() accordingly.

Signed-off-by: Rafael J. Wysocki <[email protected]>
---
drivers/acpi/glue.c | 42 +++++++++++++++++++++++++++++++++---------
1 file changed, 33 insertions(+), 9 deletions(-)

Index: linux/drivers/acpi/glue.c
===================================================================
--- linux.orig/drivers/acpi/glue.c
+++ linux/drivers/acpi/glue.c
@@ -135,41 +135,54 @@ static int acpi_bind_one(struct device *
int retval = -EINVAL;

if (dev->acpi_handle) {
- dev_warn(dev, "Drivers changed 'acpi_handle'\n");
- return -EINVAL;
+ if (handle) {
+ dev_warn(dev, "ACPI handle is already set\n");
+ return -EINVAL;
+ } else {
+ handle = dev->acpi_handle;
+ }
}
+ 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(physical_node, &acpi_dev->physical_node_list, node)
+ if (physical_node->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->acpi_handle = handle;
+ if (!dev->acpi_handle)
+ dev->acpi_handle = handle;

if (!physical_node->node_id)
strcpy(physical_node_name, PHYSICAL_NODE_STRING);
@@ -187,8 +200,14 @@ static int acpi_bind_one(struct device *
return 0;

err:
+ dev->acpi_handle = 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)
@@ -247,6 +266,10 @@ static int acpi_platform_notify(struct d
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);
@@ -260,10 +283,11 @@ static int acpi_platform_notify(struct d
}
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 };

2012-11-18 21:11:21

by Rafael J. Wysocki

[permalink] [raw]
Subject: [PATCH 0/2] ACPI: Simplify "glueing" to physical nodes (was: Re: [PATCH v2 3/3 UPDATED] i2c / ACPI: add ACPI enumeration support)

On Sunday, November 18, 2012 05:55:39 PM Mika Westerberg wrote:
> On Sat, Nov 17, 2012 at 12:24:45PM +0100, Rafael J. Wysocki wrote:
> > Well, maybe there is one. Perhaps we can make acpi_platform_notify()
> > call acpi_bind_one() upfront and only if that fails, do the whole
> > type->find_device() dance? Of course, acpi_bind_one() would need to
> > be modified slightly too, like in the patch below.
> >
> > If we did that, acpi_i2c_add_device() would only need to assign acpi_handle
> > as appropriate before calling i2c_new_device() (and analogously for SPI).
> >
> > What do you think?
>
> This is certainly better than the thing we use currently. It makes adding
> I2C and SPI support much shorter and simpler. If others don't object I
> would suggest that we switch to use this method.

OK, thanks.

The first of the following two patches is a slightly modified version of the
one that you commented. Patch [2/2] implements the idea for platform devices
and since it modifies struct platform_device_info, I'm adding a CC to Greg.

The patches are on top of current linux-pm.git/linux-next.

It looks like we may be able to use this approach for PCI too, in which case
the whole .find_device() stuff won't be necessary any more.

Thanks,
Rafael


--
I speak only for myself.
Rafael J. Wysocki, Intel Open Source Technology Center.

2012-11-19 09:39:26

by Mika Westerberg

[permalink] [raw]
Subject: Re: [PATCH 1/2] ACPI: Allow ACPI handles of devices to be initialized in advance

On Sun, Nov 18, 2012 at 10:12:52PM +0100, Rafael J. Wysocki wrote:
> From: Rafael J. Wysocki <[email protected]>
>
> Currently, the ACPI handles of devices are initialized from within
> device_add(), by acpi_bind_one() called from acpi_platform_notify()
> which first uses the .find_device() routine provided by the device's
> bus type to find the matching device node in the ACPI namespace.
> This is a source of some computational overhead and, moreover, the
> correctness of the result depends on the implementation of
> .find_device() which is known to fail occasionally for some bus types
> (e.g. PCI). In some cases, however, the corresponding ACPI device
> node is known already before calling device_add() for the given
> struct device object and the whole .find_device() dance in
> acpi_platform_notify() is then simply unnecessary.
>
> For this reason, make it possible to initialize the ACPI handles of
> devices before calling device_add() for them. Modify
> acpi_platform_notify() to call acpi_bind_one() in advance to check
> the device's existing ACPI handle and skip the .find_device()
> search if that is successful. Change acpi_bind_one() accordingly.
>
> Signed-off-by: Rafael J. Wysocki <[email protected]>
> ---
> drivers/acpi/glue.c | 42 +++++++++++++++++++++++++++++++++---------
> 1 file changed, 33 insertions(+), 9 deletions(-)
>
> Index: linux/drivers/acpi/glue.c
> ===================================================================
> --- linux.orig/drivers/acpi/glue.c
> +++ linux/drivers/acpi/glue.c
> @@ -135,41 +135,54 @@ static int acpi_bind_one(struct device *
> int retval = -EINVAL;
>
> if (dev->acpi_handle) {
> - dev_warn(dev, "Drivers changed 'acpi_handle'\n");
> - return -EINVAL;
> + if (handle) {
> + dev_warn(dev, "ACPI handle is already set\n");
> + return -EINVAL;
> + } else {
> + handle = dev->acpi_handle;
> + }
> }
> + 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);

Here we allocate memory for the physical node...

> if (!physical_node) {
> retval = -ENOMEM;
> goto err;
> }
>
> mutex_lock(&acpi_dev->physical_node_lock);
> +
> + /* Sanity check. */
> + list_for_each_entry(physical_node, &acpi_dev->physical_node_list, node)

.. and overwrite it here ;-)

Maybe using a different variable for the sanity check?

I've changed the SPI/I2C patches to use this as well and they got a lot
smaller as we don't have to do the .find_device() magic.

Once you have fixed the above, you can add my

Reviewed-by: Mika Westerberg <[email protected]>

to these two patches, if you like.

2012-11-19 12:29:19

by Rafael J. Wysocki

[permalink] [raw]
Subject: [Update][PATCH 1/2] ACPI: Allow ACPI handles of devices to be initialized in advance

On Monday, November 19, 2012 11:42:34 AM Mika Westerberg wrote:
> On Sun, Nov 18, 2012 at 10:12:52PM +0100, Rafael J. Wysocki wrote:
> > From: Rafael J. Wysocki <[email protected]>
> >
> > Currently, the ACPI handles of devices are initialized from within
> > device_add(), by acpi_bind_one() called from acpi_platform_notify()
> > which first uses the .find_device() routine provided by the device's
> > bus type to find the matching device node in the ACPI namespace.
> > This is a source of some computational overhead and, moreover, the
> > correctness of the result depends on the implementation of
> > .find_device() which is known to fail occasionally for some bus types
> > (e.g. PCI). In some cases, however, the corresponding ACPI device
> > node is known already before calling device_add() for the given
> > struct device object and the whole .find_device() dance in
> > acpi_platform_notify() is then simply unnecessary.
> >
> > For this reason, make it possible to initialize the ACPI handles of
> > devices before calling device_add() for them. Modify
> > acpi_platform_notify() to call acpi_bind_one() in advance to check
> > the device's existing ACPI handle and skip the .find_device()
> > search if that is successful. Change acpi_bind_one() accordingly.
> >
> > Signed-off-by: Rafael J. Wysocki <[email protected]>
> > ---
> > drivers/acpi/glue.c | 42 +++++++++++++++++++++++++++++++++---------
> > 1 file changed, 33 insertions(+), 9 deletions(-)
> >
> > Index: linux/drivers/acpi/glue.c
> > ===================================================================
> > --- linux.orig/drivers/acpi/glue.c
> > +++ linux/drivers/acpi/glue.c
> > @@ -135,41 +135,54 @@ static int acpi_bind_one(struct device *
> > int retval = -EINVAL;
> >
> > if (dev->acpi_handle) {
> > - dev_warn(dev, "Drivers changed 'acpi_handle'\n");
> > - return -EINVAL;
> > + if (handle) {
> > + dev_warn(dev, "ACPI handle is already set\n");
> > + return -EINVAL;
> > + } else {
> > + handle = dev->acpi_handle;
> > + }
> > }
> > + 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);
>
> Here we allocate memory for the physical node...
>
> > if (!physical_node) {
> > retval = -ENOMEM;
> > goto err;
> > }
> >
> > mutex_lock(&acpi_dev->physical_node_lock);
> > +
> > + /* Sanity check. */
> > + list_for_each_entry(physical_node, &acpi_dev->physical_node_list, node)
>
> .. and overwrite it here ;-)

Ah, good catch!

> Maybe using a different variable for the sanity check?

Yeah, I wanted to be overly smart. :-)

> I've changed the SPI/I2C patches to use this as well and they got a lot
> smaller as we don't have to do the .find_device() magic.
>
> Once you have fixed the above, you can add my
>
> Reviewed-by: Mika Westerberg <[email protected]>
>
> to these two patches, if you like.

I will.

In the meantime, updated patch is appended.

Thanks,
Rafael


---
From: Rafael J. Wysocki <[email protected]>
Subject: ACPI: Allow ACPI handles of devices to be initialized in advance

Currently, the ACPI handles of devices are initialized from within
device_add(), by acpi_bind_one() called from acpi_platform_notify()
which first uses the .find_device() routine provided by the device's
bus type to find the matching device node in the ACPI namespace.
This is a source of some computational overhead and, moreover, the
correctness of the result depends on the implementation of
.find_device() which is known to fail occasionally for some bus types
(e.g. PCI). In some cases, however, the corresponding ACPI device
node is known already before calling device_add() for the given
struct device object and the whole .find_device() dance in
acpi_platform_notify() is then simply unnecessary.

For this reason, make it possible to initialize the ACPI handles of
devices before calling device_add() for them. Modify
acpi_platform_notify() to call acpi_bind_one() in advance to check
the device's existing ACPI handle and skip the .find_device()
search if that is successful. Change acpi_bind_one() accordingly.

Signed-off-by: Rafael J. Wysocki <[email protected]>
---
drivers/acpi/glue.c | 44 ++++++++++++++++++++++++++++++++++----------
1 file changed, 34 insertions(+), 10 deletions(-)

Index: linux/drivers/acpi/glue.c
===================================================================
--- linux.orig/drivers/acpi/glue.c
+++ linux/drivers/acpi/glue.c
@@ -130,46 +130,59 @@ static int acpi_bind_one(struct device *
{
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->acpi_handle) {
- dev_warn(dev, "Drivers changed 'acpi_handle'\n");
- return -EINVAL;
+ if (handle) {
+ dev_warn(dev, "ACPI handle is already set\n");
+ return -EINVAL;
+ } else {
+ handle = dev->acpi_handle;
+ }
}
+ 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->acpi_handle = handle;
+ if (!dev->acpi_handle)
+ dev->acpi_handle = handle;

if (!physical_node->node_id)
strcpy(physical_node_name, PHYSICAL_NODE_STRING);
@@ -187,8 +200,14 @@ static int acpi_bind_one(struct device *
return 0;

err:
+ dev->acpi_handle = 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)
@@ -247,6 +266,10 @@ static int acpi_platform_notify(struct d
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);
@@ -260,10 +283,11 @@ static int acpi_platform_notify(struct d
}
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 };


--
I speak only for myself.
Rafael J. Wysocki, Intel Open Source Technology Center.

2012-11-19 16:23:42

by Greg Kroah-Hartman

[permalink] [raw]
Subject: Re: [PATCH 2/2] ACPI / platform: Initialize ACPI handles of platform devices in advance

On Sun, Nov 18, 2012 at 10:13:59PM +0100, Rafael J. Wysocki wrote:
> From: Rafael J. Wysocki <[email protected]>
>
> The current platform device creation and registration code in
> acpi_create_platform_device() is quite convoluted. This function
> takes an ACPI device node as an argument and eventually calls
> platform_device_register_resndata() to create and register a
> platform device object on the basis of the information contained
> in that code. However, it doesn't associate the new platform
> device with the ACPI node directly, but instead it relies on
> acpi_platform_notify(), called from within device_add(), to find
> that ACPI node again with the help of acpi_platform_find_device()
> and acpi_platform_match() and then attach the new platform device
> to it. This causes an additional ACPI namespace walk to happen and
> is clearly suboptimal.
>
> Use the observation that it is now possible to initialize the ACPI
> handle of a device before calling device_add() for it to make this
> code more straightforward. Namely, add a new field to struct
> platform_device_info allowing us to pass the ACPI handle of interest
> to platform_device_register_full(), which will then use it to
> initialize the new device's ACPI handle before registering it.
> This will cause acpi_platform_notify() to use the ACPI handle from
> the device structure directly instead of using the .find_device()
> routine provided by the device's bus type. In consequence,
> acpi_platform_bus, acpi_platform_find_device(), and
> acpi_platform_match() are not necessary any more, so remove them.

Why can't you use the platform_data * that is already in struct device
for this, instead of adding an acpi-specific field to the
platform_device structure?

If not that, surely there is another field in struct device that you
could use that is free for this type of device?

> struct platform_device_info {
> struct device *parent;
> + void *acpi_handle;

Oh, and if I do accept this, I want a "real" structure pointer here
please, not a void * "handle". That way is a slippery slope to the
Windows kernel programming style :)

thanks,

greg k-h

2012-11-19 17:27:42

by Rafael J. Wysocki

[permalink] [raw]
Subject: Re: [PATCH 2/2] ACPI / platform: Initialize ACPI handles of platform devices in advance

On Monday, November 19, 2012 08:23:34 AM Greg Kroah-Hartman wrote:
> On Sun, Nov 18, 2012 at 10:13:59PM +0100, Rafael J. Wysocki wrote:
> > From: Rafael J. Wysocki <[email protected]>
> >
> > The current platform device creation and registration code in
> > acpi_create_platform_device() is quite convoluted. This function
> > takes an ACPI device node as an argument and eventually calls
> > platform_device_register_resndata() to create and register a
> > platform device object on the basis of the information contained
> > in that code. However, it doesn't associate the new platform
> > device with the ACPI node directly, but instead it relies on
> > acpi_platform_notify(), called from within device_add(), to find
> > that ACPI node again with the help of acpi_platform_find_device()
> > and acpi_platform_match() and then attach the new platform device
> > to it. This causes an additional ACPI namespace walk to happen and
> > is clearly suboptimal.
> >
> > Use the observation that it is now possible to initialize the ACPI
> > handle of a device before calling device_add() for it to make this
> > code more straightforward. Namely, add a new field to struct
> > platform_device_info allowing us to pass the ACPI handle of interest
> > to platform_device_register_full(), which will then use it to
> > initialize the new device's ACPI handle before registering it.
> > This will cause acpi_platform_notify() to use the ACPI handle from
> > the device structure directly instead of using the .find_device()
> > routine provided by the device's bus type. In consequence,
> > acpi_platform_bus, acpi_platform_find_device(), and
> > acpi_platform_match() are not necessary any more, so remove them.
>
> Why can't you use the platform_data * that is already in struct device
> for this, instead of adding an acpi-specific field to the
> platform_device structure?

Hmm, I kind of don't understand the question. :-)

Yes, we have acpi_handle in struct device (it actually is being added by a
patch you've acked) and we use it. The whole point here is to streamline
of the initalization of that field.

> If not that, surely there is another field in struct device that you
> could use that is free for this type of device?

Yes, there is one and as I said above. :-)

I'd be happy to use the struct device's field directly, but
platform_device_register_full() allocates memory for the struct device in
question, so that field actually doesn't exist yet when it is called.

> > struct platform_device_info {
> > struct device *parent;
> > + void *acpi_handle;
>
> Oh, and if I do accept this, I want a "real" structure pointer here
> please, not a void * "handle". That way is a slippery slope to the
> Windows kernel programming style :)

This is (void *), because the field being initialized is (void *). That field,
in turn, is (void *), because ACPICA defines it that way. I thought about
wrapping that in some more meaningless data type, but I did't find a way
that would work both when CONFIG_ACPI is set and when it is not. If you
have an idea how to do that in a clean way, I'd be happy to implement it. :-)

Thanks,
Rafael


--
I speak only for myself.
Rafael J. Wysocki, Intel Open Source Technology Center.

2012-11-19 17:40:57

by Rafael J. Wysocki

[permalink] [raw]
Subject: Re: [PATCH 2/2] ACPI / platform: Initialize ACPI handles of platform devices in advance

On Monday, November 19, 2012 06:32:06 PM Rafael J. Wysocki wrote:
> On Monday, November 19, 2012 08:23:34 AM Greg Kroah-Hartman wrote:
> > On Sun, Nov 18, 2012 at 10:13:59PM +0100, Rafael J. Wysocki wrote:
> > > From: Rafael J. Wysocki <[email protected]>
> > >
> > > The current platform device creation and registration code in
> > > acpi_create_platform_device() is quite convoluted. This function
> > > takes an ACPI device node as an argument and eventually calls
> > > platform_device_register_resndata() to create and register a
> > > platform device object on the basis of the information contained
> > > in that code. However, it doesn't associate the new platform
> > > device with the ACPI node directly, but instead it relies on
> > > acpi_platform_notify(), called from within device_add(), to find
> > > that ACPI node again with the help of acpi_platform_find_device()
> > > and acpi_platform_match() and then attach the new platform device
> > > to it. This causes an additional ACPI namespace walk to happen and
> > > is clearly suboptimal.
> > >
> > > Use the observation that it is now possible to initialize the ACPI
> > > handle of a device before calling device_add() for it to make this
> > > code more straightforward. Namely, add a new field to struct
> > > platform_device_info allowing us to pass the ACPI handle of interest
> > > to platform_device_register_full(), which will then use it to
> > > initialize the new device's ACPI handle before registering it.
> > > This will cause acpi_platform_notify() to use the ACPI handle from
> > > the device structure directly instead of using the .find_device()
> > > routine provided by the device's bus type. In consequence,
> > > acpi_platform_bus, acpi_platform_find_device(), and
> > > acpi_platform_match() are not necessary any more, so remove them.
> >
> > Why can't you use the platform_data * that is already in struct device
> > for this, instead of adding an acpi-specific field to the
> > platform_device structure?
>
> Hmm, I kind of don't understand the question. :-)
>
> Yes, we have acpi_handle in struct device (it actually is being added by a
> patch you've acked) and we use it. The whole point here is to streamline
> of the initalization of that field.
>
> > If not that, surely there is another field in struct device that you
> > could use that is free for this type of device?
>
> Yes, there is one and as I said above. :-)
>
> I'd be happy to use the struct device's field directly, but
> platform_device_register_full() allocates memory for the struct device in
> question, so that field actually doesn't exist yet when it is called.
>
> > > struct platform_device_info {
> > > struct device *parent;
> > > + void *acpi_handle;
> >
> > Oh, and if I do accept this, I want a "real" structure pointer here
> > please, not a void * "handle". That way is a slippery slope to the
> > Windows kernel programming style :)
>
> This is (void *), because the field being initialized is (void *). That field,
> in turn, is (void *), because ACPICA defines it that way. I thought about
> wrapping that in some more meaningless data type, but I did't find a way

s/meaningless/meaningful/

(/me hides)


--
I speak only for myself.
Rafael J. Wysocki, Intel Open Source Technology Center.

2012-11-19 18:20:44

by Rafael J. Wysocki

[permalink] [raw]
Subject: Re: [PATCH 2/2] ACPI / platform: Initialize ACPI handles of platform devices in advance

On Monday, November 19, 2012 06:32:06 PM Rafael J. Wysocki wrote:
> On Monday, November 19, 2012 08:23:34 AM Greg Kroah-Hartman wrote:
> > On Sun, Nov 18, 2012 at 10:13:59PM +0100, Rafael J. Wysocki wrote:
> > > From: Rafael J. Wysocki <[email protected]>
> > >
> > > The current platform device creation and registration code in
> > > acpi_create_platform_device() is quite convoluted. This function
> > > takes an ACPI device node as an argument and eventually calls
> > > platform_device_register_resndata() to create and register a
> > > platform device object on the basis of the information contained
> > > in that code. However, it doesn't associate the new platform
> > > device with the ACPI node directly, but instead it relies on
> > > acpi_platform_notify(), called from within device_add(), to find
> > > that ACPI node again with the help of acpi_platform_find_device()
> > > and acpi_platform_match() and then attach the new platform device
> > > to it. This causes an additional ACPI namespace walk to happen and
> > > is clearly suboptimal.
> > >
> > > Use the observation that it is now possible to initialize the ACPI
> > > handle of a device before calling device_add() for it to make this
> > > code more straightforward. Namely, add a new field to struct
> > > platform_device_info allowing us to pass the ACPI handle of interest
> > > to platform_device_register_full(), which will then use it to
> > > initialize the new device's ACPI handle before registering it.
> > > This will cause acpi_platform_notify() to use the ACPI handle from
> > > the device structure directly instead of using the .find_device()
> > > routine provided by the device's bus type. In consequence,
> > > acpi_platform_bus, acpi_platform_find_device(), and
> > > acpi_platform_match() are not necessary any more, so remove them.
> >
> > Why can't you use the platform_data * that is already in struct device
> > for this, instead of adding an acpi-specific field to the
> > platform_device structure?
>
> Hmm, I kind of don't understand the question. :-)
>
> Yes, we have acpi_handle in struct device (it actually is being added by a
> patch you've acked) and we use it. The whole point here is to streamline
> of the initalization of that field.
>
> > If not that, surely there is another field in struct device that you
> > could use that is free for this type of device?
>
> Yes, there is one and as I said above. :-)
>
> I'd be happy to use the struct device's field directly, but
> platform_device_register_full() allocates memory for the struct device in
> question, so that field actually doesn't exist yet when it is called.

So what happens is we want to use platform_device_register_full(), because
it initializes a struct platform_device for use and registers it for us, so we
don't need to worry about all that. However, platform_device_register_full()
also creates the struct platform_device it registers and we need to let it
know what value to put into the acpi_handle field of that struct platform_device
object's struct device component. That's what this all is about. :-)

Thanks,
Rafael


--
I speak only for myself.
Rafael J. Wysocki, Intel Open Source Technology Center.

2012-11-19 20:39:57

by Rafael J. Wysocki

[permalink] [raw]
Subject: Re: [PATCH 2/2] ACPI / platform: Initialize ACPI handles of platform devices in advance

On Monday, November 19, 2012 06:45:22 PM Rafael J. Wysocki wrote:
> On Monday, November 19, 2012 06:32:06 PM Rafael J. Wysocki wrote:
> > On Monday, November 19, 2012 08:23:34 AM Greg Kroah-Hartman wrote:
> > > On Sun, Nov 18, 2012 at 10:13:59PM +0100, Rafael J. Wysocki wrote:
> > > > From: Rafael J. Wysocki <[email protected]>
> > > >
> > > > The current platform device creation and registration code in
> > > > acpi_create_platform_device() is quite convoluted. This function
> > > > takes an ACPI device node as an argument and eventually calls
> > > > platform_device_register_resndata() to create and register a
> > > > platform device object on the basis of the information contained
> > > > in that code. However, it doesn't associate the new platform
> > > > device with the ACPI node directly, but instead it relies on
> > > > acpi_platform_notify(), called from within device_add(), to find
> > > > that ACPI node again with the help of acpi_platform_find_device()
> > > > and acpi_platform_match() and then attach the new platform device
> > > > to it. This causes an additional ACPI namespace walk to happen and
> > > > is clearly suboptimal.
> > > >
> > > > Use the observation that it is now possible to initialize the ACPI
> > > > handle of a device before calling device_add() for it to make this
> > > > code more straightforward. Namely, add a new field to struct
> > > > platform_device_info allowing us to pass the ACPI handle of interest
> > > > to platform_device_register_full(), which will then use it to
> > > > initialize the new device's ACPI handle before registering it.
> > > > This will cause acpi_platform_notify() to use the ACPI handle from
> > > > the device structure directly instead of using the .find_device()
> > > > routine provided by the device's bus type. In consequence,
> > > > acpi_platform_bus, acpi_platform_find_device(), and
> > > > acpi_platform_match() are not necessary any more, so remove them.
> > >
> > > Why can't you use the platform_data * that is already in struct device
> > > for this, instead of adding an acpi-specific field to the
> > > platform_device structure?
> >
> > Hmm, I kind of don't understand the question. :-)
> >
> > Yes, we have acpi_handle in struct device (it actually is being added by a
> > patch you've acked) and we use it. The whole point here is to streamline
> > of the initalization of that field.
> >
> > > If not that, surely there is another field in struct device that you
> > > could use that is free for this type of device?
> >
> > Yes, there is one and as I said above. :-)
> >
> > I'd be happy to use the struct device's field directly, but
> > platform_device_register_full() allocates memory for the struct device in
> > question, so that field actually doesn't exist yet when it is called.
> >
> > > > struct platform_device_info {
> > > > struct device *parent;
> > > > + void *acpi_handle;
> > >
> > > Oh, and if I do accept this, I want a "real" structure pointer here
> > > please, not a void * "handle". That way is a slippery slope to the
> > > Windows kernel programming style :)
> >
> > This is (void *), because the field being initialized is (void *). That field,
> > in turn, is (void *), because ACPICA defines it that way. I thought about
> > wrapping that in some more meaningless data type, but I did't find a way
>
> s/meaningless/meaningful/

Well, perhaps I'll describe the problem to you, maybe you can help. :-)

So, we want to have acpi_handle (or acpi_node) in addition to of_node in struct
device (to be used in the analogous way plus for the execution of AML methods),
but we don't want all users of device.h to have to include ACPI headers
where the acpi_handle data type is defined. For this reason, we're using
(void *) as its data type now, which let's say I'm not really happy with.

I've been thinking about that for quite a while, though, and I'm not really
sure what to do about that. Perhaps we could define something like

struct acpi_dev_node {
#ifdef CONFIG_ACPI
void *handle;
#endif
};

in device.h and use that as "struct acpi_dev_node acpi_node;" in struct device.
Then, we could add the following macro

#ifdef CONFIG_ACPI
#define ACPI_HANDLE(dev) ((dev)->acpi_node.handle)
#else
#define ACPI_HANDLE(dev) (NULL)
#endif

and redefine DEVICE_ACPI_HANDLE(dev) as ((acpi_handle)ACPI_HANDLE(dev)).

Then, the $subject patch would add "struct acpi_dev_node acpi_node;" to
struct platform_device_info and use ACPI_HANDLE(dev) instead of accessing
the struct device's field directly.

I wonder what you think?

Rafael


--
I speak only for myself.
Rafael J. Wysocki, Intel Open Source Technology Center.

2012-11-19 21:02:40

by Mika Westerberg

[permalink] [raw]
Subject: Re: [PATCH 2/2] ACPI / platform: Initialize ACPI handles of platform devices in advance

On Mon, Nov 19, 2012 at 09:44:21PM +0100, Rafael J. Wysocki wrote:
> So, we want to have acpi_handle (or acpi_node) in addition to of_node in struct
> device (to be used in the analogous way plus for the execution of AML methods),
> but we don't want all users of device.h to have to include ACPI headers
> where the acpi_handle data type is defined. For this reason, we're using
> (void *) as its data type now, which let's say I'm not really happy with.
>
> I've been thinking about that for quite a while, though, and I'm not really
> sure what to do about that. Perhaps we could define something like
>
> struct acpi_dev_node {
> #ifdef CONFIG_ACPI
> void *handle;
> #endif
> };
>
> in device.h and use that as "struct acpi_dev_node acpi_node;" in struct device.
> Then, we could add the following macro
>
> #ifdef CONFIG_ACPI
> #define ACPI_HANDLE(dev) ((dev)->acpi_node.handle)
> #else
> #define ACPI_HANDLE(dev) (NULL)
> #endif
>
> and redefine DEVICE_ACPI_HANDLE(dev) as ((acpi_handle)ACPI_HANDLE(dev)).
>
> Then, the $subject patch would add "struct acpi_dev_node acpi_node;" to
> struct platform_device_info and use ACPI_HANDLE(dev) instead of accessing
> the struct device's field directly.

In addition to struct platform_device_info, we are also going to add
similar to struct i2c_board_info. There already is of_node pointer so I was
thinking to add acpi_handle like you did for platform_device. Type of that
pointer of course needs to be figured out :)

2012-11-19 21:52:27

by Rafael J. Wysocki

[permalink] [raw]
Subject: Re: [PATCH 2/2] ACPI / platform: Initialize ACPI handles of platform devices in advance

On Monday, November 19, 2012 11:05:28 PM Mika Westerberg wrote:
> On Mon, Nov 19, 2012 at 09:44:21PM +0100, Rafael J. Wysocki wrote:
> > So, we want to have acpi_handle (or acpi_node) in addition to of_node in struct
> > device (to be used in the analogous way plus for the execution of AML methods),
> > but we don't want all users of device.h to have to include ACPI headers
> > where the acpi_handle data type is defined. For this reason, we're using
> > (void *) as its data type now, which let's say I'm not really happy with.
> >
> > I've been thinking about that for quite a while, though, and I'm not really
> > sure what to do about that. Perhaps we could define something like
> >
> > struct acpi_dev_node {
> > #ifdef CONFIG_ACPI
> > void *handle;
> > #endif
> > };
> >
> > in device.h and use that as "struct acpi_dev_node acpi_node;" in struct device.
> > Then, we could add the following macro
> >
> > #ifdef CONFIG_ACPI
> > #define ACPI_HANDLE(dev) ((dev)->acpi_node.handle)
> > #else
> > #define ACPI_HANDLE(dev) (NULL)
> > #endif
> >
> > and redefine DEVICE_ACPI_HANDLE(dev) as ((acpi_handle)ACPI_HANDLE(dev)).
> >
> > Then, the $subject patch would add "struct acpi_dev_node acpi_node;" to
> > struct platform_device_info and use ACPI_HANDLE(dev) instead of accessing
> > the struct device's field directly.
>
> In addition to struct platform_device_info, we are also going to add
> similar to struct i2c_board_info. There already is of_node pointer so I was
> thinking to add acpi_handle like you did for platform_device.

Yeah, that's kind of something that comes to mind immediately. :-)

> Type of that pointer of course needs to be figured out :)

Yup.


--
I speak only for myself.
Rafael J. Wysocki, Intel Open Source Technology Center.

2012-11-19 22:30:48

by Greg Kroah-Hartman

[permalink] [raw]
Subject: Re: [PATCH 2/2] ACPI / platform: Initialize ACPI handles of platform devices in advance

On Mon, Nov 19, 2012 at 06:32:06PM +0100, Rafael J. Wysocki wrote:
> On Monday, November 19, 2012 08:23:34 AM Greg Kroah-Hartman wrote:
> > On Sun, Nov 18, 2012 at 10:13:59PM +0100, Rafael J. Wysocki wrote:
> > > From: Rafael J. Wysocki <[email protected]>
> > >
> > > The current platform device creation and registration code in
> > > acpi_create_platform_device() is quite convoluted. This function
> > > takes an ACPI device node as an argument and eventually calls
> > > platform_device_register_resndata() to create and register a
> > > platform device object on the basis of the information contained
> > > in that code. However, it doesn't associate the new platform
> > > device with the ACPI node directly, but instead it relies on
> > > acpi_platform_notify(), called from within device_add(), to find
> > > that ACPI node again with the help of acpi_platform_find_device()
> > > and acpi_platform_match() and then attach the new platform device
> > > to it. This causes an additional ACPI namespace walk to happen and
> > > is clearly suboptimal.
> > >
> > > Use the observation that it is now possible to initialize the ACPI
> > > handle of a device before calling device_add() for it to make this
> > > code more straightforward. Namely, add a new field to struct
> > > platform_device_info allowing us to pass the ACPI handle of interest
> > > to platform_device_register_full(), which will then use it to
> > > initialize the new device's ACPI handle before registering it.
> > > This will cause acpi_platform_notify() to use the ACPI handle from
> > > the device structure directly instead of using the .find_device()
> > > routine provided by the device's bus type. In consequence,
> > > acpi_platform_bus, acpi_platform_find_device(), and
> > > acpi_platform_match() are not necessary any more, so remove them.
> >
> > Why can't you use the platform_data * that is already in struct device
> > for this, instead of adding an acpi-specific field to the
> > platform_device structure?
>
> Hmm, I kind of don't understand the question. :-)
>
> Yes, we have acpi_handle in struct device (it actually is being added by a
> patch you've acked) and we use it. The whole point here is to streamline
> of the initalization of that field.

Ok, but then why would you need it again in platform device? That's
what is confusing me.

> > If not that, surely there is another field in struct device that you
> > could use that is free for this type of device?
>
> Yes, there is one and as I said above. :-)
>
> I'd be happy to use the struct device's field directly, but
> platform_device_register_full() allocates memory for the struct device in
> question, so that field actually doesn't exist yet when it is called.

Ah, this is in the _info structure, not the platform_device structure.
Doh, sorry about that, I totally missed that. Nevermind about my
objections.

thanks,

greg k-h

2012-11-19 22:31:33

by Greg Kroah-Hartman

[permalink] [raw]
Subject: Re: [PATCH 2/2] ACPI / platform: Initialize ACPI handles of platform devices in advance

On Mon, Nov 19, 2012 at 09:44:21PM +0100, Rafael J. Wysocki wrote:
> On Monday, November 19, 2012 06:45:22 PM Rafael J. Wysocki wrote:
> > On Monday, November 19, 2012 06:32:06 PM Rafael J. Wysocki wrote:
> > > On Monday, November 19, 2012 08:23:34 AM Greg Kroah-Hartman wrote:
> > > > On Sun, Nov 18, 2012 at 10:13:59PM +0100, Rafael J. Wysocki wrote:
> > > > > From: Rafael J. Wysocki <[email protected]>
> > > > >
> > > > > The current platform device creation and registration code in
> > > > > acpi_create_platform_device() is quite convoluted. This function
> > > > > takes an ACPI device node as an argument and eventually calls
> > > > > platform_device_register_resndata() to create and register a
> > > > > platform device object on the basis of the information contained
> > > > > in that code. However, it doesn't associate the new platform
> > > > > device with the ACPI node directly, but instead it relies on
> > > > > acpi_platform_notify(), called from within device_add(), to find
> > > > > that ACPI node again with the help of acpi_platform_find_device()
> > > > > and acpi_platform_match() and then attach the new platform device
> > > > > to it. This causes an additional ACPI namespace walk to happen and
> > > > > is clearly suboptimal.
> > > > >
> > > > > Use the observation that it is now possible to initialize the ACPI
> > > > > handle of a device before calling device_add() for it to make this
> > > > > code more straightforward. Namely, add a new field to struct
> > > > > platform_device_info allowing us to pass the ACPI handle of interest
> > > > > to platform_device_register_full(), which will then use it to
> > > > > initialize the new device's ACPI handle before registering it.
> > > > > This will cause acpi_platform_notify() to use the ACPI handle from
> > > > > the device structure directly instead of using the .find_device()
> > > > > routine provided by the device's bus type. In consequence,
> > > > > acpi_platform_bus, acpi_platform_find_device(), and
> > > > > acpi_platform_match() are not necessary any more, so remove them.
> > > >
> > > > Why can't you use the platform_data * that is already in struct device
> > > > for this, instead of adding an acpi-specific field to the
> > > > platform_device structure?
> > >
> > > Hmm, I kind of don't understand the question. :-)
> > >
> > > Yes, we have acpi_handle in struct device (it actually is being added by a
> > > patch you've acked) and we use it. The whole point here is to streamline
> > > of the initalization of that field.
> > >
> > > > If not that, surely there is another field in struct device that you
> > > > could use that is free for this type of device?
> > >
> > > Yes, there is one and as I said above. :-)
> > >
> > > I'd be happy to use the struct device's field directly, but
> > > platform_device_register_full() allocates memory for the struct device in
> > > question, so that field actually doesn't exist yet when it is called.
> > >
> > > > > struct platform_device_info {
> > > > > struct device *parent;
> > > > > + void *acpi_handle;
> > > >
> > > > Oh, and if I do accept this, I want a "real" structure pointer here
> > > > please, not a void * "handle". That way is a slippery slope to the
> > > > Windows kernel programming style :)
> > >
> > > This is (void *), because the field being initialized is (void *). That field,
> > > in turn, is (void *), because ACPICA defines it that way. I thought about
> > > wrapping that in some more meaningless data type, but I did't find a way
> >
> > s/meaningless/meaningful/
>
> Well, perhaps I'll describe the problem to you, maybe you can help. :-)
>
> So, we want to have acpi_handle (or acpi_node) in addition to of_node in struct
> device (to be used in the analogous way plus for the execution of AML methods),
> but we don't want all users of device.h to have to include ACPI headers
> where the acpi_handle data type is defined. For this reason, we're using
> (void *) as its data type now, which let's say I'm not really happy with.
>
> I've been thinking about that for quite a while, though, and I'm not really
> sure what to do about that. Perhaps we could define something like
>
> struct acpi_dev_node {
> #ifdef CONFIG_ACPI
> void *handle;
> #endif
> };
>
> in device.h and use that as "struct acpi_dev_node acpi_node;" in struct device.
> Then, we could add the following macro
>
> #ifdef CONFIG_ACPI
> #define ACPI_HANDLE(dev) ((dev)->acpi_node.handle)
> #else
> #define ACPI_HANDLE(dev) (NULL)
> #endif
>
> and redefine DEVICE_ACPI_HANDLE(dev) as ((acpi_handle)ACPI_HANDLE(dev)).
>
> Then, the $subject patch would add "struct acpi_dev_node acpi_node;" to
> struct platform_device_info and use ACPI_HANDLE(dev) instead of accessing
> the struct device's field directly.
>
> I wonder what you think?

I like the hack of using an empty structure here, that's fine with me,
and makes me feel a little bit better about the whole "void *" stuff.
If you respin the patch with this, I'll ack it.

thanks,

greg k-h

2012-11-19 22:40:06

by Rafael J. Wysocki

[permalink] [raw]
Subject: Re: [PATCH 2/2] ACPI / platform: Initialize ACPI handles of platform devices in advance

On Monday, November 19, 2012 02:32:21 PM Greg Kroah-Hartman wrote:
> On Mon, Nov 19, 2012 at 09:44:21PM +0100, Rafael J. Wysocki wrote:
> > On Monday, November 19, 2012 06:45:22 PM Rafael J. Wysocki wrote:
> > > On Monday, November 19, 2012 06:32:06 PM Rafael J. Wysocki wrote:
> > > > On Monday, November 19, 2012 08:23:34 AM Greg Kroah-Hartman wrote:
> > > > > On Sun, Nov 18, 2012 at 10:13:59PM +0100, Rafael J. Wysocki wrote:
> > > > > > From: Rafael J. Wysocki <[email protected]>
> > > > > >
> > > > > > The current platform device creation and registration code in
> > > > > > acpi_create_platform_device() is quite convoluted. This function
> > > > > > takes an ACPI device node as an argument and eventually calls
> > > > > > platform_device_register_resndata() to create and register a
> > > > > > platform device object on the basis of the information contained
> > > > > > in that code. However, it doesn't associate the new platform
> > > > > > device with the ACPI node directly, but instead it relies on
> > > > > > acpi_platform_notify(), called from within device_add(), to find
> > > > > > that ACPI node again with the help of acpi_platform_find_device()
> > > > > > and acpi_platform_match() and then attach the new platform device
> > > > > > to it. This causes an additional ACPI namespace walk to happen and
> > > > > > is clearly suboptimal.
> > > > > >
> > > > > > Use the observation that it is now possible to initialize the ACPI
> > > > > > handle of a device before calling device_add() for it to make this
> > > > > > code more straightforward. Namely, add a new field to struct
> > > > > > platform_device_info allowing us to pass the ACPI handle of interest
> > > > > > to platform_device_register_full(), which will then use it to
> > > > > > initialize the new device's ACPI handle before registering it.
> > > > > > This will cause acpi_platform_notify() to use the ACPI handle from
> > > > > > the device structure directly instead of using the .find_device()
> > > > > > routine provided by the device's bus type. In consequence,
> > > > > > acpi_platform_bus, acpi_platform_find_device(), and
> > > > > > acpi_platform_match() are not necessary any more, so remove them.
> > > > >
> > > > > Why can't you use the platform_data * that is already in struct device
> > > > > for this, instead of adding an acpi-specific field to the
> > > > > platform_device structure?
> > > >
> > > > Hmm, I kind of don't understand the question. :-)
> > > >
> > > > Yes, we have acpi_handle in struct device (it actually is being added by a
> > > > patch you've acked) and we use it. The whole point here is to streamline
> > > > of the initalization of that field.
> > > >
> > > > > If not that, surely there is another field in struct device that you
> > > > > could use that is free for this type of device?
> > > >
> > > > Yes, there is one and as I said above. :-)
> > > >
> > > > I'd be happy to use the struct device's field directly, but
> > > > platform_device_register_full() allocates memory for the struct device in
> > > > question, so that field actually doesn't exist yet when it is called.
> > > >
> > > > > > struct platform_device_info {
> > > > > > struct device *parent;
> > > > > > + void *acpi_handle;
> > > > >
> > > > > Oh, and if I do accept this, I want a "real" structure pointer here
> > > > > please, not a void * "handle". That way is a slippery slope to the
> > > > > Windows kernel programming style :)
> > > >
> > > > This is (void *), because the field being initialized is (void *). That field,
> > > > in turn, is (void *), because ACPICA defines it that way. I thought about
> > > > wrapping that in some more meaningless data type, but I did't find a way
> > >
> > > s/meaningless/meaningful/
> >
> > Well, perhaps I'll describe the problem to you, maybe you can help. :-)
> >
> > So, we want to have acpi_handle (or acpi_node) in addition to of_node in struct
> > device (to be used in the analogous way plus for the execution of AML methods),
> > but we don't want all users of device.h to have to include ACPI headers
> > where the acpi_handle data type is defined. For this reason, we're using
> > (void *) as its data type now, which let's say I'm not really happy with.
> >
> > I've been thinking about that for quite a while, though, and I'm not really
> > sure what to do about that. Perhaps we could define something like
> >
> > struct acpi_dev_node {
> > #ifdef CONFIG_ACPI
> > void *handle;
> > #endif
> > };
> >
> > in device.h and use that as "struct acpi_dev_node acpi_node;" in struct device.
> > Then, we could add the following macro
> >
> > #ifdef CONFIG_ACPI
> > #define ACPI_HANDLE(dev) ((dev)->acpi_node.handle)
> > #else
> > #define ACPI_HANDLE(dev) (NULL)
> > #endif
> >
> > and redefine DEVICE_ACPI_HANDLE(dev) as ((acpi_handle)ACPI_HANDLE(dev)).
> >
> > Then, the $subject patch would add "struct acpi_dev_node acpi_node;" to
> > struct platform_device_info and use ACPI_HANDLE(dev) instead of accessing
> > the struct device's field directly.
> >
> > I wonder what you think?
>
> I like the hack of using an empty structure here, that's fine with me,
> and makes me feel a little bit better about the whole "void *" stuff.
> If you respin the patch with this, I'll ack it.

I will, but I think I'll cut two patches instead, one introducing that
stuff above and the other as a replacement for the $subject one on top
of that.

Thanks,
Rafael


--
I speak only for myself.
Rafael J. Wysocki, Intel Open Source Technology Center.

2012-11-19 22:41:30

by Rafael J. Wysocki

[permalink] [raw]
Subject: Re: [PATCH 2/2] ACPI / platform: Initialize ACPI handles of platform devices in advance

On Monday, November 19, 2012 02:31:35 PM Greg Kroah-Hartman wrote:
> On Mon, Nov 19, 2012 at 06:32:06PM +0100, Rafael J. Wysocki wrote:
> > On Monday, November 19, 2012 08:23:34 AM Greg Kroah-Hartman wrote:
> > > On Sun, Nov 18, 2012 at 10:13:59PM +0100, Rafael J. Wysocki wrote:
> > > > From: Rafael J. Wysocki <[email protected]>
> > > >
> > > > The current platform device creation and registration code in
> > > > acpi_create_platform_device() is quite convoluted. This function
> > > > takes an ACPI device node as an argument and eventually calls
> > > > platform_device_register_resndata() to create and register a
> > > > platform device object on the basis of the information contained
> > > > in that code. However, it doesn't associate the new platform
> > > > device with the ACPI node directly, but instead it relies on
> > > > acpi_platform_notify(), called from within device_add(), to find
> > > > that ACPI node again with the help of acpi_platform_find_device()
> > > > and acpi_platform_match() and then attach the new platform device
> > > > to it. This causes an additional ACPI namespace walk to happen and
> > > > is clearly suboptimal.
> > > >
> > > > Use the observation that it is now possible to initialize the ACPI
> > > > handle of a device before calling device_add() for it to make this
> > > > code more straightforward. Namely, add a new field to struct
> > > > platform_device_info allowing us to pass the ACPI handle of interest
> > > > to platform_device_register_full(), which will then use it to
> > > > initialize the new device's ACPI handle before registering it.
> > > > This will cause acpi_platform_notify() to use the ACPI handle from
> > > > the device structure directly instead of using the .find_device()
> > > > routine provided by the device's bus type. In consequence,
> > > > acpi_platform_bus, acpi_platform_find_device(), and
> > > > acpi_platform_match() are not necessary any more, so remove them.
> > >
> > > Why can't you use the platform_data * that is already in struct device
> > > for this, instead of adding an acpi-specific field to the
> > > platform_device structure?
> >
> > Hmm, I kind of don't understand the question. :-)
> >
> > Yes, we have acpi_handle in struct device (it actually is being added by a
> > patch you've acked) and we use it. The whole point here is to streamline
> > of the initalization of that field.
>
> Ok, but then why would you need it again in platform device? That's
> what is confusing me.
>
> > > If not that, surely there is another field in struct device that you
> > > could use that is free for this type of device?
> >
> > Yes, there is one and as I said above. :-)
> >
> > I'd be happy to use the struct device's field directly, but
> > platform_device_register_full() allocates memory for the struct device in
> > question, so that field actually doesn't exist yet when it is called.
>
> Ah, this is in the _info structure, not the platform_device structure.
> Doh, sorry about that, I totally missed that. Nevermind about my
> objections.

Cool, thanks! :-)

I'll try to fight with the (void *) things a bit, though.

Thanks,
Rafael


--
I speak only for myself.
Rafael J. Wysocki, Intel Open Source Technology Center.

2012-11-19 22:49:50

by Bjorn Helgaas

[permalink] [raw]
Subject: Re: [PATCH v2 3/3 UPDATED] i2c / ACPI: add ACPI enumeration support

On Sat, Nov 17, 2012 at 2:55 AM, Mika Westerberg
<[email protected]> wrote:
> On Sat, Nov 17, 2012 at 10:03:54AM +0200, Mika Westerberg wrote:
>> On Fri, Nov 16, 2012 at 11:46:40PM -0700, Bjorn Helgaas wrote:
>> > On Fri, Nov 16, 2012 at 10:28 AM, Mika Westerberg
>> > <[email protected]> wrote:
>> > > ...
>> > > From: Mika Westerberg <[email protected]>
>> > > Date: Mon, 10 Sep 2012 12:12:32 +0300
>> > > Subject: [PATCH] i2c / ACPI: add ACPI enumeration support
>> > >
>> > > ACPI 5 introduced I2cSerialBus resource that makes it possible to enumerate
>> > > and configure the I2C slave devices behind the I2C controller. This patch
>> > > adds helper functions to support I2C slave enumeration.
>> > >
>> > > An ACPI enabled I2C controller driver only needs to call acpi_i2c_register_devices()
>> > > in order to get its slave devices enumerated, created and bound to the
>> > > corresponding ACPI handle.
>> >
>> > I must admit I don't understand the strategy here. Likely it's only
>> > because I haven't been paying enough attention, but I'll ask anyway in
>> > case anybody else is similarly confused.
>> >
>> > The callchain when we enumerate these slave devices looks like this:
>> >
>> > acpi_i2c_register_devices(struct i2c_adapter *)
>> > acpi_walk_namespace(adapter->dev.acpi_handle, acpi_i2c_add_device)
>> > acpi_i2c_add_device
>> > acpi_bus_get_device
>> > acpi_bus_get_status
>> > acpi_dev_get_resources(..., acpi_i2c_add_resource, ...)
>> > <find IRQ, addr>
>> > acpi_dev_free_resources
>> > i2c_new_device
>> > client = kzalloc
>> > client->dev = ...
>> > device_register(&client->dev)
>> >
>> > Is the ACPI namespace in question something like the following?
>> >
>> > Device { # i2C master, i.e., the i2c_adapter
>> > _HID PNPmmmm
>> > Device { # I2C slave 1, i.e., a client
>> > _HID PNPsss1
>> > _CRS
>> > SerialBus/I2C addr addr1, mode mode1
>> > IRQ irq1
>> > }
>> > Device { # I2C slave 2
>> > _HID PNPsss2
>> > _CRS
>> > SerialBus/I2C addr addr2, mode mode2
>> > IRQ irq2
>> > }
>> > }
>>
>> Yes.
>>
>> > _CRS is a device configuration method, so I would expect that it
>> > exists within the scope of a Device() object. The way I'm used to
>> > this working is for a driver to specify "I know about PNPsss1
>> > devices."
>>
>> Yes.
>>
>> > But it looks like acpi_i2c_register() walks the namespace below an i2c
>> > master device, registering a new i2c device (a slave) for every ACPI
>> > device node with a _CRS method that contains a SERIAL_BUS/TYPE_I2C
>> > descriptor. It seems like you're basically claiming those devices
>> > nodes based on the contents of their _CRS, not based on their PNP IDs,
>> > which seems strange to me.
>>
>> Yes, if we only matched the PNP IDs we would get bunch of PNP devices which
>> certainly doesn't help us to reuse the existing I2C drivers. So instead of
>> creating a new glue driver for ACPI or PNP device we added this enumeration
>> method that then creates the I2C devices, just like DT does.
>
> In other words, what this whole thing is trying to achieve is something
> along the lines of:
>
> - Instead of making PNP or ACPI devices out of every device in the
> ACPI namespace we use the resources returned by the _CRS
> method for a given device as a hint of what type of device it is.
>
> - If we find I2CSerialBus() we assume it is an I2C device and
> create i2c_device (and i2c_client) and register this to the I2C
> core.
>
> - If we find SPISerialBus() we assume it is a SPI device and create
> corresponding spidevice and register it to the SPI core.
>
> - Devices that don't have a bus are represented as platform devices
> (based on the table in drivers/acpi/scan.c). The reason for this
> is that most of the SoC devices have already platform driver so
> we can easily reuse the existing drivers.

Using _CRS contents to infer the device type feels like a mistake to
me. It doesn't generalize to arbitrary devices. I don't think it's
the intent of the spec, which seems clearly to be "start with the
_HID/_CID to identify devices," so it violates the principle of least
surprise.

I'm not sure it's even safe to rely on _CRS being useful until after
the OS runs _SRS. Sec 6.2 of the spec (ACPI 5.0) says the OS uses
_PRS to determine what resources the device needs and _SRS to assign
them, and it *may* use _CRS to learn any current assignments (I know
this doesn't match current Linux behavior very well). I interpret
that to mean the device may be disabled and return nothing in _CRS
until after the OS evaluates _SRS to enable the device.

I think it will make it harder to reason about and refactor ACPI
because it's "unusual." For example, the acpi_i2c_register_devices ->
acpi_i2c_add_device path allocates a new struct device (in struct
i2c_client) and registers it. Now we have a struct device in struct
acpi_device, in struct pnp_dev, *and* in struct i2c_client, and all
refer to the same thing. What does that mean? The sysfs picture
seems confusing to me.

I assume you mean the acpi_platform_device_ids[] table you added with
91e56878058. Having a table of IDs that are treated specially by the
core is a bit of a concern for me because it means we need to add
things to it every time a new platform device comes along. The patch
didn't include clear criteria for deciding what qualifies. For
example, I don't know whether PCI host bridges would qualify as
platform devices. I guess maybe they would, because they don't have a
bus (though of course they have acpi_bus_type like all other ACPI
devices)?

> The implementation follows the Device Tree as much as possible so that
> adding support for DT and ACPI to a driver would be similar and thus easy
> for people who know either method.
>
> An alternative would be to create PNP or ACPI glue drivers for each device
> that then create the corresponding real device like platform or I2C which
> means that we need add much more lines of unnecessary code to the kernel
> compared to adding the ACPI/PNP IDs to the driver which takes only few
> lines of code.
>
> We still allow more complex configuration with the means of
> dev->acpi_handle. So for example if driver needs to call _DSM in order to
> retrieve some parameters for the device it can do so with the help of
> dev->acpi_handle.

I think the benefit here is that you can merely point
.acpi_match_table at an acpi_device_id[] table, then use
platform_get_resource() as a generic way to get resources, whether the
platform device came from OF, ACPI, etc. The alternative would be to
add, e.g., a PNP driver with a .probe() method that uses
pnp_get_resource(). That's not very much code, but it is more, even
if the .probe() method just calls a device registration function
that's shared across bus types.

That benefit seems like a great thing, and my question then is why
wouldn't we just do it across the board and make platform devices for
*all* ACPI devices without having the I2C and SPI special cases?

Bjorn

2012-11-19 23:11:20

by Rafael J. Wysocki

[permalink] [raw]
Subject: Re: [PATCH v2 3/3 UPDATED] i2c / ACPI: add ACPI enumeration support

On Monday, November 19, 2012 03:49:25 PM Bjorn Helgaas wrote:
> On Sat, Nov 17, 2012 at 2:55 AM, Mika Westerberg
> <[email protected]> wrote:
> > On Sat, Nov 17, 2012 at 10:03:54AM +0200, Mika Westerberg wrote:
> >> On Fri, Nov 16, 2012 at 11:46:40PM -0700, Bjorn Helgaas wrote:
> >> > On Fri, Nov 16, 2012 at 10:28 AM, Mika Westerberg
> >> > <[email protected]> wrote:
> >> > > ...
> >> > > From: Mika Westerberg <[email protected]>
> >> > > Date: Mon, 10 Sep 2012 12:12:32 +0300
> >> > > Subject: [PATCH] i2c / ACPI: add ACPI enumeration support
> >> > >
> >> > > ACPI 5 introduced I2cSerialBus resource that makes it possible to enumerate
> >> > > and configure the I2C slave devices behind the I2C controller. This patch
> >> > > adds helper functions to support I2C slave enumeration.
> >> > >
> >> > > An ACPI enabled I2C controller driver only needs to call acpi_i2c_register_devices()
> >> > > in order to get its slave devices enumerated, created and bound to the
> >> > > corresponding ACPI handle.
> >> >
> >> > I must admit I don't understand the strategy here. Likely it's only
> >> > because I haven't been paying enough attention, but I'll ask anyway in
> >> > case anybody else is similarly confused.
> >> >
> >> > The callchain when we enumerate these slave devices looks like this:
> >> >
> >> > acpi_i2c_register_devices(struct i2c_adapter *)
> >> > acpi_walk_namespace(adapter->dev.acpi_handle, acpi_i2c_add_device)
> >> > acpi_i2c_add_device
> >> > acpi_bus_get_device
> >> > acpi_bus_get_status
> >> > acpi_dev_get_resources(..., acpi_i2c_add_resource, ...)
> >> > <find IRQ, addr>
> >> > acpi_dev_free_resources
> >> > i2c_new_device
> >> > client = kzalloc
> >> > client->dev = ...
> >> > device_register(&client->dev)
> >> >
> >> > Is the ACPI namespace in question something like the following?
> >> >
> >> > Device { # i2C master, i.e., the i2c_adapter
> >> > _HID PNPmmmm
> >> > Device { # I2C slave 1, i.e., a client
> >> > _HID PNPsss1
> >> > _CRS
> >> > SerialBus/I2C addr addr1, mode mode1
> >> > IRQ irq1
> >> > }
> >> > Device { # I2C slave 2
> >> > _HID PNPsss2
> >> > _CRS
> >> > SerialBus/I2C addr addr2, mode mode2
> >> > IRQ irq2
> >> > }
> >> > }
> >>
> >> Yes.
> >>
> >> > _CRS is a device configuration method, so I would expect that it
> >> > exists within the scope of a Device() object. The way I'm used to
> >> > this working is for a driver to specify "I know about PNPsss1
> >> > devices."
> >>
> >> Yes.
> >>
> >> > But it looks like acpi_i2c_register() walks the namespace below an i2c
> >> > master device, registering a new i2c device (a slave) for every ACPI
> >> > device node with a _CRS method that contains a SERIAL_BUS/TYPE_I2C
> >> > descriptor. It seems like you're basically claiming those devices
> >> > nodes based on the contents of their _CRS, not based on their PNP IDs,
> >> > which seems strange to me.
> >>
> >> Yes, if we only matched the PNP IDs we would get bunch of PNP devices which
> >> certainly doesn't help us to reuse the existing I2C drivers. So instead of
> >> creating a new glue driver for ACPI or PNP device we added this enumeration
> >> method that then creates the I2C devices, just like DT does.
> >
> > In other words, what this whole thing is trying to achieve is something
> > along the lines of:
> >
> > - Instead of making PNP or ACPI devices out of every device in the
> > ACPI namespace we use the resources returned by the _CRS
> > method for a given device as a hint of what type of device it is.
> >
> > - If we find I2CSerialBus() we assume it is an I2C device and
> > create i2c_device (and i2c_client) and register this to the I2C
> > core.
> >
> > - If we find SPISerialBus() we assume it is a SPI device and create
> > corresponding spidevice and register it to the SPI core.
> >
> > - Devices that don't have a bus are represented as platform devices
> > (based on the table in drivers/acpi/scan.c). The reason for this
> > is that most of the SoC devices have already platform driver so
> > we can easily reuse the existing drivers.
>
> Using _CRS contents to infer the device type feels like a mistake to
> me. It doesn't generalize to arbitrary devices. I don't think it's
> the intent of the spec, which seems clearly to be "start with the
> _HID/_CID to identify devices," so it violates the principle of least
> surprise.

This is a chicken-and-egg problem, kind of. Namely, we need a struct
i2c_device (in this particular case) for a driver to bind to, before the
driver will use its device IDs to identify it. :-)

> I'm not sure it's even safe to rely on _CRS being useful until after
> the OS runs _SRS. Sec 6.2 of the spec (ACPI 5.0) says the OS uses
> _PRS to determine what resources the device needs and _SRS to assign
> them, and it *may* use _CRS to learn any current assignments (I know
> this doesn't match current Linux behavior very well).

Ideally, we'll do all those things some time in the future. We'll then
make sure that acpi_i2c_register_devices() doesn't run before we've
done them.

> I interpret that to mean the device may be disabled and return nothing in
> _CRS until after the OS evaluates _SRS to enable the device.

Yes, that may be the case in theory. No, I haven't seen any evidence that it
happens in practice.

> I think it will make it harder to reason about and refactor ACPI
> because it's "unusual." For example, the acpi_i2c_register_devices ->
> acpi_i2c_add_device path allocates a new struct device (in struct
> i2c_client) and registers it. Now we have a struct device in struct
> acpi_device, in struct pnp_dev, *and* in struct i2c_client, and all
> refer to the same thing. What does that mean? The sysfs picture
> seems confusing to me.

We don't want that in pnp_dev and we'll make this one go away going forward.

Also, we don't want drivers to bind to the one in struct acpi_device,
so that struct acpi_device only is a representation of an ACPI device node
(analogously to PCI). The fact that it is visible through sysfs doesn't
seem to hurt (for PCI it even helps sometimes :-)).

> I assume you mean the acpi_platform_device_ids[] table you added with
> 91e56878058. Having a table of IDs that are treated specially by the
> core is a bit of a concern for me because it means we need to add
> things to it every time a new platform device comes along.

That's a safety measure so that adding things handled by the new code is
under tight control to start with. We're going to get rid of it at one
point, when we decide it's safe.

> The patch didn't include clear criteria for deciding what qualifies. For
> example, I don't know whether PCI host bridges would qualify as
> platform devices. I guess maybe they would, because they don't have a
> bus (though of course they have acpi_bus_type like all other ACPI
> devices)?

They would in principle, but they are kind of special. We may want to have
a special bus type for them.

I would like to make acpi_bus_type go away in the future, if possible,
because it's a source of major confusion (as this very thread shows clearly :-)).

> > The implementation follows the Device Tree as much as possible so that
> > adding support for DT and ACPI to a driver would be similar and thus easy
> > for people who know either method.
> >
> > An alternative would be to create PNP or ACPI glue drivers for each device
> > that then create the corresponding real device like platform or I2C which
> > means that we need add much more lines of unnecessary code to the kernel
> > compared to adding the ACPI/PNP IDs to the driver which takes only few
> > lines of code.
> >
> > We still allow more complex configuration with the means of
> > dev->acpi_handle. So for example if driver needs to call _DSM in order to
> > retrieve some parameters for the device it can do so with the help of
> > dev->acpi_handle.
>
> I think the benefit here is that you can merely point
> .acpi_match_table at an acpi_device_id[] table, then use
> platform_get_resource() as a generic way to get resources, whether the
> platform device came from OF, ACPI, etc. The alternative would be to
> add, e.g., a PNP driver with a .probe() method that uses
> pnp_get_resource(). That's not very much code, but it is more, even
> if the .probe() method just calls a device registration function
> that's shared across bus types.
>
> That benefit seems like a great thing, and my question then is why
> wouldn't we just do it across the board and make platform devices for
> *all* ACPI devices without having the I2C and SPI special cases?

Simply because there are existing I2C and SPI drivers for some IP blocks
are represented by those ACPI device nodes and we want to use them to
handles those devices. :-)

Thanks,
Rafael


--
I speak only for myself.
Rafael J. Wysocki, Intel Open Source Technology Center.

2012-11-19 23:23:47

by Rafael J. Wysocki

[permalink] [raw]
Subject: Re: [PATCH v2 3/3 UPDATED] i2c / ACPI: add ACPI enumeration support

On Monday, November 19, 2012 03:49:25 PM Bjorn Helgaas wrote:
> On Sat, Nov 17, 2012 at 2:55 AM, Mika Westerberg
> <[email protected]> wrote:
> > On Sat, Nov 17, 2012 at 10:03:54AM +0200, Mika Westerberg wrote:
> >> On Fri, Nov 16, 2012 at 11:46:40PM -0700, Bjorn Helgaas wrote:
> >> > On Fri, Nov 16, 2012 at 10:28 AM, Mika Westerberg
> >> > <[email protected]> wrote:
> >> > > ...
> >> > > From: Mika Westerberg <[email protected]>
> >> > > Date: Mon, 10 Sep 2012 12:12:32 +0300
> >> > > Subject: [PATCH] i2c / ACPI: add ACPI enumeration support
> >> > >
> >> > > ACPI 5 introduced I2cSerialBus resource that makes it possible to enumerate
> >> > > and configure the I2C slave devices behind the I2C controller. This patch
> >> > > adds helper functions to support I2C slave enumeration.
> >> > >
> >> > > An ACPI enabled I2C controller driver only needs to call acpi_i2c_register_devices()
> >> > > in order to get its slave devices enumerated, created and bound to the
> >> > > corresponding ACPI handle.
> >> >
> >> > I must admit I don't understand the strategy here. Likely it's only
> >> > because I haven't been paying enough attention, but I'll ask anyway in
> >> > case anybody else is similarly confused.
> >> >
> >> > The callchain when we enumerate these slave devices looks like this:
> >> >
> >> > acpi_i2c_register_devices(struct i2c_adapter *)
> >> > acpi_walk_namespace(adapter->dev.acpi_handle, acpi_i2c_add_device)
> >> > acpi_i2c_add_device
> >> > acpi_bus_get_device
> >> > acpi_bus_get_status
> >> > acpi_dev_get_resources(..., acpi_i2c_add_resource, ...)
> >> > <find IRQ, addr>
> >> > acpi_dev_free_resources
> >> > i2c_new_device
> >> > client = kzalloc
> >> > client->dev = ...
> >> > device_register(&client->dev)
> >> >
> >> > Is the ACPI namespace in question something like the following?
> >> >
> >> > Device { # i2C master, i.e., the i2c_adapter
> >> > _HID PNPmmmm
> >> > Device { # I2C slave 1, i.e., a client
> >> > _HID PNPsss1
> >> > _CRS
> >> > SerialBus/I2C addr addr1, mode mode1
> >> > IRQ irq1
> >> > }
> >> > Device { # I2C slave 2
> >> > _HID PNPsss2
> >> > _CRS
> >> > SerialBus/I2C addr addr2, mode mode2
> >> > IRQ irq2
> >> > }
> >> > }
> >>
> >> Yes.
> >>
> >> > _CRS is a device configuration method, so I would expect that it
> >> > exists within the scope of a Device() object. The way I'm used to
> >> > this working is for a driver to specify "I know about PNPsss1
> >> > devices."
> >>
> >> Yes.
> >>
> >> > But it looks like acpi_i2c_register() walks the namespace below an i2c
> >> > master device, registering a new i2c device (a slave) for every ACPI
> >> > device node with a _CRS method that contains a SERIAL_BUS/TYPE_I2C
> >> > descriptor. It seems like you're basically claiming those devices
> >> > nodes based on the contents of their _CRS, not based on their PNP IDs,
> >> > which seems strange to me.
> >>
> >> Yes, if we only matched the PNP IDs we would get bunch of PNP devices which
> >> certainly doesn't help us to reuse the existing I2C drivers. So instead of
> >> creating a new glue driver for ACPI or PNP device we added this enumeration
> >> method that then creates the I2C devices, just like DT does.
> >
> > In other words, what this whole thing is trying to achieve is something
> > along the lines of:
> >
> > - Instead of making PNP or ACPI devices out of every device in the
> > ACPI namespace we use the resources returned by the _CRS
> > method for a given device as a hint of what type of device it is.
> >
> > - If we find I2CSerialBus() we assume it is an I2C device and
> > create i2c_device (and i2c_client) and register this to the I2C
> > core.
> >
> > - If we find SPISerialBus() we assume it is a SPI device and create
> > corresponding spidevice and register it to the SPI core.
> >
> > - Devices that don't have a bus are represented as platform devices
> > (based on the table in drivers/acpi/scan.c). The reason for this
> > is that most of the SoC devices have already platform driver so
> > we can easily reuse the existing drivers.
>
> Using _CRS contents to infer the device type feels like a mistake to
> me. It doesn't generalize to arbitrary devices. I don't think it's
> the intent of the spec, which seems clearly to be "start with the
> _HID/_CID to identify devices," so it violates the principle of least
> surprise.
>
> I'm not sure it's even safe to rely on _CRS being useful until after
> the OS runs _SRS. Sec 6.2 of the spec (ACPI 5.0) says the OS uses
> _PRS to determine what resources the device needs and _SRS to assign
> them, and it *may* use _CRS to learn any current assignments (I know
> this doesn't match current Linux behavior very well). I interpret
> that to mean the device may be disabled and return nothing in _CRS
> until after the OS evaluates _SRS to enable the device.
>
> I think it will make it harder to reason about and refactor ACPI
> because it's "unusual." For example, the acpi_i2c_register_devices ->
> acpi_i2c_add_device path allocates a new struct device (in struct
> i2c_client) and registers it. Now we have a struct device in struct
> acpi_device, in struct pnp_dev, *and* in struct i2c_client, and all
> refer to the same thing. What does that mean? The sysfs picture
> seems confusing to me.
>
> I assume you mean the acpi_platform_device_ids[] table you added with
> 91e56878058. Having a table of IDs that are treated specially by the
> core is a bit of a concern for me because it means we need to add
> things to it every time a new platform device comes along. The patch
> didn't include clear criteria for deciding what qualifies.

The current criterion is: If we know for a fact that the given device ID
matches a piece of hardware that we have an existing platform driver for
(e.g. an SPI controller), we'll add it to that table. For now, that's
about it (although the "vision" is to extend that to other situations
and, ideally, to get rid of that table in the future).

All of that is about avoiding the need to have two different drivers for the
same piece of hardware, just because once it is used in a system with an
ACPI BIOS, and some other time it is used in a system where we get device
information from Device Trees. And yes, that applies to PCI host bridges too. :-)

Thanks,
Rafael


--
I speak only for myself.
Rafael J. Wysocki, Intel Open Source Technology Center.

2012-11-20 00:56:59

by Rafael J. Wysocki

[permalink] [raw]
Subject: [Update][PATCH 3/3] ACPI / platform: Initialize ACPI handles of platform devices in advance

From: Rafael J. Wysocki <[email protected]>

The current platform device creation and registration code in
acpi_create_platform_device() is quite convoluted. This function
takes an ACPI device node as an argument and eventually calls
platform_device_register_resndata() to create and register a
platform device object on the basis of the information contained
in that code. However, it doesn't associate the new platform
device with the ACPI node directly, but instead it relies on
acpi_platform_notify(), called from within device_add(), to find
that ACPI node again with the help of acpi_platform_find_device()
and acpi_platform_match() and then attach the new platform device
to it. This causes an additional ACPI namespace walk to happen and
is clearly suboptimal.

Use the observation that it is now possible to initialize the ACPI
handle of a device before calling device_add() for it to make this
code more straightforward. Namely, add a new field to struct
platform_device_info allowing us to pass the ACPI handle of interest
to platform_device_register_full(), which will then use it to
initialize the new device's ACPI handle before registering it.
This will cause acpi_platform_notify() to use the ACPI handle from
the device structure directly instead of using the .find_device()
routine provided by the device's bus type. In consequence,
acpi_platform_bus, acpi_platform_find_device(), and
acpi_platform_match() are not necessary any more, so remove them.

Signed-off-by: Rafael J. Wysocki <[email protected]>
Reviewed-by: Mika Westerberg <[email protected]>
---
drivers/acpi/acpi_platform.c | 76 +++++-----------------------------------
drivers/base/platform.c | 2 +
include/linux/platform_device.h | 1
3 files changed, 13 insertions(+), 66 deletions(-)

Index: linux/include/linux/platform_device.h
===================================================================
--- linux.orig/include/linux/platform_device.h
+++ linux/include/linux/platform_device.h
@@ -55,6 +55,7 @@ extern int platform_add_devices(struct p

struct platform_device_info {
struct device *parent;
+ struct acpi_dev_node acpi_node;

const char *name;
int id;
Index: linux/drivers/acpi/acpi_platform.c
===================================================================
--- linux.orig/drivers/acpi/acpi_platform.c
+++ linux/drivers/acpi/acpi_platform.c
@@ -33,7 +33,7 @@ struct platform_device *acpi_create_plat
{
struct platform_device *pdev = NULL;
struct acpi_device *acpi_parent;
- struct device *parent = NULL;
+ struct platform_device_info pdevinfo;
struct resource_list_entry *rentry;
struct list_head resource_list;
struct resource *resources;
@@ -60,11 +60,13 @@ struct platform_device *acpi_create_plat

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;
@@ -76,12 +78,16 @@ struct platform_device *acpi_create_plat
entry = list_first_entry(list,
struct acpi_device_physical_node,
node);
- parent = entry->dev;
+ pdevinfo.parent = entry->dev;
}
mutex_unlock(&acpi_parent->physical_node_lock);
}
- pdev = platform_device_register_resndata(parent, dev_name(&adev->dev),
- -1, resources, count, NULL, 0);
+ 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));
@@ -94,65 +100,3 @@ struct platform_device *acpi_create_plat
kfree(resources);
return pdev;
}
-
-static acpi_status acpi_platform_match(acpi_handle handle, u32 depth,
- void *data, void **return_value)
-{
- struct platform_device *pdev = data;
- struct acpi_device *adev;
- acpi_status status;
-
- status = acpi_bus_get_device(handle, &adev);
- if (ACPI_FAILURE(status))
- return status;
-
- /* Skip ACPI devices that have physical device attached */
- if (adev->physical_node_count)
- return AE_OK;
-
- if (!strcmp(dev_name(&pdev->dev), dev_name(&adev->dev))) {
- *(acpi_handle *)return_value = handle;
- return AE_CTRL_TERMINATE;
- }
-
- return AE_OK;
-}
-
-static int acpi_platform_find_device(struct device *dev, acpi_handle *handle)
-{
- struct platform_device *pdev = to_platform_device(dev);
- char *name, *tmp, *hid;
-
- /*
- * The platform device is named using the ACPI device name
- * _HID:INSTANCE so we strip the INSTANCE out in order to find the
- * correct device using its _HID.
- */
- name = kstrdup(dev_name(dev), GFP_KERNEL);
- if (!name)
- return -ENOMEM;
-
- tmp = name;
- hid = strsep(&tmp, ":");
- if (!hid) {
- kfree(name);
- return -ENODEV;
- }
-
- *handle = NULL;
- acpi_get_devices(hid, acpi_platform_match, pdev, handle);
-
- kfree(name);
- return *handle ? 0 : -ENODEV;
-}
-
-static struct acpi_bus_type acpi_platform_bus = {
- .bus = &platform_bus_type,
- .find_device = acpi_platform_find_device,
-};
-
-static int __init acpi_platform_init(void)
-{
- return register_acpi_bus_type(&acpi_platform_bus);
-}
-arch_initcall(acpi_platform_init);
Index: linux/drivers/base/platform.c
===================================================================
--- linux.orig/drivers/base/platform.c
+++ linux/drivers/base/platform.c
@@ -437,6 +437,7 @@ struct platform_device *platform_device_
goto err_alloc;

pdev->dev.parent = pdevinfo->parent;
+ ACPI_HANDLE_SET(&pdev->dev, pdevinfo->acpi_node.handle);

if (pdevinfo->dma_mask) {
/*
@@ -467,6 +468,7 @@ struct platform_device *platform_device_
ret = platform_device_add(pdev);
if (ret) {
err:
+ ACPI_HANDLE_SET(&pdev->dev, NULL);
kfree(pdev->dev.dma_mask);

err_alloc:

2012-11-20 00:57:03

by Rafael J. Wysocki

[permalink] [raw]
Subject: [Update][PATCH 0/3] ACPI: Simplify "glueing" to physical nodes

On Sunday, November 18, 2012 10:10:33 PM Rafael J. Wysocki wrote:
> On Sunday, November 18, 2012 05:55:39 PM Mika Westerberg wrote:
> > On Sat, Nov 17, 2012 at 12:24:45PM +0100, Rafael J. Wysocki wrote:
> > > Well, maybe there is one. Perhaps we can make acpi_platform_notify()
> > > call acpi_bind_one() upfront and only if that fails, do the whole
> > > type->find_device() dance? Of course, acpi_bind_one() would need to
> > > be modified slightly too, like in the patch below.
> > >
> > > If we did that, acpi_i2c_add_device() would only need to assign acpi_handle
> > > as appropriate before calling i2c_new_device() (and analogously for SPI).
> > >
> > > What do you think?
> >
> > This is certainly better than the thing we use currently. It makes adding
> > I2C and SPI support much shorter and simpler. If others don't object I
> > would suggest that we switch to use this method.
>
> OK, thanks.
>
> The first of the following two patches is a slightly modified version of the
> one that you commented. Patch [2/2] implements the idea for platform devices
> and since it modifies struct platform_device_info, I'm adding a CC to Greg.
>
> The patches are on top of current linux-pm.git/linux-next.
>
> It looks like we may be able to use this approach for PCI too, in which case
> the whole .find_device() stuff won't be necessary any more.

Following is the series with the Greg's feedback taken into account.
Patch [1/3] is the same as before with the bug found by Mika fixed, [2/3] is
an additional patch adding struct acpi_dev_node to compile out unused stuff if
CONFIG_ACPI is not set and [3/3] is the previous [2/2] rebased on top of it.

Thanks,
Rafael


--
I speak only for myself.
Rafael J. Wysocki, Intel Open Source Technology Center.

2012-11-20 00:57:24

by Rafael J. Wysocki

[permalink] [raw]
Subject: [Update][PATCH 2/3] ACPI / driver core: Introduce struct acpi_dev_node and related macros

From: Rafael J. Wysocki <[email protected]>

To avoid adding an ACPI handle pointer to struct device on
architectures that don't use ACPI, or generally when CONFIG_ACPI is
not set, in which cases that pointer is useless, define struct
acpi_dev_node that will contain the handle pointer if CONFIG_ACPI is
set and will be empty otherwise and use it to represent the ACPI
device node field in struct device.

In addition to that define macros for reading and setting the ACPI
handle of a device that don't generate code when CONFIG_ACPI is
unset. Modify the ACPI subsystem to use those macros instead of
referring to the given device's ACPI handle directly.

Signed-off-by: Rafael J. Wysocki <[email protected]>
---
drivers/acpi/glue.c | 16 ++++++++--------
drivers/acpi/scan.c | 4 ++--
include/acpi/acpi_bus.h | 2 +-
include/linux/device.h | 16 +++++++++++++++-
4 files changed, 26 insertions(+), 12 deletions(-)

Index: linux/include/linux/device.h
===================================================================
--- linux.orig/include/linux/device.h
+++ linux/include/linux/device.h
@@ -578,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.
@@ -683,7 +689,7 @@ struct device {
struct dev_archdata archdata;

struct device_node *of_node; /* associated device tree node */
- void *acpi_handle; /* associated ACPI device node */
+ struct acpi_dev_node acpi_node; /* associated ACPI device node */

dev_t devt; /* dev_t, creates the sysfs "dev" */
u32 id; /* device instance */
@@ -704,6 +710,14 @@ static inline struct device *kobj_to_dev
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>

Index: linux/include/acpi/acpi_bus.h
===================================================================
--- linux.orig/include/acpi/acpi_bus.h
+++ linux/include/acpi/acpi_bus.h
@@ -411,7 +411,7 @@ acpi_handle acpi_get_child(acpi_handle,
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)->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);
Index: linux/drivers/acpi/glue.c
===================================================================
--- linux.orig/drivers/acpi/glue.c
+++ linux/drivers/acpi/glue.c
@@ -134,12 +134,12 @@ static int acpi_bind_one(struct device *
char physical_node_name[sizeof(PHYSICAL_NODE_STRING) + 2];
int retval = -EINVAL;

- if (dev->acpi_handle) {
+ if (ACPI_HANDLE(dev)) {
if (handle) {
dev_warn(dev, "ACPI handle is already set\n");
return -EINVAL;
} else {
- handle = dev->acpi_handle;
+ handle = ACPI_HANDLE(dev);
}
}
if (!handle)
@@ -181,8 +181,8 @@ static int acpi_bind_one(struct device *

mutex_unlock(&acpi_dev->physical_node_lock);

- if (!dev->acpi_handle)
- dev->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);
@@ -200,7 +200,7 @@ static int acpi_bind_one(struct device *
return 0;

err:
- dev->acpi_handle = NULL;
+ ACPI_HANDLE_SET(dev, NULL);
put_device(dev);
return retval;

@@ -217,10 +217,10 @@ static int acpi_unbind_one(struct device
acpi_status status;
struct list_head *node, *next;

- if (!dev->acpi_handle)
+ if (!ACPI_HANDLE(dev))
return 0;

- status = acpi_bus_get_device(dev->acpi_handle, &acpi_dev);
+ status = acpi_bus_get_device(ACPI_HANDLE(dev), &acpi_dev);
if (ACPI_FAILURE(status))
goto err;

@@ -246,7 +246,7 @@ static int acpi_unbind_one(struct device

sysfs_remove_link(&acpi_dev->dev.kobj, physical_node_name);
sysfs_remove_link(&dev->kobj, "firmware_node");
- dev->acpi_handle = NULL;
+ ACPI_HANDLE_SET(dev, NULL);
/* acpi_bind_one increase refcnt by one */
put_device(dev);
kfree(entry);
Index: linux/drivers/acpi/scan.c
===================================================================
--- linux.orig/drivers/acpi/scan.c
+++ linux/drivers/acpi/scan.c
@@ -443,8 +443,8 @@ const struct acpi_device_id *acpi_match_
{
struct acpi_device *adev;

- if (!ids || !dev->acpi_handle
- || ACPI_FAILURE(acpi_bus_get_device(dev->acpi_handle, &adev)))
+ if (!ids || !ACPI_HANDLE(dev)
+ || ACPI_FAILURE(acpi_bus_get_device(ACPI_HANDLE(dev), &adev)))
return NULL;

return __acpi_match_device(adev, ids);

2012-11-20 00:57:23

by Rafael J. Wysocki

[permalink] [raw]
Subject: [Update][PATCH 1/3] ACPI: Allow ACPI handles of devices to be initialized in advance

From: Rafael J. Wysocki <[email protected]>

Currently, the ACPI handles of devices are initialized from within
device_add(), by acpi_bind_one() called from acpi_platform_notify()
which first uses the .find_device() routine provided by the device's
bus type to find the matching device node in the ACPI namespace.
This is a source of some computational overhead and, moreover, the
correctness of the result depends on the implementation of
.find_device() which is known to fail occasionally for some bus types
(e.g. PCI). In some cases, however, the corresponding ACPI device
node is known already before calling device_add() for the given
struct device object and the whole .find_device() dance in
acpi_platform_notify() is then simply unnecessary.

For this reason, make it possible to initialize the ACPI handles of
devices before calling device_add() for them. Modify
acpi_platform_notify() to call acpi_bind_one() in advance to check
the device's existing ACPI handle and skip the .find_device()
search if that is successful. Change acpi_bind_one() accordingly.

Signed-off-by: Rafael J. Wysocki <[email protected]>
Reviewed-by: Mika Westerberg <[email protected]>
---
drivers/acpi/glue.c | 44 ++++++++++++++++++++++++++++++++++----------
1 file changed, 34 insertions(+), 10 deletions(-)

Index: linux/drivers/acpi/glue.c
===================================================================
--- linux.orig/drivers/acpi/glue.c
+++ linux/drivers/acpi/glue.c
@@ -130,46 +130,59 @@ static int acpi_bind_one(struct device *
{
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->acpi_handle) {
- dev_warn(dev, "Drivers changed 'acpi_handle'\n");
- return -EINVAL;
+ if (handle) {
+ dev_warn(dev, "ACPI handle is already set\n");
+ return -EINVAL;
+ } else {
+ handle = dev->acpi_handle;
+ }
}
+ 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->acpi_handle = handle;
+ if (!dev->acpi_handle)
+ dev->acpi_handle = handle;

if (!physical_node->node_id)
strcpy(physical_node_name, PHYSICAL_NODE_STRING);
@@ -187,8 +200,14 @@ static int acpi_bind_one(struct device *
return 0;

err:
+ dev->acpi_handle = 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)
@@ -247,6 +266,10 @@ static int acpi_platform_notify(struct d
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);
@@ -260,10 +283,11 @@ static int acpi_platform_notify(struct d
}
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 };

2012-11-20 07:04:49

by Mika Westerberg

[permalink] [raw]
Subject: Re: [PATCH v2 3/3 UPDATED] i2c / ACPI: add ACPI enumeration support

On Mon, Nov 19, 2012 at 03:49:25PM -0700, Bjorn Helgaas wrote:
> I think the benefit here is that you can merely point
> .acpi_match_table at an acpi_device_id[] table, then use
> platform_get_resource() as a generic way to get resources, whether the
> platform device came from OF, ACPI, etc. The alternative would be to
> add, e.g., a PNP driver with a .probe() method that uses
> pnp_get_resource(). That's not very much code, but it is more, even
> if the .probe() method just calls a device registration function
> that's shared across bus types.
>
> That benefit seems like a great thing, and my question then is why
> wouldn't we just do it across the board and make platform devices for
> *all* ACPI devices without having the I2C and SPI special cases?

That wouldn't be any better than having a PNP or ACPI device. We must still
create the corresponding I2C or SPI device in order to have a driver that
can plug into I2C or SPI core.

2012-11-20 09:07:04

by Mika Westerberg

[permalink] [raw]
Subject: Re: [Update][PATCH 2/3] ACPI / driver core: Introduce struct acpi_dev_node and related macros

On Tue, Nov 20, 2012 at 01:59:23AM +0100, Rafael J. Wysocki wrote:
> Index: linux/include/linux/device.h
> ===================================================================
> --- linux.orig/include/linux/device.h
> +++ linux/include/linux/device.h
> @@ -578,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.
> @@ -683,7 +689,7 @@ struct device {
> struct dev_archdata archdata;
>
> struct device_node *of_node; /* associated device tree node */
> - void *acpi_handle; /* associated ACPI device node */
> + struct acpi_dev_node acpi_node; /* associated ACPI device node */

Please update the kerneldoc comment as well.

2012-11-20 09:08:34

by Mika Westerberg

[permalink] [raw]
Subject: Re: [Update][PATCH 0/3] ACPI: Simplify "glueing" to physical nodes

On Tue, Nov 20, 2012 at 01:55:46AM +0100, Rafael J. Wysocki wrote:
>
> Following is the series with the Greg's feedback taken into account.
> Patch [1/3] is the same as before with the bug found by Mika fixed, [2/3] is
> an additional patch adding struct acpi_dev_node to compile out unused stuff if
> CONFIG_ACPI is not set and [3/3] is the previous [2/2] rebased on top of it.

I've tested this on my ACPI 5 test machine and it works as expected. I also
adapted the I2C, GPIO and SPI patches on top of this series and planning to
post them shortly.

Thanks.

2012-11-20 09:27:22

by Rafael J. Wysocki

[permalink] [raw]
Subject: Re: [Update][PATCH 0/3] ACPI: Simplify "glueing" to physical nodes

On Tuesday, November 20, 2012 11:11:41 AM Mika Westerberg wrote:
> On Tue, Nov 20, 2012 at 01:55:46AM +0100, Rafael J. Wysocki wrote:
> >
> > Following is the series with the Greg's feedback taken into account.
> > Patch [1/3] is the same as before with the bug found by Mika fixed, [2/3] is
> > an additional patch adding struct acpi_dev_node to compile out unused stuff if
> > CONFIG_ACPI is not set and [3/3] is the previous [2/2] rebased on top of it.
>
> I've tested this on my ACPI 5 test machine and it works as expected. I also
> adapted the I2C, GPIO and SPI patches on top of this series and planning to
> post them shortly.

Great, thanks a lot!

Rafael


--
I speak only for myself.
Rafael J. Wysocki, Intel Open Source Technology Center.

2012-11-20 09:29:42

by Rafael J. Wysocki

[permalink] [raw]
Subject: [Update 2][PATCH 2/3] ACPI / driver core: Introduce struct acpi_dev_node and related macros

On Tuesday, November 20, 2012 11:10:07 AM Mika Westerberg wrote:
> On Tue, Nov 20, 2012 at 01:59:23AM +0100, Rafael J. Wysocki wrote:
> > Index: linux/include/linux/device.h
> > ===================================================================
> > --- linux.orig/include/linux/device.h
> > +++ linux/include/linux/device.h
> > @@ -578,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.
> > @@ -683,7 +689,7 @@ struct device {
> > struct dev_archdata archdata;
> >
> > struct device_node *of_node; /* associated device tree node */
> > - void *acpi_handle; /* associated ACPI device node */
> > + struct acpi_dev_node acpi_node; /* associated ACPI device node */
>
> Please update the kerneldoc comment as well.

Right, thanks for the reminder. :-)

Updated patch is appended.

Thanks,
Rafael


---
From: Rafael J. Wysocki <[email protected]>
Subject: ACPI / driver core: Introduce struct acpi_dev_node and related macros

To avoid adding an ACPI handle pointer to struct device on
architectures that don't use ACPI, or generally when CONFIG_ACPI is
not set, in which cases that pointer is useless, define struct
acpi_dev_node that will contain the handle pointer if CONFIG_ACPI is
set and will be empty otherwise and use it to represent the ACPI
device node field in struct device.

In addition to that define macros for reading and setting the ACPI
handle of a device that don't generate code when CONFIG_ACPI is
unset. Modify the ACPI subsystem to use those macros instead of
referring to the given device's ACPI handle directly.

Signed-off-by: Rafael J. Wysocki <[email protected]>
---
drivers/acpi/glue.c | 16 ++++++++--------
drivers/acpi/scan.c | 4 ++--
include/acpi/acpi_bus.h | 2 +-
include/linux/device.h | 18 ++++++++++++++++--
4 files changed, 27 insertions(+), 13 deletions(-)

Index: linux/include/linux/device.h
===================================================================
--- linux.orig/include/linux/device.h
+++ linux/include/linux/device.h
@@ -578,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.
@@ -618,7 +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_handle: Associated ACPI device node's namespace handle.
+ * @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.
@@ -683,7 +689,7 @@ struct device {
struct dev_archdata archdata;

struct device_node *of_node; /* associated device tree node */
- void *acpi_handle; /* associated ACPI device node */
+ struct acpi_dev_node acpi_node; /* associated ACPI device node */

dev_t devt; /* dev_t, creates the sysfs "dev" */
u32 id; /* device instance */
@@ -704,6 +710,14 @@ static inline struct device *kobj_to_dev
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>

Index: linux/include/acpi/acpi_bus.h
===================================================================
--- linux.orig/include/acpi/acpi_bus.h
+++ linux/include/acpi/acpi_bus.h
@@ -411,7 +411,7 @@ acpi_handle acpi_get_child(acpi_handle,
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)->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);
Index: linux/drivers/acpi/glue.c
===================================================================
--- linux.orig/drivers/acpi/glue.c
+++ linux/drivers/acpi/glue.c
@@ -134,12 +134,12 @@ static int acpi_bind_one(struct device *
char physical_node_name[sizeof(PHYSICAL_NODE_STRING) + 2];
int retval = -EINVAL;

- if (dev->acpi_handle) {
+ if (ACPI_HANDLE(dev)) {
if (handle) {
dev_warn(dev, "ACPI handle is already set\n");
return -EINVAL;
} else {
- handle = dev->acpi_handle;
+ handle = ACPI_HANDLE(dev);
}
}
if (!handle)
@@ -181,8 +181,8 @@ static int acpi_bind_one(struct device *

mutex_unlock(&acpi_dev->physical_node_lock);

- if (!dev->acpi_handle)
- dev->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);
@@ -200,7 +200,7 @@ static int acpi_bind_one(struct device *
return 0;

err:
- dev->acpi_handle = NULL;
+ ACPI_HANDLE_SET(dev, NULL);
put_device(dev);
return retval;

@@ -217,10 +217,10 @@ static int acpi_unbind_one(struct device
acpi_status status;
struct list_head *node, *next;

- if (!dev->acpi_handle)
+ if (!ACPI_HANDLE(dev))
return 0;

- status = acpi_bus_get_device(dev->acpi_handle, &acpi_dev);
+ status = acpi_bus_get_device(ACPI_HANDLE(dev), &acpi_dev);
if (ACPI_FAILURE(status))
goto err;

@@ -246,7 +246,7 @@ static int acpi_unbind_one(struct device

sysfs_remove_link(&acpi_dev->dev.kobj, physical_node_name);
sysfs_remove_link(&dev->kobj, "firmware_node");
- dev->acpi_handle = NULL;
+ ACPI_HANDLE_SET(dev, NULL);
/* acpi_bind_one increase refcnt by one */
put_device(dev);
kfree(entry);
Index: linux/drivers/acpi/scan.c
===================================================================
--- linux.orig/drivers/acpi/scan.c
+++ linux/drivers/acpi/scan.c
@@ -443,8 +443,8 @@ const struct acpi_device_id *acpi_match_
{
struct acpi_device *adev;

- if (!ids || !dev->acpi_handle
- || ACPI_FAILURE(acpi_bus_get_device(dev->acpi_handle, &adev)))
+ if (!ids || !ACPI_HANDLE(dev)
+ || ACPI_FAILURE(acpi_bus_get_device(ACPI_HANDLE(dev), &adev)))
return NULL;

return __acpi_match_device(adev, ids);

2012-11-20 10:26:37

by Mika Westerberg

[permalink] [raw]
Subject: [PATCH v3 1/3] gpio / ACPI: add ACPI support

From: Mathias Nyman <[email protected]>

Add support for translating ACPI GPIO pin numbers to Linux GPIO API pins.
Needs a gpio controller driver with the acpi handler hook set.

Drivers can use acpi_get_gpio() to translate ACPI5 GpioIO and GpioInt
resources to Linux GPIO's.

Signed-off-by: Mathias Nyman <[email protected]>
Signed-off-by: Mika Westerberg <[email protected]>
---
drivers/gpio/Kconfig | 4 ++++
drivers/gpio/Makefile | 1 +
drivers/gpio/gpiolib-acpi.c | 56 +++++++++++++++++++++++++++++++++++++++++++
include/linux/acpi_gpio.h | 19 +++++++++++++++
4 files changed, 80 insertions(+)
create mode 100644 drivers/gpio/gpiolib-acpi.c
create mode 100644 include/linux/acpi_gpio.h

diff --git a/drivers/gpio/Kconfig b/drivers/gpio/Kconfig
index f11d8e3..5c9b384 100644
--- a/drivers/gpio/Kconfig
+++ b/drivers/gpio/Kconfig
@@ -49,6 +49,10 @@ config OF_GPIO
def_bool y
depends on OF

+config GPIO_ACPI
+ def_bool y
+ depends on ACPI
+
config DEBUG_GPIO
bool "Debug GPIO calls"
depends on DEBUG_KERNEL
diff --git a/drivers/gpio/Makefile b/drivers/gpio/Makefile
index 9aeed67..420dbac 100644
--- a/drivers/gpio/Makefile
+++ b/drivers/gpio/Makefile
@@ -4,6 +4,7 @@ ccflags-$(CONFIG_DEBUG_GPIO) += -DDEBUG

obj-$(CONFIG_GPIOLIB) += gpiolib.o devres.o
obj-$(CONFIG_OF_GPIO) += gpiolib-of.o
+obj-$(CONFIG_GPIO_ACPI) += gpiolib-acpi.o

# Device drivers. Generally keep list sorted alphabetically
obj-$(CONFIG_GPIO_GENERIC) += gpio-generic.o
diff --git a/drivers/gpio/gpiolib-acpi.c b/drivers/gpio/gpiolib-acpi.c
new file mode 100644
index 0000000..8285144
--- /dev/null
+++ b/drivers/gpio/gpiolib-acpi.c
@@ -0,0 +1,56 @@
+/*
+ * ACPI helpers for GPIO API
+ *
+ * Copyright (C) 2012, Intel Corporation
+ * Authors: Mathias Nyman <[email protected]>
+ * Mika Westerberg <[email protected]>
+ *
+ * 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/errno.h>
+#include <linux/gpio.h>
+#include <linux/export.h>
+#include <linux/acpi_gpio.h>
+#include <linux/acpi.h>
+
+static int acpi_gpiochip_find(struct gpio_chip *gc, void *data)
+{
+ acpi_handle handle = data;
+
+ if (!gc->dev)
+ return false;
+
+ return ACPI_HANDLE(gc->dev) == handle;
+}
+
+/**
+ * acpi_get_gpio() - Translate ACPI GPIO pin to GPIO number usable with GPIO API
+ * @path: ACPI GPIO controller full path name, (e.g. "\\_SB.GPO1")
+ * @pin: ACPI GPIO pin number (0-based, controller-relative)
+ *
+ * Returns GPIO number to use with Linux generic GPIO API, or errno error value
+ */
+
+int acpi_get_gpio(char *path, int pin)
+{
+ struct gpio_chip *chip;
+ acpi_handle handle;
+ acpi_status status;
+
+ status = acpi_get_handle(NULL, path, &handle);
+ if (ACPI_FAILURE(status))
+ return -ENODEV;
+
+ chip = gpiochip_find(handle, acpi_gpiochip_find);
+ if (!chip)
+ return -ENODEV;
+
+ if (!gpio_is_valid(chip->base + pin))
+ return -EINVAL;
+
+ return chip->base + pin;
+}
+EXPORT_SYMBOL_GPL(acpi_get_gpio);
diff --git a/include/linux/acpi_gpio.h b/include/linux/acpi_gpio.h
new file mode 100644
index 0000000..91615a3
--- /dev/null
+++ b/include/linux/acpi_gpio.h
@@ -0,0 +1,19 @@
+#ifndef _LINUX_ACPI_GPIO_H_
+#define _LINUX_ACPI_GPIO_H_
+
+#include <linux/errno.h>
+
+#ifdef CONFIG_GPIO_ACPI
+
+int acpi_get_gpio(char *path, int pin);
+
+#else /* CONFIG_GPIO_ACPI */
+
+static inline int acpi_get_gpio(char *path, int pin)
+{
+ return -ENODEV;
+}
+
+#endif /* CONFIG_GPIO_ACPI */
+
+#endif /* _LINUX_ACPI_GPIO_H_ */
--
1.7.10.4

2012-11-20 10:26:40

by Mika Westerberg

[permalink] [raw]
Subject: [PATCH v3 3/3] i2c / ACPI: add ACPI enumeration support

ACPI 5 introduced I2cSerialBus resource that makes it possible to enumerate
and configure the I2C slave devices behind the I2C controller. This patch
adds helper functions to support I2C slave enumeration.

An ACPI enabled I2C controller driver only needs to call acpi_i2c_register_devices()
in order to get its slave devices enumerated, created and bound to the
corresponding ACPI handle.

Signed-off-by: Mika Westerberg <[email protected]>
---
drivers/acpi/Kconfig | 6 +++
drivers/acpi/Makefile | 1 +
drivers/acpi/acpi_i2c.c | 112 +++++++++++++++++++++++++++++++++++++++++++++++
drivers/i2c/i2c-core.c | 6 +++
include/linux/i2c.h | 9 ++++
5 files changed, 134 insertions(+)
create mode 100644 drivers/acpi/acpi_i2c.c

diff --git a/drivers/acpi/Kconfig b/drivers/acpi/Kconfig
index 119d58d..0300bf6 100644
--- a/drivers/acpi/Kconfig
+++ b/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
diff --git a/drivers/acpi/Makefile b/drivers/acpi/Makefile
index 7289828..2a4502b 100644
--- a/drivers/acpi/Makefile
+++ b/drivers/acpi/Makefile
@@ -70,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
diff --git a/drivers/acpi/acpi_i2c.c b/drivers/acpi/acpi_i2c.c
new file mode 100644
index 0000000..185183d
--- /dev/null
+++ b/drivers/acpi/acpi_i2c.c
@@ -0,0 +1,112 @@
+/*
+ * ACPI I2C enumeration support
+ *
+ * Copyright (C) 2012, Intel Corporation
+ * Author: Mika Westerberg <[email protected]>
+ *
+ * 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 acpi_resource_i2c_serialbus *sb;
+ struct i2c_board_info *info = data;
+ struct resource r;
+
+ switch (ares->type) {
+ case ACPI_RESOURCE_TYPE_IRQ:
+ case ACPI_RESOURCE_TYPE_EXTENDED_IRQ:
+ /* Only use the first interrupt resource and skip the rest */
+ memset(&r, 0, sizeof(r));
+ if (info->irq < 0 && acpi_dev_resource_interrupt(ares, 0, &r))
+ info->irq = r.start;
+ return 1;
+
+ case ACPI_RESOURCE_TYPE_SERIAL_BUS:
+ 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;
+ return 1;
+ }
+ }
+ return 0;
+ }
+
+ return 0;
+}
+
+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);
+ if (ret < 0)
+ return AE_OK;
+
+ acpi_dev_free_resource_list(&resource_list);
+
+ if (!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);
diff --git a/drivers/i2c/i2c-core.c b/drivers/i2c/i2c-core.c
index a7edf98..e388590 100644
--- a/drivers/i2c/i2c-core.c
+++ b/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),
diff --git a/include/linux/i2c.h b/include/linux/i2c.h
index 800de22..d0c4db7 100644
--- a/include/linux/i2c.h
+++ b/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.7.10.4

2012-11-20 10:26:50

by Mika Westerberg

[permalink] [raw]
Subject: [PATCH v3 0/3] ACPI 5 support for GPIO, SPI and I2C

This is a third version of the series. I've based these on top of Rafael's
"simplify glueing ACPI handles to physical nodes" seen here:

https://lkml.org/lkml/2012/11/19/588

There is a dependency to linux-pm tree and to the above patches so I
propose to merge these via that same tree.

Changes to v2:
- drop the ACPI ->find_device() glue magic in preference of the new
simplified mechanism where we just assign the ACPI handle
- correct the IRQ resource handling to take the first resource and
skip the rest
- moved declaration of acpi_i2c_register_devices() to i2c.h instead
of having a separate header for a single function
- added acpi_node to struct i2c_board_info (analoguous to of_node).

Changes to the original version:
[gpio]
- CONFIG_GPIO_ACPI instead of CONFIG_ACPI_GPIO
- removed redundant test in acpi_gpiochip_find()

[spi and i2c]
- switched to use ACPI centralized _CRS evaluation framework
introduced by Rafael
- dropped request_module() call
- dropped the acpi_enumerate_spi/i2c_device()
- added required includes and dropped <linux/acpi.h> from
acpi_i2c.h


Mathias Nyman (1):
gpio / ACPI: add ACPI support

Mika Westerberg (2):
spi / ACPI: add ACPI enumeration support
i2c / ACPI: add ACPI enumeration support

drivers/acpi/Kconfig | 6 +++
drivers/acpi/Makefile | 1 +
drivers/acpi/acpi_i2c.c | 112 +++++++++++++++++++++++++++++++++++++++++
drivers/gpio/Kconfig | 4 ++
drivers/gpio/Makefile | 1 +
drivers/gpio/gpiolib-acpi.c | 56 +++++++++++++++++++++
drivers/i2c/i2c-core.c | 6 +++
drivers/spi/spi.c | 115 ++++++++++++++++++++++++++++++++++++++++++-
include/linux/acpi_gpio.h | 19 +++++++
include/linux/i2c.h | 9 ++++
10 files changed, 328 insertions(+), 1 deletion(-)
create mode 100644 drivers/acpi/acpi_i2c.c
create mode 100644 drivers/gpio/gpiolib-acpi.c
create mode 100644 include/linux/acpi_gpio.h

--
1.7.10.4

2012-11-20 10:27:24

by Mika Westerberg

[permalink] [raw]
Subject: [PATCH v3 2/3] spi / ACPI: add ACPI enumeration support

ACPI 5 introduced SPISerialBus resource that allows us to enumerate and
configure the SPI slave devices behind the SPI controller. This patch adds
support for this to the SPI core.

In addition we bind ACPI nodes to SPI devices. This makes it possible for
the slave drivers to get the ACPI handle for further configuration.

Signed-off-by: Mika Westerberg <[email protected]>
---
drivers/spi/spi.c | 115 ++++++++++++++++++++++++++++++++++++++++++++++++++++-
1 file changed, 114 insertions(+), 1 deletion(-)

diff --git a/drivers/spi/spi.c b/drivers/spi/spi.c
index 84c2861..3ae5351 100644
--- a/drivers/spi/spi.c
+++ b/drivers/spi/spi.c
@@ -35,6 +35,8 @@
#include <linux/sched.h>
#include <linux/delay.h>
#include <linux/kthread.h>
+#include <linux/ioport.h>
+#include <linux/acpi.h>

static void spidev_release(struct device *dev)
{
@@ -93,6 +95,10 @@ static int spi_match_device(struct device *dev, struct device_driver *drv)
if (of_driver_match_device(dev, drv))
return 1;

+ /* Then try ACPI */
+ if (acpi_driver_match_device(dev, drv))
+ return 1;
+
if (sdrv->id_table)
return !!spi_match_id(sdrv->id_table, spi);

@@ -888,6 +894,112 @@ static void of_register_spi_devices(struct spi_master *master)
static void of_register_spi_devices(struct spi_master *master) { }
#endif

+#ifdef CONFIG_ACPI
+static int acpi_spi_add_resource(struct acpi_resource *ares, void *data)
+{
+ struct acpi_resource_spi_serialbus *sb;
+ struct spi_device *spi = data;
+ struct resource r;
+
+ switch (ares->type) {
+ case ACPI_RESOURCE_TYPE_IRQ:
+ case ACPI_RESOURCE_TYPE_EXTENDED_IRQ:
+ /* Only use the first interrupt resource and skip the rest */
+ memset(&r, 0, sizeof(r));
+ if (spi->irq < 0 && acpi_dev_resource_interrupt(ares, 0, &r))
+ spi->irq = r.start;
+ return 1;
+
+ case ACPI_RESOURCE_TYPE_SERIAL_BUS:
+ sb = &ares->data.spi_serial_bus;
+ if (sb->type == ACPI_RESOURCE_SERIAL_TYPE_SPI) {
+ spi->chip_select = sb->device_selection;
+ spi->max_speed_hz = sb->connection_speed;
+
+ if (sb->clock_phase == ACPI_SPI_SECOND_PHASE)
+ spi->mode |= SPI_CPHA;
+ if (sb->clock_polarity == ACPI_SPI_START_HIGH)
+ spi->mode |= SPI_CPOL;
+ if (sb->device_polarity == ACPI_SPI_ACTIVE_HIGH)
+ spi->mode |= SPI_CS_HIGH;
+
+ return 1;
+ }
+ return 0;
+ }
+
+ return 0;
+}
+
+static acpi_status acpi_spi_add_device(acpi_handle handle, u32 level,
+ void *data, void **return_value)
+{
+ struct spi_master *master = data;
+ struct list_head resource_list;
+ struct acpi_device *adev;
+ struct spi_device *spi;
+ int ret;
+
+ if (acpi_bus_get_device(handle, &adev))
+ return AE_OK;
+ if (acpi_bus_get_status(adev) || !adev->status.present)
+ return AE_OK;
+
+ spi = spi_alloc_device(master);
+ if (!spi) {
+ dev_err(&master->dev, "failed to allocate SPI device for %s\n",
+ dev_name(&adev->dev));
+ return AE_NO_MEMORY;
+ }
+
+ ACPI_HANDLE_SET(&spi->dev, handle);
+ spi->irq = -1;
+
+ INIT_LIST_HEAD(&resource_list);
+ ret = acpi_dev_get_resources(adev, &resource_list,
+ acpi_spi_add_resource, spi);
+ if (ret < 0)
+ goto fail_put_dev;
+
+ acpi_dev_free_resource_list(&resource_list);
+
+ if (!spi->max_speed_hz)
+ goto fail_put_dev;
+
+ strlcpy(spi->modalias, dev_name(&adev->dev), sizeof(spi->modalias));
+ if (spi_add_device(spi)) {
+ dev_err(&master->dev, "failed to add SPI device %s from ACPI\n",
+ dev_name(&adev->dev));
+ goto fail_put_dev;
+ }
+
+ return AE_OK;
+
+fail_put_dev:
+ spi_dev_put(spi);
+
+ return AE_OK;
+}
+
+static void acpi_register_spi_devices(struct spi_master *master)
+{
+ acpi_status status;
+ acpi_handle handle;
+
+ handle = ACPI_HANDLE(&master->dev);
+ if (!handle)
+ return;
+
+ status = acpi_walk_namespace(ACPI_TYPE_DEVICE, handle, 1,
+ acpi_spi_add_device, NULL,
+ master, NULL);
+ if (ACPI_FAILURE(status))
+ dev_warn(&master->dev, "failed to enumerate SPI slaves\n");
+}
+#else
+static inline void acpi_register_spi_devices(struct spi_master *master) {}
+#endif /* CONFIG_ACPI */
+
static void spi_master_release(struct device *dev)
{
struct spi_master *master;
@@ -1023,8 +1135,9 @@ int spi_register_master(struct spi_master *master)
spi_match_master_to_boardinfo(master, &bi->board_info);
mutex_unlock(&board_lock);

- /* Register devices from the device tree */
+ /* Register devices from the device tree and ACPI */
of_register_spi_devices(master);
+ acpi_register_spi_devices(master);
done:
return status;
}
--
1.7.10.4

2012-11-20 12:42:09

by Rafael J. Wysocki

[permalink] [raw]
Subject: Re: [PATCH v3 1/3] gpio / ACPI: add ACPI support

On Tuesday, November 20, 2012 12:29:42 PM Mika Westerberg wrote:
> From: Mathias Nyman <[email protected]>
>
> Add support for translating ACPI GPIO pin numbers to Linux GPIO API pins.
> Needs a gpio controller driver with the acpi handler hook set.
>
> Drivers can use acpi_get_gpio() to translate ACPI5 GpioIO and GpioInt
> resources to Linux GPIO's.
>
> Signed-off-by: Mathias Nyman <[email protected]>
> Signed-off-by: Mika Westerberg <[email protected]>
> ---
> drivers/gpio/Kconfig | 4 ++++
> drivers/gpio/Makefile | 1 +
> drivers/gpio/gpiolib-acpi.c | 56 +++++++++++++++++++++++++++++++++++++++++++
> include/linux/acpi_gpio.h | 19 +++++++++++++++
> 4 files changed, 80 insertions(+)
> create mode 100644 drivers/gpio/gpiolib-acpi.c
> create mode 100644 include/linux/acpi_gpio.h
>
> diff --git a/drivers/gpio/Kconfig b/drivers/gpio/Kconfig
> index f11d8e3..5c9b384 100644
> --- a/drivers/gpio/Kconfig
> +++ b/drivers/gpio/Kconfig
> @@ -49,6 +49,10 @@ config OF_GPIO
> def_bool y
> depends on OF
>
> +config GPIO_ACPI
> + def_bool y
> + depends on ACPI
> +
> config DEBUG_GPIO
> bool "Debug GPIO calls"
> depends on DEBUG_KERNEL
> diff --git a/drivers/gpio/Makefile b/drivers/gpio/Makefile
> index 9aeed67..420dbac 100644
> --- a/drivers/gpio/Makefile
> +++ b/drivers/gpio/Makefile
> @@ -4,6 +4,7 @@ ccflags-$(CONFIG_DEBUG_GPIO) += -DDEBUG
>
> obj-$(CONFIG_GPIOLIB) += gpiolib.o devres.o
> obj-$(CONFIG_OF_GPIO) += gpiolib-of.o
> +obj-$(CONFIG_GPIO_ACPI) += gpiolib-acpi.o
>
> # Device drivers. Generally keep list sorted alphabetically
> obj-$(CONFIG_GPIO_GENERIC) += gpio-generic.o
> diff --git a/drivers/gpio/gpiolib-acpi.c b/drivers/gpio/gpiolib-acpi.c
> new file mode 100644
> index 0000000..8285144
> --- /dev/null
> +++ b/drivers/gpio/gpiolib-acpi.c
> @@ -0,0 +1,56 @@
> +/*
> + * ACPI helpers for GPIO API
> + *
> + * Copyright (C) 2012, Intel Corporation
> + * Authors: Mathias Nyman <[email protected]>
> + * Mika Westerberg <[email protected]>
> + *
> + * 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/errno.h>
> +#include <linux/gpio.h>
> +#include <linux/export.h>
> +#include <linux/acpi_gpio.h>
> +#include <linux/acpi.h>
> +
> +static int acpi_gpiochip_find(struct gpio_chip *gc, void *data)
> +{
> + acpi_handle handle = data;
> +
> + if (!gc->dev)
> + return false;
> +
> + return ACPI_HANDLE(gc->dev) == handle;

I would compare ACPI_HANDLE(gc->dev) to data directly here, but that's just
a matter of cleanliness. :-)

> +}
> +
> +/**
> + * acpi_get_gpio() - Translate ACPI GPIO pin to GPIO number usable with GPIO API
> + * @path: ACPI GPIO controller full path name, (e.g. "\\_SB.GPO1")
> + * @pin: ACPI GPIO pin number (0-based, controller-relative)
> + *
> + * Returns GPIO number to use with Linux generic GPIO API, or errno error value
> + */
> +
> +int acpi_get_gpio(char *path, int pin)
> +{
> + struct gpio_chip *chip;
> + acpi_handle handle;
> + acpi_status status;
> +
> + status = acpi_get_handle(NULL, path, &handle);
> + if (ACPI_FAILURE(status))
> + return -ENODEV;
> +
> + chip = gpiochip_find(handle, acpi_gpiochip_find);
> + if (!chip)
> + return -ENODEV;
> +
> + if (!gpio_is_valid(chip->base + pin))
> + return -EINVAL;
> +
> + return chip->base + pin;
> +}
> +EXPORT_SYMBOL_GPL(acpi_get_gpio);
> diff --git a/include/linux/acpi_gpio.h b/include/linux/acpi_gpio.h
> new file mode 100644
> index 0000000..91615a3
> --- /dev/null
> +++ b/include/linux/acpi_gpio.h
> @@ -0,0 +1,19 @@
> +#ifndef _LINUX_ACPI_GPIO_H_
> +#define _LINUX_ACPI_GPIO_H_
> +
> +#include <linux/errno.h>
> +
> +#ifdef CONFIG_GPIO_ACPI
> +
> +int acpi_get_gpio(char *path, int pin);
> +
> +#else /* CONFIG_GPIO_ACPI */
> +
> +static inline int acpi_get_gpio(char *path, int pin)
> +{
> + return -ENODEV;
> +}
> +
> +#endif /* CONFIG_GPIO_ACPI */
> +
> +#endif /* _LINUX_ACPI_GPIO_H_ */

Thanks,
Rafael


--
I speak only for myself.
Rafael J. Wysocki, Intel Open Source Technology Center.

2012-11-20 12:54:17

by Mika Westerberg

[permalink] [raw]
Subject: Re: [Update 2][PATCH 2/3] ACPI / driver core: Introduce struct acpi_dev_node and related macros

On Tue, Nov 20, 2012 at 10:34:04AM +0100, Rafael J. Wysocki wrote:
> On Tuesday, November 20, 2012 11:10:07 AM Mika Westerberg wrote:
> > On Tue, Nov 20, 2012 at 01:59:23AM +0100, Rafael J. Wysocki wrote:
> > > Index: linux/include/linux/device.h
> > > ===================================================================
> > > --- linux.orig/include/linux/device.h
> > > +++ linux/include/linux/device.h
> > > @@ -578,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.
> > > @@ -683,7 +689,7 @@ struct device {
> > > struct dev_archdata archdata;
> > >
> > > struct device_node *of_node; /* associated device tree node */
> > > - void *acpi_handle; /* associated ACPI device node */
> > > + struct acpi_dev_node acpi_node; /* associated ACPI device node */
> >
> > Please update the kerneldoc comment as well.
>
> Right, thanks for the reminder. :-)
>
> Updated patch is appended.
>
> Thanks,
> Rafael
>
>
> ---
> From: Rafael J. Wysocki <[email protected]>
> Subject: ACPI / driver core: Introduce struct acpi_dev_node and related macros
>
> To avoid adding an ACPI handle pointer to struct device on
> architectures that don't use ACPI, or generally when CONFIG_ACPI is
> not set, in which cases that pointer is useless, define struct
> acpi_dev_node that will contain the handle pointer if CONFIG_ACPI is
> set and will be empty otherwise and use it to represent the ACPI
> device node field in struct device.
>
> In addition to that define macros for reading and setting the ACPI
> handle of a device that don't generate code when CONFIG_ACPI is
> unset. Modify the ACPI subsystem to use those macros instead of
> referring to the given device's ACPI handle directly.
>
> Signed-off-by: Rafael J. Wysocki <[email protected]>

Reviewed-by: Mika Westerberg <[email protected]>

2012-11-20 13:01:00

by Rafael J. Wysocki

[permalink] [raw]
Subject: Re: [PATCH v3 2/3] spi / ACPI: add ACPI enumeration support

On Tuesday, November 20, 2012 12:29:43 PM Mika Westerberg wrote:
> ACPI 5 introduced SPISerialBus resource that allows us to enumerate and
> configure the SPI slave devices behind the SPI controller. This patch adds
> support for this to the SPI core.
>
> In addition we bind ACPI nodes to SPI devices. This makes it possible for
> the slave drivers to get the ACPI handle for further configuration.
>
> Signed-off-by: Mika Westerberg <[email protected]>
> ---
> drivers/spi/spi.c | 115 ++++++++++++++++++++++++++++++++++++++++++++++++++++-
> 1 file changed, 114 insertions(+), 1 deletion(-)
>
> diff --git a/drivers/spi/spi.c b/drivers/spi/spi.c
> index 84c2861..3ae5351 100644
> --- a/drivers/spi/spi.c
> +++ b/drivers/spi/spi.c
> @@ -35,6 +35,8 @@
> #include <linux/sched.h>
> #include <linux/delay.h>
> #include <linux/kthread.h>
> +#include <linux/ioport.h>
> +#include <linux/acpi.h>
>
> static void spidev_release(struct device *dev)
> {
> @@ -93,6 +95,10 @@ static int spi_match_device(struct device *dev, struct device_driver *drv)
> if (of_driver_match_device(dev, drv))
> return 1;
>
> + /* Then try ACPI */
> + if (acpi_driver_match_device(dev, drv))
> + return 1;
> +
> if (sdrv->id_table)
> return !!spi_match_id(sdrv->id_table, spi);
>
> @@ -888,6 +894,112 @@ static void of_register_spi_devices(struct spi_master *master)
> static void of_register_spi_devices(struct spi_master *master) { }
> #endif
>
> +#ifdef CONFIG_ACPI
> +static int acpi_spi_add_resource(struct acpi_resource *ares, void *data)
> +{
> + struct acpi_resource_spi_serialbus *sb;
> + struct spi_device *spi = data;
> + struct resource r;
> +
> + switch (ares->type) {
> + case ACPI_RESOURCE_TYPE_IRQ:
> + case ACPI_RESOURCE_TYPE_EXTENDED_IRQ:

It is not necessary to check the resource type for IRQ resources here,
because acpi_dev_resource_interrupt() will do it for you anyway. :-)

So, I would first check if the resource type is ACPI_RESOURCE_TYPE_SERIAL_BUS
(and populate the spi_device fields if so) and then do something like this:

if (acpi_dev_resource_interrupt(ares, 0, &r)) {
if (spi->irq < 0)
spi->irq = r.start;

return 1;
}

We don't even need to memset(), because we're not going to use that resource
object going forward.


> + /* Only use the first interrupt resource and skip the rest */
> + memset(&r, 0, sizeof(r));
> + if (spi->irq < 0 && acpi_dev_resource_interrupt(ares, 0, &r))
> + spi->irq = r.start;
> + return 1;
> +
> + case ACPI_RESOURCE_TYPE_SERIAL_BUS:
> + sb = &ares->data.spi_serial_bus;
> + if (sb->type == ACPI_RESOURCE_SERIAL_TYPE_SPI) {
> + spi->chip_select = sb->device_selection;
> + spi->max_speed_hz = sb->connection_speed;
> +
> + if (sb->clock_phase == ACPI_SPI_SECOND_PHASE)
> + spi->mode |= SPI_CPHA;
> + if (sb->clock_polarity == ACPI_SPI_START_HIGH)
> + spi->mode |= SPI_CPOL;
> + if (sb->device_polarity == ACPI_SPI_ACTIVE_HIGH)
> + spi->mode |= SPI_CS_HIGH;
> +
> + return 1;
> + }
> + return 0;
> + }
> +
> + return 0;

We're not interested in any resources except for the above, so I think we
can just always return 1 from this function, or am I missing anything?

> +}
> +
> +static acpi_status acpi_spi_add_device(acpi_handle handle, u32 level,
> + void *data, void **return_value)
> +{
> + struct spi_master *master = data;
> + struct list_head resource_list;
> + struct acpi_device *adev;
> + struct spi_device *spi;
> + int ret;
> +
> + if (acpi_bus_get_device(handle, &adev))
> + return AE_OK;
> + if (acpi_bus_get_status(adev) || !adev->status.present)
> + return AE_OK;
> +
> + spi = spi_alloc_device(master);
> + if (!spi) {
> + dev_err(&master->dev, "failed to allocate SPI device for %s\n",
> + dev_name(&adev->dev));
> + return AE_NO_MEMORY;
> + }
> +
> + ACPI_HANDLE_SET(&spi->dev, handle);
> + spi->irq = -1;
> +
> + INIT_LIST_HEAD(&resource_list);
> + ret = acpi_dev_get_resources(adev, &resource_list,
> + acpi_spi_add_resource, spi);

acpi_dev_free_resource_list(&resource_list); can be done here (the list
is going to be empty anyway if acpi_spi_add_resource() always returns 1)
and then you won't need the fail_put_dev label.

> + if (ret < 0)
> + goto fail_put_dev;
> +
> + acpi_dev_free_resource_list(&resource_list);
> +
> + if (!spi->max_speed_hz)
> + goto fail_put_dev;
> +
> + strlcpy(spi->modalias, dev_name(&adev->dev), sizeof(spi->modalias));
> + if (spi_add_device(spi)) {
> + dev_err(&master->dev, "failed to add SPI device %s from ACPI\n",
> + dev_name(&adev->dev));
> + goto fail_put_dev;
> + }
> +
> + return AE_OK;
> +
> +fail_put_dev:
> + spi_dev_put(spi);
> +
> + return AE_OK;
> +}
> +
> +static void acpi_register_spi_devices(struct spi_master *master)
> +{
> + acpi_status status;
> + acpi_handle handle;
> +
> + handle = ACPI_HANDLE(&master->dev);
> + if (!handle)
> + return;
> +
> + status = acpi_walk_namespace(ACPI_TYPE_DEVICE, handle, 1,
> + acpi_spi_add_device, NULL,
> + master, NULL);
> + if (ACPI_FAILURE(status))
> + dev_warn(&master->dev, "failed to enumerate SPI slaves\n");
> +}
> +#else
> +static inline void acpi_register_spi_devices(struct spi_master *master) {}
> +#endif /* CONFIG_ACPI */
> +
> static void spi_master_release(struct device *dev)
> {
> struct spi_master *master;
> @@ -1023,8 +1135,9 @@ int spi_register_master(struct spi_master *master)
> spi_match_master_to_boardinfo(master, &bi->board_info);
> mutex_unlock(&board_lock);
>
> - /* Register devices from the device tree */
> + /* Register devices from the device tree and ACPI */
> of_register_spi_devices(master);
> + acpi_register_spi_devices(master);
> done:
> return status;
> }

Thanks,
Rafael


--
I speak only for myself.
Rafael J. Wysocki, Intel Open Source Technology Center.

2012-11-20 13:02:20

by Rafael J. Wysocki

[permalink] [raw]
Subject: Re: [PATCH v3 3/3] i2c / ACPI: add ACPI enumeration support

On Tuesday, November 20, 2012 12:29:44 PM Mika Westerberg wrote:
> ACPI 5 introduced I2cSerialBus resource that makes it possible to enumerate
> and configure the I2C slave devices behind the I2C controller. This patch
> adds helper functions to support I2C slave enumeration.
>
> An ACPI enabled I2C controller driver only needs to call acpi_i2c_register_devices()
> in order to get its slave devices enumerated, created and bound to the
> corresponding ACPI handle.

My comments from the SPI patch apply here too almost verbatim. :-)

Thanks,
Rafael


--
I speak only for myself.
Rafael J. Wysocki, Intel Open Source Technology Center.

2012-11-20 13:12:17

by Mika Westerberg

[permalink] [raw]
Subject: Re: [PATCH v3 2/3] spi / ACPI: add ACPI enumeration support

On Tue, Nov 20, 2012 at 02:05:26PM +0100, Rafael J. Wysocki wrote:
> On Tuesday, November 20, 2012 12:29:43 PM Mika Westerberg wrote:
> > ACPI 5 introduced SPISerialBus resource that allows us to enumerate and
> > configure the SPI slave devices behind the SPI controller. This patch adds
> > support for this to the SPI core.
> >
> > In addition we bind ACPI nodes to SPI devices. This makes it possible for
> > the slave drivers to get the ACPI handle for further configuration.
> >
> > Signed-off-by: Mika Westerberg <[email protected]>
> > ---
> > drivers/spi/spi.c | 115 ++++++++++++++++++++++++++++++++++++++++++++++++++++-
> > 1 file changed, 114 insertions(+), 1 deletion(-)
> >
> > diff --git a/drivers/spi/spi.c b/drivers/spi/spi.c
> > index 84c2861..3ae5351 100644
> > --- a/drivers/spi/spi.c
> > +++ b/drivers/spi/spi.c
> > @@ -35,6 +35,8 @@
> > #include <linux/sched.h>
> > #include <linux/delay.h>
> > #include <linux/kthread.h>
> > +#include <linux/ioport.h>
> > +#include <linux/acpi.h>
> >
> > static void spidev_release(struct device *dev)
> > {
> > @@ -93,6 +95,10 @@ static int spi_match_device(struct device *dev, struct device_driver *drv)
> > if (of_driver_match_device(dev, drv))
> > return 1;
> >
> > + /* Then try ACPI */
> > + if (acpi_driver_match_device(dev, drv))
> > + return 1;
> > +
> > if (sdrv->id_table)
> > return !!spi_match_id(sdrv->id_table, spi);
> >
> > @@ -888,6 +894,112 @@ static void of_register_spi_devices(struct spi_master *master)
> > static void of_register_spi_devices(struct spi_master *master) { }
> > #endif
> >
> > +#ifdef CONFIG_ACPI
> > +static int acpi_spi_add_resource(struct acpi_resource *ares, void *data)
> > +{
> > + struct acpi_resource_spi_serialbus *sb;
> > + struct spi_device *spi = data;
> > + struct resource r;
> > +
> > + switch (ares->type) {
> > + case ACPI_RESOURCE_TYPE_IRQ:
> > + case ACPI_RESOURCE_TYPE_EXTENDED_IRQ:
>
> It is not necessary to check the resource type for IRQ resources here,
> because acpi_dev_resource_interrupt() will do it for you anyway. :-)
>
> So, I would first check if the resource type is ACPI_RESOURCE_TYPE_SERIAL_BUS
> (and populate the spi_device fields if so) and then do something like this:
>
> if (acpi_dev_resource_interrupt(ares, 0, &r)) {
> if (spi->irq < 0)
> spi->irq = r.start;
>
> return 1;
> }
>
> We don't even need to memset(), because we're not going to use that resource
> object going forward.

But doesn't acpi_dev_resource_interrupt() do acpi_register_gsi() and all
that stuff? And we were supposed to avoid that.

>
> > + /* Only use the first interrupt resource and skip the rest */
> > + memset(&r, 0, sizeof(r));
> > + if (spi->irq < 0 && acpi_dev_resource_interrupt(ares, 0, &r))
> > + spi->irq = r.start;
> > + return 1;
> > +
> > + case ACPI_RESOURCE_TYPE_SERIAL_BUS:
> > + sb = &ares->data.spi_serial_bus;
> > + if (sb->type == ACPI_RESOURCE_SERIAL_TYPE_SPI) {
> > + spi->chip_select = sb->device_selection;
> > + spi->max_speed_hz = sb->connection_speed;
> > +
> > + if (sb->clock_phase == ACPI_SPI_SECOND_PHASE)
> > + spi->mode |= SPI_CPHA;
> > + if (sb->clock_polarity == ACPI_SPI_START_HIGH)
> > + spi->mode |= SPI_CPOL;
> > + if (sb->device_polarity == ACPI_SPI_ACTIVE_HIGH)
> > + spi->mode |= SPI_CS_HIGH;
> > +
> > + return 1;
> > + }
> > + return 0;
> > + }
> > +
> > + return 0;
>
> We're not interested in any resources except for the above, so I think we
> can just always return 1 from this function, or am I missing anything?

Right you are, we can return 1 always. I'll update this.

> > +}
> > +
> > +static acpi_status acpi_spi_add_device(acpi_handle handle, u32 level,
> > + void *data, void **return_value)
> > +{
> > + struct spi_master *master = data;
> > + struct list_head resource_list;
> > + struct acpi_device *adev;
> > + struct spi_device *spi;
> > + int ret;
> > +
> > + if (acpi_bus_get_device(handle, &adev))
> > + return AE_OK;
> > + if (acpi_bus_get_status(adev) || !adev->status.present)
> > + return AE_OK;
> > +
> > + spi = spi_alloc_device(master);
> > + if (!spi) {
> > + dev_err(&master->dev, "failed to allocate SPI device for %s\n",
> > + dev_name(&adev->dev));
> > + return AE_NO_MEMORY;
> > + }
> > +
> > + ACPI_HANDLE_SET(&spi->dev, handle);
> > + spi->irq = -1;
> > +
> > + INIT_LIST_HEAD(&resource_list);
> > + ret = acpi_dev_get_resources(adev, &resource_list,
> > + acpi_spi_add_resource, spi);
>
> acpi_dev_free_resource_list(&resource_list); can be done here (the list
> is going to be empty anyway if acpi_spi_add_resource() always returns 1)
> and then you won't need the fail_put_dev label.

OK, but there are still two cases below where we need to do
spi_dev_put(spi). Or do you mean that for each case I just call that
directly instead of goto fail_put_dev?

> > + if (ret < 0)
> > + goto fail_put_dev;
> > +
> > + acpi_dev_free_resource_list(&resource_list);
> > +
> > + if (!spi->max_speed_hz)
> > + goto fail_put_dev;
> > +
> > + strlcpy(spi->modalias, dev_name(&adev->dev), sizeof(spi->modalias));
> > + if (spi_add_device(spi)) {
> > + dev_err(&master->dev, "failed to add SPI device %s from ACPI\n",
> > + dev_name(&adev->dev));
> > + goto fail_put_dev;
> > + }
> > +
> > + return AE_OK;
> > +
> > +fail_put_dev:
> > + spi_dev_put(spi);
> > +
> > + return AE_OK;
> > +}
> > +
> > +static void acpi_register_spi_devices(struct spi_master *master)
> > +{
> > + acpi_status status;
> > + acpi_handle handle;
> > +
> > + handle = ACPI_HANDLE(&master->dev);
> > + if (!handle)
> > + return;
> > +
> > + status = acpi_walk_namespace(ACPI_TYPE_DEVICE, handle, 1,
> > + acpi_spi_add_device, NULL,
> > + master, NULL);
> > + if (ACPI_FAILURE(status))
> > + dev_warn(&master->dev, "failed to enumerate SPI slaves\n");
> > +}
> > +#else
> > +static inline void acpi_register_spi_devices(struct spi_master *master) {}
> > +#endif /* CONFIG_ACPI */
> > +
> > static void spi_master_release(struct device *dev)
> > {
> > struct spi_master *master;
> > @@ -1023,8 +1135,9 @@ int spi_register_master(struct spi_master *master)
> > spi_match_master_to_boardinfo(master, &bi->board_info);
> > mutex_unlock(&board_lock);
> >
> > - /* Register devices from the device tree */
> > + /* Register devices from the device tree and ACPI */
> > of_register_spi_devices(master);
> > + acpi_register_spi_devices(master);
> > done:
> > return status;
> > }
>
> Thanks,
> Rafael
>
>
> --
> I speak only for myself.
> Rafael J. Wysocki, Intel Open Source Technology Center.

2012-11-20 13:19:50

by Rafael J. Wysocki

[permalink] [raw]
Subject: Re: [PATCH v3 2/3] spi / ACPI: add ACPI enumeration support

On Tuesday, November 20, 2012 03:15:25 PM Mika Westerberg wrote:
> On Tue, Nov 20, 2012 at 02:05:26PM +0100, Rafael J. Wysocki wrote:
> > On Tuesday, November 20, 2012 12:29:43 PM Mika Westerberg wrote:
> > > ACPI 5 introduced SPISerialBus resource that allows us to enumerate and
> > > configure the SPI slave devices behind the SPI controller. This patch adds
> > > support for this to the SPI core.
> > >
> > > In addition we bind ACPI nodes to SPI devices. This makes it possible for
> > > the slave drivers to get the ACPI handle for further configuration.
> > >
> > > Signed-off-by: Mika Westerberg <[email protected]>
> > > ---
> > > drivers/spi/spi.c | 115 ++++++++++++++++++++++++++++++++++++++++++++++++++++-
> > > 1 file changed, 114 insertions(+), 1 deletion(-)
> > >
> > > diff --git a/drivers/spi/spi.c b/drivers/spi/spi.c
> > > index 84c2861..3ae5351 100644
> > > --- a/drivers/spi/spi.c
> > > +++ b/drivers/spi/spi.c
> > > @@ -35,6 +35,8 @@
> > > #include <linux/sched.h>
> > > #include <linux/delay.h>
> > > #include <linux/kthread.h>
> > > +#include <linux/ioport.h>
> > > +#include <linux/acpi.h>
> > >
> > > static void spidev_release(struct device *dev)
> > > {
> > > @@ -93,6 +95,10 @@ static int spi_match_device(struct device *dev, struct device_driver *drv)
> > > if (of_driver_match_device(dev, drv))
> > > return 1;
> > >
> > > + /* Then try ACPI */
> > > + if (acpi_driver_match_device(dev, drv))
> > > + return 1;
> > > +
> > > if (sdrv->id_table)
> > > return !!spi_match_id(sdrv->id_table, spi);
> > >
> > > @@ -888,6 +894,112 @@ static void of_register_spi_devices(struct spi_master *master)
> > > static void of_register_spi_devices(struct spi_master *master) { }
> > > #endif
> > >
> > > +#ifdef CONFIG_ACPI
> > > +static int acpi_spi_add_resource(struct acpi_resource *ares, void *data)
> > > +{
> > > + struct acpi_resource_spi_serialbus *sb;
> > > + struct spi_device *spi = data;
> > > + struct resource r;
> > > +
> > > + switch (ares->type) {
> > > + case ACPI_RESOURCE_TYPE_IRQ:
> > > + case ACPI_RESOURCE_TYPE_EXTENDED_IRQ:
> >
> > It is not necessary to check the resource type for IRQ resources here,
> > because acpi_dev_resource_interrupt() will do it for you anyway. :-)
> >
> > So, I would first check if the resource type is ACPI_RESOURCE_TYPE_SERIAL_BUS
> > (and populate the spi_device fields if so) and then do something like this:
> >
> > if (acpi_dev_resource_interrupt(ares, 0, &r)) {
> > if (spi->irq < 0)
> > spi->irq = r.start;
> >
> > return 1;
> > }
> >
> > We don't even need to memset(), because we're not going to use that resource
> > object going forward.
>
> But doesn't acpi_dev_resource_interrupt() do acpi_register_gsi() and all
> that stuff? And we were supposed to avoid that.

Right.

So, because the function will always return 1 anyway, you can do

if (spi->irq < 0) {
struct resource r;

if (acpi_dev_resource_interrupt(ares, 0, &r))
spi->irq = r.start;
}

after checking the ACPI_RESOURCE_TYPE_SERIAL_BUS type.

> >
> > > + /* Only use the first interrupt resource and skip the rest */
> > > + memset(&r, 0, sizeof(r));
> > > + if (spi->irq < 0 && acpi_dev_resource_interrupt(ares, 0, &r))
> > > + spi->irq = r.start;
> > > + return 1;
> > > +
> > > + case ACPI_RESOURCE_TYPE_SERIAL_BUS:
> > > + sb = &ares->data.spi_serial_bus;
> > > + if (sb->type == ACPI_RESOURCE_SERIAL_TYPE_SPI) {
> > > + spi->chip_select = sb->device_selection;
> > > + spi->max_speed_hz = sb->connection_speed;
> > > +
> > > + if (sb->clock_phase == ACPI_SPI_SECOND_PHASE)
> > > + spi->mode |= SPI_CPHA;
> > > + if (sb->clock_polarity == ACPI_SPI_START_HIGH)
> > > + spi->mode |= SPI_CPOL;
> > > + if (sb->device_polarity == ACPI_SPI_ACTIVE_HIGH)
> > > + spi->mode |= SPI_CS_HIGH;
> > > +
> > > + return 1;
> > > + }
> > > + return 0;
> > > + }
> > > +
> > > + return 0;
> >
> > We're not interested in any resources except for the above, so I think we
> > can just always return 1 from this function, or am I missing anything?
>
> Right you are, we can return 1 always. I'll update this.
>
> > > +}
> > > +
> > > +static acpi_status acpi_spi_add_device(acpi_handle handle, u32 level,
> > > + void *data, void **return_value)
> > > +{
> > > + struct spi_master *master = data;
> > > + struct list_head resource_list;
> > > + struct acpi_device *adev;
> > > + struct spi_device *spi;
> > > + int ret;
> > > +
> > > + if (acpi_bus_get_device(handle, &adev))
> > > + return AE_OK;
> > > + if (acpi_bus_get_status(adev) || !adev->status.present)
> > > + return AE_OK;
> > > +
> > > + spi = spi_alloc_device(master);
> > > + if (!spi) {
> > > + dev_err(&master->dev, "failed to allocate SPI device for %s\n",
> > > + dev_name(&adev->dev));
> > > + return AE_NO_MEMORY;
> > > + }
> > > +
> > > + ACPI_HANDLE_SET(&spi->dev, handle);
> > > + spi->irq = -1;
> > > +
> > > + INIT_LIST_HEAD(&resource_list);
> > > + ret = acpi_dev_get_resources(adev, &resource_list,
> > > + acpi_spi_add_resource, spi);
> >
> > acpi_dev_free_resource_list(&resource_list); can be done here (the list
> > is going to be empty anyway if acpi_spi_add_resource() always returns 1)
> > and then you won't need the fail_put_dev label.
>
> OK, but there are still two cases below where we need to do
> spi_dev_put(spi). Or do you mean that for each case I just call that
> directly instead of goto fail_put_dev?

Yes, that's what I meant. I'd just do

if (ret < 0 || !spi->max_speed_hz) {
spi_dev_put(spi);
return AE_OK;
}

> > > + if (ret < 0)
> > > + goto fail_put_dev;
> > > +
> > > + acpi_dev_free_resource_list(&resource_list);
> > > +
> > > + if (!spi->max_speed_hz)
> > > + goto fail_put_dev;
> > > +
> > > + strlcpy(spi->modalias, dev_name(&adev->dev), sizeof(spi->modalias));
> > > + if (spi_add_device(spi)) {
> > > + dev_err(&master->dev, "failed to add SPI device %s from ACPI\n",
> > > + dev_name(&adev->dev));
> > > + goto fail_put_dev;
> > > + }
> > > +
> > > + return AE_OK;
> > > +
> > > +fail_put_dev:
> > > + spi_dev_put(spi);
> > > +
> > > + return AE_OK;
> > > +}
> > > +
> > > +static void acpi_register_spi_devices(struct spi_master *master)
> > > +{
> > > + acpi_status status;
> > > + acpi_handle handle;
> > > +
> > > + handle = ACPI_HANDLE(&master->dev);
> > > + if (!handle)
> > > + return;
> > > +
> > > + status = acpi_walk_namespace(ACPI_TYPE_DEVICE, handle, 1,
> > > + acpi_spi_add_device, NULL,
> > > + master, NULL);
> > > + if (ACPI_FAILURE(status))
> > > + dev_warn(&master->dev, "failed to enumerate SPI slaves\n");
> > > +}
> > > +#else
> > > +static inline void acpi_register_spi_devices(struct spi_master *master) {}
> > > +#endif /* CONFIG_ACPI */
> > > +
> > > static void spi_master_release(struct device *dev)
> > > {
> > > struct spi_master *master;
> > > @@ -1023,8 +1135,9 @@ int spi_register_master(struct spi_master *master)
> > > spi_match_master_to_boardinfo(master, &bi->board_info);
> > > mutex_unlock(&board_lock);
> > >
> > > - /* Register devices from the device tree */
> > > + /* Register devices from the device tree and ACPI */
> > > of_register_spi_devices(master);
> > > + acpi_register_spi_devices(master);
> > > done:
> > > return status;
> > > }

Thanks,
Rafael


--
I speak only for myself.
Rafael J. Wysocki, Intel Open Source Technology Center.

2012-11-20 13:54:04

by Mika Westerberg

[permalink] [raw]
Subject: Re: [PATCH v3 3/3] i2c / ACPI: add ACPI enumeration support

On Tue, Nov 20, 2012 at 02:06:46PM +0100, Rafael J. Wysocki wrote:
> On Tuesday, November 20, 2012 12:29:44 PM Mika Westerberg wrote:
> > ACPI 5 introduced I2cSerialBus resource that makes it possible to enumerate
> > and configure the I2C slave devices behind the I2C controller. This patch
> > adds helper functions to support I2C slave enumeration.
> >
> > An ACPI enabled I2C controller driver only needs to call acpi_i2c_register_devices()
> > in order to get its slave devices enumerated, created and bound to the
> > corresponding ACPI handle.
>
> My comments from the SPI patch apply here too almost verbatim. :-)

OK.

Thanks for the comments. I'll wait a bit to get comments from other
subsystem maintainers (I hope they comment something) and then do v4 with
all comments addressed.

2012-11-20 18:08:25

by Greg Kroah-Hartman

[permalink] [raw]
Subject: Re: [Update 2][PATCH 2/3] ACPI / driver core: Introduce struct acpi_dev_node and related macros

On Tue, Nov 20, 2012 at 10:34:04AM +0100, Rafael J. Wysocki wrote:
> From: Rafael J. Wysocki <[email protected]>
> Subject: ACPI / driver core: Introduce struct acpi_dev_node and related macros
>
> To avoid adding an ACPI handle pointer to struct device on
> architectures that don't use ACPI, or generally when CONFIG_ACPI is
> not set, in which cases that pointer is useless, define struct
> acpi_dev_node that will contain the handle pointer if CONFIG_ACPI is
> set and will be empty otherwise and use it to represent the ACPI
> device node field in struct device.
>
> In addition to that define macros for reading and setting the ACPI
> handle of a device that don't generate code when CONFIG_ACPI is
> unset. Modify the ACPI subsystem to use those macros instead of
> referring to the given device's ACPI handle directly.
>
> Signed-off-by: Rafael J. Wysocki <[email protected]>


Acked-by: Greg Kroah-Hartman <[email protected]>

2012-11-20 18:08:34

by Greg Kroah-Hartman

[permalink] [raw]
Subject: Re: [Update][PATCH 3/3] ACPI / platform: Initialize ACPI handles of platform devices in advance

On Tue, Nov 20, 2012 at 02:01:01AM +0100, Rafael J. Wysocki wrote:
> From: Rafael J. Wysocki <[email protected]>
>
> The current platform device creation and registration code in
> acpi_create_platform_device() is quite convoluted. This function
> takes an ACPI device node as an argument and eventually calls
> platform_device_register_resndata() to create and register a
> platform device object on the basis of the information contained
> in that code. However, it doesn't associate the new platform
> device with the ACPI node directly, but instead it relies on
> acpi_platform_notify(), called from within device_add(), to find
> that ACPI node again with the help of acpi_platform_find_device()
> and acpi_platform_match() and then attach the new platform device
> to it. This causes an additional ACPI namespace walk to happen and
> is clearly suboptimal.
>
> Use the observation that it is now possible to initialize the ACPI
> handle of a device before calling device_add() for it to make this
> code more straightforward. Namely, add a new field to struct
> platform_device_info allowing us to pass the ACPI handle of interest
> to platform_device_register_full(), which will then use it to
> initialize the new device's ACPI handle before registering it.
> This will cause acpi_platform_notify() to use the ACPI handle from
> the device structure directly instead of using the .find_device()
> routine provided by the device's bus type. In consequence,
> acpi_platform_bus, acpi_platform_find_device(), and
> acpi_platform_match() are not necessary any more, so remove them.
>
> Signed-off-by: Rafael J. Wysocki <[email protected]>
> Reviewed-by: Mika Westerberg <[email protected]>

Acked-by: Greg Kroah-Hartman <[email protected]>

2012-11-20 18:09:11

by Greg Kroah-Hartman

[permalink] [raw]
Subject: Re: [Update][PATCH 0/3] ACPI: Simplify "glueing" to physical nodes

On Tue, Nov 20, 2012 at 01:55:46AM +0100, Rafael J. Wysocki wrote:
> On Sunday, November 18, 2012 10:10:33 PM Rafael J. Wysocki wrote:
> > On Sunday, November 18, 2012 05:55:39 PM Mika Westerberg wrote:
> > > On Sat, Nov 17, 2012 at 12:24:45PM +0100, Rafael J. Wysocki wrote:
> > > > Well, maybe there is one. Perhaps we can make acpi_platform_notify()
> > > > call acpi_bind_one() upfront and only if that fails, do the whole
> > > > type->find_device() dance? Of course, acpi_bind_one() would need to
> > > > be modified slightly too, like in the patch below.
> > > >
> > > > If we did that, acpi_i2c_add_device() would only need to assign acpi_handle
> > > > as appropriate before calling i2c_new_device() (and analogously for SPI).
> > > >
> > > > What do you think?
> > >
> > > This is certainly better than the thing we use currently. It makes adding
> > > I2C and SPI support much shorter and simpler. If others don't object I
> > > would suggest that we switch to use this method.
> >
> > OK, thanks.
> >
> > The first of the following two patches is a slightly modified version of the
> > one that you commented. Patch [2/2] implements the idea for platform devices
> > and since it modifies struct platform_device_info, I'm adding a CC to Greg.
> >
> > The patches are on top of current linux-pm.git/linux-next.
> >
> > It looks like we may be able to use this approach for PCI too, in which case
> > the whole .find_device() stuff won't be necessary any more.
>
> Following is the series with the Greg's feedback taken into account.
> Patch [1/3] is the same as before with the bug found by Mika fixed, [2/3] is
> an additional patch adding struct acpi_dev_node to compile out unused stuff if
> CONFIG_ACPI is not set and [3/3] is the previous [2/2] rebased on top of it.

Looks great, thanks for the changes. I'm assuming this will go through
your tree, right?

greg k-h

2012-11-20 18:10:22

by Mika Westerberg

[permalink] [raw]
Subject: [PATCH v4 0/3] ACPI 5 support for GPIO, SPI and I2C

This is fourth version of the series. I've based these on top of Rafael's
"simplify glueing ACPI handles to physical nodes" available from here:

https://lkml.org/lkml/2012/11/19/588

There is a dependency to linux-pm tree and to the above patches so I
propose to merge these via that same tree. Subsystem maintainers, can you
ack these if you think that they are a suitable shape?

Changes to v3:
- simplify acpi_gpiochip_find()
- acpi_spi/i2c_add_resource() uses acpi_dev_resource_interrupt()
directly instead of first checking the resource type
- acpi_spi/i2c_add_device() calls acpi_dev_free_resource_list()
immediately after walking the resources and get rid of
fail_put_dev label.

Changes to v2:
- drop the ACPI ->find_device() glue magic in preference of the new
simplified mechanism where we just assign the ACPI handle
- correct the IRQ resource handling to take the first resource and
skip the rest
- moved declaration of acpi_i2c_register_devices() to i2c.h instead
of having a separate header for a single function

Changes to the original version:
[gpio]
- CONFIG_GPIO_ACPI instead of CONFIG_ACPI_GPIO
- removed redundant test in acpi_gpiochip_find()

[spi and i2c]
- switched to use ACPI centralized _CRS evaluation framework
introduced by Rafael
- dropped request_module() call
- dropped the acpi_enumerate_spi/i2c_device()
- added required includes and dropped <linux/acpi.h> from
acpi_i2c.h

Thanks.

Mathias Nyman (1):
gpio / ACPI: add ACPI support

Mika Westerberg (2):
spi / ACPI: add ACPI enumeration support
i2c / ACPI: add ACPI enumeration support

drivers/acpi/Kconfig | 6 +++
drivers/acpi/Makefile | 1 +
drivers/acpi/acpi_i2c.c | 103 +++++++++++++++++++++++++++++++++++++++++++
drivers/gpio/Kconfig | 4 ++
drivers/gpio/Makefile | 1 +
drivers/gpio/gpiolib-acpi.c | 54 +++++++++++++++++++++++
drivers/i2c/i2c-core.c | 6 +++
drivers/spi/spi.c | 103 ++++++++++++++++++++++++++++++++++++++++++-
include/linux/acpi_gpio.h | 19 ++++++++
include/linux/i2c.h | 9 ++++
10 files changed, 305 insertions(+), 1 deletion(-)
create mode 100644 drivers/acpi/acpi_i2c.c
create mode 100644 drivers/gpio/gpiolib-acpi.c
create mode 100644 include/linux/acpi_gpio.h

--
1.7.10.4

2012-11-20 18:10:27

by Mika Westerberg

[permalink] [raw]
Subject: [PATCH v4 3/3] i2c / ACPI: add ACPI enumeration support

ACPI 5 introduced I2cSerialBus resource that makes it possible to enumerate
and configure the I2C slave devices behind the I2C controller. This patch
adds helper functions to support I2C slave enumeration.

An ACPI enabled I2C controller driver only needs to call acpi_i2c_register_devices()
in order to get its slave devices enumerated, created and bound to the
corresponding ACPI handle.

Signed-off-by: Mika Westerberg <[email protected]>
---
drivers/acpi/Kconfig | 6 +++
drivers/acpi/Makefile | 1 +
drivers/acpi/acpi_i2c.c | 103 +++++++++++++++++++++++++++++++++++++++++++++++
drivers/i2c/i2c-core.c | 6 +++
include/linux/i2c.h | 9 +++++
5 files changed, 125 insertions(+)
create mode 100644 drivers/acpi/acpi_i2c.c

diff --git a/drivers/acpi/Kconfig b/drivers/acpi/Kconfig
index 119d58d..0300bf6 100644
--- a/drivers/acpi/Kconfig
+++ b/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
diff --git a/drivers/acpi/Makefile b/drivers/acpi/Makefile
index 7289828..2a4502b 100644
--- a/drivers/acpi/Makefile
+++ b/drivers/acpi/Makefile
@@ -70,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
diff --git a/drivers/acpi/acpi_i2c.c b/drivers/acpi/acpi_i2c.c
new file mode 100644
index 0000000..82045e3
--- /dev/null
+++ b/drivers/acpi/acpi_i2c.c
@@ -0,0 +1,103 @@
+/*
+ * ACPI I2C enumeration support
+ *
+ * Copyright (C) 2012, Intel Corporation
+ * Author: Mika Westerberg <[email protected]>
+ *
+ * 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);
diff --git a/drivers/i2c/i2c-core.c b/drivers/i2c/i2c-core.c
index a7edf98..e388590 100644
--- a/drivers/i2c/i2c-core.c
+++ b/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),
diff --git a/include/linux/i2c.h b/include/linux/i2c.h
index 800de22..d0c4db7 100644
--- a/include/linux/i2c.h
+++ b/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.7.10.4

2012-11-20 18:10:21

by Mika Westerberg

[permalink] [raw]
Subject: [PATCH v4 2/3] spi / ACPI: add ACPI enumeration support

ACPI 5 introduced SPISerialBus resource that allows us to enumerate and
configure the SPI slave devices behind the SPI controller. This patch adds
support for this to the SPI core.

In addition we bind ACPI nodes to SPI devices. This makes it possible for
the slave drivers to get the ACPI handle for further configuration.

Signed-off-by: Mika Westerberg <[email protected]>
---
drivers/spi/spi.c | 103 ++++++++++++++++++++++++++++++++++++++++++++++++++++-
1 file changed, 102 insertions(+), 1 deletion(-)

diff --git a/drivers/spi/spi.c b/drivers/spi/spi.c
index 84c2861..1ab0523 100644
--- a/drivers/spi/spi.c
+++ b/drivers/spi/spi.c
@@ -35,6 +35,8 @@
#include <linux/sched.h>
#include <linux/delay.h>
#include <linux/kthread.h>
+#include <linux/ioport.h>
+#include <linux/acpi.h>

static void spidev_release(struct device *dev)
{
@@ -93,6 +95,10 @@ static int spi_match_device(struct device *dev, struct device_driver *drv)
if (of_driver_match_device(dev, drv))
return 1;

+ /* Then try ACPI */
+ if (acpi_driver_match_device(dev, drv))
+ return 1;
+
if (sdrv->id_table)
return !!spi_match_id(sdrv->id_table, spi);

@@ -888,6 +894,100 @@ static void of_register_spi_devices(struct spi_master *master)
static void of_register_spi_devices(struct spi_master *master) { }
#endif

+#ifdef CONFIG_ACPI
+static int acpi_spi_add_resource(struct acpi_resource *ares, void *data)
+{
+ struct spi_device *spi = data;
+
+ if (ares->type == ACPI_RESOURCE_TYPE_SERIAL_BUS) {
+ struct acpi_resource_spi_serialbus *sb;
+
+ sb = &ares->data.spi_serial_bus;
+ if (sb->type == ACPI_RESOURCE_SERIAL_TYPE_SPI) {
+ spi->chip_select = sb->device_selection;
+ spi->max_speed_hz = sb->connection_speed;
+
+ if (sb->clock_phase == ACPI_SPI_SECOND_PHASE)
+ spi->mode |= SPI_CPHA;
+ if (sb->clock_polarity == ACPI_SPI_START_HIGH)
+ spi->mode |= SPI_CPOL;
+ if (sb->device_polarity == ACPI_SPI_ACTIVE_HIGH)
+ spi->mode |= SPI_CS_HIGH;
+ }
+ } else if (spi->irq < 0) {
+ struct resource r;
+
+ if (acpi_dev_resource_interrupt(ares, 0, &r))
+ spi->irq = r.start;
+ }
+
+ /* Always tell the ACPI core to skip this resource */
+ return 1;
+}
+
+static acpi_status acpi_spi_add_device(acpi_handle handle, u32 level,
+ void *data, void **return_value)
+{
+ struct spi_master *master = data;
+ struct list_head resource_list;
+ struct acpi_device *adev;
+ struct spi_device *spi;
+ int ret;
+
+ if (acpi_bus_get_device(handle, &adev))
+ return AE_OK;
+ if (acpi_bus_get_status(adev) || !adev->status.present)
+ return AE_OK;
+
+ spi = spi_alloc_device(master);
+ if (!spi) {
+ dev_err(&master->dev, "failed to allocate SPI device for %s\n",
+ dev_name(&adev->dev));
+ return AE_NO_MEMORY;
+ }
+
+ ACPI_HANDLE_SET(&spi->dev, handle);
+ spi->irq = -1;
+
+ INIT_LIST_HEAD(&resource_list);
+ ret = acpi_dev_get_resources(adev, &resource_list,
+ acpi_spi_add_resource, spi);
+ acpi_dev_free_resource_list(&resource_list);
+
+ if (ret < 0 || !spi->max_speed_hz) {
+ spi_dev_put(spi);
+ return AE_OK;
+ }
+
+ strlcpy(spi->modalias, dev_name(&adev->dev), sizeof(spi->modalias));
+ if (spi_add_device(spi)) {
+ dev_err(&master->dev, "failed to add SPI device %s from ACPI\n",
+ dev_name(&adev->dev));
+ spi_dev_put(spi);
+ }
+
+ return AE_OK;
+}
+
+static void acpi_register_spi_devices(struct spi_master *master)
+{
+ acpi_status status;
+ acpi_handle handle;
+
+ handle = ACPI_HANDLE(&master->dev);
+ if (!handle)
+ return;
+
+ status = acpi_walk_namespace(ACPI_TYPE_DEVICE, handle, 1,
+ acpi_spi_add_device, NULL,
+ master, NULL);
+ if (ACPI_FAILURE(status))
+ dev_warn(&master->dev, "failed to enumerate SPI slaves\n");
+}
+#else
+static inline void acpi_register_spi_devices(struct spi_master *master) {}
+#endif /* CONFIG_ACPI */
+
static void spi_master_release(struct device *dev)
{
struct spi_master *master;
@@ -1023,8 +1123,9 @@ int spi_register_master(struct spi_master *master)
spi_match_master_to_boardinfo(master, &bi->board_info);
mutex_unlock(&board_lock);

- /* Register devices from the device tree */
+ /* Register devices from the device tree and ACPI */
of_register_spi_devices(master);
+ acpi_register_spi_devices(master);
done:
return status;
}
--
1.7.10.4

2012-11-20 18:10:19

by Mika Westerberg

[permalink] [raw]
Subject: [PATCH v4 1/3] gpio / ACPI: add ACPI support

From: Mathias Nyman <[email protected]>

Add support for translating ACPI GPIO pin numbers to Linux GPIO API pins.
Needs a gpio controller driver with the acpi handler hook set.

Drivers can use acpi_get_gpio() to translate ACPI5 GpioIO and GpioInt
resources to Linux GPIO's.

Signed-off-by: Mathias Nyman <[email protected]>
Signed-off-by: Mika Westerberg <[email protected]>
---
drivers/gpio/Kconfig | 4 ++++
drivers/gpio/Makefile | 1 +
drivers/gpio/gpiolib-acpi.c | 54 +++++++++++++++++++++++++++++++++++++++++++
include/linux/acpi_gpio.h | 19 +++++++++++++++
4 files changed, 78 insertions(+)
create mode 100644 drivers/gpio/gpiolib-acpi.c
create mode 100644 include/linux/acpi_gpio.h

diff --git a/drivers/gpio/Kconfig b/drivers/gpio/Kconfig
index f11d8e3..5c9b384 100644
--- a/drivers/gpio/Kconfig
+++ b/drivers/gpio/Kconfig
@@ -49,6 +49,10 @@ config OF_GPIO
def_bool y
depends on OF

+config GPIO_ACPI
+ def_bool y
+ depends on ACPI
+
config DEBUG_GPIO
bool "Debug GPIO calls"
depends on DEBUG_KERNEL
diff --git a/drivers/gpio/Makefile b/drivers/gpio/Makefile
index 9aeed67..420dbac 100644
--- a/drivers/gpio/Makefile
+++ b/drivers/gpio/Makefile
@@ -4,6 +4,7 @@ ccflags-$(CONFIG_DEBUG_GPIO) += -DDEBUG

obj-$(CONFIG_GPIOLIB) += gpiolib.o devres.o
obj-$(CONFIG_OF_GPIO) += gpiolib-of.o
+obj-$(CONFIG_GPIO_ACPI) += gpiolib-acpi.o

# Device drivers. Generally keep list sorted alphabetically
obj-$(CONFIG_GPIO_GENERIC) += gpio-generic.o
diff --git a/drivers/gpio/gpiolib-acpi.c b/drivers/gpio/gpiolib-acpi.c
new file mode 100644
index 0000000..cbad6e9
--- /dev/null
+++ b/drivers/gpio/gpiolib-acpi.c
@@ -0,0 +1,54 @@
+/*
+ * ACPI helpers for GPIO API
+ *
+ * Copyright (C) 2012, Intel Corporation
+ * Authors: Mathias Nyman <[email protected]>
+ * Mika Westerberg <[email protected]>
+ *
+ * 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/errno.h>
+#include <linux/gpio.h>
+#include <linux/export.h>
+#include <linux/acpi_gpio.h>
+#include <linux/acpi.h>
+
+static int acpi_gpiochip_find(struct gpio_chip *gc, void *data)
+{
+ if (!gc->dev)
+ return false;
+
+ return ACPI_HANDLE(gc->dev) == data;
+}
+
+/**
+ * acpi_get_gpio() - Translate ACPI GPIO pin to GPIO number usable with GPIO API
+ * @path: ACPI GPIO controller full path name, (e.g. "\\_SB.GPO1")
+ * @pin: ACPI GPIO pin number (0-based, controller-relative)
+ *
+ * Returns GPIO number to use with Linux generic GPIO API, or errno error value
+ */
+
+int acpi_get_gpio(char *path, int pin)
+{
+ struct gpio_chip *chip;
+ acpi_handle handle;
+ acpi_status status;
+
+ status = acpi_get_handle(NULL, path, &handle);
+ if (ACPI_FAILURE(status))
+ return -ENODEV;
+
+ chip = gpiochip_find(handle, acpi_gpiochip_find);
+ if (!chip)
+ return -ENODEV;
+
+ if (!gpio_is_valid(chip->base + pin))
+ return -EINVAL;
+
+ return chip->base + pin;
+}
+EXPORT_SYMBOL_GPL(acpi_get_gpio);
diff --git a/include/linux/acpi_gpio.h b/include/linux/acpi_gpio.h
new file mode 100644
index 0000000..91615a3
--- /dev/null
+++ b/include/linux/acpi_gpio.h
@@ -0,0 +1,19 @@
+#ifndef _LINUX_ACPI_GPIO_H_
+#define _LINUX_ACPI_GPIO_H_
+
+#include <linux/errno.h>
+
+#ifdef CONFIG_GPIO_ACPI
+
+int acpi_get_gpio(char *path, int pin);
+
+#else /* CONFIG_GPIO_ACPI */
+
+static inline int acpi_get_gpio(char *path, int pin)
+{
+ return -ENODEV;
+}
+
+#endif /* CONFIG_GPIO_ACPI */
+
+#endif /* _LINUX_ACPI_GPIO_H_ */
--
1.7.10.4

2012-11-20 21:36:01

by Rafael J. Wysocki

[permalink] [raw]
Subject: Re: [Update][PATCH 0/3] ACPI: Simplify "glueing" to physical nodes

On Tuesday, November 20, 2012 10:09:05 AM Greg Kroah-Hartman wrote:
> On Tue, Nov 20, 2012 at 01:55:46AM +0100, Rafael J. Wysocki wrote:
> > On Sunday, November 18, 2012 10:10:33 PM Rafael J. Wysocki wrote:
> > > On Sunday, November 18, 2012 05:55:39 PM Mika Westerberg wrote:
> > > > On Sat, Nov 17, 2012 at 12:24:45PM +0100, Rafael J. Wysocki wrote:
> > > > > Well, maybe there is one. Perhaps we can make acpi_platform_notify()
> > > > > call acpi_bind_one() upfront and only if that fails, do the whole
> > > > > type->find_device() dance? Of course, acpi_bind_one() would need to
> > > > > be modified slightly too, like in the patch below.
> > > > >
> > > > > If we did that, acpi_i2c_add_device() would only need to assign acpi_handle
> > > > > as appropriate before calling i2c_new_device() (and analogously for SPI).
> > > > >
> > > > > What do you think?
> > > >
> > > > This is certainly better than the thing we use currently. It makes adding
> > > > I2C and SPI support much shorter and simpler. If others don't object I
> > > > would suggest that we switch to use this method.
> > >
> > > OK, thanks.
> > >
> > > The first of the following two patches is a slightly modified version of the
> > > one that you commented. Patch [2/2] implements the idea for platform devices
> > > and since it modifies struct platform_device_info, I'm adding a CC to Greg.
> > >
> > > The patches are on top of current linux-pm.git/linux-next.
> > >
> > > It looks like we may be able to use this approach for PCI too, in which case
> > > the whole .find_device() stuff won't be necessary any more.
> >
> > Following is the series with the Greg's feedback taken into account.
> > Patch [1/3] is the same as before with the bug found by Mika fixed, [2/3] is
> > an additional patch adding struct acpi_dev_node to compile out unused stuff if
> > CONFIG_ACPI is not set and [3/3] is the previous [2/2] rebased on top of it.
>
> Looks great, thanks for the changes.

Thanks and no problem.

> I'm assuming this will go through your tree, right?

Yes, it depends some previous changes already there.

Thanks,
Rafael


--
I speak only for myself.
Rafael J. Wysocki, Intel Open Source Technology Center.

2012-11-22 18:37:06

by Linus Walleij

[permalink] [raw]
Subject: Re: [PATCH v4 0/3] ACPI 5 support for GPIO, SPI and I2C

On Wed, Nov 21, 2012 at 10:31 PM, Rafael J. Wysocki <[email protected]> wrote:

> This patchset has been around for quite a while and went through a few
> iterations, so I think it's as good as it gets at this point.
>
> I wonder if the GPIO / SPI / I2C maintainers have any objections against it or
> would like the patches to be modified somehow?
>
> If not, then I'd like to take it for v3.8 into the linux-pm.git tree, because
> the patches depend on some changes already in that tree. Hopefully, that's OK.

For GPIO I want Grant to ACK this.

He has experience with both Device Tree and GPIO, knows what ACPI and
UEFI is and is way better suited than me to give feedback on this kind of
stuff.

So from my stance it's "neutral, whatever Grant says goes".

Yours,
Linus Walleij

2012-11-22 18:42:45

by Mark Brown

[permalink] [raw]
Subject: Re: [PATCH v4 0/3] ACPI 5 support for GPIO, SPI and I2C

On Wed, Nov 21, 2012 at 10:31:15PM +0100, Rafael J. Wysocki wrote:

> I wonder if the GPIO / SPI / I2C maintainers have any objections against it or
> would like the patches to be modified somehow?

> If not, then I'd like to take it for v3.8 into the linux-pm.git tree, because
> the patches depend on some changes already in that tree. Hopefully, that's OK.

Honestly I stopped reading these patches as there were so many patch
revisions and incremental versions mixed in to one big thread that it's
very hard to follow. Will go back and check...


Attachments:
(No filename) (551.00 B)
signature.asc (836.00 B)
Digital signature
Download all attachments

2012-11-22 18:56:52

by Rafael J. Wysocki

[permalink] [raw]
Subject: Re: [PATCH v4 0/3] ACPI 5 support for GPIO, SPI and I2C

On Thursday, November 22, 2012 10:43:28 AM Linus Walleij wrote:
> On Wed, Nov 21, 2012 at 10:31 PM, Rafael J. Wysocki <[email protected]> wrote:
>
> > This patchset has been around for quite a while and went through a few
> > iterations, so I think it's as good as it gets at this point.
> >
> > I wonder if the GPIO / SPI / I2C maintainers have any objections against it or
> > would like the patches to be modified somehow?
> >
> > If not, then I'd like to take it for v3.8 into the linux-pm.git tree, because
> > the patches depend on some changes already in that tree. Hopefully, that's OK.
>
> For GPIO I want Grant to ACK this.
>
> He has experience with both Device Tree and GPIO, knows what ACPI and
> UEFI is and is way better suited than me to give feedback on this kind of
> stuff.
>
> So from my stance it's "neutral, whatever Grant says goes".

OK, we're waiting for a word from Grant, then. :-)

Thanks,
Rafael


--
I speak only for myself.
Rafael J. Wysocki, Intel Open Source Technology Center.

2012-11-22 21:49:19

by Jean Delvare

[permalink] [raw]
Subject: Re: [PATCH v4 0/3] ACPI 5 support for GPIO, SPI and I2C

On Wed, 21 Nov 2012 22:31:15 +0100, Rafael J. Wysocki wrote:
> > Mathias Nyman (1):
> > gpio / ACPI: add ACPI support
> >
> > Mika Westerberg (2):
> > spi / ACPI: add ACPI enumeration support
> > i2c / ACPI: add ACPI enumeration support
>
> This patchset has been around for quite a while and went through a few
> iterations, so I think it's as good as it gets at this point.
>
> I wonder if the GPIO / SPI / I2C maintainers have any objections against it or
> would like the patches to be modified somehow?

I'd say go ahead, any issue that shows up can be fixed afterward.

> If not, then I'd like to take it for v3.8 into the linux-pm.git tree, because
> the patches depend on some changes already in that tree. Hopefully, that's OK.

Yes.

--
Jean Delvare

2012-11-22 22:02:36

by Rafael J. Wysocki

[permalink] [raw]
Subject: Re: [PATCH v4 0/3] ACPI 5 support for GPIO, SPI and I2C

On Tuesday, November 20, 2012 08:13:29 PM Mika Westerberg wrote:
> This is fourth version of the series. I've based these on top of Rafael's
> "simplify glueing ACPI handles to physical nodes" available from here:
>
> https://lkml.org/lkml/2012/11/19/588
>
> There is a dependency to linux-pm tree and to the above patches so I
> propose to merge these via that same tree. Subsystem maintainers, can you
> ack these if you think that they are a suitable shape?
>
> Changes to v3:
> - simplify acpi_gpiochip_find()
> - acpi_spi/i2c_add_resource() uses acpi_dev_resource_interrupt()
> directly instead of first checking the resource type
> - acpi_spi/i2c_add_device() calls acpi_dev_free_resource_list()
> immediately after walking the resources and get rid of
> fail_put_dev label.
>
> Changes to v2:
> - drop the ACPI ->find_device() glue magic in preference of the new
> simplified mechanism where we just assign the ACPI handle
> - correct the IRQ resource handling to take the first resource and
> skip the rest
> - moved declaration of acpi_i2c_register_devices() to i2c.h instead
> of having a separate header for a single function
>
> Changes to the original version:
> [gpio]
> - CONFIG_GPIO_ACPI instead of CONFIG_ACPI_GPIO
> - removed redundant test in acpi_gpiochip_find()
>
> [spi and i2c]
> - switched to use ACPI centralized _CRS evaluation framework
> introduced by Rafael
> - dropped request_module() call
> - dropped the acpi_enumerate_spi/i2c_device()
> - added required includes and dropped <linux/acpi.h> from
> acpi_i2c.h
>
> Thanks.
>
> Mathias Nyman (1):
> gpio / ACPI: add ACPI support
>
> Mika Westerberg (2):
> spi / ACPI: add ACPI enumeration support
> i2c / ACPI: add ACPI enumeration support

This patchset has been around for quite a while and went through a few
iterations, so I think it's as good as it gets at this point.

I wonder if the GPIO / SPI / I2C maintainers have any objections against it or
would like the patches to be modified somehow?

If not, then I'd like to take it for v3.8 into the linux-pm.git tree, because
the patches depend on some changes already in that tree. Hopefully, that's OK.

Thanks,
Rafael


--
I speak only for myself.
Rafael J. Wysocki, Intel Open Source Technology Center.

2012-11-23 11:35:12

by Rafael J. Wysocki

[permalink] [raw]
Subject: Re: [PATCH v4 0/3] ACPI 5 support for GPIO, SPI and I2C

On Wednesday, November 21, 2012 10:54:50 PM Jean Delvare wrote:
> On Wed, 21 Nov 2012 22:31:15 +0100, Rafael J. Wysocki wrote:
> > > Mathias Nyman (1):
> > > gpio / ACPI: add ACPI support
> > >
> > > Mika Westerberg (2):
> > > spi / ACPI: add ACPI enumeration support
> > > i2c / ACPI: add ACPI enumeration support
> >
> > This patchset has been around for quite a while and went through a few
> > iterations, so I think it's as good as it gets at this point.
> >
> > I wonder if the GPIO / SPI / I2C maintainers have any objections against it or
> > would like the patches to be modified somehow?
>
> I'd say go ahead, any issue that shows up can be fixed afterward.
>
> > If not, then I'd like to take it for v3.8 into the linux-pm.git tree, because
> > the patches depend on some changes already in that tree. Hopefully, that's OK.
>
> Yes.

Cool, thanks! :-)

I took the i2c patch for linux-next (targeting v3.8) and I'm waiting with
the GPIO and SPI patches for a word from Grant.

Thanks,
Rafael


--
I speak only for myself.
Rafael J. Wysocki, Intel Open Source Technology Center.

2012-11-28 12:32:50

by Mika Westerberg

[permalink] [raw]
Subject: Re: [PATCH v4 0/3] ACPI 5 support for GPIO, SPI and I2C

On Thu, Nov 22, 2012 at 11:03:26AM +0100, Rafael J. Wysocki wrote:
> On Thursday, November 22, 2012 10:43:28 AM Linus Walleij wrote:
> > On Wed, Nov 21, 2012 at 10:31 PM, Rafael J. Wysocki <[email protected]> wrote:
> >
> > > This patchset has been around for quite a while and went through a few
> > > iterations, so I think it's as good as it gets at this point.
> > >
> > > I wonder if the GPIO / SPI / I2C maintainers have any objections against it or
> > > would like the patches to be modified somehow?
> > >
> > > If not, then I'd like to take it for v3.8 into the linux-pm.git tree, because
> > > the patches depend on some changes already in that tree. Hopefully, that's OK.
> >
> > For GPIO I want Grant to ACK this.
> >
> > He has experience with both Device Tree and GPIO, knows what ACPI and
> > UEFI is and is way better suited than me to give feedback on this kind of
> > stuff.
> >
> > So from my stance it's "neutral, whatever Grant says goes".
>
> OK, we're waiting for a word from Grant, then. :-)

Grant, do you have any input on this? Do you want us to change something in
order to get these merged?

Thanks.

2012-11-30 11:21:07

by Grant Likely

[permalink] [raw]
Subject: Re: [PATCH v4 1/3] gpio / ACPI: add ACPI support

On Tue, 20 Nov 2012 20:13:30 +0200, Mika Westerberg <[email protected]> wrote:
> From: Mathias Nyman <[email protected]>
>
> Add support for translating ACPI GPIO pin numbers to Linux GPIO API pins.
> Needs a gpio controller driver with the acpi handler hook set.
>
> Drivers can use acpi_get_gpio() to translate ACPI5 GpioIO and GpioInt
> resources to Linux GPIO's.
>
> Signed-off-by: Mathias Nyman <[email protected]>
> Signed-off-by: Mika Westerberg <[email protected]>

Acked-by: Grant Likely <[email protected]>

This series goes together, so feel free to take it in whatever tree the
rest are merged through.

g.

> ---
> drivers/gpio/Kconfig | 4 ++++
> drivers/gpio/Makefile | 1 +
> drivers/gpio/gpiolib-acpi.c | 54 +++++++++++++++++++++++++++++++++++++++++++
> include/linux/acpi_gpio.h | 19 +++++++++++++++
> 4 files changed, 78 insertions(+)
> create mode 100644 drivers/gpio/gpiolib-acpi.c
> create mode 100644 include/linux/acpi_gpio.h
>
> diff --git a/drivers/gpio/Kconfig b/drivers/gpio/Kconfig
> index f11d8e3..5c9b384 100644
> --- a/drivers/gpio/Kconfig
> +++ b/drivers/gpio/Kconfig
> @@ -49,6 +49,10 @@ config OF_GPIO
> def_bool y
> depends on OF
>
> +config GPIO_ACPI
> + def_bool y
> + depends on ACPI
> +
> config DEBUG_GPIO
> bool "Debug GPIO calls"
> depends on DEBUG_KERNEL
> diff --git a/drivers/gpio/Makefile b/drivers/gpio/Makefile
> index 9aeed67..420dbac 100644
> --- a/drivers/gpio/Makefile
> +++ b/drivers/gpio/Makefile
> @@ -4,6 +4,7 @@ ccflags-$(CONFIG_DEBUG_GPIO) += -DDEBUG
>
> obj-$(CONFIG_GPIOLIB) += gpiolib.o devres.o
> obj-$(CONFIG_OF_GPIO) += gpiolib-of.o
> +obj-$(CONFIG_GPIO_ACPI) += gpiolib-acpi.o
>
> # Device drivers. Generally keep list sorted alphabetically
> obj-$(CONFIG_GPIO_GENERIC) += gpio-generic.o
> diff --git a/drivers/gpio/gpiolib-acpi.c b/drivers/gpio/gpiolib-acpi.c
> new file mode 100644
> index 0000000..cbad6e9
> --- /dev/null
> +++ b/drivers/gpio/gpiolib-acpi.c
> @@ -0,0 +1,54 @@
> +/*
> + * ACPI helpers for GPIO API
> + *
> + * Copyright (C) 2012, Intel Corporation
> + * Authors: Mathias Nyman <[email protected]>
> + * Mika Westerberg <[email protected]>
> + *
> + * 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/errno.h>
> +#include <linux/gpio.h>
> +#include <linux/export.h>
> +#include <linux/acpi_gpio.h>
> +#include <linux/acpi.h>
> +
> +static int acpi_gpiochip_find(struct gpio_chip *gc, void *data)
> +{
> + if (!gc->dev)
> + return false;
> +
> + return ACPI_HANDLE(gc->dev) == data;
> +}
> +
> +/**
> + * acpi_get_gpio() - Translate ACPI GPIO pin to GPIO number usable with GPIO API
> + * @path: ACPI GPIO controller full path name, (e.g. "\\_SB.GPO1")
> + * @pin: ACPI GPIO pin number (0-based, controller-relative)
> + *
> + * Returns GPIO number to use with Linux generic GPIO API, or errno error value
> + */
> +
> +int acpi_get_gpio(char *path, int pin)
> +{
> + struct gpio_chip *chip;
> + acpi_handle handle;
> + acpi_status status;
> +
> + status = acpi_get_handle(NULL, path, &handle);
> + if (ACPI_FAILURE(status))
> + return -ENODEV;
> +
> + chip = gpiochip_find(handle, acpi_gpiochip_find);
> + if (!chip)
> + return -ENODEV;
> +
> + if (!gpio_is_valid(chip->base + pin))
> + return -EINVAL;
> +
> + return chip->base + pin;
> +}
> +EXPORT_SYMBOL_GPL(acpi_get_gpio);
> diff --git a/include/linux/acpi_gpio.h b/include/linux/acpi_gpio.h
> new file mode 100644
> index 0000000..91615a3
> --- /dev/null
> +++ b/include/linux/acpi_gpio.h
> @@ -0,0 +1,19 @@
> +#ifndef _LINUX_ACPI_GPIO_H_
> +#define _LINUX_ACPI_GPIO_H_
> +
> +#include <linux/errno.h>
> +
> +#ifdef CONFIG_GPIO_ACPI
> +
> +int acpi_get_gpio(char *path, int pin);
> +
> +#else /* CONFIG_GPIO_ACPI */
> +
> +static inline int acpi_get_gpio(char *path, int pin)
> +{
> + return -ENODEV;
> +}
> +
> +#endif /* CONFIG_GPIO_ACPI */
> +
> +#endif /* _LINUX_ACPI_GPIO_H_ */
> --
> 1.7.10.4
>

--
Grant Likely, B.Sc, P.Eng.
Secret Lab Technologies, Ltd.

2012-11-30 11:22:55

by Rafael J. Wysocki

[permalink] [raw]
Subject: Re: [PATCH v4 1/3] gpio / ACPI: add ACPI support

On Friday, November 30, 2012 11:20:57 AM Grant Likely wrote:
> On Tue, 20 Nov 2012 20:13:30 +0200, Mika Westerberg <[email protected]> wrote:
> > From: Mathias Nyman <[email protected]>
> >
> > Add support for translating ACPI GPIO pin numbers to Linux GPIO API pins.
> > Needs a gpio controller driver with the acpi handler hook set.
> >
> > Drivers can use acpi_get_gpio() to translate ACPI5 GpioIO and GpioInt
> > resources to Linux GPIO's.
> >
> > Signed-off-by: Mathias Nyman <[email protected]>
> > Signed-off-by: Mika Westerberg <[email protected]>
>
> Acked-by: Grant Likely <[email protected]>
>
> This series goes together, so feel free to take it in whatever tree the
> rest are merged through.

I will, thanks a lot!

Rafael


> > ---
> > drivers/gpio/Kconfig | 4 ++++
> > drivers/gpio/Makefile | 1 +
> > drivers/gpio/gpiolib-acpi.c | 54 +++++++++++++++++++++++++++++++++++++++++++
> > include/linux/acpi_gpio.h | 19 +++++++++++++++
> > 4 files changed, 78 insertions(+)
> > create mode 100644 drivers/gpio/gpiolib-acpi.c
> > create mode 100644 include/linux/acpi_gpio.h
> >
> > diff --git a/drivers/gpio/Kconfig b/drivers/gpio/Kconfig
> > index f11d8e3..5c9b384 100644
> > --- a/drivers/gpio/Kconfig
> > +++ b/drivers/gpio/Kconfig
> > @@ -49,6 +49,10 @@ config OF_GPIO
> > def_bool y
> > depends on OF
> >
> > +config GPIO_ACPI
> > + def_bool y
> > + depends on ACPI
> > +
> > config DEBUG_GPIO
> > bool "Debug GPIO calls"
> > depends on DEBUG_KERNEL
> > diff --git a/drivers/gpio/Makefile b/drivers/gpio/Makefile
> > index 9aeed67..420dbac 100644
> > --- a/drivers/gpio/Makefile
> > +++ b/drivers/gpio/Makefile
> > @@ -4,6 +4,7 @@ ccflags-$(CONFIG_DEBUG_GPIO) += -DDEBUG
> >
> > obj-$(CONFIG_GPIOLIB) += gpiolib.o devres.o
> > obj-$(CONFIG_OF_GPIO) += gpiolib-of.o
> > +obj-$(CONFIG_GPIO_ACPI) += gpiolib-acpi.o
> >
> > # Device drivers. Generally keep list sorted alphabetically
> > obj-$(CONFIG_GPIO_GENERIC) += gpio-generic.o
> > diff --git a/drivers/gpio/gpiolib-acpi.c b/drivers/gpio/gpiolib-acpi.c
> > new file mode 100644
> > index 0000000..cbad6e9
> > --- /dev/null
> > +++ b/drivers/gpio/gpiolib-acpi.c
> > @@ -0,0 +1,54 @@
> > +/*
> > + * ACPI helpers for GPIO API
> > + *
> > + * Copyright (C) 2012, Intel Corporation
> > + * Authors: Mathias Nyman <[email protected]>
> > + * Mika Westerberg <[email protected]>
> > + *
> > + * 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/errno.h>
> > +#include <linux/gpio.h>
> > +#include <linux/export.h>
> > +#include <linux/acpi_gpio.h>
> > +#include <linux/acpi.h>
> > +
> > +static int acpi_gpiochip_find(struct gpio_chip *gc, void *data)
> > +{
> > + if (!gc->dev)
> > + return false;
> > +
> > + return ACPI_HANDLE(gc->dev) == data;
> > +}
> > +
> > +/**
> > + * acpi_get_gpio() - Translate ACPI GPIO pin to GPIO number usable with GPIO API
> > + * @path: ACPI GPIO controller full path name, (e.g. "\\_SB.GPO1")
> > + * @pin: ACPI GPIO pin number (0-based, controller-relative)
> > + *
> > + * Returns GPIO number to use with Linux generic GPIO API, or errno error value
> > + */
> > +
> > +int acpi_get_gpio(char *path, int pin)
> > +{
> > + struct gpio_chip *chip;
> > + acpi_handle handle;
> > + acpi_status status;
> > +
> > + status = acpi_get_handle(NULL, path, &handle);
> > + if (ACPI_FAILURE(status))
> > + return -ENODEV;
> > +
> > + chip = gpiochip_find(handle, acpi_gpiochip_find);
> > + if (!chip)
> > + return -ENODEV;
> > +
> > + if (!gpio_is_valid(chip->base + pin))
> > + return -EINVAL;
> > +
> > + return chip->base + pin;
> > +}
> > +EXPORT_SYMBOL_GPL(acpi_get_gpio);
> > diff --git a/include/linux/acpi_gpio.h b/include/linux/acpi_gpio.h
> > new file mode 100644
> > index 0000000..91615a3
> > --- /dev/null
> > +++ b/include/linux/acpi_gpio.h
> > @@ -0,0 +1,19 @@
> > +#ifndef _LINUX_ACPI_GPIO_H_
> > +#define _LINUX_ACPI_GPIO_H_
> > +
> > +#include <linux/errno.h>
> > +
> > +#ifdef CONFIG_GPIO_ACPI
> > +
> > +int acpi_get_gpio(char *path, int pin);
> > +
> > +#else /* CONFIG_GPIO_ACPI */
> > +
> > +static inline int acpi_get_gpio(char *path, int pin)
> > +{
> > + return -ENODEV;
> > +}
> > +
> > +#endif /* CONFIG_GPIO_ACPI */
> > +
> > +#endif /* _LINUX_ACPI_GPIO_H_ */
>
>
--
I speak only for myself.
Rafael J. Wysocki, Intel Open Source Technology Center.

2012-11-30 11:24:20

by Grant Likely

[permalink] [raw]
Subject: Re: [PATCH v4 2/3] spi / ACPI: add ACPI enumeration support

On Tue, 20 Nov 2012 20:13:31 +0200, Mika Westerberg <[email protected]> wrote:
> ACPI 5 introduced SPISerialBus resource that allows us to enumerate and
> configure the SPI slave devices behind the SPI controller. This patch adds
> support for this to the SPI core.
>
> In addition we bind ACPI nodes to SPI devices. This makes it possible for
> the slave drivers to get the ACPI handle for further configuration.
>
> Signed-off-by: Mika Westerberg <[email protected]>

Acked-by: Grant Likely <[email protected]>

> ---
> drivers/spi/spi.c | 103 ++++++++++++++++++++++++++++++++++++++++++++++++++++-
> 1 file changed, 102 insertions(+), 1 deletion(-)
>
> diff --git a/drivers/spi/spi.c b/drivers/spi/spi.c
> index 84c2861..1ab0523 100644
> --- a/drivers/spi/spi.c
> +++ b/drivers/spi/spi.c
> @@ -35,6 +35,8 @@
> #include <linux/sched.h>
> #include <linux/delay.h>
> #include <linux/kthread.h>
> +#include <linux/ioport.h>
> +#include <linux/acpi.h>
>
> static void spidev_release(struct device *dev)
> {
> @@ -93,6 +95,10 @@ static int spi_match_device(struct device *dev, struct device_driver *drv)
> if (of_driver_match_device(dev, drv))
> return 1;
>
> + /* Then try ACPI */
> + if (acpi_driver_match_device(dev, drv))
> + return 1;
> +
> if (sdrv->id_table)
> return !!spi_match_id(sdrv->id_table, spi);
>
> @@ -888,6 +894,100 @@ static void of_register_spi_devices(struct spi_master *master)
> static void of_register_spi_devices(struct spi_master *master) { }
> #endif
>
> +#ifdef CONFIG_ACPI
> +static int acpi_spi_add_resource(struct acpi_resource *ares, void *data)
> +{
> + struct spi_device *spi = data;
> +
> + if (ares->type == ACPI_RESOURCE_TYPE_SERIAL_BUS) {
> + struct acpi_resource_spi_serialbus *sb;
> +
> + sb = &ares->data.spi_serial_bus;
> + if (sb->type == ACPI_RESOURCE_SERIAL_TYPE_SPI) {
> + spi->chip_select = sb->device_selection;
> + spi->max_speed_hz = sb->connection_speed;
> +
> + if (sb->clock_phase == ACPI_SPI_SECOND_PHASE)
> + spi->mode |= SPI_CPHA;
> + if (sb->clock_polarity == ACPI_SPI_START_HIGH)
> + spi->mode |= SPI_CPOL;
> + if (sb->device_polarity == ACPI_SPI_ACTIVE_HIGH)
> + spi->mode |= SPI_CS_HIGH;
> + }
> + } else if (spi->irq < 0) {
> + struct resource r;
> +
> + if (acpi_dev_resource_interrupt(ares, 0, &r))
> + spi->irq = r.start;
> + }
> +
> + /* Always tell the ACPI core to skip this resource */
> + return 1;
> +}
> +
> +static acpi_status acpi_spi_add_device(acpi_handle handle, u32 level,
> + void *data, void **return_value)
> +{
> + struct spi_master *master = data;
> + struct list_head resource_list;
> + struct acpi_device *adev;
> + struct spi_device *spi;
> + int ret;
> +
> + if (acpi_bus_get_device(handle, &adev))
> + return AE_OK;
> + if (acpi_bus_get_status(adev) || !adev->status.present)
> + return AE_OK;
> +
> + spi = spi_alloc_device(master);
> + if (!spi) {
> + dev_err(&master->dev, "failed to allocate SPI device for %s\n",
> + dev_name(&adev->dev));
> + return AE_NO_MEMORY;
> + }
> +
> + ACPI_HANDLE_SET(&spi->dev, handle);
> + spi->irq = -1;
> +
> + INIT_LIST_HEAD(&resource_list);
> + ret = acpi_dev_get_resources(adev, &resource_list,
> + acpi_spi_add_resource, spi);
> + acpi_dev_free_resource_list(&resource_list);
> +
> + if (ret < 0 || !spi->max_speed_hz) {
> + spi_dev_put(spi);
> + return AE_OK;
> + }
> +
> + strlcpy(spi->modalias, dev_name(&adev->dev), sizeof(spi->modalias));
> + if (spi_add_device(spi)) {
> + dev_err(&master->dev, "failed to add SPI device %s from ACPI\n",
> + dev_name(&adev->dev));
> + spi_dev_put(spi);
> + }
> +
> + return AE_OK;
> +}
> +
> +static void acpi_register_spi_devices(struct spi_master *master)
> +{
> + acpi_status status;
> + acpi_handle handle;
> +
> + handle = ACPI_HANDLE(&master->dev);
> + if (!handle)
> + return;
> +
> + status = acpi_walk_namespace(ACPI_TYPE_DEVICE, handle, 1,
> + acpi_spi_add_device, NULL,
> + master, NULL);
> + if (ACPI_FAILURE(status))
> + dev_warn(&master->dev, "failed to enumerate SPI slaves\n");
> +}
> +#else
> +static inline void acpi_register_spi_devices(struct spi_master *master) {}
> +#endif /* CONFIG_ACPI */
> +
> static void spi_master_release(struct device *dev)
> {
> struct spi_master *master;
> @@ -1023,8 +1123,9 @@ int spi_register_master(struct spi_master *master)
> spi_match_master_to_boardinfo(master, &bi->board_info);
> mutex_unlock(&board_lock);
>
> - /* Register devices from the device tree */
> + /* Register devices from the device tree and ACPI */
> of_register_spi_devices(master);
> + acpi_register_spi_devices(master);
> done:
> return status;
> }
> --
> 1.7.10.4
>

--
Grant Likely, B.Sc, P.Eng.
Secret Lab Technologies, Ltd.

2012-11-30 11:31:50

by Rafael J. Wysocki

[permalink] [raw]
Subject: Re: [PATCH v4 2/3] spi / ACPI: add ACPI enumeration support

On Friday, November 30, 2012 11:24:13 AM Grant Likely wrote:
> On Tue, 20 Nov 2012 20:13:31 +0200, Mika Westerberg <[email protected]> wrote:
> > ACPI 5 introduced SPISerialBus resource that allows us to enumerate and
> > configure the SPI slave devices behind the SPI controller. This patch adds
> > support for this to the SPI core.
> >
> > In addition we bind ACPI nodes to SPI devices. This makes it possible for
> > the slave drivers to get the ACPI handle for further configuration.
> >
> > Signed-off-by: Mika Westerberg <[email protected]>
>
> Acked-by: Grant Likely <[email protected]>

Thanks a lot!


--
I speak only for myself.
Rafael J. Wysocki, Intel Open Source Technology Center.