drivers: i2c_nrfx_twim: Fix frequency configuration

Change the way this shim driver configures the I2C frequency, so that
it is possible to use also 1 MHz on nRF5340 (the nrfx driver performs
extra initialization steps for this frequency, hence it needs to be
reinitialized when the shim is reconfigured).
Correct the shim to handle selection of 1 MHz (or FAST_PLUS) bitrate
both through dts and I2C API.

Signed-off-by: Andrzej Głąbek <andrzej.glabek@nordicsemi.no>
This commit is contained in:
Andrzej Głąbek 2022-02-04 14:38:14 +01:00 committed by Carles Cufí
commit e57d6368d0

View file

@ -19,18 +19,20 @@ LOG_MODULE_REGISTER(i2c_nrfx_twim, CONFIG_I2C_LOG_LEVEL);
struct i2c_nrfx_twim_data {
struct k_sem transfer_sync;
struct k_sem completion_sync;
nrfx_twim_config_t twim_config;
bool twim_initialized;
volatile nrfx_err_t res;
uint32_t dev_config;
uint8_t *msg_buf;
};
struct i2c_nrfx_twim_config {
nrfx_twim_t twim;
nrfx_twim_config_t config;
uint16_t concat_buf_size;
uint16_t flash_buf_max_size;
};
static int init_twim(const struct device *dev);
static int i2c_nrfx_twim_transfer(const struct device *dev,
struct i2c_msg *msgs,
uint8_t num_msgs, uint16_t addr)
@ -45,6 +47,13 @@ static int i2c_nrfx_twim_transfer(const struct device *dev,
.address = addr
};
/* If for whatever reason the TWIM peripheral is still not initialized
* at this point, try to initialize it now.
*/
if (!dev_data->twim_initialized && init_twim(dev) < 0) {
return -EIO;
}
k_sem_take(&dev_data->transfer_sync, K_FOREVER);
/* Dummy take on completion_sync sem to be sure that it is empty */
@ -162,8 +171,8 @@ static int i2c_nrfx_twim_transfer(const struct device *dev,
*/
LOG_ERR("Error on I2C line occurred for message %d", i);
nrfx_twim_disable(&dev_config->twim);
nrfx_twim_bus_recover(dev_config->config.scl,
dev_config->config.sda);
nrfx_twim_bus_recover(dev_data->twim_config.scl,
dev_data->twim_config.sda);
ret = -EIO;
break;
}
@ -224,39 +233,76 @@ static void event_handler(nrfx_twim_evt_t const *p_event, void *p_context)
k_sem_give(&dev_data->completion_sync);
}
static int i2c_nrfx_twim_configure(const struct device *dev,
uint32_t dev_config)
static int init_twim(const struct device *dev)
{
const struct i2c_nrfx_twim_config *config = dev->config;
struct i2c_nrfx_twim_data *data = dev->data;
nrfx_twim_t const *inst = &config->twim;
const struct i2c_nrfx_twim_config *dev_config = dev->config;
struct i2c_nrfx_twim_data *dev_data = dev->data;
nrfx_err_t result = nrfx_twim_init(&dev_config->twim,
&dev_data->twim_config,
event_handler, dev_data);
if (result != NRFX_SUCCESS) {
LOG_ERR("Failed to initialize device: %s", dev->name);
return -EIO;
}
if (I2C_ADDR_10_BITS & dev_config) {
dev_data->twim_initialized = true;
return 0;
}
static void deinit_twim(const struct device *dev)
{
const struct i2c_nrfx_twim_config *dev_config = dev->config;
struct i2c_nrfx_twim_data *dev_data = dev->data;
if (dev_data->twim_initialized) {
nrfx_twim_uninit(&dev_config->twim);
dev_data->twim_initialized = false;
}
}
static int i2c_nrfx_twim_configure(const struct device *dev,
uint32_t i2c_config)
{
struct i2c_nrfx_twim_data *dev_data = dev->data;
nrf_twim_frequency_t frequency;
if (I2C_ADDR_10_BITS & i2c_config) {
return -EINVAL;
}
switch (I2C_SPEED_GET(dev_config)) {
switch (I2C_SPEED_GET(i2c_config)) {
case I2C_SPEED_STANDARD:
nrf_twim_frequency_set(inst->p_twim, NRF_TWIM_FREQ_100K);
frequency = NRF_TWIM_FREQ_100K;
break;
case I2C_SPEED_FAST:
nrf_twim_frequency_set(inst->p_twim, NRF_TWIM_FREQ_400K);
frequency = NRF_TWIM_FREQ_400K;
break;
#if NRF_TWIM_HAS_1000_KHZ_FREQ
case I2C_SPEED_FAST_PLUS:
frequency = NRF_TWIM_FREQ_1000K;
break;
#endif
default:
LOG_ERR("unsupported speed");
return -EINVAL;
}
data->dev_config = dev_config;
if (frequency != dev_data->twim_config.frequency) {
dev_data->twim_config.frequency = frequency;
deinit_twim(dev);
return init_twim(dev);
}
return 0;
}
static int i2c_nrfx_twim_recover_bus(const struct device *dev)
{
const struct i2c_nrfx_twim_config *config = dev->config;
struct i2c_nrfx_twim_data *dev_data = dev->data;
nrfx_err_t err = nrfx_twim_bus_recover(config->config.scl,
config->config.sda);
nrfx_err_t err = nrfx_twim_bus_recover(dev_data->twim_config.scl,
dev_data->twim_config.sda);
return (err == NRFX_SUCCESS ? 0 : -EBUSY);
}
@ -267,39 +313,19 @@ static const struct i2c_driver_api i2c_nrfx_twim_driver_api = {
.recover_bus = i2c_nrfx_twim_recover_bus,
};
static int init_twim(const struct device *dev)
{
const struct i2c_nrfx_twim_config *config = dev->config;
struct i2c_nrfx_twim_data *dev_data = dev->data;
nrfx_err_t result = nrfx_twim_init(&config->twim, &config->config,
event_handler, dev_data);
if (result != NRFX_SUCCESS) {
LOG_ERR("Failed to initialize device: %s",
dev->name);
return -EBUSY;
}
return 0;
}
#ifdef CONFIG_PM_DEVICE
static int twim_nrfx_pm_action(const struct device *dev,
enum pm_device_action action)
{
const struct i2c_nrfx_twim_config *config = dev->config;
struct i2c_nrfx_twim_data *data = dev->data;
int ret = 0;
switch (action) {
case PM_DEVICE_ACTION_RESUME:
init_twim(dev);
if (data->dev_config) {
i2c_nrfx_twim_configure(dev, data->dev_config);
}
ret = init_twim(dev);
break;
case PM_DEVICE_ACTION_SUSPEND:
nrfx_twim_uninit(&config->twim);
deinit_twim(dev);
break;
default:
@ -312,10 +338,12 @@ static int twim_nrfx_pm_action(const struct device *dev,
#define I2C_NRFX_TWIM_INVALID_FREQUENCY ((nrf_twim_frequency_t)-1)
#define I2C_NRFX_TWIM_FREQUENCY(bitrate) \
(bitrate == I2C_BITRATE_STANDARD ? NRF_TWIM_FREQ_100K \
: bitrate == 250000 ? NRF_TWIM_FREQ_250K \
: bitrate == I2C_BITRATE_FAST ? NRF_TWIM_FREQ_400K \
: I2C_NRFX_TWIM_INVALID_FREQUENCY)
(bitrate == I2C_BITRATE_STANDARD ? NRF_TWIM_FREQ_100K : \
bitrate == 250000 ? NRF_TWIM_FREQ_250K : \
bitrate == I2C_BITRATE_FAST ? NRF_TWIM_FREQ_400K : \
IF_ENABLED(NRF_TWIM_HAS_1000_KHZ_FREQ, \
(bitrate == I2C_BITRATE_FAST_PLUS ? NRF_TWIM_FREQ_1000K :)) \
I2C_NRFX_TWIM_INVALID_FREQUENCY)
#define I2C(idx) DT_NODELABEL(i2c##idx)
#define I2C_FREQUENCY(idx) \
@ -347,6 +375,11 @@ static int twim_nrfx_pm_action(const struct device *dev,
IF_ENABLED(USES_MSG_BUF(idx), \
(static uint8_t twim_##idx##_msg_buf[MSG_BUF_SIZE(idx)];)) \
static struct i2c_nrfx_twim_data twim_##idx##_data = { \
.twim_config = { \
.scl = DT_PROP(I2C(idx), scl_pin), \
.sda = DT_PROP(I2C(idx), sda_pin), \
.frequency = I2C_FREQUENCY(idx), \
}, \
.transfer_sync = Z_SEM_INITIALIZER( \
twim_##idx##_data.transfer_sync, 1, 1), \
.completion_sync = Z_SEM_INITIALIZER( \
@ -356,11 +389,6 @@ static int twim_nrfx_pm_action(const struct device *dev,
}; \
static const struct i2c_nrfx_twim_config twim_##idx##z_config = { \
.twim = NRFX_TWIM_INSTANCE(idx), \
.config = { \
.scl = DT_PROP(I2C(idx), scl_pin), \
.sda = DT_PROP(I2C(idx), sda_pin), \
.frequency = I2C_FREQUENCY(idx), \
}, \
.concat_buf_size = CONCAT_BUF_SIZE(idx), \
.flash_buf_max_size = FLASH_BUF_MAX_SIZE(idx), \
}; \