Skip to content

Commit f3cc550

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 f3cc550

File tree

1 file changed

+105
-4
lines changed

1 file changed

+105
-4
lines changed

drivers/i2c/i2c_litex_litei2c.c

Lines changed: 105 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,8 @@ 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+
1921
#define MASTER_STATUS_TX_READY_OFFSET 0x0
2022
#define MASTER_STATUS_RX_READY_OFFSET 0x1
2123
#define MASTER_STATUS_NACK_OFFSET 0x8
@@ -28,10 +30,18 @@ struct i2c_litex_litei2c_config {
2830
uint32_t master_rxtx_addr;
2931
uint32_t master_status_addr;
3032
uint32_t bitrate;
33+
#if I2C_LITEX_ANY_HAS_IRQ
34+
uint32_t master_ev_pending_addr;
35+
uint32_t master_ev_enable_addr;
36+
void (*irq_config_func)(const struct device *dev);
37+
#endif /* I2C_LITEX_ANY_HAS_IRQ */
3138
};
3239

3340
struct i2c_litex_litei2c_data {
3441
struct k_mutex mutex;
42+
#if I2C_LITEX_ANY_HAS_IRQ
43+
struct k_sem sem_rx_ready;
44+
#endif /* I2C_LITEX_ANY_HAS_IRQ */
3545
};
3646

3747
static int i2c_litex_configure(const struct device *dev, uint32_t dev_config)
@@ -105,6 +115,26 @@ static int i2c_litex_write_settings(const struct device *dev, uint8_t len_tx, ui
105115
return 0;
106116
}
107117

