drivers: spi: Add support for Polarfire SOC QSPI

This patch adds driver for the Microchip Polarfire SOC MSS QSPI
controller.
The interrupts of the MSS QSPI are routed through PLIC(Platform level
interrupt controller).

Tested with generic spi-nor flash driver(spi_flash) with both Fixed
flash configuration and Read flash parameters at runtime(using SFDP).

Signed-off-by: Naga Sureshkumar Relli <nagasuresh.relli@microchip.com>
This commit is contained in:
Naga Sureshkumar Relli 2022-04-12 12:00:47 +05:30 committed by Carles Cufí
commit 248047323e
4 changed files with 611 additions and 0 deletions

View file

@ -29,5 +29,6 @@ zephyr_library_sources_ifdef(CONFIG_SPI_NPCX_FIU spi_npcx_fiu.c)
zephyr_library_sources_ifdef(CONFIG_SPI_BITBANG spi_bitbang.c) zephyr_library_sources_ifdef(CONFIG_SPI_BITBANG spi_bitbang.c)
zephyr_library_sources_ifdef(CONFIG_SPI_XEC_QMSPI_LDMA spi_xec_qmspi_ldma.c) zephyr_library_sources_ifdef(CONFIG_SPI_XEC_QMSPI_LDMA spi_xec_qmspi_ldma.c)
zephyr_library_sources_ifdef(CONFIG_SPI_GD32 spi_gd32.c) zephyr_library_sources_ifdef(CONFIG_SPI_GD32 spi_gd32.c)
zephyr_library_sources_ifdef(CONFIG_SPI_MCHP_QSPI spi_mchp_mss_qspi.c)
zephyr_library_sources_ifdef(CONFIG_USERSPACE spi_handlers.c) zephyr_library_sources_ifdef(CONFIG_USERSPACE spi_handlers.c)

View file

@ -101,4 +101,6 @@ source "drivers/spi/Kconfig.xec_qmspi_ldma"
source "drivers/spi/Kconfig.gd32" source "drivers/spi/Kconfig.gd32"
source "drivers/spi/Kconfig.mchp_mss_qspi"
endif # SPI endif # SPI

View file

@ -0,0 +1,11 @@
# Microchip Polarfire SOC QSPI
# Copyright (c) 2022 Microchip Technology Inc.
# SPDX-License-Identifier: Apache-2.0
config SPI_MCHP_QSPI
bool "Microchip Polarfire SOC QSPI driver"
default y
depends on SOC_MPFS
help
Enable support for the Polarfire SOC QSPI driver.

View file

