Skip to content

Commit 3ae7fc6

Browse files
committed
drivers: smbus: stm32: support packet-error-checking (pec)
Add support for SMBus packet error checking (PEC) to the stm32 driver. This feature allows SMBust communication to be slightly more robust in the presence of noise, in that packet errors can be detected on the receive side. Signed-off-by: Andrew Lewycky <[email protected]> Signed-off-by: Chris Friedt <[email protected]>
1 parent 958fee9 commit 3ae7fc6

File tree

1 file changed

+195
-36
lines changed

1 file changed

+195
-36
lines changed

drivers/smbus/smbus_stm32.c

Lines changed: 195 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -97,11 +97,6 @@ static int smbus_stm32_configure(const struct device *dev, uint32_t config_value
9797
const struct smbus_stm32_config *config = dev->config;
9898
struct smbus_stm32_data *data = dev->data;
9999

100-
if (config_value & SMBUS_MODE_PEC) {
101-
LOG_ERR("%s: not implemented", dev->name);
102-
return -EINVAL;
103-
}
104-
105100
if (config_value & SMBUS_MODE_HOST_NOTIFY) {
106101
LOG_ERR("%s: not available", dev->name);
107102
return -EINVAL;
@@ -152,62 +147,200 @@ static int smbus_stm32_quick(const struct device *dev, uint16_t periph_addr,
152147

153148
static int smbus_stm32_byte_write(const struct device *dev, uint16_t periph_addr, uint8_t command)
154149
{
150+
uint8_t pec;
151+
uint8_t num_msgs;
152+
struct i2c_msg msgs[] = {
153+
{
154+
.buf = &command,
155+
.len = sizeof(command),
156+
.flags = I2C_MSG_WRITE,
157+
},
158+
{
159+
.buf = &pec,
160+
.len = sizeof(pec),
161+
.flags = I2C_MSG_WRITE,
162+
},
163+
};
164+
struct smbus_stm32_data *data = dev->data;
155165
const struct smbus_stm32_config *config = dev->config;
156166

157-
return i2c_write(config->i2c_dev, &command, sizeof(command), periph_addr);
167+
num_msgs = smbus_pec_num_msgs(data->config, ARRAY_SIZE(msgs));
168+
smbus_write_prepare_pec(data->config, periph_addr, msgs, num_msgs);
169+
return i2c_transfer(config->i2c_dev, msgs, num_msgs, periph_addr);
158170
}
159171

160172
static int smbus_stm32_byte_read(const struct device *dev, uint16_t periph_addr, uint8_t *byte)
161173
{
174+
int ret;
175+
uint8_t pec = 0;
176+
uint8_t num_msgs;
177+
struct i2c_msg msgs[] = {
178+
{
179+
.buf = byte,
180+
.len = sizeof(*byte),
181+
.flags = I2C_MSG_READ,
182+
},
183+
{
184+
.buf = &pec,
185+
.len = sizeof(pec),
186+
.flags = I2C_MSG_READ,
187+
},
188+
};
189+
struct smbus_stm32_data *data = dev->data;
162190
const struct smbus_stm32_config *config = dev->config;
163191

164-
return i2c_read(config->i2c_dev, byte, sizeof(*byte), periph_addr);
192+
num_msgs = smbus_pec_num_msgs(data->config, ARRAY_SIZE(msgs));
193+
ret = i2c_transfer(config->i2c_dev, msgs, num_msgs, periph_addr);
194+
if (ret < 0) {
195+
return ret;
196+
}
197+
198+
ret = smbus_read_check_pec(data->config, periph_addr, msgs, num_msgs);
199+
if (ret < 0) {
200+
return ret;
201+
}
202+
203+
return 0;
165204
}
166205

167206
static int smbus_stm32_byte_data_write(const struct device *dev, uint16_t periph_addr,
168207
uint8_t command, uint8_t byte)
169208
{
170-
const struct smbus_stm32_config *config = dev->config;
171-
uint8_t buffer[] = {
172-
command,
173-
byte,
209+
uint8_t pec;
210+
uint8_t num_msgs;
211+
struct i2c_msg msgs[] = {
212+
{
213+
.buf = &command,
214+
.len = sizeof(command),
215+
.flags = I2C_MSG_WRITE,
216+
},
217+
{
218+
.buf = &byte,
219+
.len = sizeof(byte),
220+
.flags = I2C_MSG_WRITE,
221+
},
222+
{
223+
.buf = &pec,
224+
.len = sizeof(pec),
225+
.flags = I2C_MSG_WRITE,
226+
},
174227
};
228+
struct smbus_stm32_data *data = dev->data;
229+
const struct smbus_stm32_config *config = dev->config;
175230

176-
return i2c_write(config->i2c_dev, buffer, ARRAY_SIZE(buffer), periph_addr);
231+
num_msgs = smbus_pec_num_msgs(data->config, ARRAY_SIZE(msgs));
232+
smbus_write_prepare_pec(data->config, periph_addr, msgs, num_msgs);
233+
return i2c_transfer(config->i2c_dev, msgs, num_msgs, periph_addr);
177234
}
178235

179236
static int smbus_stm32_byte_data_read(const struct device *dev, uint16_t periph_addr,
180237
uint8_t command, uint8_t *byte)
181238
{
239+
int ret;
240+
uint8_t pec;
241+
uint8_t num_msgs;
242+
struct i2c_msg msgs[] = {
243+
{
244+
.buf = &command,
245+
.len = sizeof(command),
246+
.flags = I2C_MSG_WRITE,
247+
},
248+
{
249+
.buf = byte,
250+
.len = sizeof(*byte),
251+
.flags = I2C_MSG_READ | I2C_MSG_RESTART,
252+
},
253+
{
254+
.buf = &pec,
255+
.len = sizeof(pec),
256+
.flags = I2C_MSG_READ,
257+
},
258+
};
259+
struct smbus_stm32_data *data = dev->data;
182260
const struct smbus_stm32_config *config = dev->config;
183261

184-
return i2c_write_read(config->i2c_dev, periph_addr, &command, sizeof(command), byte,
185-
sizeof(*byte));
262+
num_msgs = smbus_pec_num_msgs(data->config, ARRAY_SIZE(msgs));
263+
ret = i2c_transfer(config->i2c_dev, msgs, num_msgs, periph_addr);
264+
if (ret < 0) {
265+
return ret;
266+
}
267+
268+
ret = smbus_read_check_pec(data->config, periph_addr, msgs, num_msgs);
269+
if (ret < 0) {
270+
return ret;
271+
}
272+
273+
return 0;
186274
}
187275

188276
static int smbus_stm32_word_data_write(const struct device *dev, uint16_t periph_addr,
189277
uint8_t command, uint16_t word)
190278
{
279+
uint8_t pec;
280+
uint8_t num_msgs;
281+
struct i2c_msg msgs[] = {
282+
{
283+
.buf = &command,
284+
.len = sizeof(command),
285+
.flags = I2C_MSG_WRITE,
286+
},
287+
{
288+
.buf = (uint8_t *)&word,
289+
.len = sizeof(word),
290+
.flags = I2C_MSG_WRITE,
291+
},
292+
{
293+
.buf = &pec,
294+
.len = sizeof(pec),
295+
.flags = I2C_MSG_WRITE,
296+
},
297+
};
298+
struct smbus_stm32_data *data = dev->data;
191299
const struct smbus_stm32_config *config = dev->config;
192-
uint8_t buffer[sizeof(command) + sizeof(word)];
193-
194-
buffer[0] = command;
195-
sys_put_le16(word, buffer + 1);
196300

197-
return i2c_write(config->i2c_dev, buffer, ARRAY_SIZE(buffer), periph_addr);
301+
num_msgs = smbus_pec_num_msgs(data->config, ARRAY_SIZE(msgs));
302+
smbus_write_prepare_pec(data->config, periph_addr, msgs, num_msgs);
303+
return i2c_transfer(config->i2c_dev, msgs, num_msgs, periph_addr);
198304
}
199305

200306
static int smbus_stm32_word_data_read(const struct device *dev, uint16_t periph_addr,
201307
uint8_t command, uint16_t *word)
202308
{
309+
int ret;
310+
uint8_t pec;
311+
uint8_t num_msgs;
312+
struct i2c_msg messages[] = {
313+
{
314+
.buf = &command,
315+
.len = sizeof(command),
316+
.flags = I2C_MSG_WRITE,
317+
},
318+
{
319+
.buf = (uint8_t *)word,
320+
.len = sizeof(*word),
321+
.flags = I2C_MSG_READ | I2C_MSG_RESTART,
322+
},
323+
{
324+
.buf = &pec,
325+
.len = sizeof(pec),
326+
.flags = I2C_MSG_READ,
327+
},
328+
};
329+
struct smbus_stm32_data *data = dev->data;
203330
const struct smbus_stm32_config *config = dev->config;
204-
int result;
205331

206-
result = i2c_write_read(config->i2c_dev, periph_addr, &command, sizeof(command), word,
207-
sizeof(*word));
208-
*word = sys_le16_to_cpu(*word);
332+
num_msgs = smbus_pec_num_msgs(data->config, ARRAY_SIZE(messages));
333+
ret = i2c_transfer(config->i2c_dev, messages, num_msgs, periph_addr);
334+
if (ret < 0) {
335+
return ret;
336+
}
209337

210-
return result;
338+
ret = smbus_read_check_pec(data->config, periph_addr, messages, num_msgs);
339+
if (ret < 0) {
340+
return ret;
341+
}
342+
343+
return 0;
211344
}
212345

213346
static int smbus_stm32_pcall(const struct device *dev, uint16_t periph_addr, uint8_t command,
@@ -230,8 +363,9 @@ static int smbus_stm32_pcall(const struct device *dev, uint16_t periph_addr, uin
230363
static int smbus_stm32_block_write(const struct device *dev, uint16_t periph_addr, uint8_t command,
231364
uint8_t count, uint8_t *buf)
232365
{
233-
const struct smbus_stm32_config *config = dev->config;
234-
struct i2c_msg messages[] = {
366+
uint8_t pec;
367+
uint8_t num_msgs;
368+
struct i2c_msg msgs[] = {
235369
{
236370
.buf = &command,
237371
.len = sizeof(command),
@@ -246,18 +380,28 @@ static int smbus_stm32_block_write(const struct device *dev, uint16_t periph_add
246380
.buf = buf,
247381
.len = count,
248382
.flags = I2C_MSG_WRITE,
249-
}
383+
},
384+
{
385+
.buf = &pec,
386+
.len = 1,
387+
.flags = I2C_MSG_WRITE,
388+
},
250389
};
390+
struct smbus_stm32_data *data = dev->data;
391+
const struct smbus_stm32_config *config = dev->config;
251392

252-
return i2c_transfer(config->i2c_dev, messages, ARRAY_SIZE(messages), periph_addr);
393+
num_msgs = smbus_pec_num_msgs(data->config, ARRAY_SIZE(msgs));
394+
smbus_write_prepare_pec(data->config, periph_addr, msgs, ARRAY_SIZE(msgs));
395+
return i2c_transfer(config->i2c_dev, msgs, num_msgs, periph_addr);
253396
}
254397

255398
static int smbus_stm32_block_read(const struct device *dev, uint16_t periph_addr, uint8_t command,
256399
uint8_t *count, uint8_t *buf)
257400
{
258-
const struct smbus_stm32_config *config = dev->config;
259-
260-
struct i2c_msg messages[] = {
401+
int ret;
402+
uint8_t num_msgs;
403+
uint8_t received_pec;
404+
struct i2c_msg msgs[] = {
261405
{
262406
.buf = &command,
263407
.len = sizeof(command),
@@ -272,20 +416,35 @@ static int smbus_stm32_block_read(const struct device *dev, uint16_t periph_addr
272416
.buf = buf,
273417
.len = 0, /* written by previous message! */
274418
.flags = I2C_MSG_READ,
275-
}
419+
},
420+
{
421+
.buf = &received_pec,
422+
.len = 1,
423+
.flags = I2C_MSG_READ,
424+
},
276425
};
426+
struct smbus_stm32_data *data = dev->data;
427+
const struct smbus_stm32_config *config = dev->config;
277428

278429
/* Count is read in msg 1 and stored in the len of msg 2.
279430
* This works because the STM I2C driver processes each message serially.
280431
* The addressing math assumes little-endian.
281432
*/
282-
messages[1].buf = (uint8_t *)&messages[2].len;
433+
msgs[1].buf = (uint8_t *)&msgs[2].len;
283434

284-
int res = i2c_transfer(config->i2c_dev, messages, ARRAY_SIZE(messages), periph_addr);
435+
num_msgs = smbus_pec_num_msgs(data->config, ARRAY_SIZE(msgs));
436+
ret = i2c_transfer(config->i2c_dev, msgs, num_msgs, periph_addr);
437+
if (ret < 0) {
438+
return ret;
439+
}
285440

286-
*count = messages[2].len;
441+
*count = msgs[2].len;
442+
ret = smbus_read_check_pec(data->config, periph_addr, msgs, num_msgs);
443+
if (ret < 0) {
444+
return ret;
445+
}
287446

288-
return res;
447+
return 0;
289448
}
290449

291450
static DEVICE_API(smbus, smbus_stm32_api) = {

0 commit comments

Comments
 (0)