Skip to content

Commit 3266911

Browse files
committed
drivers: i2c: litex: litei2c: support interrupts
support interrupts for rx_ready, so we can use the time we are waiting for other stuff. Signed-off-by: Fin Maaß <f.maass@vogl-electronic.com>
1 parent 0285cf4 commit 3266911

File tree

1 file changed

+116
-13
lines changed

1 file changed

+116
-13
lines changed

drivers/i2c/i2c_litex_litei2c.c

Lines changed: 116 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,11 @@ LOG_MODULE_REGISTER(i2c_litex_litei2c, CONFIG_I2C_LOG_LEVEL);
1616

1717
#include <soc.h>
1818

19+
#define I2C_LITEX_ANY_HAS_IRQ DT_ANY_INST_HAS_PROP_STATUS_OKAY(interrupts)
20+
#define I2C_LITEX_ALL_HAS_IRQ DT_ALL_INST_HAS_PROP_STATUS_OKAY(interrupts)
21+
22+
#define I2C_LITEX_HAS_IRQ UTIL_OR(I2C_LITEX_ALL_HAS_IRQ, config->has_irq)
23+
1924
#define MASTER_STATUS_TX_READY_OFFSET 0x0
2025
#define MASTER_STATUS_RX_READY_OFFSET 0x1
2126
#define MASTER_STATUS_NACK_OFFSET 0x8
@@ -28,10 +33,21 @@ struct i2c_litex_litei2c_config {
2833
uint32_t master_rxtx_addr;
2934
uint32_t master_status_addr;
3035
uint32_t bitrate;
36+
#if I2C_LITEX_ANY_HAS_IRQ
37+
uint32_t master_ev_pending_addr;
38+
uint32_t master_ev_enable_addr;
39+
void (*irq_config_func)(const struct device *dev);
40+
#if !I2C_LITEX_ALL_HAS_IRQ
41+
bool has_irq;
42+
#endif /* !I2C_LITEX_ALL_HAS_IRQ */
43+
#endif /* I2C_LITEX_ANY_HAS_IRQ */
3144
};
3245

3346
struct i2c_litex_litei2c_data {
3447
struct k_mutex mutex;
48+
#if I2C_LITEX_ANY_HAS_IRQ
49+
struct k_sem sem_rx_ready;
50+
#endif /* I2C_LITEX_ANY_HAS_IRQ */
3551
};
3652

3753
static int i2c_litex_configure(const struct device *dev, uint32_t dev_config)
@@ -105,6 +121,26 @@ static int i2c_litex_write_settings(const struct device *dev, uint8_t len_tx, ui
105121
return 0;
106122
}
107123