@ -0,0 +1,597 @@
/*
* Copyright (c) 2022 Microchip Technology Inc.
*
* SPDX-License-Identifier: Apache-2.0
*/
#define DT_DRV_COMPAT microchip_mpfs_qspi
#include <device.h>
#include <drivers/spi.h>
#include <sys/sys_io.h>
#include <sys/util.h>
#include <logging/log.h>
LOG_MODULE_REGISTER(mss_qspi, CONFIG_SPI_LOG_LEVEL);
#include "spi_context.h"
/*MSS QSPI Register offsets */
#define MSS_QSPI_REG_CONTROL (0x00)
#define MSS_QSPI_REG_FRAMES (0x04)
#define MSS_QSPI_REG_IEN (0x0c)
#define MSS_QSPI_REG_STATUS (0x10)
#define MSS_QSPI_REG_DIRECT_ACCESS (0x14)
#define MSS_QSPI_REG_UPPER_ACCESS (0x18)
#define MSS_QSPI_REG_RX_DATA (0x40)
#define MSS_QSPI_REG_TX_DATA (0x44)
#define MSS_QSPI_REG_X4_RX_DATA (0x48)
#define MSS_QSPI_REG_X4_TX_DATA (0x4c)
#define MSS_QSPI_REG_FRAMESUP (0x50)
/* QSPICR bit definitions */
#define MSS_QSPI_CONTROL_ENABLE BIT(0)
#define MSS_QSPI_CONTROL_MASTER BIT(1)
#define MSS_QSPI_CONTROL_XIP BIT(2)
#define MSS_QSPI_CONTROL_XIPADDR BIT(3)
#define MSS_QSPI_CONTROL_CLKIDLE BIT(10)
#define MSS_QSPI_CONTROL_SAMPLE_MSK (3 << 11)
#define MSS_QSPI_CONTROL_MODE0 BIT(13)
#define MSS_QSPI_CONTROL_MODE_EXQUAD (0x6 << 13)
#define MSS_QSPI_CONTROL_MODE_EXDUAL (0x2 << 13)
#define MSS_QSPI_CONTROL_MODE12_MSK (3 << 14)
#define MSS_QSPI_CONTROL_FLAGSX4 BIT(16)
#define MSS_QSPI_CONTROL_CLKRATE_MSK (0xf << 24)
#define MSS_QSPI_CONTROL_CLKRATE 24
/* QSPIFRAMES bit definitions */
#define MSS_QSPI_FRAMES_TOTALBYTES_MSK (0xffff << 0)
#define MSS_QSPI_FRAMES_TOTALBYTES_MSK (0xffff << 0)
#define MSS_QSPI_FRAMES_CMDBYTES_MSK (0x1ff << 16)
#define MSS_QSPI_FRAMES_CMDBYTES 16
#define MSS_QSPI_FRAMES_QSPI BIT(25)
#define MSS_QSPI_FRAMES_IDLE_MSK (0xf << 26)
#define MSS_QSPI_FRAMES_FLAGBYTE BIT(30)
#define MSS_QSPI_FRAMES_FLAGWORD BIT(31)
/* QSPIIEN bit definitions */
#define MSS_QSPI_IEN_TXDONE BIT(0)
#define MSS_QSPI_IEN_RXDONE BIT(1)
#define MSS_QSPI_IEN_RXAVAILABLE BIT(2)
#define MSS_QSPI_IEN_TXAVAILABLE BIT(3)
#define MSS_QSPI_IEN_RXFIFOEMPTY BIT(4)
#define MSS_QSPI_IEN_TXFIFOFULL BIT(5)
#define MSS_QSPI_IEN_FLAGSX4 BIT(8)
/* QSPIST bit definitions */
#define MSS_QSPI_STATUS_TXDONE BIT(0)
#define MSS_QSPI_STATUS_RXDONE BIT(1)
#define MSS_QSPI_STATUS_RXAVAILABLE BIT(2)
#define MSS_QSPI_STATUS_TXAVAILABLE BIT(3)
#define MSS_QSPI_STATUS_RXFIFOEMPTY BIT(4)
#define MSS_QSPI_STATUS_TXFIFOFULL BIT(5)
#define MSS_QSPI_STATUS_READY BIT(7)
#define MSS_QSPI_STATUS_FLAGSX4 BIT(8)
/* QSPIDA bit definitions */
#define MSS_QSPI_DA_EN_SSEL BIT(0)
#define MSS_QSPI_DA_OP_SSEL BIT(1)
#define MSS_QSPI_DA_EN_SCLK BIT(2)
#define MSS_QSPI_DA_OP_SCLK BIT(3)
#define MSS_QSPI_DA_EN_SDO_MSK (0xf << 4)
#define MSS_QSPI_DA_OP_SDO_MSK (0xf << 8)
#define MSS_QSPI_DA_OP_SDATA_MSK (0xf << 12)
#define MSS_QSPI_DA_IP_SDI_MSK (0xf << 16)
#define MSS_QSPI_DA_IP_SCLK BIT(21)
#define MSS_QSPI_DA_IP_SSEL BIT(22)
#define MSS_QSPI_DA_IDLE BIT(23)
#define MSS_QSPI_RXDATA_MSK (0xff << 0)
#define MSS_QSPI_TXDATA_MSK (0xff << 0)
/* QSPIFRAMESUP bit definitions */
#define MSS_QSPI_FRAMESUP_UP_BYTES_MSK (0xFFFF << 16)
#define MSS_QSPI_FRAMESUP_LO_BYTES_MSK (0xFFFF << 0)
/*
* Private data structure for an SPI slave
*/
struct mss_qspi_config {
mm_reg_t base;
void (*irq_config_func)(const struct device *dev);
int irq;
uint32_t clock_freq;
};
/* Device run time data */
struct mss_qspi_data {
struct spi_context ctx;
};
static inline uint32_t mss_qspi_read(const struct mss_qspi_config *cfg,
mm_reg_t offset)
{
return sys_read32(cfg->base + offset);
}
static inline void mss_qspi_write(const struct mss_qspi_config *cfg,
uint32_t val, mm_reg_t offset)
{
sys_write32(val, cfg->base + offset);
}
static void mss_qspi_enable_ints(const struct mss_qspi_config *s)
{
uint32_t mask = MSS_QSPI_IEN_TXDONE |
MSS_QSPI_IEN_RXDONE |
MSS_QSPI_IEN_RXAVAILABLE;
mss_qspi_write(s, mask, MSS_QSPI_REG_IEN);
}
static void mss_qspi_disable_ints(const struct mss_qspi_config *s)
{
uint32_t mask = 0;
mss_qspi_write(s, mask, MSS_QSPI_REG_IEN);
}
static inline void mss_qspi_transmit_x8(const struct device *dev, uint32_t len)
{
const struct mss_qspi_config *s = dev->config;
struct mss_qspi_data *data = dev->data;
struct spi_context *ctx = &data->ctx;
uint32_t count, skips;
skips = mss_qspi_read(s, MSS_QSPI_REG_CONTROL);
skips &= ~MSS_QSPI_CONTROL_FLAGSX4;
mss_qspi_write(s, skips, MSS_QSPI_REG_CONTROL);
for (count = 0; count < len; ++count) {
while (mss_qspi_read(s, MSS_QSPI_REG_STATUS)
& MSS_QSPI_STATUS_TXFIFOFULL)
;
if (spi_context_tx_buf_on(ctx)) {
mss_qspi_write(s, ctx->tx_buf[0], MSS_QSPI_REG_TX_DATA);
spi_context_update_tx(ctx, 1, 1);
}
}
}
static inline void mss_qspi_transmit_x32(const struct device *dev, uint32_t len)
{
const struct mss_qspi_config *s = dev->config;
struct mss_qspi_data *data = dev->data;
struct spi_context *ctx = &data->ctx;
uint32_t count, ctrl, wdata;
ctrl = mss_qspi_read(s, MSS_QSPI_REG_CONTROL);
ctrl |= MSS_QSPI_CONTROL_FLAGSX4;
mss_qspi_write(s, ctrl, MSS_QSPI_REG_CONTROL);
for (count = 0; count < len / 4; ++count) {
while (mss_qspi_read(s, MSS_QSPI_REG_STATUS)
& MSS_QSPI_STATUS_TXFIFOFULL)
;
if (spi_context_tx_buf_on(ctx)) {
wdata = UNALIGNED_GET((uint32_t *)(ctx->tx_buf));
mss_qspi_write(s, wdata, MSS_QSPI_REG_X4_TX_DATA);
spi_context_update_tx(ctx, 1, 4);
}
}
}
static inline void mss_qspi_receive_x32(const struct device *dev, uint32_t len)
{
const struct mss_qspi_config *s = dev->config;
struct mss_qspi_data *data = dev->data;
struct spi_context *ctx = &data->ctx;
uint32_t count, ctrl, temp;
ctrl = mss_qspi_read(s, MSS_QSPI_REG_CONTROL);
ctrl |= MSS_QSPI_CONTROL_FLAGSX4;
mss_qspi_write(s, ctrl, MSS_QSPI_REG_CONTROL);
for (count = 0; count < len / 4; ++count) {
while ((mss_qspi_read(s, MSS_QSPI_REG_STATUS)
& MSS_QSPI_STATUS_RXFIFOEMPTY))
;
if (spi_context_rx_buf_on(ctx)) {
temp = mss_qspi_read(s, MSS_QSPI_REG_X4_RX_DATA);
UNALIGNED_PUT(temp, (uint32_t *)ctx->rx_buf);
spi_context_update_rx(ctx, 1, 4);
}
}
}
static inline void mss_qspi_receive_x8(const struct device *dev, uint32_t len)
{
const struct mss_qspi_config *s = dev->config;
struct mss_qspi_data *data = dev->data;
struct spi_context *ctx = &data->ctx;
uint32_t rdata, count;
rdata = mss_qspi_read(s, MSS_QSPI_REG_CONTROL);
rdata &= ~MSS_QSPI_CONTROL_FLAGSX4;
mss_qspi_write(s, rdata, MSS_QSPI_REG_CONTROL);
for (count = 0; count < len; ++count) {
while (mss_qspi_read(s, MSS_QSPI_REG_STATUS)
& MSS_QSPI_STATUS_RXFIFOEMPTY)
;
if (spi_context_rx_buf_on(ctx)) {
rdata = mss_qspi_read(s, MSS_QSPI_REG_RX_DATA);
UNALIGNED_PUT(rdata, (uint8_t *)ctx->rx_buf);
spi_context_update_rx(ctx, 1, 1);
}
}
}
static inline void mss_qspi_config_frames(const struct device *dev,
uint32_t total_bytes,
uint32_t cmd_bytes, bool x8)
{
const struct mss_qspi_config *s = dev->config;
uint32_t skips;
mss_qspi_write(s, (total_bytes & MSS_QSPI_FRAMESUP_UP_BYTES_MSK),
MSS_QSPI_REG_FRAMESUP);
skips = (total_bytes & MSS_QSPI_FRAMESUP_LO_BYTES_MSK);
if (cmd_bytes) {
skips |= ((cmd_bytes << MSS_QSPI_FRAMES_CMDBYTES) & MSS_QSPI_FRAMES_CMDBYTES_MSK);
} else {
skips |= ((total_bytes << MSS_QSPI_FRAMES_CMDBYTES) & MSS_QSPI_FRAMES_CMDBYTES_MSK);
}
if (mss_qspi_read(s, MSS_QSPI_REG_CONTROL) & MSS_QSPI_CONTROL_MODE0)
skips |= MSS_QSPI_FRAMES_QSPI;
skips &= ~MSS_QSPI_FRAMES_IDLE_MSK;
if (x8)
skips |= MSS_QSPI_FRAMES_FLAGBYTE;
else
skips |= MSS_QSPI_FRAMES_FLAGWORD;
mss_qspi_write(s, skips, MSS_QSPI_REG_FRAMES);
}
static inline void mss_qspi_transmit(const struct device *dev)
{
const struct mss_qspi_config *s = dev->config;
struct mss_qspi_data *data = dev->data;
struct spi_context *ctx = &data->ctx;
uint32_t total_byte_cnt, cmd_bytes;
cmd_bytes = spi_context_longest_current_buf(ctx);
total_byte_cnt = spi_context_total_tx_len(ctx);
/*
* As per the MSS QSPI IP spec,
* The number of command and data bytes are controlled by the frames register
* for each SPI sequence. This supports the SPI flash memory read and writes
* sequences as below. so configure the cmd and total bytes accordingly.
* ---------------------------------------------------------------------
* TOTAL BYTES | CMD BYTES | What happens |
* ______________________________________________________________________
* | | |
* 1 | 1 | The SPI core will transmit a single byte |
* | | and receive data is discarded |
* | | |
* 1 | 0 | The SPI core will transmit a single byte |
* | | and return a single byte |
* | | |
* 10 | 4 | The SPI core will transmit 4 command |
* | | bytes discarding the receive data and |
* | | transmits 6 dummy bytes returning the 6 |
* | | received bytes and return a single byte |
* | | |
* 10 | 10 | The SPI core will transmit 10 command |
* | | |
* 10 | 0 | The SPI core will transmit 10 command |
* | | bytes and returning 10 received bytes |
* ______________________________________________________________________
*/
if (!ctx->rx_buf) {
if (total_byte_cnt - cmd_bytes) {
mss_qspi_config_frames(dev, total_byte_cnt, 0, false);
mss_qspi_transmit_x8(dev, cmd_bytes);
mss_qspi_transmit_x32(dev, (total_byte_cnt - cmd_bytes));
} else {
mss_qspi_config_frames(dev, total_byte_cnt, cmd_bytes, true);
mss_qspi_transmit_x8(dev, cmd_bytes);
}
} else {
mss_qspi_config_frames(dev, total_byte_cnt, cmd_bytes, true);
mss_qspi_transmit_x8(dev, cmd_bytes);
}
mss_qspi_enable_ints(s);
}
static inline void mss_qspi_receive(const struct device *dev)
{
const struct mss_qspi_config *s = dev->config;
struct mss_qspi_data *data = dev->data;
struct spi_context *ctx = &data->ctx;
uint32_t rd_bytes, skips, idx, rdata;
/*
* Point the rx buffer where the actual read data
* will be stored
*/
spi_context_update_rx(ctx, 1, ctx->rx_len);
rd_bytes = spi_context_longest_current_buf(ctx);
if (rd_bytes) {
if (rd_bytes >= 4)
mss_qspi_receive_x32(dev, rd_bytes);
skips = mss_qspi_read(s, MSS_QSPI_REG_CONTROL);
skips &= ~MSS_QSPI_CONTROL_FLAGSX4;
mss_qspi_write(s, skips, MSS_QSPI_REG_CONTROL);
idx = (rd_bytes - (rd_bytes % 4u));
for (; idx < rd_bytes; ++idx) {
while (mss_qspi_read(s, MSS_QSPI_REG_STATUS) & MSS_QSPI_STATUS_RXFIFOEMPTY)
;
if (spi_context_rx_buf_on(ctx)) {
rdata = mss_qspi_read(s, MSS_QSPI_REG_RX_DATA);
UNALIGNED_PUT(rdata, (uint8_t *)ctx->rx_buf);
spi_context_update_rx(ctx, 1, 1);
}
}
}
}
static inline int mss_qspi_clk_gen_set(const struct mss_qspi_config *s,
const struct spi_config *spi_cfg)
{
uint32_t control = mss_qspi_read(s, MSS_QSPI_REG_CONTROL);
uint32_t idx, clkrate, val = 0, speed;
if (spi_cfg->frequency > s->clock_freq)
speed = s->clock_freq / 2;
for (idx = 1; idx < 16; idx++) {
clkrate = s->clock_freq / (2 * idx);
if (clkrate <= spi_cfg->frequency) {
val = idx;
break;
}
}
if (val) {
control = mss_qspi_read(s, MSS_QSPI_REG_CONTROL);
control &= ~MSS_QSPI_CONTROL_CLKRATE_MSK;
control |= (val << MSS_QSPI_CONTROL_CLKRATE);
mss_qspi_write(s, control, MSS_QSPI_REG_CONTROL);
} else {
return -1;
}
return 0;
}
static inline int mss_qspi_hw_mode_set(const struct mss_qspi_config *s,
uint16_t mode)
{
uint32_t ctrl = mss_qspi_read(s, MSS_QSPI_REG_CONTROL);
if ((mode & SPI_MODE_CPHA) && (mode & SPI_MODE_CPOL)) {
/* mode 3 */
ctrl |= MSS_QSPI_CONTROL_CLKIDLE;
} else if (!(mode & SPI_MODE_CPHA) && !(mode & SPI_MODE_CPOL)) {
/* mode 0 */
ctrl &= ~MSS_QSPI_CONTROL_CLKIDLE;
} else {
return -1;
}
if ((mode & SPI_LINES_QUAD)) {
/* Quad mode */
ctrl &= ~(MSS_QSPI_CONTROL_MODE0);
ctrl |= (MSS_QSPI_CONTROL_MODE_EXQUAD);
} else if ((mode & SPI_LINES_DUAL)) {
/* Dual mode */
ctrl &= ~(MSS_QSPI_CONTROL_MODE0);
ctrl |= (MSS_QSPI_CONTROL_MODE_EXDUAL);
} else {
/* Normal mode */
ctrl &= ~(MSS_QSPI_CONTROL_MODE0);
}
mss_qspi_write(s, ctrl, MSS_QSPI_REG_CONTROL);
return 0;
}
static int mss_qspi_release(const struct device *dev,
const struct spi_config *config)
{
struct mss_qspi_data *data = dev->data;
const struct mss_qspi_config *cfg = dev->config;
uint32_t control = mss_qspi_read(cfg, MSS_QSPI_REG_CONTROL);
mss_qspi_disable_ints(cfg);
control &= ~MSS_QSPI_CONTROL_ENABLE;
mss_qspi_write(cfg, control, MSS_QSPI_REG_CONTROL);
spi_context_unlock_unconditionally(&data->ctx);
return 0;
}
static void mss_qspi_interrupt(const struct device *dev)
{
const struct mss_qspi_config *cfg = dev->config;
struct mss_qspi_data *data = dev->data;
struct spi_context *ctx = &data->ctx;
int intfield = mss_qspi_read(cfg, MSS_QSPI_REG_STATUS);
int ienfield = mss_qspi_read(cfg, MSS_QSPI_REG_IEN);
if ((intfield & ienfield) == 0)
return;
if (intfield & MSS_QSPI_IEN_TXDONE) {
mss_qspi_write(cfg, MSS_QSPI_IEN_TXDONE, MSS_QSPI_REG_STATUS);
}
if (intfield & MSS_QSPI_IEN_RXAVAILABLE) {
mss_qspi_write(cfg, MSS_QSPI_IEN_RXAVAILABLE, MSS_QSPI_REG_STATUS);
mss_qspi_receive(dev);
}
if ((intfield & MSS_QSPI_IEN_RXDONE)) {
mss_qspi_write(cfg, MSS_QSPI_IEN_RXDONE, MSS_QSPI_REG_STATUS);
spi_context_complete(ctx, 0);
}
if (intfield & MSS_QSPI_IEN_TXAVAILABLE) {
mss_qspi_write(cfg, MSS_QSPI_IEN_TXAVAILABLE, MSS_QSPI_REG_STATUS);
}
if (intfield & MSS_QSPI_IEN_RXFIFOEMPTY) {
mss_qspi_write(cfg, MSS_QSPI_IEN_RXFIFOEMPTY, MSS_QSPI_REG_STATUS);
}
if (intfield & MSS_QSPI_IEN_TXFIFOFULL) {
mss_qspi_write(cfg, MSS_QSPI_IEN_TXFIFOFULL, MSS_QSPI_REG_STATUS);
}
}
static int mss_qspi_configure(const struct device *dev,
const struct spi_config *spi_cfg)
{
const struct mss_qspi_config *cfg = dev->config;
if (spi_cfg->operation & SPI_OP_MODE_SLAVE) {
LOG_ERR("Slave mode is not supported\n\r");
return -ENOTSUP;
}
if (spi_cfg->operation & SPI_MODE_LOOP) {
LOG_ERR("Loop back mode is not supported\n\r");
return -ENOTSUP;
}
if (spi_cfg->operation & (SPI_TRANSFER_LSB) ||
((IS_ENABLED(CONFIG_SPI_EXTENDED_MODES) &&
(spi_cfg->operation & (SPI_LINES_DUAL |
SPI_LINES_QUAD |
SPI_LINES_OCTAL))))) {
LOG_ERR("Unsupported configuration\n\r");
return -ENOTSUP;
}
if (mss_qspi_clk_gen_set(cfg, spi_cfg)) {
LOG_ERR("can't set clk divider\n");
return -EINVAL;
}
return 0;
}
static int mss_qspi_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, struct k_poll_signal *sig)
{
const struct mss_qspi_config *config = dev->config;
struct mss_qspi_data *data = dev->data;
struct spi_context *ctx = &data->ctx;
int ret = 0;
spi_context_lock(ctx, async, sig, spi_cfg);
ret = mss_qspi_configure(dev, spi_cfg);
if (ret) {
goto out;
}
mss_qspi_hw_mode_set(config, spi_cfg->operation);
spi_context_buffers_setup(ctx, tx_bufs, rx_bufs,
1);
mss_qspi_transmit(dev);
ret = spi_context_wait_for_completion(ctx);
out:
spi_context_release(ctx, ret);
mss_qspi_disable_ints(config);
return ret;
}
static int mss_qspi_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_qspi_transceive(dev, spi_cfg, tx_bufs, rx_bufs, false,
NULL);
}
#ifdef CONFIG_SPI_ASYNC
static int mss_qspi_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,
struct k_poll_signal *async)
{
return mss_qspi_transceive(dev, spi_cfg, tx_bufs, rx_bufs, true,
async);
}
#endif /* CONFIG_SPI_ASYNC */
static int mss_qspi_init(const struct device *dev)
{
const struct mss_qspi_config *cfg = dev->config;
struct mss_qspi_data *data = dev->data;
unsigned int ret = 0;
uint32_t control = 0;
cfg->irq_config_func(dev);
control &= ~(MSS_QSPI_CONTROL_SAMPLE_MSK);
control &= ~(MSS_QSPI_CONTROL_MODE0);
control |= (MSS_QSPI_CONTROL_CLKRATE_MSK);
control &= ~(MSS_QSPI_CONTROL_XIP);
control |= (MSS_QSPI_CONTROL_CLKIDLE | MSS_QSPI_CONTROL_ENABLE);
mss_qspi_write(cfg, control, MSS_QSPI_REG_CONTROL);
mss_qspi_disable_ints(cfg);
spi_context_unlock_unconditionally(&data->ctx);
return ret;
}
static const struct spi_driver_api mss_qspi_driver_api = {
.transceive = mss_qspi_transceive_blocking,
#ifdef CONFIG_SPI_ASYNC
.transceive_async = mss_qspi_transceive_async,
#endif /* CONFIG_SPI_ASYNC */
.release = mss_qspi_release,
};
#define MSS_QSPI_INIT(n) \
static void mss_qspi_config_func_##n(const struct device *dev); \
\
static const struct mss_qspi_config mss_qspi_config_##n = { \
.base = DT_INST_REG_ADDR(n), \
.irq_config_func = mss_qspi_config_func_##n, \
.clock_freq = DT_INST_PROP(n, clock_frequency), \
}; \
\
static struct mss_qspi_data mss_qspi_data_##n = { \
SPI_CONTEXT_INIT_LOCK(mss_qspi_data_##n, ctx), \
SPI_CONTEXT_INIT_SYNC(mss_qspi_data_##n, ctx), \
}; \
\
DEVICE_DT_INST_DEFINE(n, &mss_qspi_init, \
NULL, \
&mss_qspi_data_##n, \
&mss_qspi_config_##n, POST_KERNEL, \
CONFIG_KERNEL_INIT_PRIORITY_DEVICE, \
&mss_qspi_driver_api); \
\
static void mss_qspi_config_func_##n(const struct device *dev) \
{ \
IRQ_CONNECT(DT_INST_IRQN(n), DT_INST_IRQ(n, priority), \
mss_qspi_interrupt, \
DEVICE_DT_INST_GET(n), 0); \
irq_enable(DT_INST_IRQN(n)); \
}
DT_INST_FOREACH_STATUS_OKAY(MSS_QSPI_INIT)