Skip to content

Commit 2a2c685

Browse files
committed
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 <[email protected]>
1 parent fa8f0b5 commit 2a2c685

File tree

1 file changed

+86
-63
lines changed

1 file changed

+86
-63
lines changed

drivers/i2c/i2c_silabs.c

Lines changed: 86 additions & 63 deletions
Original file line numberDiff line numberDiff line change
@@ -10,17 +10,13 @@
1010
#include <zephyr/drivers/pinctrl.h>
1111
#include <zephyr/kernel.h>
1212
#include <zephyr/logging/log.h>
13-
#if defined(CONFIG_I2C_SILABS_DMA)
1413
#include <zephyr/drivers/dma.h>
15-
#endif
1614
#include <zephyr/drivers/clock_control.h>
1715
#include <zephyr/drivers/clock_control/clock_control_silabs.h>
1816
#include <zephyr/pm/device.h>
1917
#include <zephyr/pm/device_runtime.h>
2018
#include <zephyr/pm/policy.h>
21-
#include <sl_hal_i2c.h>
2219
#include <sl_i2c.h>
23-
#include <sl_status.h>
2420
#include <sli_i2c.h>
2521

2622
#define LOG_LEVEL CONFIG_I2C_LOG_LEVEL
@@ -36,7 +32,7 @@ struct i2c_silabs_dma_config {
3632
/* Structure for I2C device configuration */
3733
struct i2c_silabs_dev_config {
3834
const struct pinctrl_dev_config *pcfg; /* Pin configuration for the I2C instance */
39-
I2C_TypeDef *base; /* I2C peripheral base address */
35+
sl_peripheral_t peripheral; /* I2C peripheral structure */
4036
uint32_t bitrate; /* I2C bitrate (clock frequency) */
4137
void (*irq_config_func)(void); /* IRQ configuration function */
4238
const struct device *clock; /* Clock device */
@@ -47,11 +43,12 @@ struct i2c_silabs_dev_config {
4743
struct i2c_silabs_dev_data {
4844
struct k_sem bus_lock; /* Semaphore to lock the I2C bus */
4945
struct k_sem transfer_sem; /* Semaphore to manage transfer */
50-
sli_i2c_instance_t i2c_instance; /* I2C instance structure */
46+
sl_i2c_handle_t i2c_handle; /* I2C handle structure */
5147
struct i2c_silabs_dma_config dma_rx; /* DMA configuration for RX */
5248
struct i2c_silabs_dma_config dma_tx; /* DMA configuration for TX */
5349
bool asynchronous; /* Indicates if transfer is asynchronous */
5450
bool last_transfer; /* Transfer is the last in the sequence */
51+
bool is_10bit_addr; /* Indicates if addr is 7-bit or 10-bit */
5552
#if defined CONFIG_I2C_CALLBACK
5653
i2c_callback_t callback; /* I2C callback function pointer */
5754
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
6461

6562
static bool i2c_silabs_is_dma_enabled_instance(const struct device *dev)
6663
{
67-
#ifdef CONFIG_I2C_SILABS_DMA
6864
struct i2c_silabs_dev_data *data = dev->data;
65+
66+
if (!IS_ENABLED(CONFIG_I2C_SILABS_DMA)) {
67+
return false;
68+
}
6969

7070
__ASSERT_NO_MSG(!!data->dma_tx.dma_dev == !!data->dma_rx.dma_dev);
7171

7272
return data->dma_rx.dma_dev != NULL;
73-
#else
74-
return false;
75-
#endif
7673
}
7774

7875
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
9289
{
9390
const struct i2c_silabs_dev_config *config = dev->config;
9491
struct i2c_silabs_dev_data *data = dev->data;
95-
sl_i2c_init_params_t init_params;
9692

9793
/* Determine the I2C speed and corresponding baudrate */
9894
switch (I2C_SPEED_GET(dev_config)) {
9995
case I2C_SPEED_STANDARD:
100-
init_params.freq_mode = SL_I2C_FREQ_STANDARD_MODE;
96+
data->i2c_handle.frequency_mode = SL_I2C_FREQ_STANDARD_MODE;
10197
break;
10298
case I2C_SPEED_FAST:
103-
init_params.freq_mode = SL_I2C_FREQ_FAST_MODE;
99+
data->i2c_handle.frequency_mode = SL_I2C_FREQ_FAST_MODE;
104100
break;
105101
case I2C_SPEED_FAST_PLUS:
106-
init_params.freq_mode = SL_I2C_FREQ_FASTPLUS_MODE;
102+
data->i2c_handle.frequency_mode = SL_I2C_FREQ_FASTPLUS_MODE;
107103
break;
108104
default:
109105
return -EINVAL;
@@ -112,19 +108,17 @@ static int i2c_silabs_dev_configure(const struct device *dev, uint32_t dev_confi
112108
/* Take the bus lock semaphore to ensure exclusive access */
113109
k_sem_take(&data->bus_lock, K_FOREVER);
114110
/* Initialize I2C parameters */
115-
init_params.i2c_base_addr = config->base;
116-
data->i2c_instance.i2c_base_addr = init_params.i2c_base_addr;
111+
data->i2c_handle.i2c_peripheral = config->peripheral;
117112

118113
/* Set the operating mode (leader or follower) */
119114
#if defined(CONFIG_I2C_TARGET)
120-
init_params.operating_mode = SL_I2C_FOLLOWER_MODE;
115+
data->i2c_handle.operating_mode = SL_I2C_FOLLOWER_MODE;
121116
#else
122-
init_params.operating_mode = SL_I2C_LEADER_MODE;
117+
data->i2c_handle.operating_mode = SL_I2C_LEADER_MODE;
123118
#endif /* CONFIG_I2C_TARGET */
124-
data->i2c_instance.operating_mode = init_params.operating_mode;
125119

126120
/* Configure the I2C instance */
127-
sli_i2c_instance_configuration(&init_params);
121+
sli_i2c_init_core(&data->i2c_handle);
128122

129123
/* Release the bus lock semaphore */
130124
k_sem_give(&data->bus_lock);
@@ -137,25 +131,22 @@ static int i2c_silabs_transfer_dma(const struct device *dev, struct i2c_msg *msg
137131
uint16_t addr, i2c_callback_t cb, void *userdata,
138132
bool asynchronous)
139133
{
140-
#if defined(CONFIG_I2C_SILABS_DMA)
141134
struct i2c_silabs_dev_data *data = dev->data;
142135
__maybe_unused const struct i2c_silabs_dev_config *config = dev->config;
143-
sl_i2c_handle_t *i2c_handle = (sl_i2c_handle_t *)&data->i2c_instance;
144136
#if defined(CONFIG_I2C_CALLBACK)
145137
data->callback_invoked = false;
146138
#endif
147139
data->pm_lock_done = false;
148140
uint8_t i = 0;
149141
int err = 0;
150142

143+
if (!IS_ENABLED(CONFIG_I2C_SILABS_DMA)) {
144+
return -ENOTSUP;
145+
}
146+
151147
/* Get the power management policy state lock */
152148
i2c_silabs_pm_policy_state_lock_get(dev);
153149

154-
#if defined(CONFIG_I2C_TARGET)
155-
/* Set follower address in target mode */
156-
sli_i2c_set_follower_address(config->base, addr, data->i2c_instance.is_10bit_addr);
157-
#endif /* CONFIG_I2C_TARGET */
158-
159150
while (i < num_msgs) {
160151
uint8_t msgs_in_transfer = 1;
161152

@@ -167,33 +158,49 @@ static int i2c_silabs_transfer_dma(const struct device *dev, struct i2c_msg *msg
167158
data->last_transfer = (i + msgs_in_transfer) == num_msgs;
168159

169160
if (msgs_in_transfer == 2) {
170-
if (sl_i2c_transfer_non_blocking(i2c_handle, msgs[i].buf, msgs[i].len,
171-
msgs[i + 1].buf, msgs[i + 1].len, NULL,
172-
NULL) != 0) {
161+
if (sl_i2c_leader_transfer_non_blocking(
162+
&data->i2c_handle, addr, msgs[i].buf, msgs[i].len,
163+
msgs[i + 1].buf, msgs[i + 1].len, NULL) != 0) {
173164
k_sem_give(&data->bus_lock);
174165
return -EIO;
175166
}
176167
} else if (msgs[i].flags & I2C_MSG_READ) {
177168
/* Start DMA receive */
178-
if (sl_i2c_receive_non_blocking(i2c_handle, msgs[i].buf, msgs[i].len, NULL,
179-
NULL) != 0) {
169+
#if defined(CONFIG_I2C_TARGET)
170+
if (sl_i2c_follower_receive_non_blocking(&data->i2c_handle, msgs[i].buf,
171+
msgs[i].len, NULL) != 0) {
172+
k_sem_give(&data->bus_lock);
173+
return -EIO;
174+
}
175+
#else
176+
if (sl_i2c_leader_receive_non_blocking(&data->i2c_handle, addr, msgs[i].buf,
177+
msgs[i].len, NULL) != 0) {
180178
k_sem_give(&data->bus_lock);
181179
return -EIO;
182180
}
181+
#endif
183182
} else {
184183
/* Start DMA send */
185-
if (sl_i2c_send_non_blocking(i2c_handle, msgs[i].buf, msgs[i].len, NULL,
186-
NULL) != 0) {
184+
#if defined(CONFIG_I2C_TARGET)
185+
if (sl_i2c_follower_send_non_blocking(&data->i2c_handle, msgs[i].buf,
186+
msgs[i].len, NULL) != 0) {
187+
k_sem_give(&data->bus_lock);
188+
return -EIO;
189+
}
190+
#else
191+
if (sl_i2c_leader_send_non_blocking(&data->i2c_handle, addr, msgs[i].buf,
192+
msgs[i].len, NULL) != 0) {
187193
k_sem_give(&data->bus_lock);
188194
return -EIO;
189195
}
196+
#endif
190197
}
191198
if (!asynchronous) {
192199
/* Wait for DMA transfer to complete */
193200
if (k_sem_take(&data->transfer_sem, K_MSEC(CONFIG_I2C_SILABS_TIMEOUT))) {
194201
err = -ETIMEDOUT;
195202
}
196-
if (data->i2c_instance.state == SLI_I2C_STATE_ERROR) {
203+
if (data->i2c_handle.state == SL_I2C_STATE_ERROR) {
197204
err = -EIO;
198205
}
199206
k_sem_reset(&data->transfer_sem);
@@ -205,17 +212,13 @@ static int i2c_silabs_transfer_dma(const struct device *dev, struct i2c_msg *msg
205212
}
206213

207214
return err;
208-
#else
209-
return -ENOTSUP;
210-
#endif /* CONFIG_I2C_SILABS_DMA */
211215
}
212216

213217
/* Function to handle synchronous transfer */
214218
static int i2c_silabs_transfer_sync(const struct device *dev, struct i2c_msg *msgs,
215219
uint8_t num_msgs, uint16_t addr)
216220
{
217221
struct i2c_silabs_dev_data *data = dev->data;
218-
sl_i2c_handle_t *i2c_handle = (sl_i2c_handle_t *)&data->i2c_instance;
219222
uint8_t i = 0;
220223

221224
/* 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
227230
if ((msgs[i].flags & I2C_MSG_WRITE) == 0 && (i + 1 < num_msgs) &&
228231
(msgs[i + 1].flags & I2C_MSG_READ)) {
229232
msgs_in_transfer = 2;
230-
if (sl_i2c_transfer(i2c_handle, msgs[i].buf, msgs[i].len, msgs[i + 1].buf,
231-
msgs[i + 1].len) != 0) {
233+
if (sl_i2c_leader_transfer_blocking(&data->i2c_handle, addr, msgs[i].buf,
234+
msgs[i].len, msgs[i + 1].buf,
235+
msgs[i + 1].len,
236+
CONFIG_I2C_SILABS_TIMEOUT) != 0) {
232237
k_sem_give(&data->bus_lock);
233238
return -EIO;
234239
}
235240
i++;
236241
} else if (msgs[i].flags & I2C_MSG_READ) {
237-
if (sl_i2c_receive_blocking(i2c_handle, msgs[i].buf, msgs[i].len,
238-
CONFIG_I2C_SILABS_TIMEOUT) != 0) {
242+
#if defined(CONFIG_I2C_TARGET)
243+
if (sl_i2c_follower_receive_blocking(&data->i2c_handle, msgs[i].buf,
244+
msgs[i].len,
245+
CONFIG_I2C_SILABS_TIMEOUT) != 0) {
239246
k_sem_give(&data->bus_lock);
240247
return -ETIMEDOUT;
241248
}
249+
#else
250+
if (sl_i2c_leader_receive_blocking(&data->i2c_handle, addr, msgs[i].buf,
251+
msgs[i].len,
252+
CONFIG_I2C_SILABS_TIMEOUT) != 0) {
253+
k_sem_give(&data->bus_lock);
254+
return -ETIMEDOUT;
255+
}
256+
#endif
242257
} else {
243-
if (sl_i2c_send_blocking(i2c_handle, msgs[i].buf, msgs[i].len,
244-
CONFIG_I2C_SILABS_TIMEOUT) != 0) {
258+
#if defined(CONFIG_I2C_TARGET)
259+
if (sl_i2c_follower_send_blocking(&data->i2c_handle, msgs[i].buf,
260+
msgs[i].len,
261+
CONFIG_I2C_SILABS_TIMEOUT) != 0) {
262+
k_sem_give(&data->bus_lock);
263+
return -ETIMEDOUT;
264+
}
265+
#else
266+
if (sl_i2c_leader_send_blocking(&data->i2c_handle, addr, msgs[i].buf,
267+
msgs[i].len,
268+
CONFIG_I2C_SILABS_TIMEOUT) != 0) {
245269
k_sem_give(&data->bus_lock);
246270
return -ETIMEDOUT;
247271
}
272+
#endif
248273
}
249274
i += msgs_in_transfer;
250275
}
@@ -265,7 +290,6 @@ static int i2c_silabs_transfer_impl(const struct device *dev, struct i2c_msg *ms
265290
{
266291
struct i2c_silabs_dev_data *data = dev->data;
267292
__maybe_unused const struct i2c_silabs_dev_config *config = dev->config;
268-
sl_i2c_handle_t *i2c_handle = (sl_i2c_handle_t *)&data->i2c_instance;
269293
int ret = -EINVAL; /* Initialize ret to a default error value */
270294

271295
/* Check for invalid number of messages */
@@ -276,9 +300,9 @@ static int i2c_silabs_transfer_impl(const struct device *dev, struct i2c_msg *ms
276300
/* Check and set the address mode (7-bit or 10-bit) based on */
277301
/* the provided address */
278302
if (addr <= 0x7F) {
279-
data->i2c_instance.is_10bit_addr = false; /* 7-bit address */
303+
data->is_10bit_addr = false; /* 7-bit address */
280304
} else if (addr <= 0x3FF) {
281-
data->i2c_instance.is_10bit_addr = true; /* 10-bit address */
305+
data->is_10bit_addr = true; /* 10-bit address */
282306
} else {
283307
return -EINVAL;
284308
}
@@ -292,11 +316,13 @@ static int i2c_silabs_transfer_impl(const struct device *dev, struct i2c_msg *ms
292316
return ret;
293317
}
294318

319+
#if defined(CONFIG_I2C_TARGET)
295320
/* Set the follower address */
296-
if (sl_i2c_set_follower_address(i2c_handle, addr) != 0) {
321+
if (sl_i2c_set_follower_address(&data->i2c_handle, addr, data->is_10bit_addr) != 0) {
297322
k_sem_give(&data->bus_lock);
298323
return -EINVAL;
299324
}
325+
#endif
300326

301327
if (i2c_silabs_is_dma_enabled_instance(dev)) {
302328
/* DMA transfer handle a/synchronous transfers */
@@ -373,25 +399,23 @@ static int i2c_silabs_dev_init(const struct device *dev)
373399
return -EINVAL;
374400
}
375401

376-
#if defined(CONFIG_I2C_SILABS_DMA)
377-
if (i2c_silabs_is_dma_enabled_instance(dev)) {
402+
if (IS_ENABLED(CONFIG_I2C_SILABS_DMA) && i2c_silabs_is_dma_enabled_instance(dev)) {
378403
if (!device_is_ready(data->dma_rx.dma_dev) ||
379404
!device_is_ready(data->dma_tx.dma_dev)) {
380405
return -ENODEV;
381406
}
382407
data->dma_rx.dma_channel = dma_request_channel(data->dma_rx.dma_dev, NULL);
383-
data->i2c_instance.dma_channel.dma_rx_channel = data->dma_rx.dma_channel;
408+
data->i2c_handle.dma_channel.dma_rx_channel = data->dma_rx.dma_channel;
384409

385410
data->dma_tx.dma_channel = dma_request_channel(data->dma_tx.dma_dev, NULL);
386-
data->i2c_instance.dma_channel.dma_tx_channel = data->dma_tx.dma_channel;
411+
data->i2c_handle.dma_channel.dma_tx_channel = data->dma_tx.dma_channel;
387412

388413
if (data->dma_rx.dma_channel < 0 || data->dma_tx.dma_channel < 0) {
389414
dma_release_channel(data->dma_rx.dma_dev, data->dma_rx.dma_channel);
390415
dma_release_channel(data->dma_tx.dma_dev, data->dma_tx.dma_channel);
391416
return -EAGAIN;
392417
}
393418
}
394-
#endif /* CONFIG_I2C_SILABS_DMA */
395419

396420
/* Configure IRQ */
397421
config->irq_config_func();
@@ -445,15 +469,14 @@ static int i2c_silabs_pm_action(const struct device *dev, enum pm_device_action
445469
void i2c_silabs_isr_handler(const struct device *dev)
446470
{
447471
struct i2c_silabs_dev_data *data = dev->data;
448-
sli_i2c_instance_t *sl_i2c_instance = &data->i2c_instance;
472+
sl_i2c_handle_t *sl_i2c_handle = &data->i2c_handle;
449473

450474
#if defined(CONFIG_I2C_TARGET)
451-
sli_i2c_follower_dispatch_interrupt(sl_i2c_instance);
475+
sli_i2c_follower_dispatch_interrupt(sl_i2c_handle);
452476
#else
453-
sli_i2c_leader_dispatch_interrupt(sl_i2c_instance);
477+
sli_i2c_leader_dispatch_interrupt(sl_i2c_handle);
454478
#endif
455-
if (sl_i2c_instance->transfer_event != SL_I2C_EVENT_IN_PROGRESS &&
456-
sl_i2c_instance->rstart == 0) {
479+
if (sl_i2c_handle->event != SL_I2C_EVENT_IN_PROGRESS) {
457480
if (!data->asynchronous) {
458481
k_sem_give(&data->transfer_sem);
459482
}
@@ -462,9 +485,9 @@ void i2c_silabs_isr_handler(const struct device *dev)
462485
int err = 0;
463486

464487
data->callback_invoked = true;
465-
if (sl_i2c_instance->transfer_event == SL_I2C_EVENT_ARBITRATION_LOST ||
466-
sl_i2c_instance->transfer_event == SL_I2C_EVENT_BUS_ERROR ||
467-
sl_i2c_instance->transfer_event == SL_I2C_EVENT_INVALID_ADDR) {
488+
if (sl_i2c_handle->event == SL_I2C_EVENT_ARBITRATION_LOST ||
489+
sl_i2c_handle->event == SL_I2C_EVENT_BUS_ERROR ||
490+
sl_i2c_handle->event == SL_I2C_EVENT_INVALID_ADDR) {
468491
err = -EIO;
469492
}
470493
data->callback(dev, err, data->callback_context);
@@ -506,7 +529,7 @@ static DEVICE_API(i2c, i2c_silabs_dev_driver_api) = {
506529
\
507530
static const struct i2c_silabs_dev_config i2c_silabs_dev_config_##idx = { \
508531
.pcfg = PINCTRL_DT_INST_DEV_CONFIG_GET(idx), \
509-
.base = (I2C_TypeDef *)DT_INST_REG_ADDR(idx), \
532+
.peripheral = SL_PERIPHERAL_I2C##idx, \
510533
.bitrate = DT_INST_PROP(idx, clock_frequency), \
511534
.irq_config_func = i2c_silabs_irq_config_##idx, \
512535
.clock = DEVICE_DT_GET(DT_INST_CLOCKS_CTLR(idx)), \

0 commit comments

Comments
 (0)