118+
static void i2c_litex_wait_for_rx_ready(const struct device *dev)
119+
{
120+
const struct i2c_litex_litei2c_config *config = dev->config;
121+
122+
#if I2C_LITEX_ANY_HAS_IRQ
123+
struct i2c_litex_litei2c_data *data = dev->data;
124+
125+
if (config->irq_config_func) {
126+
/* Wait for the RX ready event */
127+
k_sem_take(&data->sem_rx_ready, K_FOREVER);
128+
return;
129+
}
130+
#endif /* I2C_LITEX_ANY_HAS_IRQ */
131+
132+
while (!(litex_read8(config->master_status_addr) &
133+
BIT(MASTER_STATUS_RX_READY_OFFSET))) {
134+
;
135+
}
136+
}
137+
108138
static int i2c_litex_transfer(const struct device *dev, struct i2c_msg *msgs, uint8_t num_msgs,
109139
uint16_t addr)
110140
{
@@ -130,6 +160,21 @@ static int i2c_litex_transfer(const struct device *dev, struct i2c_msg *msgs, ui
130160

131161
litex_write8(1, config->master_active_addr);
132162

163+
/* Flush RX buffer */
164+
while ((litex_read8(config->master_status_addr) &
165+
BIT(MASTER_STATUS_RX_READY_OFFSET))) {
166+
rx_buf = litex_read32(config->master_rxtx_addr);
167+
LOG_DBG("flushed rxd: 0x%x", rx_buf);
168+
}
169+
170+
#if I2C_LITEX_ANY_HAS_IRQ
171+
if (config->irq_config_func) {
172+
litex_write8(BIT(0), config->master_ev_enable_addr);
173+
litex_write8(BIT(0), config->master_ev_pending_addr);
174+
k_sem_reset(&data->sem_rx_ready);
175+
}
176+
#endif /* I2C_LITEX_ANY_HAS_IRQ */
177+
133178
LOG_DBG("addr: 0x%x", addr);
134179
litex_write8((uint8_t)addr, config->master_addr_addr);
135180

@@ -214,6 +259,8 @@ static int i2c_litex_transfer(const struct device *dev, struct i2c_msg *msgs, ui
214259
LOG_DBG("tx_buf: 0x%x", tx_buf);
215260
litex_write32(tx_buf, config->master_rxtx_addr);
216261

262+
i2c_litex_wait_for_rx_ready(dev);
263+
217264
while (!(litex_read8(config->master_status_addr) &
218265
BIT(MASTER_STATUS_RX_READY_OFFSET))) {
219266
;
@@ -269,6 +316,12 @@ static int i2c_litex_transfer(const struct device *dev, struct i2c_msg *msgs, ui
269316

270317
litex_write8(0, config->master_active_addr);
271318

319+
#if I2C_LITEX_ANY_HAS_IRQ
320+
if (config->irq_config_func) {
321+
litex_write8(0, config->master_ev_enable_addr);
322+
}
323+
#endif /* I2C_LITEX_ANY_HAS_IRQ */
324+
272325
k_mutex_unlock(&data->mutex);
273326

274327
return ret;
@@ -304,19 +357,40 @@ static int i2c_litex_recover_bus(const struct device *dev)
304357
return 0;
305358
}
306359

307-
static int i2c_litex_init(const struct device *dev)
360+
#if I2C_LITEX_ANY_HAS_IRQ
361+
static void i2c_litex_irq_handler(const struct device *dev)
308362
{
309363
const struct i2c_litex_litei2c_config *config = dev->config;
310364
struct i2c_litex_litei2c_data *data = dev->data;
311-
int ret;
312365

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

315380
ret = i2c_litex_configure(dev, I2C_MODE_CONTROLLER | i2c_map_dt_bitrate(config->bitrate));
316381
if (ret != 0) {
317382
LOG_ERR("failed to configure I2C: %d", ret);
318383
}
319384

385+
#if I2C_LITEX_ANY_HAS_IRQ
386+
if (config->irq_config_func != NULL) {
387+
/* Disable interrupts initially */
388+
litex_write8(0, config->master_ev_enable_addr);
389+
390+
config->irq_config_func(dev);
391+
}
392+
#endif /* I2C_LITEX_ANY_HAS_IRQ */
393+
320394
return ret;
321395
}
322396

@@ -332,8 +406,34 @@ static DEVICE_API(i2c, i2c_litex_litei2c_driver_api) = {
332406

333407
/* Device Instantiation */
334408

409+
#define I2C_LITEX_IRQ(n) \
410+
BUILD_ASSERT(DT_INST_REG_HAS_NAME(n, master_ev_pending) && \
411+
DT_INST_REG_HAS_NAME(n, master_ev_enable), "registers for interrupts missing"); \
412+
\
413+
static void i2c_litex_irq_config##n(const struct device *dev) \
414+
{ \
415+
IRQ_CONNECT(DT_INST_IRQN(n), DT_INST_IRQ(n, priority), i2c_litex_irq_handler, \
416+
DEVICE_DT_INST_GET(n), 0); \
417+
\
418+
irq_enable(DT_INST_IRQN(n)); \
419+
};
420+
421+
#define I2C_LITEC_IRQ_DATA(n) \
422+
.sem_rx_ready = Z_SEM_INITIALIZER(i2c_litex_litei2c_data_##n.sem_rx_ready, 0, 1),
423+
424+
#define I2C_LITEC_IRQ_CONFIG(n) \
425+
.master_ev_pending_addr = DT_INST_REG_ADDR_BY_NAME_OR(n, master_ev_pending, 0), \
426+
.master_ev_enable_addr = DT_INST_REG_ADDR_BY_NAME_OR(n, master_ev_enable, 0), \
427+
.irq_config_func = COND_CODE_1(DT_INST_IRQ_HAS_IDX(n, 0), \
428+
(i2c_litex_irq_config##n), (NULL)),
429+
335430
#define I2C_LITEX_INIT(n) \
336-
static struct i2c_litex_litei2c_data i2c_litex_litei2c_data_##n; \
431+
IF_ENABLED(DT_INST_IRQ_HAS_IDX(n, 0), (I2C_LITEX_IRQ(n))) \
432+
\
433+
static struct i2c_litex_litei2c_data i2c_litex_litei2c_data_##n = { \
434+
.mutex = Z_MUTEX_INITIALIZER(i2c_litex_litei2c_data_##n.mutex), \
435+
IF_ENABLED(I2C_LITEX_ANY_HAS_IRQ, (I2C_LITEC_IRQ_DATA(n))) \
436+
}; \
337437
\
338438
static const struct i2c_litex_litei2c_config i2c_litex_litei2c_config_##n = { \
339439
.phy_speed_mode_addr = DT_INST_REG_ADDR_BY_NAME(n, phy_speed_mode), \
@@ -343,6 +443,7 @@ static DEVICE_API(i2c, i2c_litex_litei2c_driver_api) = {
343443
.master_rxtx_addr = DT_INST_REG_ADDR_BY_NAME(n, master_rxtx), \
344444
.master_status_addr = DT_INST_REG_ADDR_BY_NAME(n, master_status), \
345445
.bitrate = DT_INST_PROP(n, clock_frequency), \
446+
IF_ENABLED(I2C_LITEX_ANY_HAS_IRQ, (I2C_LITEC_IRQ_CONFIG(n))) \
346447
}; \
347448
\
348449
I2C_DEVICE_DT_INST_DEFINE(n, i2c_litex_init, NULL, &i2c_litex_litei2c_data_##n, \

0 commit comments

Comments
 (0)