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:
parent
248047323e
commit
363989a40d
1 changed files with 21 additions and 5 deletions
|
@ -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 */
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue