stm32,i2c: Fix large I2C transactions on I2C V1
Previous commit added support of large transactions on I2C v2, this commit implements some changes to also add support of large transactions on I2C v1. Some refactoring is also done to put the code in the right source files. Fixes zephyrproject-rtos#58866 Signed-off-by: Michael Grand <m.grand@trustngo.tech>
This commit is contained in:
parent
a8b28f13c1
commit
78d3f2a6a0
4 changed files with 75 additions and 65 deletions
|
@ -93,56 +93,6 @@ int i2c_stm32_runtime_configure(const struct device *dev, uint32_t config)
|
|||
return ret;
|
||||
}
|
||||
|
||||
static inline int
|
||||
i2c_stm32_transaction(const struct device *dev,
|
||||
struct i2c_msg msg, uint8_t *next_msg_flags,
|
||||
uint16_t periph)
|
||||
{
|
||||
/*
|
||||
* Perform a I2C transaction, while taking into account the STM32 I2C
|
||||
* peripheral has a limited maximum chunk size. Take appropriate action
|
||||
* if the message to send exceeds that limit.
|
||||
*
|
||||
* The last chunk of a transmission uses this function's next_msg_flags
|
||||
* parameter for its backend calls (_write/_read). Any previous chunks
|
||||
* use a copy of the current message's flags, with the STOP and RESTART
|
||||
* bits turned off. This will cause the backend to use reload-mode,
|
||||
* which will make the combination of all chunks to look like one big
|
||||
* transaction on the wire.
|
||||
*/
|
||||
const uint32_t i2c_stm32_maxchunk = 255U;
|
||||
const uint8_t saved_flags = msg.flags;
|
||||
uint8_t combine_flags =
|
||||
saved_flags & ~(I2C_MSG_STOP | I2C_MSG_RESTART);
|
||||
uint8_t *flagsp = NULL;
|
||||
uint32_t rest = msg.len;
|
||||
int ret = 0;
|
||||
|
||||
do { /* do ... while to allow zero-length transactions */
|
||||
if (msg.len > i2c_stm32_maxchunk) {
|
||||
msg.len = i2c_stm32_maxchunk;
|
||||
msg.flags &= ~I2C_MSG_STOP;
|
||||
flagsp = &combine_flags;
|
||||
} else {
|
||||
msg.flags = saved_flags;
|
||||
flagsp = next_msg_flags;
|
||||
}
|
||||
if ((msg.flags & I2C_MSG_RW_MASK) == I2C_MSG_WRITE) {
|
||||
ret = stm32_i2c_msg_write(dev, &msg, flagsp, periph);
|
||||
} else {
|
||||
ret = stm32_i2c_msg_read(dev, &msg, flagsp, periph);
|
||||
}
|
||||
if (ret < 0) {
|
||||
break;
|
||||
}
|
||||
rest -= msg.len;
|
||||
msg.buf += msg.len;
|
||||
msg.len = rest;
|
||||
} while (rest > 0U);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
#define OPERATION(msg) (((struct i2c_msg *) msg)->flags & I2C_MSG_RW_MASK)
|
||||
|
||||
static int i2c_stm32_transfer(const struct device *dev, struct i2c_msg *msg,
|
||||
|
@ -220,7 +170,7 @@ static int i2c_stm32_transfer(const struct device *dev, struct i2c_msg *msg,
|
|||
next = current + 1;
|
||||
next_msg_flags = &(next->flags);
|
||||
}
|
||||
ret = i2c_stm32_transaction(dev, *current, next_msg_flags, slave);
|
||||
ret = stm32_i2c_transaction(dev, *current, next_msg_flags, slave);
|
||||
if (ret < 0) {
|
||||
break;
|
||||
}
|
||||
|
|
|
@ -80,12 +80,9 @@ struct i2c_stm32_data {
|
|||
#endif
|
||||
};
|
||||
|
||||
int32_t stm32_i2c_msg_write(const struct device *dev, struct i2c_msg *msg,
|
||||
uint8_t *flg,
|
||||
uint16_t sadr);
|
||||
int32_t stm32_i2c_msg_read(const struct device *dev, struct i2c_msg *msg,
|
||||
uint8_t *flg,
|
||||
uint16_t sadr);
|
||||
int32_t stm32_i2c_transaction(const struct device *dev,
|
||||
struct i2c_msg msg, uint8_t *next_msg_flags,
|
||||
uint16_t periph);
|
||||
int32_t stm32_i2c_configure_timing(const struct device *dev, uint32_t clk);
|
||||
int i2c_stm32_runtime_configure(const struct device *dev, uint32_t config);
|
||||
|
||||
|
|
|
@ -613,7 +613,7 @@ end:
|
|||
stm32_i2c_master_mode_end(dev);
|
||||
}
|
||||
|
||||
int32_t stm32_i2c_msg_write(const struct device *dev, struct i2c_msg *msg,
|
||||
static int32_t stm32_i2c_msg_write(const struct device *dev, struct i2c_msg *msg,
|
||||
uint8_t *next_msg_flags, uint16_t saddr)
|
||||
{
|
||||
struct i2c_stm32_data *data = dev->data;
|
||||
|
@ -632,7 +632,7 @@ int32_t stm32_i2c_msg_write(const struct device *dev, struct i2c_msg *msg,
|
|||
return msg_end(dev, next_msg_flags, __func__);
|
||||
}
|
||||
|
||||
int32_t stm32_i2c_msg_read(const struct device *dev, struct i2c_msg *msg,
|
||||
static int32_t stm32_i2c_msg_read(const struct device *dev, struct i2c_msg *msg,
|
||||
uint8_t *next_msg_flags, uint16_t saddr)
|
||||
{
|
||||
const struct i2c_stm32_config *cfg = dev->config;
|
||||
|
@ -706,7 +706,7 @@ static int stm32_i2c_wait_timeout(uint16_t *timeout)
|
|||
}
|
||||
}
|
||||
|
||||
int32_t stm32_i2c_msg_write(const struct device *dev, struct i2c_msg *msg,
|
||||
static int32_t stm32_i2c_msg_write(const struct device *dev, struct i2c_msg *msg,
|
||||
uint8_t *next_msg_flags, uint16_t saddr)
|
||||
{
|
||||
const struct i2c_stm32_config *cfg = dev->config;
|
||||
|
@ -804,7 +804,7 @@ end:
|
|||
return res;
|
||||
}
|
||||
|
||||
int32_t stm32_i2c_msg_read(const struct device *dev, struct i2c_msg *msg,
|
||||
static int32_t stm32_i2c_msg_read(const struct device *dev, struct i2c_msg *msg,
|
||||
uint8_t *next_msg_flags, uint16_t saddr)
|
||||
{
|
||||
const struct i2c_stm32_config *cfg = dev->config;
|
||||
|
@ -986,3 +986,17 @@ int32_t stm32_i2c_configure_timing(const struct device *dev, uint32_t clock)
|
|||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int stm32_i2c_transaction(const struct device *dev,
|
||||
struct i2c_msg msg, uint8_t *next_msg_flags,
|
||||
uint16_t periph)
|
||||
{
|
||||
int ret;
|
||||
|
||||
if ((msg.flags & I2C_MSG_RW_MASK) == I2C_MSG_WRITE) {
|
||||
ret = stm32_i2c_msg_write(dev, &msg, next_msg_flags, periph);
|
||||
} else {
|
||||
ret = stm32_i2c_msg_read(dev, &msg, next_msg_flags, periph);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
|
|
@ -427,7 +427,7 @@ void stm32_i2c_error_isr(void *arg)
|
|||
}
|
||||
#endif
|
||||
|
||||
int stm32_i2c_msg_write(const struct device *dev, struct i2c_msg *msg,
|
||||
static int stm32_i2c_msg_write(const struct device *dev, struct i2c_msg *msg,
|
||||
uint8_t *next_msg_flags, uint16_t slave)
|
||||
{
|
||||
const struct i2c_stm32_config *cfg = dev->config;
|
||||
|
@ -485,7 +485,7 @@ error:
|
|||
return -EIO;
|
||||
}
|
||||
|
||||
int stm32_i2c_msg_read(const struct device *dev, struct i2c_msg *msg,
|
||||
static int stm32_i2c_msg_read(const struct device *dev, struct i2c_msg *msg,
|
||||
uint8_t *next_msg_flags, uint16_t slave)
|
||||
{
|
||||
const struct i2c_stm32_config *cfg = dev->config;
|
||||
|
@ -607,7 +607,7 @@ static inline int msg_done(const struct device *dev,
|
|||
return 0;
|
||||
}
|
||||
|
||||
int stm32_i2c_msg_write(const struct device *dev, struct i2c_msg *msg,
|
||||
static int stm32_i2c_msg_write(const struct device *dev, struct i2c_msg *msg,
|
||||
uint8_t *next_msg_flags, uint16_t slave)
|
||||
{
|
||||
const struct i2c_stm32_config *cfg = dev->config;
|
||||
|
@ -637,7 +637,7 @@ int stm32_i2c_msg_write(const struct device *dev, struct i2c_msg *msg,
|
|||
return msg_done(dev, msg->flags);
|
||||
}
|
||||
|
||||
int stm32_i2c_msg_read(const struct device *dev, struct i2c_msg *msg,
|
||||
static int stm32_i2c_msg_read(const struct device *dev, struct i2c_msg *msg,
|
||||
uint8_t *next_msg_flags, uint16_t slave)
|
||||
{
|
||||
const struct i2c_stm32_config *cfg = dev->config;
|
||||
|
@ -738,3 +738,52 @@ int stm32_i2c_configure_timing(const struct device *dev, uint32_t clock)
|
|||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int stm32_i2c_transaction(const struct device *dev,
|
||||
struct i2c_msg msg, uint8_t *next_msg_flags,
|
||||
uint16_t periph)
|
||||
{
|
||||
/*
|
||||
* Perform a I2C transaction, while taking into account the STM32 I2C V2
|
||||
* peripheral has a limited maximum chunk size. Take appropriate action
|
||||
* if the message to send exceeds that limit.
|
||||
*
|
||||
* The last chunk of a transmission uses this function's next_msg_flags
|
||||
* parameter for its backend calls (_write/_read). Any previous chunks
|
||||
* use a copy of the current message's flags, with the STOP and RESTART
|
||||
* bits turned off. This will cause the backend to use reload-mode,
|
||||
* which will make the combination of all chunks to look like one big
|
||||
* transaction on the wire.
|
||||
*/
|
||||
const uint32_t i2c_stm32_maxchunk = 255U;
|
||||
const uint8_t saved_flags = msg.flags;
|
||||
uint8_t combine_flags =
|
||||
saved_flags & ~(I2C_MSG_STOP | I2C_MSG_RESTART);
|
||||
uint8_t *flagsp = NULL;
|
||||
uint32_t rest = msg.len;
|
||||
int ret = 0;
|
||||
|
||||
do { /* do ... while to allow zero-length transactions */
|
||||
if (msg.len > i2c_stm32_maxchunk) {
|
||||
msg.len = i2c_stm32_maxchunk;
|
||||
msg.flags &= ~I2C_MSG_STOP;
|
||||
flagsp = &combine_flags;
|
||||
} else {
|
||||
msg.flags = saved_flags;
|
||||
flagsp = next_msg_flags;
|
||||
}
|
||||
if ((msg.flags & I2C_MSG_RW_MASK) == I2C_MSG_WRITE) {
|
||||
ret = stm32_i2c_msg_write(dev, &msg, flagsp, periph);
|
||||
} else {
|
||||
ret = stm32_i2c_msg_read(dev, &msg, flagsp, periph);
|
||||
}
|
||||
if (ret < 0) {
|
||||
break;
|
||||
}
|
||||
rest -= msg.len;
|
||||
msg.buf += msg.len;
|
||||
msg.len = rest;
|
||||
} while (rest > 0U);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue