drivers: i2c: flexcomm: Add i2c slave support

Add i2c slave support to mcux_flexcomm driver.

Signed-off-by: Oliver Stäbler <oliver.staebler@bytesatwork.ch>
This commit is contained in:
Oliver Stäbler 2022-04-04 16:33:54 +02:00 committed by David Leach
commit 74c1d35900

View file

@ -35,6 +35,14 @@ struct mcux_flexcomm_data {
i2c_master_handle_t handle;
struct k_sem device_sync_sem;
status_t callback_status;
#ifdef CONFIG_I2C_SLAVE
i2c_slave_handle_t target_handle;
struct i2c_slave_config *target_cfg;
bool target_attached;
bool first_read;
bool first_write;
bool is_write;
#endif
};
static int mcux_flexcomm_configure(const struct device *dev,
@ -171,12 +179,141 @@ static int mcux_flexcomm_transfer(const struct device *dev,
return 0;
}
#if defined(CONFIG_I2C_SLAVE)
static void i2c_target_transfer_callback(I2C_Type *base,
volatile i2c_slave_transfer_t *transfer, void *userData)
{
struct mcux_flexcomm_data *data = userData;
const struct i2c_slave_callbacks *target_cb = data->target_cfg->callbacks;
static uint8_t rxVal, txVal;
ARG_UNUSED(base);
switch (transfer->event) {
case kI2C_SlaveTransmitEvent:
/* request to provide data to transmit */
if (data->first_read && target_cb->read_requested) {
data->first_read = false;
target_cb->read_requested(data->target_cfg, &txVal);
} else if (target_cb->read_processed) {
target_cb->read_processed(data->target_cfg, &txVal);
}
transfer->txData = &txVal;
transfer->txSize = 1;
break;
case kI2C_SlaveReceiveEvent:
/* request to provide a buffer in which to place received data */
if (data->first_write && target_cb->write_requested) {
target_cb->write_requested(data->target_cfg);
data->first_write = false;
}
transfer->rxData = &rxVal;
transfer->rxSize = 1;
data->is_write = true;
break;
case kI2C_SlaveCompletionEvent:
/* called after every transferred byte */
if (data->is_write && target_cb->write_received) {
target_cb->write_received(data->target_cfg, rxVal);
data->is_write = false;
}
break;
case kI2C_SlaveDeselectedEvent:
if (target_cb->stop) {
target_cb->stop(data->target_cfg);
}
data->first_read = true;
data->first_write = true;
break;
default:
LOG_INF("Unhandled event: %d", transfer->event);
break;
}
}
int mcux_flexcomm_target_register(const struct device *dev,
struct i2c_slave_config *target_config)
{
const struct mcux_flexcomm_config *config = dev->config;
struct mcux_flexcomm_data *data = dev->data;
I2C_Type *base = config->base;
uint32_t clock_freq;
i2c_slave_config_t i2c_cfg;
I2C_MasterDeinit(base);
/* Get the clock frequency */
if (clock_control_get_rate(config->clock_dev, config->clock_subsys,
&clock_freq)) {
return -EINVAL;
}
if (!target_config) {
return -EINVAL;
}
if (data->target_attached) {
return -EBUSY;
}
data->target_cfg = target_config;
data->target_attached = true;
data->first_read = true;
data->first_write = true;
I2C_SlaveGetDefaultConfig(&i2c_cfg);
i2c_cfg.address0.address = target_config->address;
I2C_SlaveInit(base, &i2c_cfg, clock_freq);
I2C_SlaveTransferCreateHandle(base, &data->target_handle,
i2c_target_transfer_callback, data);
I2C_SlaveTransferNonBlocking(base, &data->target_handle,
kI2C_SlaveCompletionEvent | kI2C_SlaveTransmitEvent |
kI2C_SlaveReceiveEvent | kI2C_SlaveDeselectedEvent);
return 0;
}
int mcux_flexcomm_target_unregister(const struct device *dev,
struct i2c_slave_config *target_config)
{
const struct mcux_flexcomm_config *config = dev->config;
struct mcux_flexcomm_data *data = dev->data;
I2C_Type *base = config->base;
if (!data->target_attached) {
return -EINVAL;
}
data->target_cfg = NULL;
data->target_attached = false;
I2C_SlaveDeinit(base);
return 0;
}
#endif
static void mcux_flexcomm_isr(const struct device *dev)
{
const struct mcux_flexcomm_config *config = dev->config;
struct mcux_flexcomm_data *data = dev->data;
I2C_Type *base = config->base;
#if defined(CONFIG_I2C_SLAVE)
if (data->target_attached) {
I2C_SlaveTransferHandleIRQ(base, &data->target_handle);
return;
}
#endif
I2C_MasterTransferHandleIRQ(base, &data->handle);
}
@ -225,6 +362,10 @@ static int mcux_flexcomm_init(const struct device *dev)
static const struct i2c_driver_api mcux_flexcomm_driver_api = {
.configure = mcux_flexcomm_configure,
.transfer = mcux_flexcomm_transfer,
#if defined(CONFIG_I2C_SLAVE)
.slave_register = mcux_flexcomm_target_register,
.slave_unregister = mcux_flexcomm_target_unregister,
#endif
};
#ifdef CONFIG_PINCTRL