diff --git a/drivers/i2c/i2c_litex_litei2c.c b/drivers/i2c/i2c_litex_litei2c.c index d73c8230854e..f32aee5ca12a 100644 --- a/drivers/i2c/i2c_litex_litei2c.c +++ b/drivers/i2c/i2c_litex_litei2c.c @@ -16,6 +16,11 @@ LOG_MODULE_REGISTER(i2c_litex_litei2c, CONFIG_I2C_LOG_LEVEL); #include +#define I2C_LITEX_ANY_HAS_IRQ DT_ANY_INST_HAS_PROP_STATUS_OKAY(interrupts) +#define I2C_LITEX_ALL_HAS_IRQ DT_ALL_INST_HAS_PROP_STATUS_OKAY(interrupts) + +#define I2C_LITEX_HAS_IRQ UTIL_OR(I2C_LITEX_ALL_HAS_IRQ, config->has_irq) + #define MASTER_STATUS_TX_READY_OFFSET 0x0 #define MASTER_STATUS_RX_READY_OFFSET 0x1 #define MASTER_STATUS_NACK_OFFSET 0x8 @@ -28,10 +33,21 @@ struct i2c_litex_litei2c_config { uint32_t master_rxtx_addr; uint32_t master_status_addr; uint32_t bitrate; +#if I2C_LITEX_ANY_HAS_IRQ + uint32_t master_ev_pending_addr; + uint32_t master_ev_enable_addr; + void (*irq_config_func)(const struct device *dev); +#if !I2C_LITEX_ALL_HAS_IRQ + bool has_irq; +#endif /* !I2C_LITEX_ALL_HAS_IRQ */ +#endif /* I2C_LITEX_ANY_HAS_IRQ */ }; struct i2c_litex_litei2c_data { struct k_mutex mutex; +#if I2C_LITEX_ANY_HAS_IRQ + struct k_sem sem_rx_ready; +#endif /* I2C_LITEX_ANY_HAS_IRQ */ }; 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 return 0; } +static void i2c_litex_wait_for_rx_ready(const struct device *dev) +{ + const struct i2c_litex_litei2c_config *config = dev->config; + +#if I2C_LITEX_ANY_HAS_IRQ + struct i2c_litex_litei2c_data *data = dev->data; + + if (I2C_LITEX_HAS_IRQ) { + /* Wait for the RX ready event */ + k_sem_take(&data->sem_rx_ready, K_FOREVER); + return; + } +#endif /* I2C_LITEX_ANY_HAS_IRQ */ + + while (!(litex_read8(config->master_status_addr) & + BIT(MASTER_STATUS_RX_READY_OFFSET))) { + /* Wait until RX is ready */ + } +} + static int i2c_litex_transfer(const struct device *dev, struct i2c_msg *msgs, uint8_t num_msgs, uint16_t addr) { @@ -130,6 +166,26 @@ static int i2c_litex_transfer(const struct device *dev, struct i2c_msg *msgs, ui litex_write8(1, config->master_active_addr); + /* Flush RX buffer */ + while ((litex_read8(config->master_status_addr) & + BIT(MASTER_STATUS_RX_READY_OFFSET))) { + rx_buf = litex_read32(config->master_rxtx_addr); + LOG_DBG("flushed rxd: 0x%x", rx_buf); + } + + while (!(litex_read8(config->master_status_addr) & + BIT(MASTER_STATUS_TX_READY_OFFSET))) { + (void)litex_read32(config->master_rxtx_addr); + } + +#if I2C_LITEX_ANY_HAS_IRQ + if (I2C_LITEX_HAS_IRQ) { + litex_write8(BIT(0), config->master_ev_enable_addr); + litex_write8(BIT(0), config->master_ev_pending_addr); + k_sem_reset(&data->sem_rx_ready); + } +#endif /* I2C_LITEX_ANY_HAS_IRQ */ + LOG_DBG("addr: 0x%x", addr); litex_write8((uint8_t)addr, config->master_addr_addr); @@ -206,18 +262,10 @@ static int i2c_litex_transfer(const struct device *dev, struct i2c_msg *msgs, ui LOG_DBG("len_tx: %d, len_rx: %d", len_tx, len_rx); i2c_litex_write_settings(dev, len_tx, len_rx, false); - while (!(litex_read8(config->master_status_addr) & - BIT(MASTER_STATUS_TX_READY_OFFSET))) { - ; - } - LOG_DBG("tx_buf: 0x%x", tx_buf); litex_write32(tx_buf, config->master_rxtx_addr); - while (!(litex_read8(config->master_status_addr) & - BIT(MASTER_STATUS_RX_READY_OFFSET))) { - ; - } + i2c_litex_wait_for_rx_ready(dev); if (litex_read16(config->master_status_addr) & BIT(MASTER_STATUS_NACK_OFFSET)) { @@ -269,6 +317,12 @@ static int i2c_litex_transfer(const struct device *dev, struct i2c_msg *msgs, ui litex_write8(0, config->master_active_addr); +#if I2C_LITEX_ANY_HAS_IRQ + if (I2C_LITEX_HAS_IRQ) { + litex_write8(0, config->master_ev_enable_addr); + } +#endif /* I2C_LITEX_ANY_HAS_IRQ */ + k_mutex_unlock(&data->mutex); return ret; @@ -286,13 +340,13 @@ static int i2c_litex_recover_bus(const struct device *dev) i2c_litex_write_settings(dev, 0, 0, true); while (!(litex_read8(config->master_status_addr) & BIT(MASTER_STATUS_TX_READY_OFFSET))) { - ; + /* Wait for TX ready */ } litex_write32(0, config->master_rxtx_addr); while (!(litex_read8(config->master_status_addr) & BIT(MASTER_STATUS_RX_READY_OFFSET))) { - ; + /* Wait for RX data */ } (void)litex_read32(config->master_rxtx_addr); @@ -304,19 +358,40 @@ static int i2c_litex_recover_bus(const struct device *dev) return 0; } -static int i2c_litex_init(const struct device *dev) +#if I2C_LITEX_ANY_HAS_IRQ +static void i2c_litex_irq_handler(const struct device *dev) { const struct i2c_litex_litei2c_config *config = dev->config; struct i2c_litex_litei2c_data *data = dev->data; - int ret; - k_mutex_init(&data->mutex); + if (litex_read8(config->master_ev_pending_addr) & BIT(0)) { + k_sem_give(&data->sem_rx_ready); + + /* ack reader irq */ + litex_write8(BIT(0), config->master_ev_pending_addr); + } +} +#endif /* I2C_LITEX_ANY_HAS_IRQ */ + +static int i2c_litex_init(const struct device *dev) +{ + const struct i2c_litex_litei2c_config *config = dev->config; + int ret; ret = i2c_litex_configure(dev, I2C_MODE_CONTROLLER | i2c_map_dt_bitrate(config->bitrate)); if (ret != 0) { LOG_ERR("failed to configure I2C: %d", ret); } +#if I2C_LITEX_ANY_HAS_IRQ + if (I2C_LITEX_HAS_IRQ) { + /* Disable interrupts initially */ + litex_write8(0, config->master_ev_enable_addr); + + config->irq_config_func(dev); + } +#endif /* I2C_LITEX_ANY_HAS_IRQ */ + return ret; } @@ -332,8 +407,35 @@ static DEVICE_API(i2c, i2c_litex_litei2c_driver_api) = { /* Device Instantiation */ +#define I2C_LITEX_IRQ(n) \ + BUILD_ASSERT(DT_INST_REG_HAS_NAME(n, master_ev_pending) && \ + DT_INST_REG_HAS_NAME(n, master_ev_enable), "registers for interrupts missing"); \ + \ + static void i2c_litex_irq_config##n(const struct device *dev) \ + { \ + IRQ_CONNECT(DT_INST_IRQN(n), DT_INST_IRQ(n, priority), i2c_litex_irq_handler, \ + DEVICE_DT_INST_GET(n), 0); \ + \ + irq_enable(DT_INST_IRQN(n)); \ + }; + +#define I2C_LITEC_IRQ_DATA(n) \ + .sem_rx_ready = Z_SEM_INITIALIZER(i2c_litex_litei2c_data_##n.sem_rx_ready, 0, 1), + +#define I2C_LITEC_IRQ_CONFIG(n) \ + IF_DISABLED(I2C_LITEX_ALL_HAS_IRQ, (.has_irq = DT_INST_IRQ_HAS_IDX(n, 0),)) \ + .master_ev_pending_addr = DT_INST_REG_ADDR_BY_NAME_OR(n, master_ev_pending, 0), \ + .master_ev_enable_addr = DT_INST_REG_ADDR_BY_NAME_OR(n, master_ev_enable, 0), \ + .irq_config_func = COND_CODE_1(DT_INST_IRQ_HAS_IDX(n, 0), \ + (i2c_litex_irq_config##n), (NULL)), + #define I2C_LITEX_INIT(n) \ - static struct i2c_litex_litei2c_data i2c_litex_litei2c_data_##n; \ + IF_ENABLED(DT_INST_IRQ_HAS_IDX(n, 0), (I2C_LITEX_IRQ(n))) \ + \ + static struct i2c_litex_litei2c_data i2c_litex_litei2c_data_##n = { \ + .mutex = Z_MUTEX_INITIALIZER(i2c_litex_litei2c_data_##n.mutex), \ + IF_ENABLED(I2C_LITEX_ANY_HAS_IRQ, (I2C_LITEC_IRQ_DATA(n))) \ + }; \ \ static const struct i2c_litex_litei2c_config i2c_litex_litei2c_config_##n = { \ .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) = { .master_rxtx_addr = DT_INST_REG_ADDR_BY_NAME(n, master_rxtx), \ .master_status_addr = DT_INST_REG_ADDR_BY_NAME(n, master_status), \ .bitrate = DT_INST_PROP(n, clock_frequency), \ + IF_ENABLED(I2C_LITEX_ANY_HAS_IRQ, (I2C_LITEC_IRQ_CONFIG(n))) \ }; \ \ I2C_DEVICE_DT_INST_DEFINE(n, i2c_litex_init, NULL, &i2c_litex_litei2c_data_##n, \ diff --git a/drivers/spi/spi_litex_litespi.c b/drivers/spi/spi_litex_litespi.c index 706426437723..34608a948ef0 100644 --- a/drivers/spi/spi_litex_litespi.c +++ b/drivers/spi/spi_litex_litespi.c @@ -13,32 +13,48 @@ LOG_MODULE_REGISTER(spi_litex_litespi); #include #include "spi_litex_common.h" -#define SPIFLASH_CORE_MASTER_PHYCONFIG_LEN_OFFSET 0x0 -#define SPIFLASH_CORE_MASTER_PHYCONFIG_WIDTH_OFFSET 0x1 -#define SPIFLASH_CORE_MASTER_PHYCONFIG_MASK_OFFSET 0x2 +#define SPI_LITEX_ANY_HAS_IRQ DT_ANY_INST_HAS_PROP_STATUS_OKAY(interrupts) +#define SPI_LITEX_ALL_HAS_IRQ DT_ALL_INST_HAS_PROP_STATUS_OKAY(interrupts) -#define SPIFLASH_CORE_MASTER_STATUS_TX_READY_OFFSET 0x0 -#define SPIFLASH_CORE_MASTER_STATUS_RX_READY_OFFSET 0x1 +#define SPI_LITEX_HAS_IRQ UTIL_OR(SPI_LITEX_ALL_HAS_IRQ, dev_config->has_irq) + +#define SPIFLASH_MASTER_PHYCONFIG_LEN_OFFSET 0x0 +#define SPIFLASH_MASTER_PHYCONFIG_WIDTH_OFFSET 0x1 +#define SPIFLASH_MASTER_PHYCONFIG_MASK_OFFSET 0x2 + +#define SPIFLASH_MASTER_STATUS_TX_READY_OFFSET 0x0 +#define SPIFLASH_MASTER_STATUS_RX_READY_OFFSET 0x1 #define SPI_MAX_WORD_SIZE 32 -#define SPI_MAX_CS_SIZE 4 +#define SPI_MAX_CS_SIZE 32 + +#define SPI_LITEX_WIDTH BIT(0) +#define SPI_LITEX_MASK BIT(0) struct spi_litex_dev_config { - uint32_t core_master_cs_addr; - uint32_t core_master_phyconfig_addr; - uint32_t core_master_rxtx_addr; - uint32_t core_master_rxtx_size; - uint32_t core_master_status_addr; + uint32_t master_cs_addr; + uint32_t master_phyconfig_addr; + uint32_t master_rxtx_addr; + uint32_t master_rxtx_size; + uint32_t master_status_addr; uint32_t phy_clk_divisor_addr; bool phy_clk_divisor_exists; +#if SPI_LITEX_ANY_HAS_IRQ +#if !SPI_LITEX_ALL_HAS_IRQ + bool has_irq; +#endif /* !SPI_LITEX_ALL_HAS_IRQ */ + void (*irq_config_func)(const struct device *dev); + uint32_t master_ev_pending_addr; + uint32_t master_ev_enable_addr; +#endif /* SPI_LITEX_ANY_HAS_IRQ */ }; struct spi_litex_data { struct spi_context ctx; uint8_t dfs; /* dfs in bytes: 1,2 or 4 */ + uint8_t len; /* length of the last transfer in bytes */ }; - static int spi_litex_set_frequency(const struct device *dev, const struct spi_config *config) { const struct spi_litex_dev_config *dev_config = dev->config; @@ -60,11 +76,14 @@ static int spi_config(const struct device *dev, const struct spi_config *config) { struct spi_litex_data *dev_data = dev->data; - if (config->slave != 0) { - if (config->slave >= SPI_MAX_CS_SIZE) { - LOG_ERR("More slaves than supported"); - return -ENOTSUP; - } + if (spi_context_configured(&dev_data->ctx, config)) { + /* Context is already configured */ + return 0; + } + + if (config->slave >= SPI_MAX_CS_SIZE) { + LOG_ERR("More slaves than supported"); + return -ENOTSUP; } if (config->operation & SPI_HALF_DUPLEX) { @@ -83,11 +102,6 @@ static int spi_config(const struct device *dev, const struct spi_config *config) return -ENOTSUP; } - if (config->operation & SPI_LOCK_ON) { - LOG_ERR("Lock On not supported"); - return -ENOTSUP; - } - if (IS_ENABLED(CONFIG_SPI_EXTENDED_MODES) && (config->operation & SPI_LINES_MASK) != SPI_LINES_SINGLE) { LOG_ERR("Only supports single mode"); @@ -118,6 +132,8 @@ static int spi_config(const struct device *dev, const struct spi_config *config) spi_litex_set_frequency(dev, config); + dev_data->ctx.config = config; + return 0; } @@ -125,121 +141,230 @@ static void spiflash_len_mask_width_write(uint32_t len, uint32_t width, uint32_t uint32_t addr) { uint32_t tmp = len & BIT_MASK(8); - uint32_t word = tmp << (SPIFLASH_CORE_MASTER_PHYCONFIG_LEN_OFFSET * 8); + uint32_t word = tmp << (SPIFLASH_MASTER_PHYCONFIG_LEN_OFFSET * 8); tmp = width & BIT_MASK(8); - word |= tmp << (SPIFLASH_CORE_MASTER_PHYCONFIG_WIDTH_OFFSET * 8); + word |= tmp << (SPIFLASH_MASTER_PHYCONFIG_WIDTH_OFFSET * 8); tmp = mask & BIT_MASK(8); - word |= tmp << (SPIFLASH_CORE_MASTER_PHYCONFIG_MASK_OFFSET * 8); + word |= tmp << (SPIFLASH_MASTER_PHYCONFIG_MASK_OFFSET * 8); litex_write32(word, addr); } -static int spi_litex_xfer(const struct device *dev, const struct spi_config *config) +static void spi_litex_spi_do_tx(const struct device *dev) { const struct spi_litex_dev_config *dev_config = dev->config; struct spi_litex_data *data = dev->data; struct spi_context *ctx = &data->ctx; - uint32_t txd, rxd; - int ret = 0; + uint8_t len; + uint32_t txd = 0U; + + len = MIN(spi_context_max_continuous_chunk(ctx), dev_config->master_rxtx_size); + if (len != data->len) { + spiflash_len_mask_width_write(len * 8, SPI_LITEX_WIDTH, SPI_LITEX_MASK, + dev_config->master_phyconfig_addr); + data->len = len; + } - uint8_t len = data->dfs; /* SPI Xfer length*/ - uint8_t old_len = len; /* old SPI Xfer length*/ - uint8_t width = BIT(0); /* SPI Xfer width*/ - uint8_t mask = BIT(0); /* SPI Xfer mask*/ + if (spi_context_tx_buf_on(ctx)) { + litex_spi_tx_put(len, &txd, ctx->tx_buf); + } - spiflash_len_mask_width_write(len * 8, width, mask, dev_config->core_master_phyconfig_addr); + LOG_DBG("txd: 0x%x", txd); + litex_write32(txd, dev_config->master_rxtx_addr); - litex_write32(BIT(config->slave), dev_config->core_master_cs_addr); + spi_context_update_tx(ctx, data->dfs, len / data->dfs); +} - /* Flush RX buffer */ - while ((litex_read8(dev_config->core_master_status_addr) & - BIT(SPIFLASH_CORE_MASTER_STATUS_RX_READY_OFFSET))) { - rxd = litex_read32(dev_config->core_master_rxtx_addr); - LOG_DBG("flushed rxd: 0x%x", rxd); +static void spi_litex_spi_do_rx(const struct device *dev) +{ + const struct spi_litex_dev_config *dev_config = dev->config; + struct spi_litex_data *data = dev->data; + struct spi_context *ctx = &data->ctx; + uint32_t rxd; + + rxd = litex_read32(dev_config->master_rxtx_addr); + LOG_DBG("rxd: 0x%x", rxd); + + if (spi_context_rx_buf_on(ctx)) { + litex_spi_rx_put(data->len, &rxd, ctx->rx_buf); } - do { - len = MIN(spi_context_max_continuous_chunk(ctx), dev_config->core_master_rxtx_size); - if (len != old_len) { - spiflash_len_mask_width_write(len * 8, width, mask, - dev_config->core_master_phyconfig_addr); - old_len = len; - } + spi_context_update_rx(ctx, data->dfs, data->len / data->dfs); +} - if (spi_context_tx_buf_on(ctx)) { - litex_spi_tx_put(len, &txd, ctx->tx_buf); - } else { - txd = 0U; - } +static int spi_litex_xfer(const struct device *dev, const struct spi_config *config) +{ + const struct spi_litex_dev_config *dev_config = dev->config; + struct spi_litex_data *data = dev->data; + struct spi_context *ctx = &data->ctx; + uint32_t rxd; - while (!(litex_read8(dev_config->core_master_status_addr) & - BIT(SPIFLASH_CORE_MASTER_STATUS_TX_READY_OFFSET))) { - ; - } + litex_write32(BIT(config->slave), dev_config->master_cs_addr); - LOG_DBG("txd: 0x%x", txd); - litex_write32(txd, dev_config->core_master_rxtx_addr); + /* Flush RX buffer */ + while ((litex_read8(dev_config->master_status_addr) & + BIT(SPIFLASH_MASTER_STATUS_RX_READY_OFFSET))) { + rxd = litex_read32(dev_config->master_rxtx_addr); + LOG_DBG("flushed rxd: 0x%x", rxd); + } - spi_context_update_tx(ctx, data->dfs, len / data->dfs); + while (!(litex_read8(dev_config->master_status_addr) & + BIT(SPIFLASH_MASTER_STATUS_TX_READY_OFFSET))) { + (void)litex_read32(dev_config->master_rxtx_addr); + } - while (!(litex_read8(dev_config->core_master_status_addr) & - BIT(SPIFLASH_CORE_MASTER_STATUS_RX_READY_OFFSET))) { - ; - } +#if SPI_LITEX_ANY_HAS_IRQ + if (SPI_LITEX_HAS_IRQ) { + litex_write8(BIT(0), dev_config->master_ev_enable_addr); + litex_write8(BIT(0), dev_config->master_ev_pending_addr); - rxd = litex_read32(dev_config->core_master_rxtx_addr); - LOG_DBG("rxd: 0x%x", rxd); + spi_litex_spi_do_tx(dev); - if (spi_context_rx_buf_on(ctx)) { - litex_spi_rx_put(len, &rxd, ctx->rx_buf); - } + return spi_context_wait_for_completion(ctx); + } +#endif /* SPI_LITEX_ANY_HAS_IRQ */ + + do { + spi_litex_spi_do_tx(dev); - spi_context_update_rx(ctx, data->dfs, len / data->dfs); + while (!(litex_read8(dev_config->master_status_addr) & + BIT(SPIFLASH_MASTER_STATUS_RX_READY_OFFSET))) { + /* Wait for RX data */ + } + spi_litex_spi_do_rx(dev); } while (spi_context_tx_on(ctx) || spi_context_rx_on(ctx)); - litex_write32(0, dev_config->core_master_cs_addr); + if ((config->operation & SPI_HOLD_ON_CS) == 0) { + litex_write32(0, dev_config->master_cs_addr); + } spi_context_complete(ctx, dev, 0); - return ret; + return 0; } -static int spi_litex_transceive(const struct device *dev, const struct spi_config *config, - const struct spi_buf_set *tx_bufs, - const struct spi_buf_set *rx_bufs) +static int transceive(const struct device *dev, + const struct spi_config *config, + const struct spi_buf_set *tx_bufs, + const struct spi_buf_set *rx_bufs, + bool asynchronous, + spi_callback_t cb, + void *userdata) { struct spi_litex_data *data = dev->data; - - int ret = spi_config(dev, config); - - if (ret) { - return ret; - } + int ret; if (!tx_bufs && !rx_bufs) { return 0; } + spi_context_lock(&data->ctx, asynchronous, cb, userdata, config); + + ret = spi_config(dev, config); + if (ret < 0) { + goto end; + } + spi_context_buffers_setup(&data->ctx, tx_bufs, rx_bufs, data->dfs); ret = spi_litex_xfer(dev, config); +end: + spi_context_release(&data->ctx, ret); + return ret; } +static int spi_litex_transceive(const struct device *dev, + const struct spi_config *config, + const struct spi_buf_set *tx_bufs, + const struct spi_buf_set *rx_bufs) +{ + return transceive(dev, config, tx_bufs, rx_bufs, false, NULL, NULL); +} + #ifdef CONFIG_SPI_ASYNC -static int spi_litex_transceive_async(const struct device *dev, const struct spi_config *config, +static int spi_litex_transceive_async(const struct device *dev, + const struct spi_config *config, const struct spi_buf_set *tx_bufs, const struct spi_buf_set *rx_bufs, - struct k_poll_signal *async) + spi_callback_t cb, + void *userdata) { +#if SPI_LITEX_ANY_HAS_IRQ +#if !SPI_LITEX_ALL_HAS_IRQ + const struct spi_litex_dev_config *dev_config = dev->config; +#endif /* !SPI_LITEX_ALL_HAS_IRQ */ + + if (SPI_LITEX_HAS_IRQ) { + return transceive(dev, config, tx_bufs, rx_bufs, true, cb, userdata); + } +#endif /* SPI_LITEX_ANY_HAS_IRQ */ return -ENOTSUP; } #endif /* CONFIG_SPI_ASYNC */ static int spi_litex_release(const struct device *dev, const struct spi_config *config) { + struct spi_litex_data *data = dev->data; + const struct spi_litex_dev_config *dev_config = dev->config; + + if (!spi_context_configured(&data->ctx, config)) { + return -EINVAL; + } + + litex_write32(0, dev_config->master_cs_addr); + + spi_context_unlock_unconditionally(&data->ctx); + return 0; +} + +#if SPI_LITEX_ANY_HAS_IRQ +static void spi_litex_irq_handler(const struct device *dev) +{ + struct spi_litex_data *data = dev->data; + const struct spi_litex_dev_config *dev_config = dev->config; + struct spi_context *ctx = &data->ctx; + + if (litex_read8(dev_config->master_ev_pending_addr) & BIT(0)) { + spi_litex_spi_do_rx(dev); + + /* ack reader irq */ + litex_write8(BIT(0), dev_config->master_ev_pending_addr); + + if (spi_context_tx_on(ctx) || spi_context_rx_on(ctx)) { + spi_litex_spi_do_tx(dev); + } else { + litex_write8(0, dev_config->master_ev_enable_addr); + + if ((ctx->config->operation & SPI_HOLD_ON_CS) == 0) { + litex_write32(0, dev_config->master_cs_addr); + } + + spi_context_complete(ctx, dev, 0); + } + } +} +#endif /* SPI_LITEX_ANY_HAS_IRQ */ + +static int spi_litex_init(const struct device *dev) +{ + const struct spi_litex_dev_config *dev_config = dev->config; + struct spi_litex_data *data = dev->data; + +#if SPI_LITEX_ANY_HAS_IRQ + if (SPI_LITEX_HAS_IRQ) { + dev_config->irq_config_func(dev); + } +#endif /* SPI_LITEX_ANY_HAS_IRQ */ + + data->len = dev_config->master_rxtx_size; + + spiflash_len_mask_width_write(data->len * 8, SPI_LITEX_WIDTH, SPI_LITEX_MASK, + dev_config->master_phyconfig_addr); + + spi_context_unlock_unconditionally(&data->ctx); return 0; } @@ -256,22 +381,47 @@ static DEVICE_API(spi, spi_litex_api) = { .release = spi_litex_release, }; -#define SPI_INIT(n) \ - static struct spi_litex_data spi_litex_data_##n = { \ - SPI_CONTEXT_INIT_LOCK(spi_litex_data_##n, ctx), \ - SPI_CONTEXT_INIT_SYNC(spi_litex_data_##n, ctx), \ - }; \ +#define SPI_LITEX_IRQ(n) \ + BUILD_ASSERT(DT_INST_REG_HAS_NAME(n, master_ev_pending) && \ + DT_INST_REG_HAS_NAME(n, master_ev_enable), \ + "registers for interrupts missing"); \ + \ + static void spi_litex_irq_config##n(const struct device *dev) \ + { \ + IRQ_CONNECT(DT_INST_IRQN(n), DT_INST_IRQ(n, priority), spi_litex_irq_handler, \ + DEVICE_DT_INST_GET(n), 0); \ + \ + irq_enable(DT_INST_IRQN(n)); \ + }; + +#define SPI_LITEX_IRQ_CONFIG(n) \ + .irq_config_func = COND_CODE_1(DT_INST_IRQ_HAS_IDX(n, 0), \ + (spi_litex_irq_config##n), (NULL)), \ + .master_ev_pending_addr = DT_INST_REG_ADDR_BY_NAME_OR(n, master_ev_pending, 0), \ + .master_ev_enable_addr = DT_INST_REG_ADDR_BY_NAME_OR(n, master_ev_enable, 0), \ + IF_DISABLED(SPI_LITEX_ALL_HAS_IRQ, (.has_irq = DT_INST_IRQ_HAS_IDX(n, 0),)) + +#define SPI_INIT(n) \ + IF_ENABLED(DT_INST_IRQ_HAS_IDX(n, 0), (SPI_LITEX_IRQ(n))) \ + \ + static struct spi_litex_data spi_litex_data_##n = { \ + SPI_CONTEXT_INIT_LOCK(spi_litex_data_##n, ctx), \ + SPI_CONTEXT_INIT_SYNC(spi_litex_data_##n, ctx), \ + }; \ + \ static struct spi_litex_dev_config spi_litex_cfg_##n = { \ - .core_master_cs_addr = DT_INST_REG_ADDR_BY_NAME(n, core_master_cs), \ - .core_master_phyconfig_addr = DT_INST_REG_ADDR_BY_NAME(n, core_master_phyconfig), \ - .core_master_rxtx_addr = DT_INST_REG_ADDR_BY_NAME(n, core_master_rxtx), \ - .core_master_rxtx_size = DT_INST_REG_SIZE_BY_NAME(n, core_master_rxtx), \ - .core_master_status_addr = DT_INST_REG_ADDR_BY_NAME(n, core_master_status), \ + .master_cs_addr = DT_INST_REG_ADDR_BY_NAME(n, master_cs), \ + .master_phyconfig_addr = DT_INST_REG_ADDR_BY_NAME(n, master_phyconfig), \ + .master_rxtx_addr = DT_INST_REG_ADDR_BY_NAME(n, master_rxtx), \ + .master_rxtx_size = DT_INST_REG_SIZE_BY_NAME(n, master_rxtx), \ + .master_status_addr = DT_INST_REG_ADDR_BY_NAME(n, master_status), \ .phy_clk_divisor_exists = DT_INST_REG_HAS_NAME(n, phy_clk_divisor), \ - .phy_clk_divisor_addr = DT_INST_REG_ADDR_BY_NAME_OR(n, phy_clk_divisor, 0) \ - \ + .phy_clk_divisor_addr = DT_INST_REG_ADDR_BY_NAME_OR(n, phy_clk_divisor, 0), \ + IF_ENABLED(SPI_LITEX_ANY_HAS_IRQ, (SPI_LITEX_IRQ_CONFIG(n))) \ }; \ - SPI_DEVICE_DT_INST_DEFINE(n, NULL, NULL, &spi_litex_data_##n, &spi_litex_cfg_##n, \ - POST_KERNEL, CONFIG_SPI_INIT_PRIORITY, &spi_litex_api); + \ + SPI_DEVICE_DT_INST_DEFINE(n, spi_litex_init, NULL, &spi_litex_data_##n, \ + &spi_litex_cfg_##n, POST_KERNEL, CONFIG_SPI_INIT_PRIORITY, \ + &spi_litex_api); DT_INST_FOREACH_STATUS_OKAY(SPI_INIT) diff --git a/dts/riscv/riscv32-litex-vexriscv.dtsi b/dts/riscv/riscv32-litex-vexriscv.dtsi index 6d144b69abaf..341e4f5af6c3 100644 --- a/dts/riscv/riscv32-litex-vexriscv.dtsi +++ b/dts/riscv/riscv32-litex-vexriscv.dtsi @@ -102,11 +102,11 @@ <0xe000c010 0x4>, <0xe000c800 0x4>, <0x60000000 0x1000000>; - reg-names = "core_mmap_dummy_bits", - "core_master_cs", - "core_master_phyconfig", - "core_master_rxtx", - "core_master_status", + reg-names = "mmap_dummy_bits", + "master_cs", + "master_phyconfig", + "master_rxtx", + "master_status", "phy_clk_divisor", "flash_mmap"; #address-cells = <1>;