drivers: i2c: sam_twi: Implement bus locking

Added bus locking mechanism, this patch resolves deadlocks
for more than one device on i2c bus, it is based on i2c_sam0 code.

Signed-off-by: Wojciech Slenska <wsl@trackunit.com>
This commit is contained in:
Wojciech Slenska 2022-05-30 11:58:44 +02:00 committed by Carles Cufí
commit 363989a40d

View file

@ -62,6 +62,7 @@ struct twi_msg {
/* Device run time data */
struct i2c_sam_twi_dev_data {
struct k_sem lock;
struct k_sem sem;
struct twi_msg msg;
};
@ -101,6 +102,7 @@ static int i2c_clk_set(Twi *const twi, uint32_t speed)
static int i2c_sam_twi_configure(const struct device *dev, uint32_t config)
{
const struct i2c_sam_twi_dev_cfg *const dev_cfg = dev->config;
struct i2c_sam_twi_dev_data *const dev_data = dev->data;
Twi *const twi = dev_cfg->regs;
uint32_t bitrate;
int ret;
@ -129,10 +131,12 @@ static int i2c_sam_twi_configure(const struct device *dev, uint32_t config)
return -EIO;
}
k_sem_take(&dev_data->lock, K_FOREVER);
/* Setup clock waveform */
ret = i2c_clk_set(twi, bitrate);
if (ret < 0) {
return ret;
goto unlock;
}
/* Disable Slave Mode */
@ -141,7 +145,11 @@ static int i2c_sam_twi_configure(const struct device *dev, uint32_t config)
/* Enable Master Mode */
twi->TWI_CR = TWI_CR_MSEN;
return 0;
ret = 0;
unlock:
k_sem_give(&dev_data->lock);
return ret;
}
static void write_msg_start(Twi *const twi, struct twi_msg *msg, uint8_t daddr)
@ -179,11 +187,13 @@ static int i2c_sam_twi_transfer(const struct device *dev,
const struct i2c_sam_twi_dev_cfg *const dev_cfg = dev->config;
struct i2c_sam_twi_dev_data *const dev_data = dev->data;
Twi *const twi = dev_cfg->regs;
int ret;
__ASSERT_NO_MSG(msgs);
if (!num_msgs) {
return 0;
}
k_sem_take(&dev_data->lock, K_FOREVER);
/* Clear pending interrupts, such as NACK. */
(void)twi->TWI_SR;
@ -222,11 +232,16 @@ static int i2c_sam_twi_transfer(const struct device *dev,
if (dev_data->msg.twi_sr > 0) {
/* Something went wrong */
return -EIO;
ret = -EIO;
goto unlock;
}
}
return 0;
ret = 0;
unlock:
k_sem_give(&dev_data->lock);
return ret;
}
static void i2c_sam_twi_isr(const struct device *dev)
@ -299,7 +314,8 @@ static int i2c_sam_twi_initialize(const struct device *dev)
/* Configure interrupts */
dev_cfg->irq_config();
/* Initialize semaphore */
/* Initialize semaphores */
k_sem_init(&dev_data->lock, 1, 1);
k_sem_init(&dev_data->sem, 0, 1);
/* Connect pins to the peripheral */