diff --git a/drivers/i2c/i2c.c b/drivers/i2c/i2c.c index ddf00826b..b63d94604 100644 --- a/drivers/i2c/i2c.c +++ b/drivers/i2c/i2c.c @@ -254,6 +254,7 @@ struct i2c_client *i2c_new_device(struct i2c_adapter *adapter, client->dev.platform_data = chip->platform_data; client->dev.id = DEVICE_ID_DYNAMIC; client->dev.bus = &i2c_bus; + client->dev.device_node = chip->of_node; client->adapter = adapter; client->addr = chip->addr; @@ -269,6 +270,45 @@ struct i2c_client *i2c_new_device(struct i2c_adapter *adapter, } EXPORT_SYMBOL(i2c_new_device); +void of_i2c_register_devices(struct i2c_adapter *adap) +{ + struct device_node *n; + + /* Only register child devices if the adapter has a node pointer set */ + if (!IS_ENABLED(CONFIG_OFDEVICE) || !adap->dev.device_node) + return; + + device_node_for_nach_child(adap->dev.device_node, n) { + struct i2c_board_info info = {}; + struct i2c_client *result; + const __be32 *addr; + int len; + + of_modalias_node(n, info.type, I2C_NAME_SIZE); + + info.of_node = n; + + addr = of_get_property(n, "reg", &len); + if (!addr || (len < sizeof(int))) { + dev_err(&adap->dev, "of_i2c: invalid reg on %s\n", + n->full_name); + continue; + } + + info.addr = be32_to_cpup(addr); + if (info.addr > (1 << 10) - 1) { + dev_err(&adap->dev, "of_i2c: invalid addr=%x on %s\n", + info.addr, n->full_name); + continue; + } + + result = i2c_new_device(adap, &info); + if (!result) + dev_err(&adap->dev, "of_i2c: Failure registering %s\n", + n->full_name); + } +} + /** * i2c_new_dummy - return a new i2c device bound to a dummy driver * @adapter: the adapter managing the device @@ -408,6 +448,8 @@ int i2c_add_numbered_adapter(struct i2c_adapter *adapter) /* populate children from any i2c device tables */ scan_boardinfo(adapter); + of_i2c_register_devices(adapter); + return 0; } EXPORT_SYMBOL(i2c_add_numbered_adapter); diff --git a/include/i2c/i2c.h b/include/i2c/i2c.h index 7b59a5102..3b4be45ad 100644 --- a/include/i2c/i2c.h +++ b/include/i2c/i2c.h @@ -102,6 +102,7 @@ struct i2c_board_info { char type[I2C_NAME_SIZE]; /**< name of device */ unsigned short addr; /**< stored in i2c_client.addr */ void *platform_data; /**< platform data for device */ + struct device_node *of_node; }; /**