i2c-mcux: take semaphore during transfer
Neither i2c_transfer in i2c.h nor i2c_mcux_transfer in i2c_mcux.c have any sort of locking. If e.g. an i2c eprom is updated using a shell and simultaneously another thread access a lm75 then one of the two transfers will fail or produce a random result. This changes addresses this issue by that all i2c_msgs of one i2c_transfer are completed before allowing a subsequent transfer to start. The code has been validated on a FRDM_K64F. Signed-off-by: Andreas Dröscher <github@anticat.ch>
This commit is contained in:
parent
4d536647e1
commit
49a3ce5881
1 changed files with 17 additions and 4 deletions
|
@ -34,6 +34,7 @@ struct i2c_mcux_config {
|
||||||
|
|
||||||
struct i2c_mcux_data {
|
struct i2c_mcux_data {
|
||||||
i2c_master_handle_t handle;
|
i2c_master_handle_t handle;
|
||||||
|
struct k_sem lock;
|
||||||
struct k_sem device_sync_sem;
|
struct k_sem device_sync_sem;
|
||||||
status_t callback_status;
|
status_t callback_status;
|
||||||
};
|
};
|
||||||
|
@ -42,6 +43,7 @@ static int i2c_mcux_configure(const struct device *dev,
|
||||||
uint32_t dev_config_raw)
|
uint32_t dev_config_raw)
|
||||||
{
|
{
|
||||||
I2C_Type *base = DEV_BASE(dev);
|
I2C_Type *base = DEV_BASE(dev);
|
||||||
|
struct i2c_mcux_data *data = DEV_DATA(dev);
|
||||||
const struct i2c_mcux_config *config = DEV_CFG(dev);
|
const struct i2c_mcux_config *config = DEV_CFG(dev);
|
||||||
uint32_t clock_freq;
|
uint32_t clock_freq;
|
||||||
uint32_t baudrate;
|
uint32_t baudrate;
|
||||||
|
@ -69,7 +71,9 @@ static int i2c_mcux_configure(const struct device *dev,
|
||||||
}
|
}
|
||||||
|
|
||||||
clock_freq = CLOCK_GetFreq(config->clock_source);
|
clock_freq = CLOCK_GetFreq(config->clock_source);
|
||||||
|
k_sem_take(&data->lock, K_FOREVER);
|
||||||
I2C_MasterSetBaudRate(base, baudrate, clock_freq);
|
I2C_MasterSetBaudRate(base, baudrate, clock_freq);
|
||||||
|
k_sem_give(&data->lock);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
@ -109,11 +113,15 @@ static int i2c_mcux_transfer(const struct device *dev, struct i2c_msg *msgs,
|
||||||
struct i2c_mcux_data *data = DEV_DATA(dev);
|
struct i2c_mcux_data *data = DEV_DATA(dev);
|
||||||
i2c_master_transfer_t transfer;
|
i2c_master_transfer_t transfer;
|
||||||
status_t status;
|
status_t status;
|
||||||
|
int ret = 0;
|
||||||
|
|
||||||
|
k_sem_take(&data->lock, K_FOREVER);
|
||||||
|
|
||||||
/* Iterate over all the messages */
|
/* Iterate over all the messages */
|
||||||
for (int i = 0; i < num_msgs; i++) {
|
for (int i = 0; i < num_msgs; i++) {
|
||||||
if (I2C_MSG_ADDR_10_BITS & msgs->flags) {
|
if (I2C_MSG_ADDR_10_BITS & msgs->flags) {
|
||||||
return -ENOTSUP;
|
ret = -ENOTSUP;
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Initialize the transfer descriptor */
|
/* Initialize the transfer descriptor */
|
||||||
|
@ -142,7 +150,8 @@ static int i2c_mcux_transfer(const struct device *dev, struct i2c_msg *msgs,
|
||||||
*/
|
*/
|
||||||
if (status != kStatus_Success) {
|
if (status != kStatus_Success) {
|
||||||
I2C_MasterTransferAbort(base, &data->handle);
|
I2C_MasterTransferAbort(base, &data->handle);
|
||||||
return -EIO;
|
ret = -EIO;
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Wait for the transfer to complete */
|
/* Wait for the transfer to complete */
|
||||||
|
@ -153,14 +162,17 @@ static int i2c_mcux_transfer(const struct device *dev, struct i2c_msg *msgs,
|
||||||
*/
|
*/
|
||||||
if (data->callback_status != kStatus_Success) {
|
if (data->callback_status != kStatus_Success) {
|
||||||
I2C_MasterTransferAbort(base, &data->handle);
|
I2C_MasterTransferAbort(base, &data->handle);
|
||||||
return -EIO;
|
ret = -EIO;
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Move to the next message */
|
/* Move to the next message */
|
||||||
msgs++;
|
msgs++;
|
||||||
}
|
}
|
||||||
|
|
||||||
return 0;
|
k_sem_give(&data->lock);
|
||||||
|
|
||||||
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void i2c_mcux_isr(const struct device *dev)
|
static void i2c_mcux_isr(const struct device *dev)
|
||||||
|
@ -180,6 +192,7 @@ static int i2c_mcux_init(const struct device *dev)
|
||||||
i2c_master_config_t master_config;
|
i2c_master_config_t master_config;
|
||||||
int error;
|
int error;
|
||||||
|
|
||||||
|
k_sem_init(&data->lock, 1, 1);
|
||||||
k_sem_init(&data->device_sync_sem, 0, UINT_MAX);
|
k_sem_init(&data->device_sync_sem, 0, UINT_MAX);
|
||||||
|
|
||||||
clock_freq = CLOCK_GetFreq(config->clock_source);
|
clock_freq = CLOCK_GetFreq(config->clock_source);
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue