diff --git a/drivers/smbus/smbus_stm32.c b/drivers/smbus/smbus_stm32.c index c127ccb504682..1d7ed57aae120 100644 --- a/drivers/smbus/smbus_stm32.c +++ b/drivers/smbus/smbus_stm32.c @@ -10,7 +10,6 @@ #include #include #include -#include #include #include "smbus_utils.h" @@ -346,18 +345,46 @@ static int smbus_stm32_word_data_read(const struct device *dev, uint16_t periph_ static int smbus_stm32_pcall(const struct device *dev, uint16_t periph_addr, uint8_t command, uint16_t send_word, uint16_t *recv_word) { + int ret; + uint8_t pec; + uint8_t num_msgs; + struct i2c_msg messages[] = { + { + .buf = &command, + .len = sizeof(command), + .flags = I2C_MSG_WRITE, + }, + { + .buf = &send_word, + .len = sizeof(send_word), + .flags = I2C_MSG_WRITE, + }, + { + .buf = recv_word, + .len = sizeof(*recv_word), + .flags = I2C_MSG_READ | I2C_MSG_RESTART, + }, + { + .buf = &pec, + .len = 1, + .flags = I2C_MSG_READ, + }, + }; + struct smbus_stm32_data *data = dev->data; const struct smbus_stm32_config *config = dev->config; - uint8_t buffer[sizeof(command) + sizeof(send_word)]; - int result; - buffer[0] = command; - sys_put_le16(send_word, buffer + 1); + num_msgs = smbus_pec_num_msgs(data->config, ARRAY_SIZE(messages)); + ret = i2c_transfer(config->i2c_dev, messages, num_msgs, periph_addr); + if (ret < 0) { + return ret; + } - result = i2c_write_read(config->i2c_dev, periph_addr, buffer, ARRAY_SIZE(buffer), recv_word, - sizeof(*recv_word)); - *recv_word = sys_le16_to_cpu(*recv_word); + ret = smbus_read_check_pec(data->config, periph_addr, messages, num_msgs); + if (ret < 0) { + return ret; + } - return result; + return 0; } static int smbus_stm32_block_write(const struct device *dev, uint16_t periph_addr, uint8_t command, @@ -447,6 +474,70 @@ static int smbus_stm32_block_read(const struct device *dev, uint16_t periph_addr return 0; } +int smbus_stm32_block_pcall(const struct device *dev, uint16_t addr, uint8_t cmd, + uint8_t send_count, uint8_t *send_buf, uint8_t *recv_count, + uint8_t *recv_buf) +{ + int ret; + uint8_t num_msgs; + uint8_t received_pec; + struct i2c_msg msgs[] = { + { + .buf = &cmd, + .len = sizeof(cmd), + .flags = I2C_MSG_WRITE, + }, + { + .buf = &send_count, + .len = sizeof(send_count), + .flags = I2C_MSG_WRITE, + }, + { + .buf = send_buf, + .len = send_count, + .flags = I2C_MSG_WRITE, + }, + { + .buf = NULL, /* will point to next message's len field */ + .len = 1, + .flags = I2C_MSG_READ | I2C_MSG_RESTART, + }, + { + .buf = recv_buf, + .len = 0, /* written by previous message! */ + .flags = I2C_MSG_READ, + }, + { + .buf = &received_pec, + .len = 1, + .flags = I2C_MSG_READ, + }, + }; + struct smbus_stm32_data *data = dev->data; + const struct smbus_stm32_config *config = dev->config; + + /* Count is read in msg 3 and stored in the len of msg 4. + * This works because the STM I2C driver processes each message serially. + * The addressing math assumes little-endian. + */ + msgs[3].buf = (uint8_t *)&msgs[4].len; + + num_msgs = smbus_pec_num_msgs(data->config, ARRAY_SIZE(msgs)); + ret = i2c_transfer(config->i2c_dev, msgs, num_msgs, addr); + if (ret < 0) { + return ret; + } + + ret = smbus_read_check_pec(data->config, addr, msgs, num_msgs); + if (ret < 0) { + return ret; + } + + *recv_count = msgs[4].len; + + return 0; +} + static DEVICE_API(smbus, smbus_stm32_api) = { .configure = smbus_stm32_configure, .get_config = smbus_stm32_get_config, @@ -467,7 +558,7 @@ static DEVICE_API(smbus, smbus_stm32_api) = { .smbus_smbalert_set_cb = NULL, .smbus_smbalert_remove_cb = NULL, #endif /* CONFIG_SMBUS_STM32_SMBALERT */ - .smbus_block_pcall = NULL, + .smbus_block_pcall = smbus_stm32_block_pcall, .smbus_host_notify_set_cb = NULL, .smbus_host_notify_remove_cb = NULL, };