drivers: i2c: add thread-safe semaphore
Add a semaphore to ensure that only one transaction happens at a time when threads want to transfer simultaneously. Signed-off-by: Wei-Tai Lee <wtlee@andestech.com>
This commit is contained in:
parent
1ca75e3b6e
commit
fc89a85c29
2 changed files with 14 additions and 17 deletions
|
@ -44,7 +44,8 @@ static void i2c_atciic100_default_control(const struct device *dev)
|
|||
struct i2c_atciic100_dev_data_t *dev_data = dev->data;
|
||||
uint32_t reg = 0;
|
||||
|
||||
k_sem_init(&dev_data->i2c_busy_sem, 1, 1);
|
||||
k_sem_init(&dev_data->bus_lock, 1, 1);
|
||||
k_sem_init(&dev_data->device_sync_sem, 0, 1);
|
||||
|
||||
/* Reset I2C bus */
|
||||
reg = sys_read32(I2C_CMD(dev));
|
||||
|
@ -140,7 +141,7 @@ static int i2c_atciic100_configure(const struct device *dev,
|
|||
dev_data->driver_state |= I2C_DRV_CFG_PARAM;
|
||||
|
||||
unlock:
|
||||
k_sem_give(&dev_data->i2c_busy_sem);
|
||||
k_sem_give(&dev_data->bus_lock);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
@ -154,6 +155,8 @@ static int i2c_atciic100_transfer(const struct device *dev,
|
|||
uint8_t burst_write_len = msgs[0].len + msgs[1].len;
|
||||
uint8_t burst_write_buf[I2C_MAX_COUNT + BURST_CMD_COUNT];
|
||||
|
||||
k_sem_take(&dev_data->bus_lock, K_FOREVER);
|
||||
|
||||
if ((msgs[0].flags == I2C_MSG_WRITE)
|
||||
&& (msgs[1].flags == (I2C_MSG_WRITE | I2C_MSG_STOP))) {
|
||||
|
||||
|
@ -186,14 +189,7 @@ static int i2c_atciic100_transfer(const struct device *dev,
|
|||
|
||||
exit:
|
||||
/* Wait for transfer complete */
|
||||
k_sem_take(&dev_data->i2c_busy_sem, K_FOREVER);
|
||||
|
||||
if (dev_data->status.target_ack != 1) {
|
||||
k_sem_give(&dev_data->i2c_busy_sem);
|
||||
return -EIO;
|
||||
}
|
||||
dev_data->status.target_ack = 0;
|
||||
k_sem_give(&dev_data->i2c_busy_sem);
|
||||
k_sem_give(&dev_data->bus_lock);
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
@ -213,8 +209,6 @@ static int i2c_atciic100_controller_send(const struct device *dev,
|
|||
return -EIO;
|
||||
}
|
||||
|
||||
k_sem_take(&dev_data->i2c_busy_sem, K_FOREVER);
|
||||
|
||||
/* Disable all I2C interrupts */
|
||||
reg = sys_read32(I2C_INTE(dev));
|
||||
reg &= (~IEN_ALL);
|
||||
|
@ -301,6 +295,7 @@ static int i2c_atciic100_controller_send(const struct device *dev,
|
|||
reg |= (CMD_ISSUE_TRANSACTION);
|
||||
sys_write32(reg, I2C_CMD(dev));
|
||||
|
||||
k_sem_take(&dev_data->device_sync_sem, K_FOREVER);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -319,8 +314,6 @@ static int i2c_atciic100_controller_receive(const struct device *dev,
|
|||
return -EIO;
|
||||
}
|
||||
|
||||
k_sem_take(&dev_data->i2c_busy_sem, K_FOREVER);
|
||||
|
||||
/* Disable all I2C interrupts */
|
||||
reg = sys_read32(I2C_INTE(dev));
|
||||
reg &= (~IEN_ALL);
|
||||
|
@ -394,6 +387,7 @@ static int i2c_atciic100_controller_receive(const struct device *dev,
|
|||
reg |= (CMD_ISSUE_TRANSACTION);
|
||||
sys_write32(reg, I2C_CMD(dev));
|
||||
|
||||
k_sem_take(&dev_data->device_sync_sem, K_FOREVER);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -533,6 +527,8 @@ static void i2c_cmpl_handler(const struct device *dev, uint32_t reg_stat)
|
|||
/* Clear & set driver state to controller rx complete */
|
||||
dev_data->driver_state = I2C_DRV_CONTROLLER_RX_CMPL;
|
||||
}
|
||||
|
||||
k_sem_give(&dev_data->device_sync_sem);
|
||||
}
|
||||
|
||||
#if defined(CONFIG_I2C_TARGET)
|
||||
|
@ -578,7 +574,6 @@ static void i2c_cmpl_handler(const struct device *dev, uint32_t reg_stat)
|
|||
dev_data->status.arbitration_lost = 0;
|
||||
#endif
|
||||
|
||||
k_sem_give(&dev_data->i2c_busy_sem);
|
||||
}
|
||||
|
||||
#if defined(CONFIG_I2C_TARGET)
|
||||
|
@ -594,7 +589,7 @@ static void andes_i2c_target_event(const struct device *dev,
|
|||
* A new I2C data transaction(START-ADDRESS-DATA-STOP)
|
||||
*/
|
||||
if (reg_stat & STATUS_ADDR_HIT) {
|
||||
if (k_sem_take(&dev_data->i2c_busy_sem, K_NO_WAIT) != 0) {
|
||||
if (k_sem_take(&dev_data->bus_lock, K_NO_WAIT) != 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -637,6 +632,7 @@ static void andes_i2c_target_event(const struct device *dev,
|
|||
|
||||
if (reg_stat & STATUS_CMPL) {
|
||||
i2c_cmpl_handler(dev, reg_stat);
|
||||
k_sem_give(&dev_data->bus_lock);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -223,7 +223,8 @@ struct _i2c_status {
|
|||
};
|
||||
|
||||
struct i2c_atciic100_dev_data_t {
|
||||
struct k_sem i2c_busy_sem;
|
||||
struct k_sem bus_lock;
|
||||
struct k_sem device_sync_sem;
|
||||
volatile uint32_t driver_state;
|
||||
uint8_t *middleware_rx_buf;
|
||||
uint8_t *middleware_tx_buf;
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue