All the mail mirrored from lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH v2 0/2] i2c/acpi: Support for multiple serial bus addresses
@ 2014-09-05 15:21 Srinivas Pandruvada
       [not found] ` <1409930466-31746-1-git-send-email-srinivas.pandruvada-VuQAYsv1563Yd54FQh9/CA@public.gmane.org>
  0 siblings, 1 reply; 3+ messages in thread
From: Srinivas Pandruvada @ 2014-09-05 15:21 UTC (permalink / raw
  To: wsa-z923LK4zBo2bacvFa/9K2g
  Cc: mika.westerberg-VuQAYsv1563Yd54FQh9/CA,
	linux-i2c-u79uwXL29TY76Z2rM5mHXA, Srinivas Pandruvada

The ACPI spec allows multiple i2c addresses for a single device. This
series addresses the implementation of this support in core i2c for ACPI
enumeration.

v2
Restructured based on 3.17.rc3 as acpi i2c part has been moved out of i2c-core.

v1
Create an i2c device for the first valid i2c address which is not a
SMBus reserved address and let the first enumerated driver use the other
defined addresses by providing helper function to retrieve them.

v0
Sent on Mar 6, 2014
This patchset create an i2c device at every specified i2c serial bus
address.
[PATCH 1/2] i2c/ACPI: Support for multiple serial bus addresses



Mika Westerberg (1):
  i2c / ACPI: Add support for extracting multiple I2C addresses

Srinivas Pandruvada (1):
  i2c / ACPI: Create device on a valid first address

 drivers/i2c/i2c-acpi.c | 143 +++++++++++++++++++++++++++++++++++++++++++++++++
 drivers/i2c/i2c-core.c |  61 +++++++++++++++++++++
 include/linux/i2c.h    |   8 +++
 3 files changed, 212 insertions(+)

-- 
1.9.3

^ permalink raw reply	[flat|nested] 3+ messages in thread

* [PATCH v2 1/2] i2c / ACPI: Create device on a valid first address
       [not found] ` <1409930466-31746-1-git-send-email-srinivas.pandruvada-VuQAYsv1563Yd54FQh9/CA@public.gmane.org>
@ 2014-09-05 15:21   ` Srinivas Pandruvada
  2014-09-05 15:21   ` [PATCH v2 2/2] i2c / ACPI: Add support for extracting multiple I2C addresses Srinivas Pandruvada
  1 sibling, 0 replies; 3+ messages in thread
From: Srinivas Pandruvada @ 2014-09-05 15:21 UTC (permalink / raw
  To: wsa-z923LK4zBo2bacvFa/9K2g
  Cc: mika.westerberg-VuQAYsv1563Yd54FQh9/CA,
	linux-i2c-u79uwXL29TY76Z2rM5mHXA, Srinivas Pandruvada

The ACPI spec allows multiple I2cSerialBus addresses for a single
device. The current logic creates a i2c device for the last
I2cSerialBus address. In many configuration the first address
is valid not the last one.
But in some configuration it is possible that the chosen address
is not valid, so skip to next address and create a device on it.

Examples:
1.
Method (_CRS, 0, NotSerialized)  // _CRS: Current Resource Settings
{
        Name (RBUF, ResourceTemplate ()
        {
		I2cSerialBus (0x0068, ControllerInitiated, 0x00061A80,
			AddressingMode7Bit, "\\_SB.I2C5",
			0x00, ResourceConsumer, ,
		)
		I2cSerialBus (0x000C, ControllerInitiated, 0x00061A80,
			AddressingMode7Bit, "\\_SB.I2C5",
			0x00, ResourceConsumer, ,
		)
		Interrupt (ResourceConsumer, Level, ActiveHigh, Shared, ,, )
		{
			0x00000044,
		}
	})
	Return (RBUF)
}
This device is a combo device, where the first address is a valid address
of the main controller device. So this change will create i2c device
for 0x068, the first address.

2.
Method (_CRS, 0, NotSerialized)  // _CRS: Current Resource Settings
{
	Name (SBUF, ResourceTemplate ()
	{
		I2cSerialBus (0x000C, ControllerInitiated, 0x00061A80,
			AddressingMode7Bit, "\\_SB.I2C3",
			0x00, ResourceConsumer, ,
		)
		I2cSerialBus (0x0048, ControllerInitiated, 0x00061A80,
			AddressingMode7Bit, "\\_SB.I2C3",
			0x00, ResourceConsumer, ,
		)
		Interrupt (ResourceConsumer, Level, ActiveHigh, Exclusive, ,, )
		{
			0x00000033,
		}
	})
	Return (SBUF)
}
This device is a SMBUS compliant, where 0x0C is address of alert response
address (ARA). This patch will skip 0x0C, as this is reserved address,
and will create an i2c device at 0x48.

Signed-off-by: Srinivas Pandruvada <srinivas.pandruvada-VuQAYsv1563Yd54FQh9/CA@public.gmane.org>
Signed-off-by: Mika Westerberg <mika.westerberg-VuQAYsv1563Yd54FQh9/CA@public.gmane.org>
---
 drivers/i2c/i2c-acpi.c | 36 ++++++++++++++++++++++++++++++++++++
 1 file changed, 36 insertions(+)

diff --git a/drivers/i2c/i2c-acpi.c b/drivers/i2c/i2c-acpi.c
index 0dbc18c..83db880 100644
--- a/drivers/i2c/i2c-acpi.c
+++ b/drivers/i2c/i2c-acpi.c
@@ -37,6 +37,28 @@ struct gsb_buffer {
 	};
 } __packed;
 