124+
static void i2c_litex_wait_for_rx_ready(const struct device *dev)
125+
{
126+
const struct i2c_litex_litei2c_config *config = dev->config;
127+
128+
#if I2C_LITEX_ANY_HAS_IRQ
129+
struct i2c_litex_litei2c_data *data = dev->data;
130+
131+
if (I2C_LITEX_HAS_IRQ) {
132+
/* Wait for the RX ready event */
133+
k_sem_take(&data->sem_rx_ready, K_FOREVER);
134+
return;
135+
}
136+
#endif /* I2C_LITEX_ANY_HAS_IRQ */
137+
138+
while (!(litex_read8(config->master_status_addr) &
139+
BIT(MASTER_STATUS_RX_READY_OFFSET))) {
140+
/* Wait until RX is ready */
141+
}
142+
}
143+
108144
static int i2c_litex_transfer(const struct device *dev, struct i2c_msg *msgs, uint8_t num_msgs,
109145
uint16_t addr)
110146
{
@@ -130,6 +166,26 @@ static int i2c_litex_transfer(const struct device *dev, struct i2c_msg *msgs, ui
130166

131167
litex_write8(1, config->master_active_addr);
132168

169+
/* Flush RX buffer */
170+
while ((litex_read8(config->master_status_addr) &
171+
BIT(MASTER_STATUS_RX_READY_OFFSET))) {
172+
rx_buf = litex_read32(config->master_rxtx_addr);
173+
LOG_DBG("flushed rxd: 0x%x", rx_buf);
174+
}
175+
176+
while (!(litex_read8(config->master_status_addr) &
177+
BIT(MASTER_STATUS_TX_READY_OFFSET))) {
178+
(void)litex_read32(config->master_rxtx_addr);
179+
}
180+
181+
#if I2C_LITEX_ANY_HAS_IRQ
182+
if (I2C_LITEX_HAS_IRQ) {
183+
litex_write8(BIT(0), config->master_ev_enable_addr);
184+
litex_write8(BIT(0), config->master_ev_pending_addr);
185+
k_sem_reset(&data->sem_rx_ready);
186+
}
187+
#endif /* I2C_LITEX_ANY_HAS_IRQ */
188+
133189
LOG_DBG("addr: 0x%x", addr);
134190
litex_write8((uint8_t)addr, config->master_addr_addr);
135191

@@ -206,18 +262,10 @@ static int i2c_litex_transfer(const struct device *dev, struct i2c_msg *msgs, ui
206262
LOG_DBG("len_tx: %d, len_rx: %d", len_tx, len_rx);
207263
i2c_litex_write_settings(dev, len_tx, len_rx, false);
208264

209-
while (!(litex_read8(config->master_status_addr) &
210-
BIT(MASTER_STATUS_TX_READY_OFFSET))) {
211-
;
212-
}
213-
214265
LOG_DBG("tx_buf: 0x%x", tx_buf);
215266
litex_write32(tx_buf, config->master_rxtx_addr);
216267

217-
while (!(litex_read8(config->master_status_addr) &
218-
BIT(MASTER_STATUS_RX_READY_OFFSET))) {
219-
;
220-
}
268+
i2c_litex_wait_for_rx_ready(dev);
221269

222270
if (litex_read16(config->master_status_addr) &
223271
BIT(MASTER_STATUS_NACK_OFFSET)) {
@@ -269,6 +317,12 @@ static int i2c_litex_transfer(const struct device *dev, struct i2c_msg *msgs, ui
269317

270318
litex_write8(0, config->master_active_addr);
271319

320+
#if I2C_LITEX_ANY_HAS_IRQ
321+
if (I2C_LITEX_HAS_IRQ) {
322+
litex_write8(0, config->master_ev_enable_addr);
323+
}
324+
#endif /* I2C_LITEX_ANY_HAS_IRQ */
325+
272326
k_mutex_unlock(&data->mutex);
273327

274328
return ret;
@@ -304,19 +358,40 @@ static int i2c_litex_recover_bus(const struct device *dev)
304358
return 0;
305359
}
306360

307-
static int i2c_litex_init(const struct device *dev)
361+
#if I2C_LITEX_ANY_HAS_IRQ
362+
static void i2c_litex_irq_handler(const struct device *dev)
308363
{
309364
const struct i2c_litex_litei2c_config *config = dev->config;
310365
struct i2c_litex_litei2c_data *data = dev->data;
311-
int ret;
312366

313-
k_mutex_init(&data->mutex);
367+
if (litex_read8(config->master_ev_pending_addr) & BIT(0)) {
368+
k_sem_give(&data->sem_rx_ready);
369+
370+
/* ack reader irq */
371+
litex_write8(BIT(0), config->master_ev_pending_addr);
372+
}
373+
}
374+
#endif /* I2C_LITEX_ANY_HAS_IRQ */
375+
376+
static int i2c_litex_init(const struct device *dev)
377+
{
378+
const struct i2c_litex_litei2c_config *config = dev->config;
379+
int ret;
314380

315381
ret = i2c_litex_configure(dev, I2C_MODE_CONTROLLER | i2c_map_dt_bitrate(config->bitrate));
316382
if (ret != 0) {
317383
LOG_ERR("failed to configure I2C: %d", ret);
318384
}
319385

386+
#if I2C_LITEX_ANY_HAS_IRQ
387+
if (I2C_LITEX_HAS_IRQ) {
388+
/* Disable interrupts initially */
389+
litex_write8(0, config->master_ev_enable_addr);
390+
391+
config->irq_config_func(dev);
392+
}
393+
#endif /* I2C_LITEX_ANY_HAS_IRQ */
394+
320395
return ret;
321396
}
322397

@@ -332,8 +407,35 @@ static DEVICE_API(i2c, i2c_litex_litei2c_driver_api) = {
332407

333408
/* Device Instantiation */
334409

410+
#define I2C_LITEX_IRQ(n) \
411+
BUILD_ASSERT(DT_INST_REG_HAS_NAME(n, master_ev_pending) && \
412+
DT_INST_REG_HAS_NAME(n, master_ev_enable), "registers for interrupts missing"); \
413+
\
414+
static void i2c_litex_irq_config##n(const struct device *dev) \
415+
{ \
416+
IRQ_CONNECT(DT_INST_IRQN(n), DT_INST_IRQ(n, priority), i2c_litex_irq_handler, \
417+
DEVICE_DT_INST_GET(n), 0); \
418+
\
419+
irq_enable(DT_INST_IRQN(n)); \
420+
};
421+
422+
#define I2C_LITEC_IRQ_DATA(n) \
423+
.sem_rx_ready = Z_SEM_INITIALIZER(i2c_litex_litei2c_data_##n.sem_rx_ready, 0, 1),
424+
425+
#define I2C_LITEC_IRQ_CONFIG(n) \
426+
IF_DISABLED(I2C_LITEX_ALL_HAS_IRQ, (.has_irq = DT_INST_IRQ_HAS_IDX(n, 0),)) \
427+
.master_ev_pending_addr = DT_INST_REG_ADDR_BY_NAME_OR(n, master_ev_pending, 0), \
428+
.master_ev_enable_addr = DT_INST_REG_ADDR_BY_NAME_OR(n, master_ev_enable, 0), \
429+
.irq_config_func = COND_CODE_1(DT_INST_IRQ_HAS_IDX(n, 0), \
430+
(i2c_litex_irq_config##n), (NULL)),
431+
335432
#define I2C_LITEX_INIT(n) \
336-
static struct i2c_litex_litei2c_data i2c_litex_litei2c_data_##n; \
433+
IF_ENABLED(DT_INST_IRQ_HAS_IDX(n, 0), (I2C_LITEX_IRQ(n))) \
434+
\
435+
static struct i2c_litex_litei2c_data i2c_litex_litei2c_data_##n = { \
436+
.mutex = Z_MUTEX_INITIALIZER(i2c_litex_litei2c_data_##n.mutex), \
437+
IF_ENABLED(I2C_LITEX_ANY_HAS_IRQ, (I2C_LITEC_IRQ_DATA(n))) \
438+
}; \
337439
\
338440
static const struct i2c_litex_litei2c_config i2c_litex_litei2c_config_##n = { \
339441
.phy_speed_mode_addr = DT_INST_REG_ADDR_BY_NAME(n, phy_speed_mode), \
@@ -343,6 +445,7 @@ static DEVICE_API(i2c, i2c_litex_litei2c_driver_api) = {
343445
.master_rxtx_addr = DT_INST_REG_ADDR_BY_NAME(n, master_rxtx), \
344446
.master_status_addr = DT_INST_REG_ADDR_BY_NAME(n, master_status), \
345447
.bitrate = DT_INST_PROP(n, clock_frequency), \
448+
IF_ENABLED(I2C_LITEX_ANY_HAS_IRQ, (I2C_LITEC_IRQ_CONFIG(n))) \
346449
}; \
347450
\
348451
I2C_DEVICE_DT_INST_DEFINE(n, i2c_litex_init, NULL, &i2c_litex_litei2c_data_##n, \

0 commit comments

Comments
 (0)