Merge branch 'i2c-mux/for-next' of https://github.com/peda-r/i2c-mux into i2c/for-4.17
"These patches verify the device id of the PCA984x mux chips using standardized (but rarely implemented) i2c device identification."
This commit is contained in:
@@ -58,6 +58,8 @@
|
|||||||
#define I2C_ADDR_7BITS_MAX 0x77
|
#define I2C_ADDR_7BITS_MAX 0x77
|
||||||
#define I2C_ADDR_7BITS_COUNT (I2C_ADDR_7BITS_MAX + 1)
|
#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,
|
* core_lock protects i2c_adapter_idr, and guarantees that device detection,
|
||||||
* deletion of detected devices, and attach_adapter calls are serialized
|
* deletion of detected devices, and attach_adapter calls are serialized
|
||||||
@@ -1976,6 +1978,37 @@ int i2c_transfer_buffer_flags(const struct i2c_client *client, char *buf,
|
|||||||
}
|
}
|
||||||
EXPORT_SYMBOL(i2c_transfer_buffer_flags);
|
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
|
* the i2c address scanning function
|
||||||
* Will not work for 10-bit addresses!
|
* Will not work for 10-bit addresses!
|
||||||
|
@@ -77,6 +77,7 @@ struct chip_desc {
|
|||||||
pca954x_ismux = 0,
|
pca954x_ismux = 0,
|
||||||
pca954x_isswi
|
pca954x_isswi
|
||||||
} muxtype;
|
} muxtype;
|
||||||
|
struct i2c_device_identity id;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct pca954x {
|
struct pca954x {
|
||||||
@@ -97,59 +98,83 @@ static const struct chip_desc chips[] = {
|
|||||||
.nchans = 2,
|
.nchans = 2,
|
||||||
.enable = 0x4,
|
.enable = 0x4,
|
||||||
.muxtype = pca954x_ismux,
|
.muxtype = pca954x_ismux,
|
||||||
|
.id = { .manufacturer_id = I2C_DEVICE_ID_NONE },
|
||||||
},
|
},
|
||||||
[pca_9542] = {
|
[pca_9542] = {
|
||||||
.nchans = 2,
|
.nchans = 2,
|
||||||
.enable = 0x4,
|
.enable = 0x4,
|
||||||
.has_irq = 1,
|
.has_irq = 1,
|
||||||
.muxtype = pca954x_ismux,
|
.muxtype = pca954x_ismux,
|
||||||
|
.id = { .manufacturer_id = I2C_DEVICE_ID_NONE },
|
||||||
},
|
},
|
||||||
[pca_9543] = {
|
[pca_9543] = {
|
||||||
.nchans = 2,
|
.nchans = 2,
|
||||||
.has_irq = 1,
|
.has_irq = 1,
|
||||||
.muxtype = pca954x_isswi,
|
.muxtype = pca954x_isswi,
|
||||||
|
.id = { .manufacturer_id = I2C_DEVICE_ID_NONE },
|
||||||
},
|
},
|
||||||
[pca_9544] = {
|
[pca_9544] = {
|
||||||
.nchans = 4,
|
.nchans = 4,
|
||||||
.enable = 0x4,
|
.enable = 0x4,
|
||||||
.has_irq = 1,
|
.has_irq = 1,
|
||||||
.muxtype = pca954x_ismux,
|
.muxtype = pca954x_ismux,
|
||||||
|
.id = { .manufacturer_id = I2C_DEVICE_ID_NONE },
|
||||||
},
|
},
|
||||||
[pca_9545] = {
|
[pca_9545] = {
|
||||||
.nchans = 4,
|
.nchans = 4,
|
||||||
.has_irq = 1,
|
.has_irq = 1,
|
||||||
.muxtype = pca954x_isswi,
|
.muxtype = pca954x_isswi,
|
||||||
|
.id = { .manufacturer_id = I2C_DEVICE_ID_NONE },
|
||||||
},
|
},
|
||||||
[pca_9546] = {
|
[pca_9546] = {
|
||||||
.nchans = 4,
|
.nchans = 4,
|
||||||
.muxtype = pca954x_isswi,
|
.muxtype = pca954x_isswi,
|
||||||
|
.id = { .manufacturer_id = I2C_DEVICE_ID_NONE },
|
||||||
},
|
},
|
||||||
[pca_9547] = {
|
[pca_9547] = {
|
||||||
.nchans = 8,
|
.nchans = 8,
|
||||||
.enable = 0x8,
|
.enable = 0x8,
|
||||||
.muxtype = pca954x_ismux,
|
.muxtype = pca954x_ismux,
|
||||||
|
.id = { .manufacturer_id = I2C_DEVICE_ID_NONE },
|
||||||
},
|
},
|
||||||
[pca_9548] = {
|
[pca_9548] = {
|
||||||
.nchans = 8,
|
.nchans = 8,
|
||||||
.muxtype = pca954x_isswi,
|
.muxtype = pca954x_isswi,
|
||||||
|
.id = { .manufacturer_id = I2C_DEVICE_ID_NONE },
|
||||||
},
|
},
|
||||||
[pca_9846] = {
|
[pca_9846] = {
|
||||||
.nchans = 4,
|
.nchans = 4,
|
||||||
.muxtype = pca954x_isswi,
|
.muxtype = pca954x_isswi,
|
||||||
|
.id = {
|
||||||
|
.manufacturer_id = I2C_DEVICE_ID_NXP_SEMICONDUCTORS,
|
||||||
|
.part_id = 0x10b,
|
||||||
|
},
|
||||||
},
|
},
|
||||||
[pca_9847] = {
|
[pca_9847] = {
|
||||||
.nchans = 8,
|
.nchans = 8,
|
||||||
.enable = 0x8,
|
.enable = 0x8,
|
||||||
.muxtype = pca954x_ismux,
|
.muxtype = pca954x_ismux,
|
||||||
|
.id = {
|
||||||
|
.manufacturer_id = I2C_DEVICE_ID_NXP_SEMICONDUCTORS,
|
||||||
|
.part_id = 0x108,
|
||||||
|
},
|
||||||
},
|
},
|
||||||
[pca_9848] = {
|
[pca_9848] = {
|
||||||
.nchans = 8,
|
.nchans = 8,
|
||||||
.muxtype = pca954x_isswi,
|
.muxtype = pca954x_isswi,
|
||||||
|
.id = {
|
||||||
|
.manufacturer_id = I2C_DEVICE_ID_NXP_SEMICONDUCTORS,
|
||||||
|
.part_id = 0x10a,
|
||||||
|
},
|
||||||
},
|
},
|
||||||
[pca_9849] = {
|
[pca_9849] = {
|
||||||
.nchans = 4,
|
.nchans = 4,
|
||||||
.enable = 0x4,
|
.enable = 0x4,
|
||||||
.muxtype = pca954x_ismux,
|
.muxtype = pca954x_ismux,
|
||||||
|
.id = {
|
||||||
|
.manufacturer_id = I2C_DEVICE_ID_NXP_SEMICONDUCTORS,
|
||||||
|
.part_id = 0x109,
|
||||||
|
},
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -369,6 +394,30 @@ static int pca954x_probe(struct i2c_client *client,
|
|||||||
if (IS_ERR(gpio))
|
if (IS_ERR(gpio))
|
||||||
return PTR_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
|
/* Write the mux register at addr to verify
|
||||||
* that the mux is in fact present. This also
|
* that the mux is in fact present. This also
|
||||||
* initializes the mux to disconnected state.
|
* initializes the mux to disconnected state.
|
||||||
@@ -378,12 +427,6 @@ static int pca954x_probe(struct i2c_client *client,
|
|||||||
return -ENODEV;
|
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 */
|
data->last_chan = 0; /* force the first selection */
|
||||||
|
|
||||||
idle_disconnect_dt = of_node &&
|
idle_disconnect_dt = of_node &&
|
||||||
|
@@ -47,6 +47,7 @@ struct i2c_algorithm;
|
|||||||
struct i2c_adapter;
|
struct i2c_adapter;
|
||||||
struct i2c_client;
|
struct i2c_client;
|
||||||
struct i2c_driver;
|
struct i2c_driver;
|
||||||
|
struct i2c_device_identity;
|
||||||
union i2c_smbus_data;
|
union i2c_smbus_data;
|
||||||
struct i2c_board_info;
|
struct i2c_board_info;
|
||||||
enum i2c_slave_event;
|
enum i2c_slave_event;
|
||||||
@@ -186,8 +187,37 @@ extern s32 i2c_smbus_write_i2c_block_data(const struct i2c_client *client,
|
|||||||
extern s32
|
extern s32
|
||||||
i2c_smbus_read_i2c_block_data_or_emulated(const struct i2c_client *client,
|
i2c_smbus_read_i2c_block_data_or_emulated(const struct i2c_client *client,
|
||||||
u8 command, u8 length, u8 *values);
|
u8 command, u8 length, u8 *values);
|
||||||
|
int i2c_get_device_id(const struct i2c_client *client,
|
||||||
|
struct i2c_device_identity *id);
|
||||||
#endif /* I2C */
|
#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 {
|
enum i2c_alert_protocol {
|
||||||
I2C_PROTOCOL_SMBUS_ALERT,
|
I2C_PROTOCOL_SMBUS_ALERT,
|
||||||
I2C_PROTOCOL_SMBUS_HOST_NOTIFY,
|
I2C_PROTOCOL_SMBUS_HOST_NOTIFY,
|
||||||
|
Reference in New Issue
Block a user