From bbd137d0a1fee3794b5f0817eb9724190b8c382a Mon Sep 17 00:00:00 2001 From: S Mohamed Fiaz Date: Wed, 1 Oct 2025 00:13:01 +0530 Subject: [PATCH 1/2] west.yml: Update hal_silabs revision This commit updates the hal_silabs revision Signed-off-by: S Mohamed Fiaz --- west.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/west.yml b/west.yml index c36b20ec94fb9..83fbe4fafdc4c 100644 --- a/west.yml +++ b/west.yml @@ -240,7 +240,7 @@ manifest: groups: - hal - name: hal_silabs - revision: 764d9153c69178bc851625d5a6a15fde237e626a + revision: pull/142/head path: modules/hal/silabs groups: - hal From d4d90fb99133fc1ac7a40330f33d20836068d1a6 Mon Sep 17 00:00:00 2001 From: S Mohamed Fiaz Date: Tue, 30 Sep 2025 22:03:32 +0530 Subject: [PATCH 2/2] drivers: i2c: silabs: i2c driver enhancements for EFR series 2 devices Updated the I2C driver for EFR Series 2 devices based on the design improvements in the GSDK I2C implementation Signed-off-by: S Mohamed Fiaz --- drivers/i2c/i2c_silabs.c | 158 +++++++++++++++++++++++---------------- 1 file changed, 94 insertions(+), 64 deletions(-) diff --git a/drivers/i2c/i2c_silabs.c b/drivers/i2c/i2c_silabs.c index eb302310d3d26..5189018dd47dd 100644 --- a/drivers/i2c/i2c_silabs.c +++ b/drivers/i2c/i2c_silabs.c @@ -10,17 +10,13 @@ #include #include #include -#if defined(CONFIG_I2C_SILABS_DMA) #include -#endif #include #include #include #include #include -#include #include -#include #include #define LOG_LEVEL CONFIG_I2C_LOG_LEVEL @@ -36,7 +32,7 @@ struct i2c_silabs_dma_config { /* Structure for I2C device configuration */ struct i2c_silabs_dev_config { const struct pinctrl_dev_config *pcfg; /* Pin configuration for the I2C instance */ - I2C_TypeDef *base; /* I2C peripheral base address */ + sl_peripheral_t peripheral; /* I2C peripheral structure */ uint32_t bitrate; /* I2C bitrate (clock frequency) */ void (*irq_config_func)(void); /* IRQ configuration function */ const struct device *clock; /* Clock device */ @@ -47,11 +43,12 @@ struct i2c_silabs_dev_config { struct i2c_silabs_dev_data { struct k_sem bus_lock; /* Semaphore to lock the I2C bus */ struct k_sem transfer_sem; /* Semaphore to manage transfer */ - sli_i2c_instance_t i2c_instance; /* I2C instance structure */ + sl_i2c_handle_t i2c_handle; /* I2C handle structure */ struct i2c_silabs_dma_config dma_rx; /* DMA configuration for RX */ struct i2c_silabs_dma_config dma_tx; /* DMA configuration for TX */ bool asynchronous; /* Indicates if transfer is asynchronous */ bool last_transfer; /* Transfer is the last in the sequence */ + bool is_10bit_addr; /* Indicates if addr is 7-bit or 10-bit */ #if defined CONFIG_I2C_CALLBACK i2c_callback_t callback; /* I2C callback function pointer */ void *callback_context; /* Context for I2C callback */ @@ -64,15 +61,15 @@ static int i2c_silabs_pm_action(const struct device *dev, enum pm_device_action static bool i2c_silabs_is_dma_enabled_instance(const struct device *dev) { -#ifdef CONFIG_I2C_SILABS_DMA struct i2c_silabs_dev_data *data = dev->data; + if (!IS_ENABLED(CONFIG_I2C_SILABS_DMA)) { + return false; + } + __ASSERT_NO_MSG(!!data->dma_tx.dma_dev == !!data->dma_rx.dma_dev); return data->dma_rx.dma_dev != NULL; -#else - return false; -#endif } static void i2c_silabs_pm_policy_state_lock_get(const struct device *dev) @@ -92,18 +89,17 @@ static int i2c_silabs_dev_configure(const struct device *dev, uint32_t dev_confi { const struct i2c_silabs_dev_config *config = dev->config; struct i2c_silabs_dev_data *data = dev->data; - sl_i2c_init_params_t init_params; /* Determine the I2C speed and corresponding baudrate */ switch (I2C_SPEED_GET(dev_config)) { case I2C_SPEED_STANDARD: - init_params.freq_mode = SL_I2C_FREQ_STANDARD_MODE; + data->i2c_handle.frequency_mode = SL_I2C_FREQ_STANDARD_MODE; break; case I2C_SPEED_FAST: - init_params.freq_mode = SL_I2C_FREQ_FAST_MODE; + data->i2c_handle.frequency_mode = SL_I2C_FREQ_FAST_MODE; break; case I2C_SPEED_FAST_PLUS: - init_params.freq_mode = SL_I2C_FREQ_FASTPLUS_MODE; + data->i2c_handle.frequency_mode = SL_I2C_FREQ_FASTPLUS_MODE; break; default: return -EINVAL; @@ -112,19 +108,17 @@ static int i2c_silabs_dev_configure(const struct device *dev, uint32_t dev_confi /* Take the bus lock semaphore to ensure exclusive access */ k_sem_take(&data->bus_lock, K_FOREVER); /* Initialize I2C parameters */ - init_params.i2c_base_addr = config->base; - data->i2c_instance.i2c_base_addr = init_params.i2c_base_addr; + data->i2c_handle.i2c_peripheral = config->peripheral; /* Set the operating mode (leader or follower) */ #if defined(CONFIG_I2C_TARGET) - init_params.operating_mode = SL_I2C_FOLLOWER_MODE; + data->i2c_handle.operating_mode = SL_I2C_FOLLOWER_MODE; #else - init_params.operating_mode = SL_I2C_LEADER_MODE; + data->i2c_handle.operating_mode = SL_I2C_LEADER_MODE; #endif /* CONFIG_I2C_TARGET */ - data->i2c_instance.operating_mode = init_params.operating_mode; /* Configure the I2C instance */ - sli_i2c_instance_configuration(&init_params); + sli_i2c_init_core(&data->i2c_handle); /* Release the bus lock semaphore */ k_sem_give(&data->bus_lock); @@ -137,10 +131,8 @@ static int i2c_silabs_transfer_dma(const struct device *dev, struct i2c_msg *msg uint16_t addr, i2c_callback_t cb, void *userdata, bool asynchronous) { -#if defined(CONFIG_I2C_SILABS_DMA) struct i2c_silabs_dev_data *data = dev->data; __maybe_unused const struct i2c_silabs_dev_config *config = dev->config; - sl_i2c_handle_t *i2c_handle = (sl_i2c_handle_t *)&data->i2c_instance; #if defined(CONFIG_I2C_CALLBACK) data->callback_invoked = false; #endif @@ -148,14 +140,13 @@ static int i2c_silabs_transfer_dma(const struct device *dev, struct i2c_msg *msg uint8_t i = 0; int err = 0; + if (!IS_ENABLED(CONFIG_I2C_SILABS_DMA)) { + return -ENOTSUP; + } + /* Get the power management policy state lock */ i2c_silabs_pm_policy_state_lock_get(dev); -#if defined(CONFIG_I2C_TARGET) - /* Set follower address in target mode */ - sli_i2c_set_follower_address(config->base, addr, data->i2c_instance.is_10bit_addr); -#endif /* CONFIG_I2C_TARGET */ - while (i < num_msgs) { uint8_t msgs_in_transfer = 1; @@ -167,33 +158,49 @@ static int i2c_silabs_transfer_dma(const struct device *dev, struct i2c_msg *msg data->last_transfer = (i + msgs_in_transfer) == num_msgs; if (msgs_in_transfer == 2) { - if (sl_i2c_transfer_non_blocking(i2c_handle, msgs[i].buf, msgs[i].len, - msgs[i + 1].buf, msgs[i + 1].len, NULL, - NULL) != 0) { + if (sl_i2c_leader_transfer_non_blocking( + &data->i2c_handle, addr, msgs[i].buf, msgs[i].len, + msgs[i + 1].buf, msgs[i + 1].len, NULL) != 0) { k_sem_give(&data->bus_lock); return -EIO; } } else if (msgs[i].flags & I2C_MSG_READ) { /* Start DMA receive */ - if (sl_i2c_receive_non_blocking(i2c_handle, msgs[i].buf, msgs[i].len, NULL, - NULL) != 0) { +#if defined(CONFIG_I2C_TARGET) + if (sl_i2c_follower_receive_non_blocking(&data->i2c_handle, msgs[i].buf, + msgs[i].len, NULL) != 0) { + k_sem_give(&data->bus_lock); + return -EIO; + } +#else + if (sl_i2c_leader_receive_non_blocking(&data->i2c_handle, addr, msgs[i].buf, + msgs[i].len, NULL) != 0) { k_sem_give(&data->bus_lock); return -EIO; } +#endif } else { /* Start DMA send */ - if (sl_i2c_send_non_blocking(i2c_handle, msgs[i].buf, msgs[i].len, NULL, - NULL) != 0) { +#if defined(CONFIG_I2C_TARGET) + if (sl_i2c_follower_send_non_blocking(&data->i2c_handle, msgs[i].buf, + msgs[i].len, NULL) != 0) { k_sem_give(&data->bus_lock); return -EIO; } +#else + if (sl_i2c_leader_send_non_blocking(&data->i2c_handle, addr, msgs[i].buf, + msgs[i].len, NULL) != 0) { + k_sem_give(&data->bus_lock); + return -EIO; + } +#endif } if (!asynchronous) { /* Wait for DMA transfer to complete */ if (k_sem_take(&data->transfer_sem, K_MSEC(CONFIG_I2C_SILABS_TIMEOUT))) { err = -ETIMEDOUT; } - if (data->i2c_instance.state == SLI_I2C_STATE_ERROR) { + if (data->i2c_handle.state == SL_I2C_STATE_ERROR) { err = -EIO; } k_sem_reset(&data->transfer_sem); @@ -205,9 +212,6 @@ static int i2c_silabs_transfer_dma(const struct device *dev, struct i2c_msg *msg } return err; -#else - return -ENOTSUP; -#endif /* CONFIG_I2C_SILABS_DMA */ } /* Function to handle synchronous transfer */ @@ -215,7 +219,6 @@ static int i2c_silabs_transfer_sync(const struct device *dev, struct i2c_msg *ms uint8_t num_msgs, uint16_t addr) { struct i2c_silabs_dev_data *data = dev->data; - sl_i2c_handle_t *i2c_handle = (sl_i2c_handle_t *)&data->i2c_instance; uint8_t i = 0; /* Get the power management policy state lock */ @@ -227,24 +230,46 @@ static int i2c_silabs_transfer_sync(const struct device *dev, struct i2c_msg *ms if ((msgs[i].flags & I2C_MSG_WRITE) == 0 && (i + 1 < num_msgs) && (msgs[i + 1].flags & I2C_MSG_READ)) { msgs_in_transfer = 2; - if (sl_i2c_transfer(i2c_handle, msgs[i].buf, msgs[i].len, msgs[i + 1].buf, - msgs[i + 1].len) != 0) { + if (sl_i2c_leader_transfer_blocking(&data->i2c_handle, addr, msgs[i].buf, + msgs[i].len, msgs[i + 1].buf, + msgs[i + 1].len, + CONFIG_I2C_SILABS_TIMEOUT) != 0) { k_sem_give(&data->bus_lock); return -EIO; } i++; } else if (msgs[i].flags & I2C_MSG_READ) { - if (sl_i2c_receive_blocking(i2c_handle, msgs[i].buf, msgs[i].len, - CONFIG_I2C_SILABS_TIMEOUT) != 0) { +#if defined(CONFIG_I2C_TARGET) + if (sl_i2c_follower_receive_blocking(&data->i2c_handle, msgs[i].buf, + msgs[i].len, + CONFIG_I2C_SILABS_TIMEOUT) != 0) { + k_sem_give(&data->bus_lock); + return -ETIMEDOUT; + } +#else + if (sl_i2c_leader_receive_blocking(&data->i2c_handle, addr, msgs[i].buf, + msgs[i].len, + CONFIG_I2C_SILABS_TIMEOUT) != 0) { k_sem_give(&data->bus_lock); return -ETIMEDOUT; } +#endif } else { - if (sl_i2c_send_blocking(i2c_handle, msgs[i].buf, msgs[i].len, - CONFIG_I2C_SILABS_TIMEOUT) != 0) { +#if defined(CONFIG_I2C_TARGET) + if (sl_i2c_follower_send_blocking(&data->i2c_handle, msgs[i].buf, + msgs[i].len, + CONFIG_I2C_SILABS_TIMEOUT) != 0) { k_sem_give(&data->bus_lock); return -ETIMEDOUT; } +#else + if (sl_i2c_leader_send_blocking(&data->i2c_handle, addr, msgs[i].buf, + msgs[i].len, + CONFIG_I2C_SILABS_TIMEOUT) != 0) { + k_sem_give(&data->bus_lock); + return -ETIMEDOUT; + } +#endif } i += msgs_in_transfer; } @@ -265,7 +290,6 @@ static int i2c_silabs_transfer_impl(const struct device *dev, struct i2c_msg *ms { struct i2c_silabs_dev_data *data = dev->data; __maybe_unused const struct i2c_silabs_dev_config *config = dev->config; - sl_i2c_handle_t *i2c_handle = (sl_i2c_handle_t *)&data->i2c_instance; int ret = -EINVAL; /* Initialize ret to a default error value */ /* Check for invalid number of messages */ @@ -276,9 +300,9 @@ static int i2c_silabs_transfer_impl(const struct device *dev, struct i2c_msg *ms /* Check and set the address mode (7-bit or 10-bit) based on */ /* the provided address */ if (addr <= 0x7F) { - data->i2c_instance.is_10bit_addr = false; /* 7-bit address */ + data->is_10bit_addr = false; /* 7-bit address */ } else if (addr <= 0x3FF) { - data->i2c_instance.is_10bit_addr = true; /* 10-bit address */ + data->is_10bit_addr = true; /* 10-bit address */ } else { return -EINVAL; } @@ -292,11 +316,13 @@ static int i2c_silabs_transfer_impl(const struct device *dev, struct i2c_msg *ms return ret; } +#if defined(CONFIG_I2C_TARGET) /* Set the follower address */ - if (sl_i2c_set_follower_address(i2c_handle, addr) != 0) { + if (sl_i2c_set_follower_address(&data->i2c_handle, addr, data->is_10bit_addr) != 0) { k_sem_give(&data->bus_lock); return -EINVAL; } +#endif if (i2c_silabs_is_dma_enabled_instance(dev)) { /* DMA transfer handle a/synchronous transfers */ @@ -373,17 +399,16 @@ static int i2c_silabs_dev_init(const struct device *dev) return -EINVAL; } -#if defined(CONFIG_I2C_SILABS_DMA) - if (i2c_silabs_is_dma_enabled_instance(dev)) { + if (IS_ENABLED(CONFIG_I2C_SILABS_DMA) && i2c_silabs_is_dma_enabled_instance(dev)) { if (!device_is_ready(data->dma_rx.dma_dev) || !device_is_ready(data->dma_tx.dma_dev)) { return -ENODEV; } data->dma_rx.dma_channel = dma_request_channel(data->dma_rx.dma_dev, NULL); - data->i2c_instance.dma_channel.dma_rx_channel = data->dma_rx.dma_channel; + data->i2c_handle.dma_channel.dma_rx_channel = data->dma_rx.dma_channel; data->dma_tx.dma_channel = dma_request_channel(data->dma_tx.dma_dev, NULL); - data->i2c_instance.dma_channel.dma_tx_channel = data->dma_tx.dma_channel; + data->i2c_handle.dma_channel.dma_tx_channel = data->dma_tx.dma_channel; if (data->dma_rx.dma_channel < 0 || data->dma_tx.dma_channel < 0) { dma_release_channel(data->dma_rx.dma_dev, data->dma_rx.dma_channel); @@ -391,7 +416,6 @@ static int i2c_silabs_dev_init(const struct device *dev) return -EAGAIN; } } -#endif /* CONFIG_I2C_SILABS_DMA */ /* Configure IRQ */ config->irq_config_func(); @@ -445,15 +469,14 @@ static int i2c_silabs_pm_action(const struct device *dev, enum pm_device_action void i2c_silabs_isr_handler(const struct device *dev) { struct i2c_silabs_dev_data *data = dev->data; - sli_i2c_instance_t *sl_i2c_instance = &data->i2c_instance; + sl_i2c_handle_t *sl_i2c_handle = &data->i2c_handle; #if defined(CONFIG_I2C_TARGET) - sli_i2c_follower_dispatch_interrupt(sl_i2c_instance); + sli_i2c_follower_dispatch_interrupt(sl_i2c_handle); #else - sli_i2c_leader_dispatch_interrupt(sl_i2c_instance); + sli_i2c_leader_dispatch_interrupt(sl_i2c_handle); #endif - if (sl_i2c_instance->transfer_event != SL_I2C_EVENT_IN_PROGRESS && - sl_i2c_instance->rstart == 0) { + if (sl_i2c_handle->event != SL_I2C_EVENT_IN_PROGRESS) { if (!data->asynchronous) { k_sem_give(&data->transfer_sem); } @@ -462,9 +485,9 @@ void i2c_silabs_isr_handler(const struct device *dev) int err = 0; data->callback_invoked = true; - if (sl_i2c_instance->transfer_event == SL_I2C_EVENT_ARBITRATION_LOST || - sl_i2c_instance->transfer_event == SL_I2C_EVENT_BUS_ERROR || - sl_i2c_instance->transfer_event == SL_I2C_EVENT_INVALID_ADDR) { + if (sl_i2c_handle->event == SL_I2C_EVENT_ARBITRATION_LOST || + sl_i2c_handle->event == SL_I2C_EVENT_BUS_ERROR || + sl_i2c_handle->event == SL_I2C_EVENT_INVALID_ADDR) { err = -EIO; } data->callback(dev, err, data->callback_context); @@ -503,10 +526,17 @@ static DEVICE_API(i2c, i2c_silabs_dev_driver_api) = { irq_enable(DT_INST_IRQ(idx, irq));), \ ()) \ } \ - \ + \ + static const uint32_t i2c_bus_clock_##idx = DT_INST_CLOCKS_CELL(idx, enable); \ + static const sl_peripheral_val_t i2c_peripheral_val_##idx = { \ + .base = DT_INST_REG_ADDR(idx), \ + .clk_branch = DT_INST_CLOCKS_CELL(idx, branch), \ + .bus_clock = (DT_INST_CLOCKS_CELL(idx, enable) ? &i2c_bus_clock_##idx : NULL), \ + }; \ + \ static const struct i2c_silabs_dev_config i2c_silabs_dev_config_##idx = { \ .pcfg = PINCTRL_DT_INST_DEV_CONFIG_GET(idx), \ - .base = (I2C_TypeDef *)DT_INST_REG_ADDR(idx), \ + .peripheral = &i2c_peripheral_val_##idx, \ .bitrate = DT_INST_PROP(idx, clock_frequency), \ .irq_config_func = i2c_silabs_irq_config_##idx, \ .clock = DEVICE_DT_GET(DT_INST_CLOCKS_CTLR(idx)), \