Skip to content

Commit 2d74187

Browse files
committed
i2c: mux: pca954x: verify the device id of the pca984x chips
Make sure to not disallow the chips on adapters that are not capable of reading the device id, but also make sure to check the device id before writing to the chip. Tested-by: Adrian Fiergolski <[email protected]> Signed-off-by: Peter Rosin <[email protected]>
1 parent dde67eb commit 2d74187

File tree

1 file changed

+49
-6
lines changed

1 file changed

+49
-6
lines changed

drivers/i2c/muxes/i2c-mux-pca954x.c

Lines changed: 49 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -77,6 +77,7 @@ struct chip_desc {
7777
pca954x_ismux = 0,
7878
pca954x_isswi
7979
} muxtype;
80+
struct i2c_device_identity id;
8081
};
8182

8283
struct pca954x {
@@ -97,59 +98,83 @@ static const struct chip_desc chips[] = {
9798
.nchans = 2,
9899
.enable = 0x4,
99100
.muxtype = pca954x_ismux,
101+
.id = { .manufacturer_id = I2C_DEVICE_ID_NONE },
100102
},
101103
[pca_9542] = {
102104
.nchans = 2,
103105
.enable = 0x4,
104106
.has_irq = 1,
105107
.muxtype = pca954x_ismux,
108+
.id = { .manufacturer_id = I2C_DEVICE_ID_NONE },
106109
},
107110
[pca_9543] = {
108111
.nchans = 2,
109112
.has_irq = 1,
110113
.muxtype = pca954x_isswi,
114+
.id = { .manufacturer_id = I2C_DEVICE_ID_NONE },
111115
},
112116
[pca_9544] = {
113117
.nchans = 4,
114118
.enable = 0x4,
115119
.has_irq = 1,
116120
.muxtype = pca954x_ismux,
121+
.id = { .manufacturer_id = I2C_DEVICE_ID_NONE },
117122
},
118123
[pca_9545] = {
119124
.nchans = 4,
120125
.has_irq = 1,
121126
.muxtype = pca954x_isswi,
127+
.id = { .manufacturer_id = I2C_DEVICE_ID_NONE },
122128
},
123129
[pca_9546] = {
124130
.nchans = 4,
125131
.muxtype = pca954x_isswi,
132+
.id = { .manufacturer_id = I2C_DEVICE_ID_NONE },
126133
},
127134
[pca_9547] = {
128135
.nchans = 8,
129136
.enable = 0x8,
130137
.muxtype = pca954x_ismux,
138+
.id = { .manufacturer_id = I2C_DEVICE_ID_NONE },
131139
},
132140
[pca_9548] = {
133141
.nchans = 8,
134142
.muxtype = pca954x_isswi,
143+
.id = { .manufacturer_id = I2C_DEVICE_ID_NONE },
135144
},
136145
[pca_9846] = {
137146
.nchans = 4,
138147
.muxtype = pca954x_isswi,
148+
.id = {
149+
.manufacturer_id = I2C_DEVICE_ID_NXP_SEMICONDUCTORS,
150+
.part_id = 0x10b,
151+
},
139152
},
140153
[pca_9847] = {
141154
.nchans = 8,
142155
.enable = 0x8,
143156
.muxtype = pca954x_ismux,
157+
.id = {
158+
.manufacturer_id = I2C_DEVICE_ID_NXP_SEMICONDUCTORS,
159+
.part_id = 0x108,
160+
},
144161
},
145162
[pca_9848] = {
146163
.nchans = 8,
147164
.muxtype = pca954x_isswi,
165+
.id = {
166+
.manufacturer_id = I2C_DEVICE_ID_NXP_SEMICONDUCTORS,
167+
.part_id = 0x10a,
168+
},
148169
},
149170
[pca_9849] = {
150171
.nchans = 4,
151172
.enable = 0x4,
152173
.muxtype = pca954x_ismux,
174+
.id = {
175+
.manufacturer_id = I2C_DEVICE_ID_NXP_SEMICONDUCTORS,
176+
.part_id = 0x109,
177+
},
153178
},
154179
};
155180

@@ -369,6 +394,30 @@ static int pca954x_probe(struct i2c_client *client,
369394
if (IS_ERR(gpio))
370395
return PTR_ERR(gpio);
371396

397+
match = of_match_device(of_match_ptr(pca954x_of_match), &client->dev);
398+
if (match)
399+
data->chip = of_device_get_match_data(&client->dev);
400+
else
401+
data->chip = &chips[id->driver_data];
402+
403+
if (data->chip->id.manufacturer_id != I2C_DEVICE_ID_NONE) {
404+
struct i2c_device_identity id;
405+
406+
ret = i2c_get_device_id(client, &id);
407+
if (ret && ret != -EOPNOTSUPP)
408+
return ret;
409+
410+
if (!ret &&
411+
(id.manufacturer_id != data->chip->id.manufacturer_id ||
412+
id.part_id != data->chip->id.part_id)) {
413+
dev_warn(&client->dev,
414+
"unexpected device id %03x-%03x-%x\n",
415+
id.manufacturer_id, id.part_id,
416+
id.die_revision);
417+
return -ENODEV;
418+
}
419+
}
420+
372421
/* Write the mux register at addr to verify
373422
* that the mux is in fact present. This also
374423
* initializes the mux to disconnected state.
@@ -378,12 +427,6 @@ static int pca954x_probe(struct i2c_client *client,
378427
return -ENODEV;
379428
}
380429

381-
match = of_match_device(of_match_ptr(pca954x_of_match), &client->dev);
382-
if (match)
383-
data->chip = of_device_get_match_data(&client->dev);
384-
else
385-
data->chip = &chips[id->driver_data];
386-
387430
data->last_chan = 0; /* force the first selection */
388431

389432
idle_disconnect_dt = of_node &&

0 commit comments

Comments
 (0)