drivers: i2c: i2c_dw: add bus mutex

This change adds a mutex to protect against simultaneous access to the bus
instead of returning an error during transfers. Since most I2C code doesn't
handle retries (especially with a -EIO code) not blocking on a mutex can
cause a number of problems.

Signed-off-by: Corey Wharton <xodus7@cwharton.com>
This commit is contained in:
Corey Wharton 2023-01-12 11:27:47 -08:00 committed by Carles Cufí
parent 6433e204b9
commit 46ba5e5518
2 changed files with 14 additions and 3 deletions

View file

@ -461,17 +461,22 @@ static int i2c_dw_transfer(const struct device *dev,
return 0;
}
ret = k_mutex_lock(&dw->bus_mutex, K_FOREVER);
if (ret != 0) {
return ret;
}
/* First step, check if there is current activity */
if (test_bit_status_activity(reg_base) || (dw->state & I2C_DW_BUSY)) {
return -EIO;
ret = -EBUSY;
goto error;
}
dw->state |= I2C_DW_BUSY;
ret = i2c_dw_setup(dev, slave_address);
if (ret) {
dw->state = I2C_DW_STATE_READY;
return ret;
goto error;
}
/* Enable controller */
@ -551,7 +556,9 @@ static int i2c_dw_transfer(const struct device *dev,
pm_device_busy_clear(dev);
error:
dw->state = I2C_DW_STATE_READY;
k_mutex_unlock(&dw->bus_mutex);
return ret;
}
@ -867,8 +874,11 @@ static int i2c_dw_initialize(const struct device *dev)
}
k_sem_init(&dw->device_sync_sem, 0, K_SEM_MAX_LIMIT);
k_mutex_init(&dw->bus_mutex);
uint32_t reg_base = get_regs(dev);
clear_bit_enable_en(reg_base);
/* verify that we have a valid DesignWare register first */
if (read_comp_type(reg_base) != I2C_DW_MAGIC_KEY) {
LOG_DBG("I2C: DesignWare magic key not found, check base "

View file

@ -102,6 +102,7 @@ struct i2c_dw_rom_config {
struct i2c_dw_dev_config {
DEVICE_MMIO_RAM;
struct k_sem device_sync_sem;
struct k_mutex bus_mutex;
uint32_t app_config;
uint8_t *xfr_buf;