Loading drivers/i2c/i2c-core-base.c +33 −0 Original line number Diff line number Diff line Loading @@ -58,6 +58,8 @@ #define I2C_ADDR_7BITS_MAX 0x77 #define I2C_ADDR_7BITS_COUNT (I2C_ADDR_7BITS_MAX + 1) #define I2C_ADDR_DEVICE_ID 0x7c /* * core_lock protects i2c_adapter_idr, and guarantees that device detection, * deletion of detected devices, and attach_adapter calls are serialized Loading Loading @@ -1976,6 +1978,37 @@ int i2c_transfer_buffer_flags(const struct i2c_client *client, char *buf, } EXPORT_SYMBOL(i2c_transfer_buffer_flags); /** * i2c_get_device_id - get manufacturer, part id and die revision of a device * @client: The device to query * @id: The queried information * * Returns negative errno on error, zero on success. */ int i2c_get_device_id(const struct i2c_client *client, struct i2c_device_identity *id) { struct i2c_adapter *adap = client->adapter; union i2c_smbus_data raw_id; int ret; if (!i2c_check_functionality(adap, I2C_FUNC_SMBUS_READ_I2C_BLOCK)) return -EOPNOTSUPP; raw_id.block[0] = 3; ret = i2c_smbus_xfer(adap, I2C_ADDR_DEVICE_ID, 0, I2C_SMBUS_READ, client->addr << 1, I2C_SMBUS_I2C_BLOCK_DATA, &raw_id); if (ret) return ret; id->manufacturer_id = (raw_id.block[1] << 4) | (raw_id.block[2] >> 4); id->part_id = ((raw_id.block[2] & 0xf) << 5) | (raw_id.block[3] >> 3); id->die_revision = raw_id.block[3] & 0x7; return 0; } EXPORT_SYMBOL_GPL(i2c_get_device_id); /* ---------------------------------------------------- * the i2c address scanning function * Will not work for 10-bit addresses! Loading drivers/i2c/muxes/i2c-mux-pca954x.c +49 −6 Original line number Diff line number Diff line Loading @@ -77,6 +77,7 @@ struct chip_desc { pca954x_ismux = 0, pca954x_isswi } muxtype; struct i2c_device_identity id; }; struct pca954x { Loading @@ -97,59 +98,83 @@ static const struct chip_desc chips[] = { .nchans = 2, .enable = 0x4, .muxtype = pca954x_ismux, .id = { .manufacturer_id = I2C_DEVICE_ID_NONE }, }, [pca_9542] = { .nchans = 2, .enable = 0x4, .has_irq = 1, .muxtype = pca954x_ismux, .id = { .manufacturer_id = I2C_DEVICE_ID_NONE }, }, [pca_9543] = { .nchans = 2, .has_irq = 1, .muxtype = pca954x_isswi, .id = { .manufacturer_id = I2C_DEVICE_ID_NONE }, }, [pca_9544] = { .nchans = 4, .enable = 0x4, .has_irq = 1, .muxtype = pca954x_ismux, .id = { .manufacturer_id = I2C_DEVICE_ID_NONE }, }, [pca_9545] = { .nchans = 4, .has_irq = 1, .muxtype = pca954x_isswi, .id = { .manufacturer_id = I2C_DEVICE_ID_NONE }, }, [pca_9546] = { .nchans = 4, .muxtype = pca954x_isswi, .id = { .manufacturer_id = I2C_DEVICE_ID_NONE }, }, [pca_9547] = { .nchans = 8, .enable = 0x8, .muxtype = pca954x_ismux, .id = { .manufacturer_id = I2C_DEVICE_ID_NONE }, }, [pca_9548] = { .nchans = 8, .muxtype = pca954x_isswi, .id = { .manufacturer_id = I2C_DEVICE_ID_NONE }, }, [pca_9846] = { .nchans = 4, .muxtype = pca954x_isswi, .id = { .manufacturer_id = I2C_DEVICE_ID_NXP_SEMICONDUCTORS, .part_id = 0x10b, }, }, [pca_9847] = { .nchans = 8, .enable = 0x8, .muxtype = pca954x_ismux, .id = { .manufacturer_id = I2C_DEVICE_ID_NXP_SEMICONDUCTORS, .part_id = 0x108, }, }, [pca_9848] = { .nchans = 8, .muxtype = pca954x_isswi, .id = { .manufacturer_id = I2C_DEVICE_ID_NXP_SEMICONDUCTORS, .part_id = 0x10a, }, }, [pca_9849] = { .nchans = 4, .enable = 0x4, .muxtype = pca954x_ismux, .id = { .manufacturer_id = I2C_DEVICE_ID_NXP_SEMICONDUCTORS, .part_id = 0x109, }, }, }; Loading Loading @@ -369,6 +394,30 @@ static int pca954x_probe(struct i2c_client *client, if (IS_ERR(gpio)) return PTR_ERR(gpio); match = of_match_device(of_match_ptr(pca954x_of_match), &client->dev); if (match) data->chip = of_device_get_match_data(&client->dev); else data->chip = &chips[id->driver_data]; if (data->chip->id.manufacturer_id != I2C_DEVICE_ID_NONE) { struct i2c_device_identity id; ret = i2c_get_device_id(client, &id); if (ret && ret != -EOPNOTSUPP) return ret; if (!ret && (id.manufacturer_id != data->chip->id.manufacturer_id || id.part_id != data->chip->id.part_id)) { dev_warn(&client->dev, "unexpected device id %03x-%03x-%x\n", id.manufacturer_id, id.part_id, id.die_revision); return -ENODEV; } } /* Write the mux register at addr to verify * that the mux is in fact present. This also * initializes the mux to disconnected state. Loading @@ -378,12 +427,6 @@ static int pca954x_probe(struct i2c_client *client, return -ENODEV; } match = of_match_device(of_match_ptr(pca954x_of_match), &client->dev); if (match) data->chip = of_device_get_match_data(&client->dev); else data->chip = &chips[id->driver_data]; data->last_chan = 0; /* force the first selection */ idle_disconnect_dt = of_node && Loading include/linux/i2c.h +30 −0 Original line number Diff line number Diff line Loading @@ -47,6 +47,7 @@ struct i2c_algorithm; struct i2c_adapter; struct i2c_client; struct i2c_driver; struct i2c_device_identity; union i2c_smbus_data; struct i2c_board_info; enum i2c_slave_event; Loading Loading @@ -186,8 +187,37 @@ extern s32 i2c_smbus_write_i2c_block_data(const struct i2c_client *client, extern s32 i2c_smbus_read_i2c_block_data_or_emulated(const struct i2c_client *client, u8 command, u8 length, u8 *values); int i2c_get_device_id(const struct i2c_client *client, struct i2c_device_identity *id); #endif /* I2C */ /** * struct i2c_device_identity - i2c client device identification * @manufacturer_id: 0 - 4095, database maintained by NXP * @part_id: 0 - 511, according to manufacturer * @die_revision: 0 - 7, according to manufacturer */ struct i2c_device_identity { u16 manufacturer_id; #define I2C_DEVICE_ID_NXP_SEMICONDUCTORS 0 #define I2C_DEVICE_ID_NXP_SEMICONDUCTORS_1 1 #define I2C_DEVICE_ID_NXP_SEMICONDUCTORS_2 2 #define I2C_DEVICE_ID_NXP_SEMICONDUCTORS_3 3 #define I2C_DEVICE_ID_RAMTRON_INTERNATIONAL 4 #define I2C_DEVICE_ID_ANALOG_DEVICES 5 #define I2C_DEVICE_ID_STMICROELECTRONICS 6 #define I2C_DEVICE_ID_ON_SEMICONDUCTOR 7 #define I2C_DEVICE_ID_SPRINTEK_CORPORATION 8 #define I2C_DEVICE_ID_ESPROS_PHOTONICS_AG 9 #define I2C_DEVICE_ID_FUJITSU_SEMICONDUCTOR 10 #define I2C_DEVICE_ID_FLIR 11 #define I2C_DEVICE_ID_O2MICRO 12 #define I2C_DEVICE_ID_ATMEL 13 #define I2C_DEVICE_ID_NONE 0xffff u16 part_id; u8 die_revision; }; enum i2c_alert_protocol { I2C_PROTOCOL_SMBUS_ALERT, I2C_PROTOCOL_SMBUS_HOST_NOTIFY, Loading Loading
drivers/i2c/i2c-core-base.c +33 −0 Original line number Diff line number Diff line Loading @@ -58,6 +58,8 @@ #define I2C_ADDR_7BITS_MAX 0x77 #define I2C_ADDR_7BITS_COUNT (I2C_ADDR_7BITS_MAX + 1) #define I2C_ADDR_DEVICE_ID 0x7c /* * core_lock protects i2c_adapter_idr, and guarantees that device detection, * deletion of detected devices, and attach_adapter calls are serialized Loading Loading @@ -1976,6 +1978,37 @@ int i2c_transfer_buffer_flags(const struct i2c_client *client, char *buf, } EXPORT_SYMBOL(i2c_transfer_buffer_flags); /** * i2c_get_device_id - get manufacturer, part id and die revision of a device * @client: The device to query * @id: The queried information * * Returns negative errno on error, zero on success. */ int i2c_get_device_id(const struct i2c_client *client, struct i2c_device_identity *id) { struct i2c_adapter *adap = client->adapter; union i2c_smbus_data raw_id; int ret; if (!i2c_check_functionality(adap, I2C_FUNC_SMBUS_READ_I2C_BLOCK)) return -EOPNOTSUPP; raw_id.block[0] = 3; ret = i2c_smbus_xfer(adap, I2C_ADDR_DEVICE_ID, 0, I2C_SMBUS_READ, client->addr << 1, I2C_SMBUS_I2C_BLOCK_DATA, &raw_id); if (ret) return ret; id->manufacturer_id = (raw_id.block[1] << 4) | (raw_id.block[2] >> 4); id->part_id = ((raw_id.block[2] & 0xf) << 5) | (raw_id.block[3] >> 3); id->die_revision = raw_id.block[3] & 0x7; return 0; } EXPORT_SYMBOL_GPL(i2c_get_device_id); /* ---------------------------------------------------- * the i2c address scanning function * Will not work for 10-bit addresses! Loading
drivers/i2c/muxes/i2c-mux-pca954x.c +49 −6 Original line number Diff line number Diff line Loading @@ -77,6 +77,7 @@ struct chip_desc { pca954x_ismux = 0, pca954x_isswi } muxtype; struct i2c_device_identity id; }; struct pca954x { Loading @@ -97,59 +98,83 @@ static const struct chip_desc chips[] = { .nchans = 2, .enable = 0x4, .muxtype = pca954x_ismux, .id = { .manufacturer_id = I2C_DEVICE_ID_NONE }, }, [pca_9542] = { .nchans = 2, .enable = 0x4, .has_irq = 1, .muxtype = pca954x_ismux, .id = { .manufacturer_id = I2C_DEVICE_ID_NONE }, }, [pca_9543] = { .nchans = 2, .has_irq = 1, .muxtype = pca954x_isswi, .id = { .manufacturer_id = I2C_DEVICE_ID_NONE }, }, [pca_9544] = { .nchans = 4, .enable = 0x4, .has_irq = 1, .muxtype = pca954x_ismux, .id = { .manufacturer_id = I2C_DEVICE_ID_NONE }, }, [pca_9545] = { .nchans = 4, .has_irq = 1, .muxtype = pca954x_isswi, .id = { .manufacturer_id = I2C_DEVICE_ID_NONE }, }, [pca_9546] = { .nchans = 4, .muxtype = pca954x_isswi, .id = { .manufacturer_id = I2C_DEVICE_ID_NONE }, }, [pca_9547] = { .nchans = 8, .enable = 0x8, .muxtype = pca954x_ismux, .id = { .manufacturer_id = I2C_DEVICE_ID_NONE }, }, [pca_9548] = { .nchans = 8, .muxtype = pca954x_isswi, .id = { .manufacturer_id = I2C_DEVICE_ID_NONE }, }, [pca_9846] = { .nchans = 4, .muxtype = pca954x_isswi, .id = { .manufacturer_id = I2C_DEVICE_ID_NXP_SEMICONDUCTORS, .part_id = 0x10b, }, }, [pca_9847] = { .nchans = 8, .enable = 0x8, .muxtype = pca954x_ismux, .id = { .manufacturer_id = I2C_DEVICE_ID_NXP_SEMICONDUCTORS, .part_id = 0x108, }, }, [pca_9848] = { .nchans = 8, .muxtype = pca954x_isswi, .id = { .manufacturer_id = I2C_DEVICE_ID_NXP_SEMICONDUCTORS, .part_id = 0x10a, }, }, [pca_9849] = { .nchans = 4, .enable = 0x4, .muxtype = pca954x_ismux, .id = { .manufacturer_id = I2C_DEVICE_ID_NXP_SEMICONDUCTORS, .part_id = 0x109, }, }, }; Loading Loading @@ -369,6 +394,30 @@ static int pca954x_probe(struct i2c_client *client, if (IS_ERR(gpio)) return PTR_ERR(gpio); match = of_match_device(of_match_ptr(pca954x_of_match), &client->dev); if (match) data->chip = of_device_get_match_data(&client->dev); else data->chip = &chips[id->driver_data]; if (data->chip->id.manufacturer_id != I2C_DEVICE_ID_NONE) { struct i2c_device_identity id; ret = i2c_get_device_id(client, &id); if (ret && ret != -EOPNOTSUPP) return ret; if (!ret && (id.manufacturer_id != data->chip->id.manufacturer_id || id.part_id != data->chip->id.part_id)) { dev_warn(&client->dev, "unexpected device id %03x-%03x-%x\n", id.manufacturer_id, id.part_id, id.die_revision); return -ENODEV; } } /* Write the mux register at addr to verify * that the mux is in fact present. This also * initializes the mux to disconnected state. Loading @@ -378,12 +427,6 @@ static int pca954x_probe(struct i2c_client *client, return -ENODEV; } match = of_match_device(of_match_ptr(pca954x_of_match), &client->dev); if (match) data->chip = of_device_get_match_data(&client->dev); else data->chip = &chips[id->driver_data]; data->last_chan = 0; /* force the first selection */ idle_disconnect_dt = of_node && Loading
include/linux/i2c.h +30 −0 Original line number Diff line number Diff line Loading @@ -47,6 +47,7 @@ struct i2c_algorithm; struct i2c_adapter; struct i2c_client; struct i2c_driver; struct i2c_device_identity; union i2c_smbus_data; struct i2c_board_info; enum i2c_slave_event; Loading Loading @@ -186,8 +187,37 @@ extern s32 i2c_smbus_write_i2c_block_data(const struct i2c_client *client, extern s32 i2c_smbus_read_i2c_block_data_or_emulated(const struct i2c_client *client, u8 command, u8 length, u8 *values); int i2c_get_device_id(const struct i2c_client *client, struct i2c_device_identity *id); #endif /* I2C */ /** * struct i2c_device_identity - i2c client device identification * @manufacturer_id: 0 - 4095, database maintained by NXP * @part_id: 0 - 511, according to manufacturer * @die_revision: 0 - 7, according to manufacturer */ struct i2c_device_identity { u16 manufacturer_id; #define I2C_DEVICE_ID_NXP_SEMICONDUCTORS 0 #define I2C_DEVICE_ID_NXP_SEMICONDUCTORS_1 1 #define I2C_DEVICE_ID_NXP_SEMICONDUCTORS_2 2 #define I2C_DEVICE_ID_NXP_SEMICONDUCTORS_3 3 #define I2C_DEVICE_ID_RAMTRON_INTERNATIONAL 4 #define I2C_DEVICE_ID_ANALOG_DEVICES 5 #define I2C_DEVICE_ID_STMICROELECTRONICS 6 #define I2C_DEVICE_ID_ON_SEMICONDUCTOR 7 #define I2C_DEVICE_ID_SPRINTEK_CORPORATION 8 #define I2C_DEVICE_ID_ESPROS_PHOTONICS_AG 9 #define I2C_DEVICE_ID_FUJITSU_SEMICONDUCTOR 10 #define I2C_DEVICE_ID_FLIR 11 #define I2C_DEVICE_ID_O2MICRO 12 #define I2C_DEVICE_ID_ATMEL 13 #define I2C_DEVICE_ID_NONE 0xffff u16 part_id; u8 die_revision; }; enum i2c_alert_protocol { I2C_PROTOCOL_SMBUS_ALERT, I2C_PROTOCOL_SMBUS_HOST_NOTIFY, Loading