Skip to content

Commit 6b66d3c

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 a00ecc1 commit 6b66d3c

File tree

1 file changed

+64
-81
lines changed

1 file changed

+64
-81
lines changed

drivers/i2c/i2c_silabs.c

Lines changed: 64 additions & 81 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,11 @@ 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;
6965

7066
__ASSERT_NO_MSG(!!data->dma_tx.dma_dev == !!data->dma_rx.dma_dev);
7167

7268
return data->dma_rx.dma_dev != NULL;
73-
#else
74-
return false;
75-
#endif
7669
}
7770

7871
static void i2c_silabs_pm_policy_state_lock_get(const struct device *dev)
@@ -92,18 +85,17 @@ static int i2c_silabs_dev_configure(const struct device *dev, uint32_t dev_confi
9285
{
9386
const struct i2c_silabs_dev_config *config = dev->config;
9487
struct i2c_silabs_dev_data *data = dev->data;
95-
sl_i2c_init_params_t init_params;
9688

9789
/* Determine the I2C speed and corresponding baudrate */
9890
switch (I2C_SPEED_GET(dev_config)) {
9991
case I2C_SPEED_STANDARD:
100-
init_params.freq_mode = SL_I2C_FREQ_STANDARD_MODE;
92+
data->i2c_handle.frequency_mode = SL_I2C_FREQ_STANDARD_MODE;
10193
break;
10294
case I2C_SPEED_FAST:
103-
init_params.freq_mode = SL_I2C_FREQ_FAST_MODE;
95+
data->i2c_handle.frequency_mode = SL_I2C_FREQ_FAST_MODE;
10496
break;
10597
case I2C_SPEED_FAST_PLUS:
106-
init_params.freq_mode = SL_I2C_FREQ_FASTPLUS_MODE;
98+
data->i2c_handle.frequency_mode = SL_I2C_FREQ_FASTPLUS_MODE;
10799
break;
108100
default:
109101
return -EINVAL;
@@ -112,19 +104,13 @@ static int i2c_silabs_dev_configure(const struct device *dev, uint32_t dev_confi
112104
/* Take the bus lock semaphore to ensure exclusive access */
113105
k_sem_take(&data->bus_lock, K_FOREVER);
114106
/* Initialize I2C parameters */
115-
init_params.i2c_base_addr = config->base;
116-
data->i2c_instance.i2c_base_addr = init_params.i2c_base_addr;
107+
data->i2c_handle.i2c_peripheral = config->peripheral;
117108

118-
/* Set the operating mode (leader or follower) */
119-
#if defined(CONFIG_I2C_TARGET)
120-
init_params.operating_mode = SL_I2C_FOLLOWER_MODE;
121-
#else
122-
init_params.operating_mode = SL_I2C_LEADER_MODE;
123-
#endif /* CONFIG_I2C_TARGET */
124-
data->i2c_instance.operating_mode = init_params.operating_mode;
109+
/* Set the operating mode (leader) */
110+
data->i2c_handle.operating_mode = SL_I2C_LEADER_MODE;
125111

126112
/* Configure the I2C instance */
127-
sli_i2c_instance_configuration(&init_params);
113+
sli_i2c_init_core(&data->i2c_handle);
128114

129115
/* Release the bus lock semaphore */
130116
k_sem_give(&data->bus_lock);
@@ -137,25 +123,21 @@ static int i2c_silabs_transfer_dma(const struct device *dev, struct i2c_msg *msg
137123
uint16_t addr, i2c_callback_t cb, void *userdata,
138124
bool asynchronous)
139125
{
140-
#if defined(CONFIG_I2C_SILABS_DMA)
141126
struct i2c_silabs_dev_data *data = dev->data;
142-
__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;
144127
#if defined(CONFIG_I2C_CALLBACK)
145128
data->callback_invoked = false;
146129
#endif
147130
data->pm_lock_done = false;
148131
uint8_t i = 0;
149132
int err = 0;
150133

134+
if (!IS_ENABLED(CONFIG_I2C_SILABS_DMA)) {
135+
return -ENOTSUP;
136+
}
137+
151138
/* Get the power management policy state lock */
152139
i2c_silabs_pm_policy_state_lock_get(dev);
153140

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-
159141
while (i < num_msgs) {
160142
uint8_t msgs_in_transfer = 1;
161143

@@ -167,24 +149,27 @@ static int i2c_silabs_transfer_dma(const struct device *dev, struct i2c_msg *msg
167149
data->last_transfer = (i + msgs_in_transfer) == num_msgs;
168150

169151
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) {
152+
if (sl_i2c_leader_transfer_non_blocking(
153+
&data->i2c_handle, addr, msgs[i].buf, msgs[i].len,
154+
msgs[i + 1].buf, msgs[i + 1].len, NULL) != 0) {
173155
k_sem_give(&data->bus_lock);
156+
i2c_silabs_pm_policy_state_lock_put(dev);
174157
return -EIO;
175158
}
176159
} else if (msgs[i].flags & I2C_MSG_READ) {
177160
/* Start DMA receive */
178-
if (sl_i2c_receive_non_blocking(i2c_handle, msgs[i].buf, msgs[i].len, NULL,
179-
NULL) != 0) {
161+
if (sl_i2c_leader_receive_non_blocking(&data->i2c_handle, addr, msgs[i].buf,
162+
msgs[i].len, NULL) != 0) {
180163
k_sem_give(&data->bus_lock);
164+
i2c_silabs_pm_policy_state_lock_put(dev);
181165
return -EIO;
182166
}
183167
} else {
184168
/* Start DMA send */
185-
if (sl_i2c_send_non_blocking(i2c_handle, msgs[i].buf, msgs[i].len, NULL,
186-
NULL) != 0) {
169+
if (sl_i2c_leader_send_non_blocking(&data->i2c_handle, addr, msgs[i].buf,
170+
msgs[i].len, NULL) != 0) {
187171
k_sem_give(&data->bus_lock);
172+
i2c_silabs_pm_policy_state_lock_put(dev);
188173
return -EIO;
189174
}
190175
}
@@ -193,30 +178,28 @@ static int i2c_silabs_transfer_dma(const struct device *dev, struct i2c_msg *msg
193178
if (k_sem_take(&data->transfer_sem, K_MSEC(CONFIG_I2C_SILABS_TIMEOUT))) {
194179
err = -ETIMEDOUT;
195180
}
196-
if (data->i2c_instance.state == SLI_I2C_STATE_ERROR) {
181+
if (data->i2c_handle.state == SL_I2C_STATE_ERROR) {
197182
err = -EIO;
198183
}
199184
k_sem_reset(&data->transfer_sem);
200185
if (err < 0) {
186+
i2c_silabs_pm_policy_state_lock_put(dev);
201187
break;
202188
}
203189
}
204190
i += msgs_in_transfer;
205191
}
206192

207193
return err;
208-
#else
209-
return -ENOTSUP;
210-
#endif /* CONFIG_I2C_SILABS_DMA */
211194
}
212195

213196
/* Function to handle synchronous transfer */
214197
static int i2c_silabs_transfer_sync(const struct device *dev, struct i2c_msg *msgs,
215198
uint8_t num_msgs, uint16_t addr)
216199
{
217200
struct i2c_silabs_dev_data *data = dev->data;
218-
sl_i2c_handle_t *i2c_handle = (sl_i2c_handle_t *)&data->i2c_instance;
219201
uint8_t i = 0;
202+
int err = 0;
220203

221204
/* Get the power management policy state lock */
222205
i2c_silabs_pm_policy_state_lock_get(dev);
@@ -227,35 +210,43 @@ static int i2c_silabs_transfer_sync(const struct device *dev, struct i2c_msg *ms
227210
if ((msgs[i].flags & I2C_MSG_WRITE) == 0 && (i + 1 < num_msgs) &&
228211
(msgs[i + 1].flags & I2C_MSG_READ)) {
229212
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) {
213+
if (sl_i2c_leader_transfer_blocking(&data->i2c_handle, addr, msgs[i].buf,
214+
msgs[i].len, msgs[i + 1].buf,
215+
msgs[i + 1].len,
216+
CONFIG_I2C_SILABS_TIMEOUT) != 0) {
232217
k_sem_give(&data->bus_lock);
233-
return -EIO;
218+
err = -EIO;
219+
goto out;
234220
}
235221
i++;
236222
} 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) {
223+
if (sl_i2c_leader_receive_blocking(&data->i2c_handle, addr, msgs[i].buf,
224+
msgs[i].len,
225+
CONFIG_I2C_SILABS_TIMEOUT) != 0) {
239226
k_sem_give(&data->bus_lock);
240-
return -ETIMEDOUT;
227+
err = -ETIMEDOUT;
228+
goto out;
241229
}
242230
} else {
243-
if (sl_i2c_send_blocking(i2c_handle, msgs[i].buf, msgs[i].len,
244-
CONFIG_I2C_SILABS_TIMEOUT) != 0) {
231+
if (sl_i2c_leader_send_blocking(&data->i2c_handle, addr, msgs[i].buf,
232+
msgs[i].len,
233+
CONFIG_I2C_SILABS_TIMEOUT) != 0) {
245234
k_sem_give(&data->bus_lock);
246-
return -ETIMEDOUT;
235+
err = -ETIMEDOUT;
236+
goto out;
247237
}
248238
}
249239
i += msgs_in_transfer;
250240
}
251241

242+
out:
252243
/* Release the bus lock semaphore */
253244
k_sem_give(&data->bus_lock);
254245

255246
/* Release the power management policy state lock */
256247
i2c_silabs_pm_policy_state_lock_put(dev);
257248

258-
return 0;
249+
return err;
259250
}
260251

261252
/* Function to perform I2C transfer */
@@ -264,8 +255,6 @@ static int i2c_silabs_transfer_impl(const struct device *dev, struct i2c_msg *ms
264255
void *userdata)
265256
{
266257
struct i2c_silabs_dev_data *data = dev->data;
267-
__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;
269258
int ret = -EINVAL; /* Initialize ret to a default error value */
270259

271260
/* Check for invalid number of messages */
@@ -276,9 +265,9 @@ static int i2c_silabs_transfer_impl(const struct device *dev, struct i2c_msg *ms
276265
/* Check and set the address mode (7-bit or 10-bit) based on */
277266
/* the provided address */
278267
if (addr <= 0x7F) {
279-
data->i2c_instance.is_10bit_addr = false; /* 7-bit address */
268+
data->is_10bit_addr = false; /* 7-bit address */
280269
} else if (addr <= 0x3FF) {
281-
data->i2c_instance.is_10bit_addr = true; /* 10-bit address */
270+
data->is_10bit_addr = true; /* 10-bit address */
282271
} else {
283272
return -EINVAL;
284273
}
@@ -292,12 +281,6 @@ static int i2c_silabs_transfer_impl(const struct device *dev, struct i2c_msg *ms
292281
return ret;
293282
}
294283

295-
/* Set the follower address */
296-
if (sl_i2c_set_follower_address(i2c_handle, addr) != 0) {
297-
k_sem_give(&data->bus_lock);
298-
return -EINVAL;
299-
}
300-
301284
if (i2c_silabs_is_dma_enabled_instance(dev)) {
302285
/* DMA transfer handle a/synchronous transfers */
303286
ret = i2c_silabs_transfer_dma(dev, msgs, num_msgs, addr, cb, userdata,
@@ -373,25 +356,23 @@ static int i2c_silabs_dev_init(const struct device *dev)
373356
return -EINVAL;
374357
}
375358

376-
#if defined(CONFIG_I2C_SILABS_DMA)
377359
if (i2c_silabs_is_dma_enabled_instance(dev)) {
378360
if (!device_is_ready(data->dma_rx.dma_dev) ||
379361
!device_is_ready(data->dma_tx.dma_dev)) {
380362
return -ENODEV;
381363
}
382364
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;
365+
data->i2c_handle.dma_channel.dma_rx_channel = data->dma_rx.dma_channel;
384366

385367
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;
368+
data->i2c_handle.dma_channel.dma_tx_channel = data->dma_tx.dma_channel;
387369

388370
if (data->dma_rx.dma_channel < 0 || data->dma_tx.dma_channel < 0) {
389371
dma_release_channel(data->dma_rx.dma_dev, data->dma_rx.dma_channel);
390372
dma_release_channel(data->dma_tx.dma_dev, data->dma_tx.dma_channel);
391373
return -EAGAIN;
392374
}
393375
}
394-
#endif /* CONFIG_I2C_SILABS_DMA */
395376

396377
/* Configure IRQ */
397378
config->irq_config_func();
@@ -445,15 +426,10 @@ static int i2c_silabs_pm_action(const struct device *dev, enum pm_device_action
445426
void i2c_silabs_isr_handler(const struct device *dev)
446427
{
447428
struct i2c_silabs_dev_data *data = dev->data;
448-
sli_i2c_instance_t *sl_i2c_instance = &data->i2c_instance;
429+
sl_i2c_handle_t *sl_i2c_handle = &data->i2c_handle;
449430

450-
#if defined(CONFIG_I2C_TARGET)
451-
sli_i2c_follower_dispatch_interrupt(sl_i2c_instance);
452-
#else
453-
sli_i2c_leader_dispatch_interrupt(sl_i2c_instance);
454-
#endif
455-
if (sl_i2c_instance->transfer_event != SL_I2C_EVENT_IN_PROGRESS &&
456-
sl_i2c_instance->rstart == 0) {
431+
sli_i2c_leader_dispatch_interrupt(sl_i2c_handle);
432+
if (sl_i2c_handle->event != SL_I2C_EVENT_IN_PROGRESS) {
457433
if (!data->asynchronous) {
458434
k_sem_give(&data->transfer_sem);
459435
}
@@ -462,9 +438,9 @@ void i2c_silabs_isr_handler(const struct device *dev)
462438
int err = 0;
463439

464440
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) {
441+
if (sl_i2c_handle->event == SL_I2C_EVENT_ARBITRATION_LOST ||
442+
sl_i2c_handle->event == SL_I2C_EVENT_BUS_ERROR ||
443+
sl_i2c_handle->event == SL_I2C_EVENT_INVALID_ADDR) {
468444
err = -EIO;
469445
}
470446
data->callback(dev, err, data->callback_context);
@@ -503,10 +479,17 @@ static DEVICE_API(i2c, i2c_silabs_dev_driver_api) = {
503479
irq_enable(DT_INST_IRQ(idx, irq));), \
504480
()) \
505481
} \
506-
\
482+
\
483+
static const uint32_t i2c_bus_clock_##idx = DT_INST_CLOCKS_CELL(idx, enable); \
484+
static const sl_peripheral_val_t i2c_peripheral_val_##idx = { \
485+
.base = DT_INST_REG_ADDR(idx), \
486+
.clk_branch = DT_INST_CLOCKS_CELL(idx, branch), \
487+
.bus_clock = (DT_INST_CLOCKS_CELL(idx, enable) ? &i2c_bus_clock_##idx : NULL), \
488+
}; \
489+
\
507490
static const struct i2c_silabs_dev_config i2c_silabs_dev_config_##idx = { \
508491
.pcfg = PINCTRL_DT_INST_DEV_CONFIG_GET(idx), \
509-
.base = (I2C_TypeDef *)DT_INST_REG_ADDR(idx), \
492+
.peripheral = &i2c_peripheral_val_##idx, \
510493
.bitrate = DT_INST_PROP(idx, clock_frequency), \
511494
.irq_config_func = i2c_silabs_irq_config_##idx, \
512495
.clock = DEVICE_DT_GET(DT_INST_CLOCKS_CTLR(idx)), \

0 commit comments

Comments
 (0)