zephyr/drivers/spi/spi_dw.c
Maureen Helm 55caa7b743 drivers: spi: Select HAS_DTS_SPI in designware driver
Makes the designware spi driver consistent with other spi drivers by
selecting HAS_DTS_SPI in the driver. This required adding spi nodes and
dts fixups to several arc and x86 socs, as well as enabling those nodes
in associated boards.

Also refactors the driver to use the base address, interrupt number, and
interrupt priority from dts.

Signed-off-by: Maureen Helm <maureen.helm@nxp.com>
2018-09-28 06:27:06 +05:30

725 lines
19 KiB
C

/* spi_dw.c - Designware SPI driver implementation */
/*
* Copyright (c) 2015 Intel Corporation.
*
* SPDX-License-Identifier: Apache-2.0
*/
#define SYS_LOG_DOMAIN "SPI DW"
#define SYS_LOG_LEVEL CONFIG_SYS_LOG_SPI_LEVEL
#include <logging/sys_log.h>
#if (CONFIG_SYS_LOG_SPI_LEVEL == 4)
#define DBG_COUNTER_INIT() \
u32_t __cnt = 0
#define DBG_COUNTER_INC() \
(__cnt++)
#define DBG_COUNTER_RESULT() \
(__cnt)
#else
#define DBG_COUNTER_INIT() {; }
#define DBG_COUNTER_INC() {; }
#define DBG_COUNTER_RESULT() 0
#endif
#include <errno.h>
#include <kernel.h>
#include <arch/cpu.h>
#include <board.h>
#include <device.h>
#include <init.h>
#include <sys_io.h>
#include <clock_control.h>
#include <misc/util.h>
#ifdef CONFIG_IOAPIC
#include <drivers/ioapic.h>
#endif
#include <spi.h>
#include "spi_dw.h"
#include "spi_context.h"
static inline bool spi_dw_is_slave(struct spi_dw_data *spi)
{
return (IS_ENABLED(CONFIG_SPI_SLAVE) &&
spi_context_is_slave(&spi->ctx));
}
static void completed(struct device *dev, int error)
{
const struct spi_dw_config *info = dev->config->config_info;
struct spi_dw_data *spi = dev->driver_data;
if (error) {
goto out;
}
if (spi_context_tx_on(&spi->ctx) ||
spi_context_rx_on(&spi->ctx)) {
return;
}
out:
/* need to give time for FIFOs to drain before issuing more commands */
while (test_bit_sr_busy(info->regs)) {
}
/* Disabling interrupts */
write_imr(DW_SPI_IMR_MASK, info->regs);
/* Disabling the controller */
clear_bit_ssienr(info->regs);
spi_context_cs_control(&spi->ctx, false);
SYS_LOG_DBG("SPI transaction completed %s error",
error ? "with" : "without");
spi_context_complete(&spi->ctx, error);
}
static void push_data(struct device *dev)
{
const struct spi_dw_config *info = dev->config->config_info;
struct spi_dw_data *spi = dev->driver_data;
u32_t data = 0;
u32_t f_tx;
DBG_COUNTER_INIT();
if (spi_context_rx_on(&spi->ctx)) {
f_tx = DW_SPI_FIFO_DEPTH - read_txflr(info->regs) -
read_rxflr(info->regs);
if ((int)f_tx < 0) {
f_tx = 0; /* if rx-fifo is full, hold off tx */
}
} else {
f_tx = DW_SPI_FIFO_DEPTH - read_txflr(info->regs);
}
while (f_tx) {
if (spi_context_tx_buf_on(&spi->ctx)) {
switch (spi->dfs) {
case 1:
data = UNALIGNED_GET((u8_t *)
(spi->ctx.tx_buf));
break;
case 2:
data = UNALIGNED_GET((u16_t *)
(spi->ctx.tx_buf));
break;
#ifndef CONFIG_ARC
case 4:
data = UNALIGNED_GET((u32_t *)
(spi->ctx.tx_buf));
break;
#endif
}
} else if (spi_context_rx_on(&spi->ctx)) {
/* No need to push more than necessary */
if ((int)(spi->ctx.rx_len - spi->fifo_diff) <= 0) {
break;
}
data = 0;
} else if (spi_context_tx_on(&spi->ctx)) {
data = 0;
} else {
/* Nothing to push anymore */
break;
}
write_dr(data, info->regs);
spi_context_update_tx(&spi->ctx, spi->dfs, 1);
spi->fifo_diff++;
f_tx--;
DBG_COUNTER_INC();
}
if (!spi_context_tx_on(&spi->ctx)) {
/* prevents any further interrupts demanding TX fifo fill */
write_txftlr(0, info->regs);
}
SYS_LOG_DBG("Pushed: %d", DBG_COUNTER_RESULT());
}
static void pull_data(struct device *dev)
{
const struct spi_dw_config *info = dev->config->config_info;
struct spi_dw_data *spi = dev->driver_data;
DBG_COUNTER_INIT();
while (read_rxflr(info->regs)) {
u32_t data = read_dr(info->regs);
DBG_COUNTER_INC();
if (spi_context_rx_buf_on(&spi->ctx)) {
switch (spi->dfs) {
case 1:
UNALIGNED_PUT(data, (u8_t *)spi->ctx.rx_buf);
break;
case 2:
UNALIGNED_PUT(data, (u16_t *)spi->ctx.rx_buf);
break;
#ifndef CONFIG_ARC
case 4:
UNALIGNED_PUT(data, (u32_t *)spi->ctx.rx_buf);
break;
#endif
}
}
spi_context_update_rx(&spi->ctx, spi->dfs, 1);
spi->fifo_diff--;
}
if (!spi->ctx.rx_len && spi->ctx.tx_len < DW_SPI_FIFO_DEPTH) {
write_rxftlr(spi->ctx.tx_len - 1, info->regs);
} else if (read_rxftlr(info->regs) >= spi->ctx.rx_len) {
write_rxftlr(spi->ctx.rx_len - 1, info->regs);
}
SYS_LOG_DBG("Pulled: %d", DBG_COUNTER_RESULT());
}
static int spi_dw_configure(const struct spi_dw_config *info,
struct spi_dw_data *spi,
const struct spi_config *config)
{
u32_t ctrlr0 = 0;
SYS_LOG_DBG("%p (prev %p)", config, spi->ctx.config);
if (spi_context_configured(&spi->ctx, config)) {
/* Nothing to do */
return 0;
}
/* Verify if requested op mode is relevant to this controller */
if (config->operation & SPI_OP_MODE_SLAVE) {
if (!(info->op_modes & SPI_CTX_RUNTIME_OP_MODE_SLAVE)) {
SYS_LOG_ERR("Slave mode not supported");
return -ENOTSUP;
}
} else {
if (!(info->op_modes & SPI_CTX_RUNTIME_OP_MODE_MASTER)) {
SYS_LOG_ERR("Master mode not supported");
return -ENOTSUP;
}
}
if (config->operation & (SPI_TRANSFER_LSB |
SPI_LINES_DUAL | SPI_LINES_QUAD)) {
SYS_LOG_ERR("Unsupported configuration");
return -EINVAL;
}
/* Word size */
ctrlr0 |= DW_SPI_CTRLR0_DFS(SPI_WORD_SIZE_GET(config->operation));
/* Determine how many bytes are required per-frame */
spi->dfs = SPI_WS_TO_DFS(SPI_WORD_SIZE_GET(config->operation));
/* SPI mode */
if (SPI_MODE_GET(config->operation) & SPI_MODE_CPOL) {
ctrlr0 |= DW_SPI_CTRLR0_SCPOL;
}
if (SPI_MODE_GET(config->operation) & SPI_MODE_CPHA) {
ctrlr0 |= DW_SPI_CTRLR0_SCPH;
}
if (SPI_MODE_GET(config->operation) & SPI_MODE_LOOP) {
ctrlr0 |= DW_SPI_CTRLR0_SRL;
}
/* Installing the configuration */
write_ctrlr0(ctrlr0, info->regs);
/* At this point, it's mandatory to set this on the context! */
spi->ctx.config = config;
if (!spi_dw_is_slave(spi)) {
/* Baud rate and Slave select, for master only */
write_baudr(SPI_DW_CLK_DIVIDER(config->frequency), info->regs);
write_ser(1 << config->slave, info->regs);
}
spi_context_cs_configure(&spi->ctx);
if (spi_dw_is_slave(spi)) {
SYS_LOG_DBG("Installed slave config %p:"
" ws/dfs %u/%u, mode %u/%u/%u",
config,
SPI_WORD_SIZE_GET(config->operation), spi->dfs,
(SPI_MODE_GET(config->operation) &
SPI_MODE_CPOL) ? 1 : 0,
(SPI_MODE_GET(config->operation) &
SPI_MODE_CPHA) ? 1 : 0,
(SPI_MODE_GET(config->operation) &
SPI_MODE_LOOP) ? 1 : 0);
} else {
SYS_LOG_DBG("Installed master config %p: freq %uHz (div = %u),"
" ws/dfs %u/%u, mode %u/%u/%u, slave %u",
config, config->frequency,
SPI_DW_CLK_DIVIDER(config->frequency),
SPI_WORD_SIZE_GET(config->operation), spi->dfs,
(SPI_MODE_GET(config->operation) &
SPI_MODE_CPOL) ? 1 : 0,
(SPI_MODE_GET(config->operation) &
SPI_MODE_CPHA) ? 1 : 0,
(SPI_MODE_GET(config->operation) &
SPI_MODE_LOOP) ? 1 : 0,
config->slave);
}
return 0;
}
static uint32_t spi_dw_compute_ndf(const struct spi_buf *rx_bufs,
size_t rx_count, u8_t dfs)
{
u32_t len = 0;
for (; rx_count; rx_bufs++, rx_count--) {
if (len > (UINT16_MAX - rx_bufs->len)) {
goto error;
}
len += rx_bufs->len;
}
if (len) {
return (len / dfs) - 1;
}
error:
return UINT32_MAX;
}
static void spi_dw_update_txftlr(const struct spi_dw_config *info,
struct spi_dw_data *spi)
{
u32_t reg_data = DW_SPI_TXFTLR_DFLT;
if (spi_dw_is_slave(spi)) {
if (!spi->ctx.tx_len) {
reg_data = 0;
} else if (spi->ctx.tx_len < DW_SPI_TXFTLR_DFLT) {
reg_data = spi->ctx.tx_len - 1;
}
}
SYS_LOG_DBG("TxFTLR: %u", reg_data);
write_txftlr(reg_data, info->regs);
}
static int transceive(struct device *dev,
const struct spi_config *config,
const struct spi_buf_set *tx_bufs,
const struct spi_buf_set *rx_bufs,
bool asynchronous,
struct k_poll_signal *signal)
{
const struct spi_dw_config *info = dev->config->config_info;
struct spi_dw_data *spi = dev->driver_data;
u32_t tmod = DW_SPI_CTRLR0_TMOD_TX_RX;
u32_t reg_data;
int ret;
spi_context_lock(&spi->ctx, asynchronous, signal);
/* Configure */
ret = spi_dw_configure(info, spi, config);
if (ret) {
goto out;
}
if (!rx_bufs || !rx_bufs->buffers) {
tmod = DW_SPI_CTRLR0_TMOD_TX;
} else if (!tx_bufs || !tx_bufs->buffers) {
tmod = DW_SPI_CTRLR0_TMOD_RX;
}
/* ToDo: add a way to determine EEPROM mode */
if (tmod >= DW_SPI_CTRLR0_TMOD_RX &&
!spi_dw_is_slave(spi)) {
reg_data = spi_dw_compute_ndf(rx_bufs->buffers,
rx_bufs->count,
spi->dfs);
if (reg_data == UINT32_MAX) {
ret = -EINVAL;
goto out;
}
write_ctrlr1(reg_data, info->regs);
} else {
write_ctrlr1(0, info->regs);
}
if (spi_dw_is_slave(spi)) {
/* Enabling MISO line relevantly */
if (tmod == DW_SPI_CTRLR0_TMOD_RX) {
tmod |= DW_SPI_CTRLR0_SLV_OE;
} else {
tmod &= ~DW_SPI_CTRLR0_SLV_OE;
}
}
/* Updating TMOD in CTRLR0 register */
reg_data = read_ctrlr0(info->regs);
reg_data &= ~DW_SPI_CTRLR0_TMOD_RESET;
reg_data |= tmod;
write_ctrlr0(reg_data, info->regs);
/* Set buffers info */
spi_context_buffers_setup(&spi->ctx, tx_bufs, rx_bufs, spi->dfs);
spi->fifo_diff = 0;
/* Tx Threshold */
spi_dw_update_txftlr(info, spi);
/* Does Rx thresholds needs to be lower? */
reg_data = DW_SPI_RXFTLR_DFLT;
if (spi_dw_is_slave(spi)) {
if (spi->ctx.rx_len &&
spi->ctx.rx_len < DW_SPI_RXFTLR_DFLT) {
reg_data = spi->ctx.rx_len - 1;
}
} else {
if (spi->ctx.rx_len && spi->ctx.rx_len < DW_SPI_FIFO_DEPTH) {
reg_data = spi->ctx.rx_len - 1;
}
}
/* Rx Threshold */
write_rxftlr(reg_data, info->regs);
/* Enable interrupts */
reg_data = !rx_bufs ?
DW_SPI_IMR_UNMASK & DW_SPI_IMR_MASK_RX :
DW_SPI_IMR_UNMASK;
write_imr(reg_data, info->regs);
SYS_LOG_DBG("Ctrlr0 0x%08x Ctrlr1 0x%04x Txftlr 0x%08x"
" Rxftlr 0x%08x Imr 0x%02x",
read_ctrlr0(info->regs), read_ctrlr1(info->regs),
read_txftlr(info->regs), read_rxftlr(info->regs),
read_imr(info->regs));
spi_context_cs_control(&spi->ctx, true);
SYS_LOG_DBG("Enabling controller");
set_bit_ssienr(info->regs);
ret = spi_context_wait_for_completion(&spi->ctx);
out:
spi_context_release(&spi->ctx, ret);
return ret;
}
static int spi_dw_transceive(struct device *dev,
const struct spi_config *config,
const struct spi_buf_set *tx_bufs,
const struct spi_buf_set *rx_bufs)
{
SYS_LOG_DBG("%p, %p, %p", dev, tx_bufs, rx_bufs);
return transceive(dev, config, tx_bufs, rx_bufs, false, NULL);
}
#ifdef CONFIG_SPI_ASYNC
static int spi_dw_transceive_async(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)
{
SYS_LOG_DBG("%p, %p, %p, %p", dev, tx_bufs, rx_bufs, async);
return transceive(dev, config, tx_bufs, rx_bufs, true, async);
}
#endif /* CONFIG_SPI_ASYNC */
static int spi_dw_release(struct device *dev, const struct spi_config *config)
{
struct spi_dw_data *spi = dev->driver_data;
if (!spi_context_configured(&spi->ctx, config)) {
return -EINVAL;
}
spi_context_unlock_unconditionally(&spi->ctx);
return 0;
}
void spi_dw_isr(struct device *dev)
{
const struct spi_dw_config *info = dev->config->config_info;
u32_t int_status;
int error;
int_status = read_isr(info->regs);
SYS_LOG_DBG("SPI %p int_status 0x%x - (tx: %d, rx: %d)", dev,
int_status, read_txflr(info->regs), read_rxflr(info->regs));
if (int_status & DW_SPI_ISR_ERRORS_MASK) {
error = -EIO;
goto out;
}
error = 0;
if (int_status & DW_SPI_ISR_RXFIS) {
pull_data(dev);
}
if (int_status & DW_SPI_ISR_TXEIS) {
push_data(dev);
}
out:
clear_interrupts(info->regs);
completed(dev, error);
}
static const struct spi_driver_api dw_spi_api = {
.transceive = spi_dw_transceive,
#ifdef CONFIG_SPI_ASYNC
.transceive_async = spi_dw_transceive_async,
#endif /* CONFIG_SPI_ASYNC */
.release = spi_dw_release,
};
int spi_dw_init(struct device *dev)
{
const struct spi_dw_config *info = dev->config->config_info;
struct spi_dw_data *spi = dev->driver_data;
_clock_config(dev);
_clock_on(dev);
info->config_func();
/* Masking interrupt and making sure controller is disabled */
write_imr(DW_SPI_IMR_MASK, info->regs);
clear_bit_ssienr(info->regs);
SYS_LOG_DBG("Designware SPI driver initialized on device: %p", dev);
spi_context_unlock_unconditionally(&spi->ctx);
return 0;
}
#ifdef CONFIG_SPI_0
void spi_config_0_irq(void);
struct spi_dw_data spi_dw_data_port_0 = {
SPI_CONTEXT_INIT_LOCK(spi_dw_data_port_0, ctx),
SPI_CONTEXT_INIT_SYNC(spi_dw_data_port_0, ctx),
};
const struct spi_dw_config spi_dw_config_0 = {
.regs = CONFIG_SPI_0_BASE_ADDRESS,
#ifdef CONFIG_SPI_DW_PORT_0_CLOCK_GATE
.clock_name = CONFIG_SPI_DW_PORT_1_CLOCK_GATE_DRV_NAME,
.clock_data = UINT_TO_POINTER(CONFIG_SPI_DW_PORT_0_CLOCK_GATE_SUBSYS),
#endif /* CONFIG_SPI_DW_PORT_0_CLOCK_GATE */
.config_func = spi_config_0_irq,
.op_modes = CONFIG_SPI_0_OP_MODES
};
DEVICE_AND_API_INIT(spi_dw_port_0, CONFIG_SPI_0_NAME, spi_dw_init,
&spi_dw_data_port_0, &spi_dw_config_0,
POST_KERNEL, CONFIG_SPI_INIT_PRIORITY,
&dw_spi_api);
void spi_config_0_irq(void)
{
#ifdef CONFIG_SPI_DW_PORT_0_INTERRUPT_SINGLE_LINE
IRQ_CONNECT(CONFIG_SPI_0_IRQ, CONFIG_SPI_0_IRQ_PRI,
spi_dw_isr, DEVICE_GET(spi_dw_port_0), SPI_DW_IRQ_FLAGS);
irq_enable(CONFIG_SPI_0_IRQ);
_spi_int_unmask(SPI_DW_PORT_0_INT_MASK);
#else
IRQ_CONNECT(CONFIG_SPI_0_IRQ_RX_AVAIL, CONFIG_SPI_0_IRQ_RX_AVAIL_PRI,
spi_dw_isr, DEVICE_GET(spi_dw_port_0), SPI_DW_IRQ_FLAGS);
IRQ_CONNECT(CONFIG_SPI_0_IRQ_TX_REQ, CONFIG_SPI_0_IRQ_TX_REQ_PRI,
spi_dw_isr, DEVICE_GET(spi_dw_port_0), SPI_DW_IRQ_FLAGS);
IRQ_CONNECT(CONFIG_SPI_0_IRQ_ERR_INT, CONFIG_SPI_0_IRQ_ERR_INT_PRI,
spi_dw_isr, DEVICE_GET(spi_dw_port_0), SPI_DW_IRQ_FLAGS);
irq_enable(CONFIG_SPI_0_IRQ_RX_AVAIL);
irq_enable(CONFIG_SPI_0_IRQ_TX_REQ);
irq_enable(CONFIG_SPI_0_IRQ_ERR_INT);
_spi_int_unmask(SPI_DW_PORT_0_RX_INT_MASK);
_spi_int_unmask(SPI_DW_PORT_0_TX_INT_MASK);
_spi_int_unmask(SPI_DW_PORT_0_ERROR_INT_MASK);
#endif
}
#endif /* CONFIG_SPI_0 */
#ifdef CONFIG_SPI_1
void spi_config_1_irq(void);
struct spi_dw_data spi_dw_data_port_1 = {
SPI_CONTEXT_INIT_LOCK(spi_dw_data_port_1, ctx),
SPI_CONTEXT_INIT_SYNC(spi_dw_data_port_1, ctx),
};
static const struct spi_dw_config spi_dw_config_1 = {
.regs = CONFIG_SPI_1_BASE_ADDRESS,
#ifdef CONFIG_SPI_DW_PORT_1_CLOCK_GATE
.clock_name = CONFIG_SPI_DW_PORT_1_CLOCK_GATE_DRV_NAME,
.clock_data = UINT_TO_POINTER(CONFIG_SPI_DW_PORT_1_CLOCK_GATE_SUBSYS),
#endif /* CONFIG_SPI_DW_PORT_1_CLOCK_GATE */
.config_func = spi_config_1_irq,
.op_modes = CONFIG_SPI_1_OP_MODES
};
DEVICE_AND_API_INIT(spi_dw_port_1, CONFIG_SPI_1_NAME, spi_dw_init,
&spi_dw_data_port_1, &spi_dw_config_1,
POST_KERNEL, CONFIG_SPI_INIT_PRIORITY,
&dw_spi_api);
void spi_config_1_irq(void)
{
#ifdef CONFIG_SPI_DW_PORT_1_INTERRUPT_SINGLE_LINE
IRQ_CONNECT(CONFIG_SPI_1_IRQ, CONFIG_SPI_1_IRQ_PRI,
spi_dw_isr, DEVICE_GET(spi_dw_port_1), SPI_DW_IRQ_FLAGS);
irq_enable(CONFIG_SPI_1_IRQ);
_spi_int_unmask(SPI_DW_PORT_1_INT_MASK);
#else
IRQ_CONNECT(CONFIG_SPI_1_IRQ_RX_AVAIL, CONFIG_SPI_1_IRQ_RX_AVAIL_PRI,
spi_dw_isr, DEVICE_GET(spi_dw_port_1), SPI_DW_IRQ_FLAGS);
IRQ_CONNECT(CONFIG_SPI_1_IRQ_TX_REQ, CONFIG_SPI_1_IRQ_TX_REQ_PRI,
spi_dw_isr, DEVICE_GET(spi_dw_port_1), SPI_DW_IRQ_FLAGS);
IRQ_CONNECT(CONFIG_SPI_1_IRQ_ERR_INT, CONFIG_SPI_1_IRQ_ERR_INT_PRI,
spi_dw_isr, DEVICE_GET(spi_dw_port_1), SPI_DW_IRQ_FLAGS);
irq_enable(CONFIG_SPI_1_IRQ_RX_AVAIL);
irq_enable(CONFIG_SPI_1_IRQ_TX_REQ);
irq_enable(CONFIG_SPI_1_IRQ_ERR_INT);
_spi_int_unmask(SPI_DW_PORT_1_RX_INT_MASK);
_spi_int_unmask(SPI_DW_PORT_1_TX_INT_MASK);
_spi_int_unmask(SPI_DW_PORT_1_ERROR_INT_MASK);
#endif
}
#endif /* CONFIG_SPI_1 */
#ifdef CONFIG_SPI_2
void spi_config_2_irq(void);
struct spi_dw_data spi_dw_data_port_2 = {
SPI_CONTEXT_INIT_LOCK(spi_dw_data_port_2, ctx),
SPI_CONTEXT_INIT_SYNC(spi_dw_data_port_2, ctx),
};
static const struct spi_dw_config spi_dw_config_2 = {
.regs = CONFIG_SPI_2_BASE_ADDRESS,
#ifdef CONFIG_SPI_DW_PORT_2_CLOCK_GATE
.clock_name = CONFIG_SPI_DW_PORT_2_CLOCK_GATE_DRV_NAME,
.clock_data = UINT_TO_POINTER(CONFIG_SPI_DW_PORT_2_CLOCK_GATE_SUBSYS),
#endif /* CONFIG_SPI_DW_PORT_2_CLOCK_GATE */
.config_func = spi_config_2_irq,
.op_modes = CONFIG_SPI_2_OP_MODES
};
DEVICE_AND_API_INIT(spi_dw_port_2, CONFIG_SPI_2_NAME, spi_dw_init,
&spi_dw_data_port_2, &spi_dw_config_2,
POST_KERNEL, CONFIG_SPI_INIT_PRIORITY,
&dw_spi_api);
void spi_config_2_irq(void)
{
#ifdef CONFIG_SPI_DW_PORT_2_INTERRUPT_SINGLE_LINE
IRQ_CONNECT(CONFIG_SPI_2_IRQ, CONFIG_SPI_2_IRQ_PRI,
spi_dw_isr, DEVICE_GET(spi_dw_port_2), SPI_DW_IRQ_FLAGS);
irq_enable(CONFIG_SPI_2_IRQ);
_spi_int_unmask(SPI_DW_PORT_2_INT_MASK);
#else
IRQ_CONNECT(CONFIG_SPI_2_IRQ_RX_AVAIL, CONFIG_SPI_2_IRQ_RX_AVAIL_PRI,
spi_dw_isr, DEVICE_GET(spi_dw_port_2), SPI_DW_IRQ_FLAGS);
IRQ_CONNECT(CONFIG_SPI_2_IRQ_TX_REQ, CONFIG_SPI_2_IRQ_TX_REQ_PRI,
spi_dw_isr, DEVICE_GET(spi_dw_port_2), SPI_DW_IRQ_FLAGS);
IRQ_CONNECT(CONFIG_SPI_2_IRQ_ERR_INT, CONFIG_SPI_2_IRQ_ERR_INT_PRI,
spi_dw_isr, DEVICE_GET(spi_dw_port_2), SPI_DW_IRQ_FLAGS);
irq_enable(CONFIG_SPI_2_IRQ_RX_AVAIL);
irq_enable(CONFIG_SPI_2_IRQ_TX_REQ);
irq_enable(CONFIG_SPI_2_IRQ_ERR_INT);
_spi_int_unmask(SPI_DW_PORT_2_RX_INT_MASK);
_spi_int_unmask(SPI_DW_PORT_2_TX_INT_MASK);
_spi_int_unmask(SPI_DW_PORT_2_ERROR_INT_MASK);
#endif
}
#endif /* CONFIG_SPI_2 */
#ifdef CONFIG_SPI_3
void spi_config_3_irq(void);
struct spi_dw_data spi_dw_data_port_3 = {
SPI_CONTEXT_INIT_LOCK(spi_dw_data_port_3, ctx),
SPI_CONTEXT_INIT_SYNC(spi_dw_data_port_3, ctx),
};
static const struct spi_dw_config spi_dw_config_3 = {
.regs = CONFIG_SPI_3_BASE_ADDRESS,
#ifdef CONFIG_SPI_DW_PORT_3_CLOCK_GATE
.clock_name = CONFIG_SPI_DW_PORT_3_CLOCK_GATE_DRV_NAME,
.clock_data = UINT_TO_POINTER(CONFIG_SPI_DW_PORT_3_CLOCK_GATE_SUBSYS),
#endif /* CONFIG_SPI_DW_PORT_3_CLOCK_GATE */
.config_func = spi_config_3_irq,
.op_modes = CONFIG_SPI_3_OP_MODES
};
DEVICE_AND_API_INIT(spi_dw_port_3, CONFIG_SPI_3_NAME, spi_dw_init,
&spi_dw_data_port_3, &spi_dw_config_3,
POST_KERNEL, CONFIG_SPI_INIT_PRIORITY,
&dw_spi_api);
void spi_config_3_irq(void)
{
#ifdef CONFIG_SPI_DW_PORT_3_INTERRUPT_SINGLE_LINE
IRQ_CONNECT(CONFIG_SPI_3_IRQ, CONFIG_SPI_3_IRQ_PRI,
spi_dw_isr, DEVICE_GET(spi_dw_port_3), SPI_DW_IRQ_FLAGS);
irq_enable(CONFIG_SPI_3_IRQ);
_spi_int_unmask(SPI_DW_PORT_3_INT_MASK);
#else
IRQ_CONNECT(CONFIG_SPI_3_IRQ_RX_AVAIL, CONFIG_SPI_3_IRQ_RX_AVAIL_PRI,
spi_dw_isr, DEVICE_GET(spi_dw_port_3), SPI_DW_IRQ_FLAGS);
IRQ_CONNECT(CONFIG_SPI_3_IRQ_TX_REQ, CONFIG_SPI_3_IRQ_TX_REQ_PRI,
spi_dw_isr, DEVICE_GET(spi_dw_port_3), SPI_DW_IRQ_FLAGS);
IRQ_CONNECT(CONFIG_SPI_3_IRQ_ERR_INT, CONFIG_SPI_3_IRQ_ERR_INT_PRI,
spi_dw_isr, DEVICE_GET(spi_dw_port_3), SPI_DW_IRQ_FLAGS);
irq_enable(CONFIG_SPI_3_IRQ_RX_AVAIL);
irq_enable(CONFIG_SPI_3_IRQ_TX_REQ);
irq_enable(CONFIG_SPI_3_IRQ_ERR_INT);
_spi_int_unmask(SPI_DW_PORT_3_RX_INT_MASK);
_spi_int_unmask(SPI_DW_PORT_3_TX_INT_MASK);
_spi_int_unmask(SPI_DW_PORT_3_ERROR_INT_MASK);
#endif
}
#endif /* CONFIG_SPI_3 */