|  | /* | 
|  | * Copyright (c) 2022 Microchip Technology Inc. | 
|  | * | 
|  | * SPDX-License-Identifier: Apache-2.0 | 
|  | */ | 
|  |  | 
|  | #define DT_DRV_COMPAT microchip_mpfs_spi | 
|  |  | 
|  | #include <zephyr/device.h> | 
|  | #include <zephyr/drivers/spi.h> | 
|  | #include <zephyr/sys/sys_io.h> | 
|  | #include <zephyr/sys/util.h> | 
|  | #include <zephyr/logging/log.h> | 
|  | #include <zephyr/irq.h> | 
|  |  | 
|  | LOG_MODULE_REGISTER(mss_spi, CONFIG_SPI_LOG_LEVEL); | 
|  |  | 
|  | #include "spi_context.h" | 
|  |  | 
|  | /* MSS SPI Register offsets */ | 
|  | #define MSS_SPI_REG_CONTROL     (0x00) | 
|  | #define MSS_SPI_REG_TXRXDF_SIZE (0x04) | 
|  | #define MSS_SPI_REG_STATUS      (0x08) | 
|  | #define MSS_SPI_REG_INT_CLEAR   (0x0c) | 
|  | #define MSS_SPI_REG_RX_DATA     (0x10) | 
|  | #define MSS_SPI_REG_TX_DATA     (0x14) | 
|  | #define MSS_SPI_REG_CLK_GEN     (0x18) | 
|  | #define MSS_SPI_REG_SS          (0x1c) | 
|  | #define MSS_SPI_REG_MIS         (0x20) | 
|  | #define MSS_SPI_REG_RIS         (0x24) | 
|  | #define MSS_SPI_REG_CONTROL2    (0x28) | 
|  | #define MSS_SPI_REG_COMMAND     (0x2c) | 
|  | #define MSS_SPI_REG_PKTSIZE     (0x30) | 
|  | #define MSS_SPI_REG_CMD_SIZE    (0x34) | 
|  | #define MSS_SPI_REG_HWSTATUS    (0x38) | 
|  | #define MSS_SPI_REG_FRAMESUP    (0x50) | 
|  |  | 
|  | /* SPICR bit definitions */ | 
|  | #define MSS_SPI_CONTROL_ENABLE       BIT(0) | 
|  | #define MSS_SPI_CONTROL_MASTER       BIT(1) | 
|  | #define MSS_SPI_CONTROL_PROTO_MSK    BIT(2) | 
|  | #define MSS_SPI_CONTROL_PROTO_MOTO   (0 << 2) | 
|  | #define MSS_SPI_CONTROL_RX_DATA_INT  BIT(4) | 
|  | #define MSS_SPI_CONTROL_TX_DATA_INT  BIT(5) | 
|  | #define MSS_SPI_CONTROL_RX_OVER_INT  BIT(6) | 
|  | #define MSS_SPI_CONTROL_TX_UNDER_INT BIT(7) | 
|  | #define MSS_SPI_CONTROL_CNT_MSK      (0xffff << 8) | 
|  | #define MSS_SPI_CONTROL_CNT_SHF      (8) | 
|  | #define MSS_SPI_CONTROL_SPO          BIT(24) | 
|  | #define MSS_SPI_CONTROL_SPH          BIT(25) | 
|  | #define MSS_SPI_CONTROL_SPS          BIT(26) | 
|  | #define MSS_SPI_CONTROL_FRAMEURUN    BIT(27) | 
|  | #define MSS_SPI_CONTROL_CLKMODE      BIT(28) | 
|  | #define MSS_SPI_CONTROL_BIGFIFO      BIT(29) | 
|  | #define MSS_SPI_CONTROL_OENOFF       BIT(30) | 
|  | #define MSS_SPI_CONTROL_RESET        BIT(31) | 
|  |  | 
|  | /* SPIFRAMESIZE bit definitions */ | 
|  | #define MSS_SPI_FRAMESIZE_DEFAULT (8) | 
|  |  | 
|  | /* SPISS bit definitions */ | 
|  | #define MSS_SPI_SSEL_MASK (0xff) | 
|  | #define MSS_SPI_DIRECT    (0x100) | 
|  | #define MSS_SPI_SSELOUT   (0x200) | 
|  | #define MSS_SPI_MIN_SLAVE (0) | 
|  | #define MSS_SPI_MAX_SLAVE (7) | 
|  |  | 
|  | /* SPIST bit definitions */ | 
|  | #define MSS_SPI_STATUS_ACTIVE                 BIT(14) | 
|  | #define MSS_SPI_STATUS_SSEL                   BIT(13) | 
|  | #define MSS_SPI_STATUS_FRAMESTART             BIT(12) | 
|  | #define MSS_SPI_STATUS_TXFIFO_EMPTY_NEXT_READ BIT(11) | 
|  | #define MSS_SPI_STATUS_TXFIFO_EMPTY           BIT(10) | 
|  | #define MSS_SPI_STATUS_TXFIFO_FULL_NEXT_WRITE BIT(9) | 
|  | #define MSS_SPI_STATUS_TXFIFO_FULL            BIT(8) | 
|  | #define MSS_SPI_STATUS_RXFIFO_EMPTY_NEXT_READ BIT(7) | 
|  | #define MSS_SPI_STATUS_RXFIFO_EMPTY           BIT(6) | 
|  | #define MSS_SPI_STATUS_RXFIFO_FULL_NEXT_WRITE BIT(5) | 
|  | #define MSS_SPI_STATUS_RXFIFO_FULL            BIT(4) | 
|  | #define MSS_SPI_STATUS_TX_UNDERRUN            BIT(3) | 
|  | #define MSS_SPI_STATUS_RX_OVERFLOW            BIT(2) | 
|  | #define MSS_SPI_STATUS_RXDAT_RCED             BIT(1) | 
|  | #define MSS_SPI_STATUS_TXDAT_SENT             BIT(0) | 
|  |  | 
|  | /* SPIINT register defines */ | 
|  | #define MSS_SPI_INT_TXDONE       BIT(0) | 
|  | #define MSS_SPI_INT_RXRDY        BIT(1) | 
|  | #define MSS_SPI_INT_RX_CH_OVRFLW BIT(2) | 
|  | #define MSS_SPI_INT_TX_CH_UNDRUN BIT(3) | 
|  | #define MSS_SPI_INT_CMD          BIT(4) | 
|  | #define MSS_SPI_INT_SSEND        BIT(5) | 
|  |  | 
|  | /* SPICOMMAND bit definitions */ | 
|  | #define MSS_SPI_COMMAND_FIFO_MASK (0xC) | 
|  |  | 
|  | /* SPIFRAMESUP bit definitions */ | 
|  | #define MSS_SPI_FRAMESUP_UP_BYTES_MSK (0xFFFF << 16) | 
|  | #define MSS_SPI_FRAMESUP_LO_BYTES_MSK (0xFFFF << 0) | 
|  |  | 
|  | struct mss_spi_config { | 
|  | mm_reg_t base; | 
|  | uint8_t clk_gen; | 
|  | int clock_freq; | 
|  | }; | 
|  |  | 
|  | struct mss_spi_transfer { | 
|  | uint32_t rx_len; | 
|  | uint32_t control; | 
|  | }; | 
|  |  | 
|  | struct mss_spi_data { | 
|  | struct spi_context ctx; | 
|  | struct mss_spi_transfer xfer; | 
|  | }; | 
|  |  | 
|  | static inline uint32_t mss_spi_read(const struct mss_spi_config *cfg, mm_reg_t offset) | 
|  | { | 
|  | return sys_read32(cfg->base + offset); | 
|  | } | 
|  |  | 
|  | static inline void mss_spi_write(const struct mss_spi_config *cfg, mm_reg_t offset, uint32_t val) | 
|  | { | 
|  | sys_write32(val, cfg->base + offset); | 
|  | } | 
|  |  | 
|  | static inline void mss_spi_hw_tfsz_set(const struct mss_spi_config *cfg, int len) | 
|  | { | 
|  | uint32_t control; | 
|  |  | 
|  | mss_spi_write(cfg, MSS_SPI_REG_FRAMESUP, (len & MSS_SPI_FRAMESUP_UP_BYTES_MSK)); | 
|  | control = mss_spi_read(cfg, MSS_SPI_REG_CONTROL); | 
|  | control &= ~MSS_SPI_CONTROL_CNT_MSK; | 
|  | control |= ((len & MSS_SPI_FRAMESUP_LO_BYTES_MSK) << MSS_SPI_CONTROL_CNT_SHF); | 
|  | mss_spi_write(cfg, MSS_SPI_REG_CONTROL, control); | 
|  | } | 
|  |  | 
|  | static inline void mss_spi_enable_controller(const struct mss_spi_config *cfg) | 
|  | { | 
|  | uint32_t control; | 
|  |  | 
|  | control = mss_spi_read(cfg, MSS_SPI_REG_CONTROL); | 
|  | control |= MSS_SPI_CONTROL_ENABLE; | 
|  | mss_spi_write(cfg, MSS_SPI_REG_CONTROL, control); | 
|  | } | 
|  |  | 
|  | static inline void mss_spi_disable_controller(const struct mss_spi_config *cfg) | 
|  | { | 
|  | uint32_t control; | 
|  |  | 
|  | control = mss_spi_read(cfg, MSS_SPI_REG_CONTROL); | 
|  | control &= ~MSS_SPI_CONTROL_ENABLE; | 
|  | mss_spi_write(cfg, MSS_SPI_REG_CONTROL, control); | 
|  | } | 
|  |  | 
|  | static void mss_spi_enable_ints(const struct mss_spi_config *cfg) | 
|  | { | 
|  | uint32_t control; | 
|  | uint32_t mask = MSS_SPI_CONTROL_RX_DATA_INT | MSS_SPI_CONTROL_TX_DATA_INT | | 
|  | MSS_SPI_CONTROL_RX_OVER_INT | MSS_SPI_CONTROL_TX_UNDER_INT; | 
|  |  | 
|  | control = mss_spi_read(cfg, MSS_SPI_REG_CONTROL); | 
|  | control |= mask; | 
|  | mss_spi_write(cfg, MSS_SPI_REG_CONTROL, control); | 
|  | } | 
|  |  | 
|  | static void mss_spi_disable_ints(const struct mss_spi_config *cfg) | 
|  | { | 
|  | uint32_t control; | 
|  | uint32_t mask = MSS_SPI_CONTROL_RX_DATA_INT | MSS_SPI_CONTROL_TX_DATA_INT | | 
|  | MSS_SPI_CONTROL_RX_OVER_INT | MSS_SPI_CONTROL_TX_UNDER_INT; | 
|  |  | 
|  | mask = ~mask; | 
|  | control = mss_spi_read(cfg, MSS_SPI_REG_CONTROL); | 
|  | control &= ~mask; | 
|  | mss_spi_write(cfg, MSS_SPI_REG_CONTROL, control); | 
|  | } | 
|  |  | 
|  | static inline void mss_spi_readwr_fifo(const struct device *dev) | 
|  | { | 
|  | const struct mss_spi_config *cfg = dev->config; | 
|  | struct mss_spi_data *data = dev->data; | 
|  | struct spi_context *ctx = &data->ctx; | 
|  | struct mss_spi_transfer *xfer = &data->xfer; | 
|  | uint32_t rx_raw = 0, rd_byte_size, tr_len; | 
|  | uint32_t data8, transfer_idx = 0; | 
|  | int count; | 
|  |  | 
|  | tr_len = spi_context_longest_current_buf(ctx); | 
|  | count = spi_context_total_tx_len(ctx); | 
|  | if (ctx->rx_buf) { | 
|  | rd_byte_size = count - tr_len; | 
|  | } else { | 
|  | rd_byte_size = 0; | 
|  | } | 
|  | mss_spi_hw_tfsz_set(cfg, count); | 
|  |  | 
|  | mss_spi_enable_ints(cfg); | 
|  | spi_context_update_rx(ctx, 1, xfer->rx_len); | 
|  | while (transfer_idx < count) { | 
|  | if (!(mss_spi_read(cfg, MSS_SPI_REG_STATUS) & MSS_SPI_STATUS_RXFIFO_EMPTY)) { | 
|  | rx_raw = mss_spi_read(cfg, MSS_SPI_REG_RX_DATA); | 
|  | if (transfer_idx >= tr_len) { | 
|  | if (spi_context_rx_buf_on(ctx)) { | 
|  | UNALIGNED_PUT(rx_raw, (uint8_t *)ctx->rx_buf); | 
|  | spi_context_update_rx(ctx, 1, 1); | 
|  | } | 
|  | } | 
|  | ++transfer_idx; | 
|  | } | 
|  |  | 
|  | if (!(mss_spi_read(cfg, MSS_SPI_REG_STATUS) & MSS_SPI_STATUS_TXFIFO_FULL)) { | 
|  | if (spi_context_tx_buf_on(ctx)) { | 
|  | data8 = ctx->tx_buf[0]; | 
|  | mss_spi_write(cfg, MSS_SPI_REG_TX_DATA, data8); | 
|  | spi_context_update_tx(ctx, 1, 1); | 
|  | } else { | 
|  | mss_spi_write(cfg, MSS_SPI_REG_TX_DATA, 0x0); | 
|  | } | 
|  | } | 
|  | } | 
|  | } | 
|  |  | 
|  | static inline int mss_spi_select_slave(const struct mss_spi_config *cfg, int cs) | 
|  | { | 
|  | uint32_t slave; | 
|  | uint32_t reg = mss_spi_read(cfg, MSS_SPI_REG_SS); | 
|  |  | 
|  | slave = (cs >= MSS_SPI_MIN_SLAVE && cs <= MSS_SPI_MAX_SLAVE) ? (1 << cs) : 0; | 
|  | reg &= ~MSS_SPI_SSEL_MASK; | 
|  | reg |= slave; | 
|  |  | 
|  | mss_spi_write(cfg, MSS_SPI_REG_SS, reg); | 
|  |  | 
|  | return 0; | 
|  | } | 
|  |  | 
|  | static inline void mss_spi_activate_cs(struct mss_spi_config *cfg) | 
|  | { | 
|  | uint32_t reg = mss_spi_read(cfg, MSS_SPI_REG_SS); | 
|  |  | 
|  | reg |= MSS_SPI_SSELOUT; | 
|  | mss_spi_write(cfg, MSS_SPI_REG_SS, reg); | 
|  | } | 
|  |  | 
|  | static inline void mss_spi_deactivate_cs(const struct mss_spi_config *cfg) | 
|  | { | 
|  | uint32_t reg = mss_spi_read(cfg, MSS_SPI_REG_SS); | 
|  |  | 
|  | reg &= ~MSS_SPI_SSELOUT; | 
|  | mss_spi_write(cfg, MSS_SPI_REG_SS, reg); | 
|  | } | 
|  |  | 
|  | static inline int mss_spi_clk_gen_set(const struct mss_spi_config *cfg, | 
|  | const struct spi_config *spi_cfg) | 
|  | { | 
|  | uint32_t idx, clkrate, val = 0, speed; | 
|  |  | 
|  | if (spi_cfg->frequency > cfg->clock_freq) { | 
|  | speed = cfg->clock_freq / 2; | 
|  | } | 
|  |  | 
|  | for (idx = 1; idx < 16; idx++) { | 
|  | clkrate = cfg->clock_freq / (2 * idx); | 
|  | if (clkrate <= spi_cfg->frequency) { | 
|  | val = idx; | 
|  | break; | 
|  | } | 
|  | } | 
|  |  | 
|  | mss_spi_write(cfg, MSS_SPI_REG_CLK_GEN, val); | 
|  |  | 
|  | return 0; | 
|  | } | 
|  |  | 
|  | static inline int mss_spi_hw_mode_set(const struct mss_spi_config *cfg, unsigned int mode) | 
|  | { | 
|  | uint32_t control = mss_spi_read(cfg, MSS_SPI_REG_CONTROL); | 
|  |  | 
|  | /* set the mode */ | 
|  | if (mode & SPI_MODE_CPHA) { | 
|  | control |= MSS_SPI_CONTROL_SPH; | 
|  | } else { | 
|  | control &= ~MSS_SPI_CONTROL_SPH; | 
|  | } | 
|  |  | 
|  | if (mode & SPI_MODE_CPOL) { | 
|  | control |= MSS_SPI_CONTROL_SPO; | 
|  | } else { | 
|  | control &= ~MSS_SPI_CONTROL_SPO; | 
|  | } | 
|  |  | 
|  | mss_spi_write(cfg, MSS_SPI_REG_CONTROL, control); | 
|  |  | 
|  | return 0; | 
|  | } | 
|  |  | 
|  | static void mss_spi_interrupt(const struct device *dev) | 
|  | { | 
|  | const struct mss_spi_config *cfg = dev->config; | 
|  | struct mss_spi_data *data = dev->data; | 
|  | struct spi_context *ctx = &data->ctx; | 
|  | int intfield = mss_spi_read(cfg, MSS_SPI_REG_MIS) & 0xf; | 
|  |  | 
|  | if (intfield == 0) { | 
|  | return; | 
|  | } | 
|  |  | 
|  | mss_spi_write(cfg, MSS_SPI_REG_INT_CLEAR, intfield); | 
|  | spi_context_complete(ctx, dev, 0); | 
|  | } | 
|  |  | 
|  | static int mss_spi_release(const struct device *dev, const struct spi_config *config) | 
|  | { | 
|  | const struct mss_spi_config *cfg = dev->config; | 
|  | struct mss_spi_data *data = dev->data; | 
|  |  | 
|  | mss_spi_disable_ints(cfg); | 
|  |  | 
|  | /* release kernel resources */ | 
|  | spi_context_unlock_unconditionally(&data->ctx); | 
|  | mss_spi_disable_controller(cfg); | 
|  |  | 
|  | return 0; | 
|  | } | 
|  |  | 
|  | static int mss_spi_configure(const struct device *dev, const struct spi_config *spi_cfg) | 
|  | { | 
|  | const struct mss_spi_config *cfg = dev->config; | 
|  | struct mss_spi_data *data = dev->data; | 
|  | struct spi_context *ctx = &data->ctx; | 
|  | struct mss_spi_transfer *xfer = &data->xfer; | 
|  | uint32_t control; | 
|  |  | 
|  | if (spi_cfg->operation & (SPI_TRANSFER_LSB | SPI_OP_MODE_SLAVE | SPI_MODE_LOOP)) { | 
|  | LOG_WRN("not supported operation\n\r"); | 
|  | return -ENOTSUP; | 
|  | } | 
|  |  | 
|  | if (SPI_WORD_SIZE_GET(spi_cfg->operation) != MSS_SPI_FRAMESIZE_DEFAULT) { | 
|  | return -ENOTSUP; | 
|  | } | 
|  |  | 
|  | ctx->config = spi_cfg; | 
|  | mss_spi_select_slave(cfg, spi_cfg->slave); | 
|  | control = mss_spi_read(cfg, MSS_SPI_REG_CONTROL); | 
|  |  | 
|  | /* | 
|  | * Fill up the default values | 
|  | * Slave select behaviour set | 
|  | * Fifo depth greater than 4 frames | 
|  | * Methodology to calculate SPI Clock: | 
|  | *	0:	SPICLK = 1 / (2 CLK_GEN + 1) , CLK_GEN is from 0 to 15 | 
|  | *	1:	SPICLK = 1 / (2 * (CLK_GEN + 1)) , CLK_GEN is from 0 to 255 | 
|  | */ | 
|  |  | 
|  | mss_spi_write(cfg, MSS_SPI_REG_CONTROL, xfer->control); | 
|  |  | 
|  | if (mss_spi_clk_gen_set(cfg, spi_cfg)) { | 
|  | LOG_ERR("can't set clk divider\n"); | 
|  | return -EINVAL; | 
|  | } | 
|  |  | 
|  | mss_spi_hw_mode_set(cfg, spi_cfg->operation); | 
|  | mss_spi_write(cfg, MSS_SPI_REG_TXRXDF_SIZE, MSS_SPI_FRAMESIZE_DEFAULT); | 
|  | mss_spi_enable_controller(cfg); | 
|  | mss_spi_write(cfg, MSS_SPI_REG_COMMAND, MSS_SPI_COMMAND_FIFO_MASK); | 
|  |  | 
|  | return 0; | 
|  | } | 
|  |  | 
|  | static int mss_spi_transceive(const struct device *dev, const struct spi_config *spi_cfg, | 
|  | const struct spi_buf_set *tx_bufs, const struct spi_buf_set *rx_bufs, | 
|  | bool async, spi_callback_t cb, void *userdata) | 
|  | { | 
|  |  | 
|  | const struct mss_spi_config *config = dev->config; | 
|  | struct mss_spi_data *data = dev->data; | 
|  | struct spi_context *ctx = &data->ctx; | 
|  | struct mss_spi_transfer *xfer = &data->xfer; | 
|  | int ret = 0; | 
|  |  | 
|  | spi_context_lock(ctx, async, cb, userdata, spi_cfg); | 
|  |  | 
|  | ret = mss_spi_configure(dev, spi_cfg); | 
|  | if (ret) { | 
|  | LOG_ERR("Fail to configure\n\r"); | 
|  | goto out; | 
|  | } | 
|  |  | 
|  | spi_context_buffers_setup(ctx, tx_bufs, rx_bufs, 1); | 
|  | xfer->rx_len = ctx->rx_len; | 
|  | mss_spi_readwr_fifo(dev); | 
|  | ret = spi_context_wait_for_completion(ctx); | 
|  | out: | 
|  | spi_context_release(ctx, ret); | 
|  | mss_spi_disable_ints(config); | 
|  | mss_spi_disable_controller(config); | 
|  |  | 
|  | return ret; | 
|  | } | 
|  |  | 
|  | static int mss_spi_transceive_blocking(const struct device *dev, const struct spi_config *spi_cfg, | 
|  | const struct spi_buf_set *tx_bufs, | 
|  | const struct spi_buf_set *rx_bufs) | 
|  | { | 
|  |  | 
|  | return mss_spi_transceive(dev, spi_cfg, tx_bufs, rx_bufs, false, NULL, NULL); | 
|  | } | 
|  |  | 
|  | #ifdef CONFIG_SPI_ASYNC | 
|  | static int mss_spi_transceive_async(const struct device *dev, const struct spi_config *spi_cfg, | 
|  | const struct spi_buf_set *tx_bufs, | 
|  | const struct spi_buf_set *rx_bufs, spi_callback_t cb, | 
|  | void *userdata) | 
|  | { | 
|  | return mss_spi_transceive(dev, spi_cfg, tx_bufs, rx_bufs, true, cb, userdata); | 
|  | } | 
|  | #endif /* CONFIG_SPI_ASYNC */ | 
|  |  | 
|  | static int mss_spi_init(const struct device *dev) | 
|  | { | 
|  | const struct mss_spi_config *cfg = dev->config; | 
|  | struct mss_spi_data *data = dev->data; | 
|  | struct mss_spi_transfer *xfer = &data->xfer; | 
|  | int ret = 0; | 
|  | uint32_t control = 0; | 
|  |  | 
|  | /* Remove SPI from Reset  */ | 
|  | control = mss_spi_read(cfg, MSS_SPI_REG_CONTROL); | 
|  | control &= ~MSS_SPI_CONTROL_RESET; | 
|  | mss_spi_write(cfg, MSS_SPI_REG_CONTROL, control); | 
|  |  | 
|  | /* Set master mode */ | 
|  | mss_spi_disable_controller(cfg); | 
|  | xfer->control = (MSS_SPI_CONTROL_SPS | MSS_SPI_CONTROL_BIGFIFO | MSS_SPI_CONTROL_MASTER | | 
|  | MSS_SPI_CONTROL_CLKMODE); | 
|  |  | 
|  | spi_context_unlock_unconditionally(&data->ctx); | 
|  |  | 
|  | return ret; | 
|  | } | 
|  |  | 
|  | #define MICROCHIP_SPI_PM_OPS (NULL) | 
|  |  | 
|  | static const struct spi_driver_api mss_spi_driver_api = { | 
|  | .transceive = mss_spi_transceive_blocking, | 
|  | #ifdef CONFIG_SPI_ASYNC | 
|  | .transceive_async = mss_spi_transceive_async, | 
|  | #endif /* CONFIG_SPI_ASYNC */ | 
|  | .release = mss_spi_release, | 
|  | }; | 
|  |  | 
|  | #define MSS_SPI_INIT(n)                                                                            \ | 
|  | static int mss_spi_init_##n(const struct device *dev)                                      \ | 
|  | {                                                                                          \ | 
|  | mss_spi_init(dev);                                                                 \ | 
|  | \ | 
|  | IRQ_CONNECT(DT_INST_IRQN(n), DT_INST_IRQ(n, priority), mss_spi_interrupt,          \ | 
|  | DEVICE_DT_INST_GET(n), 0);                                             \ | 
|  | \ | 
|  | irq_enable(DT_INST_IRQN(n));                                                       \ | 
|  | \ | 
|  | return 0;                                                                          \ | 
|  | }                                                                                          \ | 
|  | \ | 
|  | static const struct mss_spi_config mss_spi_config_##n = {                                  \ | 
|  | .base = DT_INST_REG_ADDR(n),                                                       \ | 
|  | .clock_freq = DT_INST_PROP(n, clock_frequency),                                    \ | 
|  | };                                                                                         \ | 
|  | \ | 
|  | static struct mss_spi_data mss_spi_data_##n = {                                            \ | 
|  | SPI_CONTEXT_INIT_LOCK(mss_spi_data_##n, ctx),                                      \ | 
|  | SPI_CONTEXT_INIT_SYNC(mss_spi_data_##n, ctx),                                      \ | 
|  | };                                                                                         \ | 
|  | \ | 
|  | DEVICE_DT_INST_DEFINE(n, mss_spi_init_##n, NULL, &mss_spi_data_##n, &mss_spi_config_##n,   \ | 
|  | POST_KERNEL, CONFIG_KERNEL_INIT_PRIORITY_DEVICE,                     \ | 
|  | &mss_spi_driver_api); | 
|  |  | 
|  | DT_INST_FOREACH_STATUS_OKAY(MSS_SPI_INIT) |