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