+static int acpi_i2c_smbus_match_reserved_addr(unsigned short addr)
+{
+	/*
+	 * Reserved addresses per SMBUS specification
+	 * in addition to i2c reserved addresses:
+	 *  0x08	SMBUS Host
+	 *  0x0C	ARA
+	 *  0x61	Device default address
+	 *  0x28	Access bus host
+	 *  0x37	Access bus default addr
+	 */
+	int i;
+	u8 resvd_addrs[] = {0x08, 0x0C, 0x061, 0x28, 0x37};
+
+	for (i = 0; i < ARRAY_SIZE(resvd_addrs); ++i) {
+		if (resvd_addrs[i] == addr)
+			return 0;
+	}
+
+	return -EINVAL;
+}
+
 static int acpi_i2c_add_resource(struct acpi_resource *ares, void *data)
 {
 	struct i2c_board_info *info = data;
@@ -46,6 +68,20 @@ static int acpi_i2c_add_resource(struct acpi_resource *ares, void *data)
 
 		sb = &ares->data.i2c_serial_bus;
 		if (sb->type == ACPI_RESOURCE_SERIAL_TYPE_I2C) {
+			if (info->addr) {
+				/*
+				 * We have multiple I2cSerialBus present. Check
+				 * the validity of last parsed address.
+				 * i2c device create rejects reserved address
+				 * for i2C. But if the last address was an
+				 * invalid SMBUS reserved address, skip to next
+				 * valid address in the list and call
+				 * i2c_new_device for this address instead.
+				 */
+				if (acpi_i2c_smbus_match_reserved_addr(
+								info->addr))
+					return 1; /* last addr was valid */
+			}
 			info->addr = sb->slave_address;
 			if (sb->access_mode == ACPI_I2C_10BIT_MODE)
 				info->flags |= I2C_CLIENT_TEN;
-- 
1.9.3

^ permalink raw reply related	[flat|nested] 3+ messages in thread

* [PATCH v2 2/2] i2c / ACPI: Add support for extracting multiple I2C addresses
       [not found] ` <1409930466-31746-1-git-send-email-srinivas.pandruvada-VuQAYsv1563Yd54FQh9/CA@public.gmane.org>
  2014-09-05 15:21   ` [PATCH v2 1/2] i2c / ACPI: Create device on a valid first address Srinivas Pandruvada
@ 2014-09-05 15:21   ` Srinivas Pandruvada
  1 sibling, 0 replies; 3+ messages in thread
From: Srinivas Pandruvada @ 2014-09-05 15:21 UTC (permalink / raw
  To: wsa-z923LK4zBo2bacvFa/9K2g
  Cc: mika.westerberg-VuQAYsv1563Yd54FQh9/CA,
	linux-i2c-u79uwXL29TY76Z2rM5mHXA, Srinivas Pandruvada

From: Mika Westerberg <mika.westerberg-VuQAYsv1563Yd54FQh9/CA@public.gmane.org>

Some I2C devices can have multiple addresses and this is allowed by the
ACPI specification as well. However, it doesn't specify how these addresses
should be interpreted but leaves it up to the OS/drivers to deal with.

Since we can't tell in a generic code whether it is a single device with
multiple addresses (like I2C attached EEPROM) or a multifunction device, we
let the corresponding first level device's driver to decide how to best
handle the addresses assigned to it.

To make driver writers life a bit easier, we add two new helper functions:
i2c_address_by_index() and i2c_num_addressess() which can be used to
extract all addresses for a given device.

Signed-off-by: Mika Westerberg <mika.westerberg-VuQAYsv1563Yd54FQh9/CA@public.gmane.org>
Signed-off-by: Srinivas Pandruvada <srinivas.pandruvada-VuQAYsv1563Yd54FQh9/CA@public.gmane.org>
---
 drivers/i2c/i2c-acpi.c | 107 +++++++++++++++++++++++++++++++++++++++++++++++++
 drivers/i2c/i2c-core.c |  61 ++++++++++++++++++++++++++++
 include/linux/i2c.h    |   8 ++++
 3 files changed, 176 insertions(+)

diff --git a/drivers/i2c/i2c-acpi.c b/drivers/i2c/i2c-acpi.c
index 83db880..ad4b9f4 100644
--- a/drivers/i2c/i2c-acpi.c
+++ b/drivers/i2c/i2c-acpi.c
@@ -37,6 +37,113 @@ struct gsb_buffer {
 	};
 } __packed;
 
+struct acpi_i2c_lookup {
+	struct i2c_board_info *info;
+	struct i2c_adapter *adapter;
+	bool found;
+	int index;
+	int n;
+};
+
+static int acpi_i2c_match_adapter(struct device *dev, void *data)
+{
+	return !!i2c_verify_adapter(dev);
+}
+
+static int acpi_i2c_find(struct acpi_resource *ares, void *data)
+{
+	struct acpi_i2c_lookup *lookup = data;
+	struct acpi_resource_i2c_serialbus *sb;
+	struct acpi_device_physical_node *phys;
+	struct acpi_device *adev;
+	acpi_status status;
+	acpi_handle handle;
+	char *path;
+
+	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 (lookup->n++ != lookup->index)
+		return 1;
+
+	/*
+	 * Need to look up the adapter from ACPI namespace and translate it
+	 * to a physical device. That device should be existing I2C
+	 * adapter.
+	 */
+	path = sb->resource_source.string_ptr;
+	status = acpi_get_handle(ACPI_ROOT_OBJECT, path, &handle);
+	if (ACPI_FAILURE(status) || acpi_bus_get_device(handle, &adev))
+		return 1;
+
+	mutex_lock(&adev->physical_node_lock);
+	list_for_each_entry(phys, &adev->physical_node_list, node) {
+		struct device *dev;
+
+		dev = device_find_child(phys->dev, NULL,
+					acpi_i2c_match_adapter);
+		if (dev) {
+			lookup->adapter = to_i2c_adapter(dev);
+			break;
+		}
+	}
+	mutex_unlock(&adev->physical_node_lock);
+
+	if (!lookup->adapter)
+		return 1;
+
+	if (lookup->info) {
+		lookup->info->addr = sb->slave_address;
+		if (sb->access_mode == ACPI_I2C_10BIT_MODE)
+			lookup->info->flags |= I2C_CLIENT_TEN;
+	}
+
+	lookup->found = true;
+	return 1;
+}
+
+int acpi_i2c_address_by_index(struct i2c_client *client, int index,
+				     struct i2c_board_info *info,
+				     struct i2c_adapter **adapter)
+{
+	struct acpi_i2c_lookup lookup;
+	struct acpi_device *adev;
+	LIST_HEAD(resources);
+	int ret;
+
+	adev = ACPI_COMPANION(&client->dev);
+	if (!adev)
+		return -ENODEV;
+
+	memset(&lookup, 0, sizeof(lookup));
+	lookup.index = index;
+	lookup.info = info;
+
+	ret = acpi_dev_get_resources(adev, &resources, acpi_i2c_find, &lookup);
+	acpi_dev_free_resource_list(&resources);
+	if (ret < 0)
+		return ret;
+
+	if (lookup.found) {
+		if (!adapter) {
+			/*
+			 * Caller is not interested in the adapter so we
+			 * will release it now. Otherwise it is up to the
+			 * caller to call put_device() for it.
+			 */
+			put_device(&lookup.adapter->dev);
+		} else {
+			*adapter = lookup.adapter;
+		}
+	}
+
+	return lookup.found ? 0 : -EADDRNOTAVAIL;
+}
+
 static int acpi_i2c_smbus_match_reserved_addr(unsigned short addr)
 {
 	/*
diff --git a/drivers/i2c/i2c-core.c b/drivers/i2c/i2c-core.c
index 632057a..d024f4a 100644
--- a/drivers/i2c/i2c-core.c
+++ b/drivers/i2c/i2c-core.c
@@ -1097,6 +1097,67 @@ EXPORT_SYMBOL(of_find_i2c_adapter_by_node);
 static void of_i2c_register_devices(struct i2c_adapter *adap) { }
 #endif /* CONFIG_OF */
 
+/*
+ * i2c_address_by_index - Return an I2C address for a device
+ * @client: the client with multiple addresses
+ * @index: index of the additional address
+ * @info: pointer to board info which is filled in
+ * @adapter: adapter on which bus the address is is stored here
+ *
+ * In case of an I2C device with multiple addresses this function can be
+ * used to look up those additional addresses. Returns %0 if the address
+ * with given @index is found or %-EADDRNOTAVAIL if no such address is
+ * found. Note that the function returns address of the current @client as
+ * well so callers need to check against that if necessary.
+ *
+ * Note that the caller must do put_device() to the @adapter->dev once it
+ * is not used anymore.
+ */
+int i2c_address_by_index(struct i2c_client *client, int index,
+			 struct i2c_board_info *info,
+			 struct i2c_adapter **adapter)
+{
+	if (IS_ENABLED(CONFIG_ACPI))
+		return acpi_i2c_address_by_index(client, index, info, adapter);
+
+	/*
+	 * Normal case means that the address at index zero is the address
+	 * of the current client device.
+	 */
+	if (!index) {
+		if (info) {
+			info->addr = client->addr;
+			info->flags = client->flags;
+			info->irq = client->irq;
+		}
+		if (adapter)
+			*adapter = client->adapter;
+
+		return 0;
+	}
+
+	return -EADDRNOTAVAIL;
+}
+EXPORT_SYMBOL_GPL(i2c_address_by_index);
+
+/*
+ * i2c_num_addresses - Returns number of addresses given device has
+ * @client: the client with multiple addresses
+ *
+ * An I2C device that has multiple addresses can use this function to find
+ * out how many of them it has. For single address devices the function
+ * always returns %1.
+ */
+size_t i2c_num_addresses(struct i2c_client *client)
+{
+	size_t n = 0;
+
+	while (!i2c_address_by_index(client, n, NULL, NULL))
+		n++;
+	return n;
+}
+EXPORT_SYMBOL_GPL(i2c_num_addresses);
+
 static int i2c_do_add_adapter(struct i2c_driver *driver,
 			      struct i2c_adapter *adap)
 {
diff --git a/include/linux/i2c.h b/include/linux/i2c.h
index a95efeb..6dc917a 100644
--- a/include/linux/i2c.h
+++ b/include/linux/i2c.h
@@ -322,6 +322,11 @@ extern int i2c_probe_func_quick_read(struct i2c_adapter *, unsigned short addr);
 extern struct i2c_client *
 i2c_new_dummy(struct i2c_adapter *adap, u16 address);
 
+extern int i2c_address_by_index(struct i2c_client *client, int index,
+				struct i2c_board_info *info,
+				struct i2c_adapter **adapter);
+extern size_t i2c_num_addresses(struct i2c_client *client);
+
 extern void i2c_unregister_device(struct i2c_client *);
 #endif /* I2C */
 
@@ -579,6 +584,9 @@ static inline struct i2c_adapter *of_find_i2c_adapter_by_node(struct device_node
 
 #ifdef CONFIG_ACPI
 void acpi_i2c_register_devices(struct i2c_adapter *adap);
+int acpi_i2c_address_by_index(struct i2c_client *client, int index,
+			      struct i2c_board_info *info,
+			      struct i2c_adapter **adapter);
 #else
 static inline void acpi_i2c_register_devices(struct i2c_adapter *adap) { }
 #endif /* CONFIG_ACPI */
-- 
1.9.3

^ permalink raw reply related	[flat|nested] 3+ messages in thread

end of thread, other threads:[~2014-09-05 15:21 UTC | newest]

Thread overview: 3+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2014-09-05 15:21 [PATCH v2 0/2] i2c/acpi: Support for multiple serial bus addresses Srinivas Pandruvada
     [not found] ` <1409930466-31746-1-git-send-email-srinivas.pandruvada-VuQAYsv1563Yd54FQh9/CA@public.gmane.org>
2014-09-05 15:21   ` [PATCH v2 1/2] i2c / ACPI: Create device on a valid first address Srinivas Pandruvada
2014-09-05 15:21   ` [PATCH v2 2/2] i2c / ACPI: Add support for extracting multiple I2C addresses Srinivas Pandruvada

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.