@@ -543,6 +543,28 @@ static int i2c_check_addr_validity(unsigned short addr)
return 0;
}
+static int 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 __i2c_check_addr_busy(struct device *dev, void *addrp)
{
struct i2c_client *client = i2c_verify_client(dev);
@@ -1109,6 +1131,22 @@ 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 i2c address or SMBUS reserved
+ * address, skip to next valid address in the
+ * list and call i2c_new_device for this
+ * address instead.
+ */
+ if (!i2c_check_addr_validity(info->addr) &&
+ 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;