drivers : spi : mec1501 : XEC SPI driver
SPI driver for MEC1501 QMSPI supporting synchronous only. Signed-off-by: Scott Worley <scott.worley@microchip.com>
This commit is contained in:
parent
f20084ff1c
commit
c8b1eb79a1
12 changed files with 876 additions and 1 deletions
|
@ -30,7 +30,7 @@ config PINMUX_XEC_GPIO140_176
|
||||||
default y
|
default y
|
||||||
|
|
||||||
config PINMUX_XEC_GPIO200_236
|
config PINMUX_XEC_GPIO200_236
|
||||||
default y if ADC_XEC
|
default y if ADC_XEC || SPI_XEC_QMSPI
|
||||||
default n
|
default n
|
||||||
|
|
||||||
config PINMUX_XEC_GPIO240_276
|
config PINMUX_XEC_GPIO240_276
|
||||||
|
@ -119,4 +119,21 @@ config PS2_XEC_1
|
||||||
|
|
||||||
endif #PS2
|
endif #PS2
|
||||||
|
|
||||||
|
if SPI
|
||||||
|
|
||||||
|
config SPI_XEC_QMSPI
|
||||||
|
default y
|
||||||
|
|
||||||
|
if SPI_XEC_QMSPI
|
||||||
|
|
||||||
|
config SPI_0
|
||||||
|
default y
|
||||||
|
|
||||||
|
config SPI_0_OP_MODES
|
||||||
|
default 1
|
||||||
|
|
||||||
|
endif # SPI_XEC_QMSPI
|
||||||
|
|
||||||
|
endif # SPI
|
||||||
|
|
||||||
endif # BOARD_MEC15XXEVB_ASSY6853
|
endif # BOARD_MEC15XXEVB_ASSY6853
|
||||||
|
|
|
@ -74,3 +74,9 @@
|
||||||
status = "okay";
|
status = "okay";
|
||||||
};
|
};
|
||||||
|
|
||||||
|
&spi0 {
|
||||||
|
status = "okay";
|
||||||
|
port_sel = <0>;
|
||||||
|
chip_select = <0>;
|
||||||
|
lines = <1>;
|
||||||
|
};
|
||||||
|
|
|
@ -22,3 +22,5 @@ CONFIG_I2C=y
|
||||||
CONFIG_I2C_INIT_PRIORITY=60
|
CONFIG_I2C_INIT_PRIORITY=60
|
||||||
|
|
||||||
CONFIG_ESPI=y
|
CONFIG_ESPI=y
|
||||||
|
|
||||||
|
CONFIG_SPI=y
|
||||||
|
|
|
@ -261,6 +261,40 @@ static int board_pinmux_init(struct device *dev)
|
||||||
MCHP_GPIO_CTRL_MUX_F1 | MCHP_GPIO_CTRL_BUFT_OPENDRAIN);
|
MCHP_GPIO_CTRL_MUX_F1 | MCHP_GPIO_CTRL_BUFT_OPENDRAIN);
|
||||||
#endif /* CONFIG_KSCAN_XEC */
|
#endif /* CONFIG_KSCAN_XEC */
|
||||||
|
|
||||||
|
#ifdef CONFIG_SPI_XEC_QMSPI
|
||||||
|
#if defined(DT_INST_0_MICROCHIP_XEC_QMSPI)
|
||||||
|
mchp_pcr_periph_slp_ctrl(PCR_QMSPI, MCHP_PCR_SLEEP_DIS);
|
||||||
|
|
||||||
|
#if DT_SPI_XEC_QMSPI_0_PORT_SEL == 0
|
||||||
|
/* Port 0: Shared SPI pins. Shared has two chip selects */
|
||||||
|
#if DT_SPI_XEC_QMSPI_0_CHIP_SELECT == 0
|
||||||
|
pinmux_pin_set(portb, MCHP_GPIO_055, MCHP_GPIO_CTRL_MUX_F2);
|
||||||
|
#else
|
||||||
|
pinmux_pin_set(porta, MCHP_GPIO_002, MCHP_GPIO_CTRL_MUX_F2);
|
||||||
|
#endif
|
||||||
|
pinmux_pin_set(portb, MCHP_GPIO_056, MCHP_GPIO_CTRL_MUX_F2);
|
||||||
|
pinmux_pin_set(porte, MCHP_GPIO_223, MCHP_GPIO_CTRL_MUX_F1);
|
||||||
|
pinmux_pin_set(porte, MCHP_GPIO_224, MCHP_GPIO_CTRL_MUX_F2);
|
||||||
|
#if DT_SPI_XEC_QMSPI_0_LINES == 4
|
||||||
|
pinmux_pin_set(porte, MCHP_GPIO_227, MCHP_GPIO_CTRL_MUX_F1);
|
||||||
|
pinmux_pin_set(porta, MCHP_GPIO_016, MCHP_GPIO_CTRL_MUX_F2);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#else
|
||||||
|
/* Port 1: Private SPI pins. Only one chip select */
|
||||||
|
pinmux_pin_set(portc, MCHP_GPIO_124, MCHP_GPIO_CTRL_MUX_F1);
|
||||||
|
pinmux_pin_set(portc, MCHP_GPIO_125, MCHP_GPIO_CTRL_MUX_F1);
|
||||||
|
pinmux_pin_set(portc, MCHP_GPIO_121, MCHP_GPIO_CTRL_MUX_F1);
|
||||||
|
pinmux_pin_set(portc, MCHP_GPIO_122, MCHP_GPIO_CTRL_MUX_F1);
|
||||||
|
#if DT_SPI_XEC_QMSPI_0_LINES == 4
|
||||||
|
pinmux_pin_set(portc, MCHP_GPIO_123, MCHP_GPIO_CTRL_MUX_F1);
|
||||||
|
pinmux_pin_set(portc, MCHP_GPIO_126, MCHP_GPIO_CTRL_MUX_F1);
|
||||||
|
#endif
|
||||||
|
#endif /* DT_SPI_XEC_QMSPI_0_PORT_SEL == 0 */
|
||||||
|
|
||||||
|
#endif /* DT_INST_0_MICROCHIP_XEC_QMSPI */
|
||||||
|
#endif /* CONFIG_SPI_XEC_QMSPI */
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -15,5 +15,6 @@ zephyr_library_sources_ifdef(CONFIG_NRFX_SPIM spi_nrfx_spim.c)
|
||||||
zephyr_library_sources_ifdef(CONFIG_NRFX_SPIS spi_nrfx_spis.c)
|
zephyr_library_sources_ifdef(CONFIG_NRFX_SPIS spi_nrfx_spis.c)
|
||||||
zephyr_library_sources_ifdef(CONFIG_SPI_LITESPI spi_litespi.c)
|
zephyr_library_sources_ifdef(CONFIG_SPI_LITESPI spi_litespi.c)
|
||||||
zephyr_library_sources_ifdef(CONFIG_SPI_OC_SIMPLE spi_oc_simple.c)
|
zephyr_library_sources_ifdef(CONFIG_SPI_OC_SIMPLE spi_oc_simple.c)
|
||||||
|
zephyr_library_sources_ifdef(CONFIG_SPI_XEC_QMSPI spi_xec_qmspi.c)
|
||||||
|
|
||||||
zephyr_library_sources_ifdef(CONFIG_USERSPACE spi_handlers.c)
|
zephyr_library_sources_ifdef(CONFIG_USERSPACE spi_handlers.c)
|
||||||
|
|
|
@ -201,4 +201,6 @@ source "drivers/spi/Kconfig.litex"
|
||||||
|
|
||||||
source "drivers/spi/Kconfig.oc_simple"
|
source "drivers/spi/Kconfig.oc_simple"
|
||||||
|
|
||||||
|
source "drivers/spi/Kconfig.xec_qmspi"
|
||||||
|
|
||||||
endif # SPI
|
endif # SPI
|
||||||
|
|
12
drivers/spi/Kconfig.xec_qmspi
Normal file
12
drivers/spi/Kconfig.xec_qmspi
Normal file
|
@ -0,0 +1,12 @@
|
||||||
|
# Kconfig - Microchip XEC QMSPI
|
||||||
|
#
|
||||||
|
# Copyright (c) 2019 Microchip Technology Inc.
|
||||||
|
# SPDX-License-Identifier: Apache-2.0
|
||||||
|
|
||||||
|
menuconfig SPI_XEC_QMSPI
|
||||||
|
bool "Microchip XEC QMSPI driver"
|
||||||
|
default y
|
||||||
|
depends on SOC_FAMILY_MEC
|
||||||
|
select DMA if SPI_ASYNC
|
||||||
|
help
|
||||||
|
Enable support for the Microchip XEC QMSPI driver.
|
681
drivers/spi/spi_xec_qmspi.c
Normal file
681
drivers/spi/spi_xec_qmspi.c
Normal file
|
@ -0,0 +1,681 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2019 Microchip Technology Inc.
|
||||||
|
*
|
||||||
|
* SPDX-License-Identifier: Apache-2.0
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <logging/log.h>
|
||||||
|
LOG_MODULE_REGISTER(spi_xec, CONFIG_SPI_LOG_LEVEL);
|
||||||
|
|
||||||
|
#include "spi_context.h"
|
||||||
|
#include <errno.h>
|
||||||
|
#include <device.h>
|
||||||
|
#include <drivers/spi.h>
|
||||||
|
#include <soc.h>
|
||||||
|
|
||||||
|
/* Device constant configuration parameters */
|
||||||
|
struct spi_qmspi_config {
|
||||||
|
QMSPI_Type *regs;
|
||||||
|
u32_t cs_timing;
|
||||||
|
u8_t girq;
|
||||||
|
u8_t girq_pos;
|
||||||
|
u8_t girq_nvic_aggr;
|
||||||
|
u8_t girq_nvic_direct;
|
||||||
|
u8_t irq_pri;
|
||||||
|
u8_t chip_sel;
|
||||||
|
u8_t width; /* 1(single), 2(dual), 4(quad) */
|
||||||
|
};
|
||||||
|
|
||||||
|
/* Device run time data */
|
||||||
|
struct spi_qmspi_data {
|
||||||
|
struct spi_context ctx;
|
||||||
|
};
|
||||||
|
|
||||||
|
static inline u32_t descr_rd(QMSPI_Type *regs, u32_t did)
|
||||||
|
{
|
||||||
|
uintptr_t raddr = (uintptr_t)regs + MCHP_QMSPI_DESC0_OFS +
|
||||||
|
((did & MCHP_QMSPI_C_NEXT_DESCR_MASK0) << 2);
|
||||||
|
|
||||||
|
return REG32(raddr);
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline void descr_wr(QMSPI_Type *regs, u32_t did, u32_t val)
|
||||||
|
{
|
||||||
|
uintptr_t raddr = (uintptr_t)regs + MCHP_QMSPI_DESC0_OFS +
|
||||||
|
((did & MCHP_QMSPI_C_NEXT_DESCR_MASK0) << 2);
|
||||||
|
|
||||||
|
REG32(raddr) = val;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline void txb_wr8(QMSPI_Type *regs, u8_t data8)
|
||||||
|
{
|
||||||
|
REG8(®s->TX_FIFO) = data8;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline u8_t rxb_rd8(QMSPI_Type *regs)
|
||||||
|
{
|
||||||
|
return REG8(®s->RX_FIFO);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Program QMSPI frequency.
|
||||||
|
* MEC1501 base frequency is 48MHz. QMSPI frequency divider field in the
|
||||||
|
* mode register is defined as: 0=maximum divider of 256. Values 1 through
|
||||||
|
* 255 divide 48MHz by that value.
|
||||||
|
*/
|
||||||
|
static void qmspi_set_frequency(QMSPI_Type *regs, u32_t freq_hz)
|
||||||
|
{
|
||||||
|
u32_t div, qmode;
|
||||||
|
|
||||||
|
if (freq_hz == 0) {
|
||||||
|
div = 0; /* max divider = 256 */
|
||||||
|
} else {
|
||||||
|
div = MCHP_QMSPI_INPUT_CLOCK_FREQ_HZ / freq_hz;
|
||||||
|
if (div == 0) {
|
||||||
|
div = 1; /* max freq. divider = 1 */
|
||||||
|
} else if (div > 0xffu) {
|
||||||
|
div = 0u; /* max divider = 256 */
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
qmode = regs->MODE & ~(MCHP_QMSPI_M_FDIV_MASK);
|
||||||
|
qmode |= (div << MCHP_QMSPI_M_FDIV_POS) & MCHP_QMSPI_M_FDIV_MASK;
|
||||||
|
regs->MODE = qmode;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* SPI signalling mode: CPOL and CPHA
|
||||||
|
* CPOL = 0 is clock idles low, 1 is clock idle high
|
||||||
|
* CPHA = 0 Transmitter changes data on trailing of preceding clock cycle.
|
||||||
|
* Receiver samples data on leading edge of clock cyle.
|
||||||
|
* 1 Transmitter changes data on leading edge of current clock cycle.
|
||||||
|
* Receiver samples data on the trailing edge of clock cycle.
|
||||||
|
* SPI Mode nomenclature:
|
||||||
|
* Mode CPOL CPHA
|
||||||
|
* 0 0 0
|
||||||
|
* 1 0 1
|
||||||
|
* 2 1 0
|
||||||
|
* 3 1 1
|
||||||
|
* MEC1501 has three controls, CPOL, CPHA for output and CPHA for input.
|
||||||
|
* SPI frequency < 48MHz
|
||||||
|
* Mode 0: CPOL=0 CHPA=0 (CHPA_MISO=0 and CHPA_MOSI=0)
|
||||||
|
* Mode 3: CPOL=1 CHPA=1 (CHPA_MISO=1 and CHPA_MOSI=1)
|
||||||
|
* Data sheet recommends when QMSPI set at max. SPI frequency (48MHz).
|
||||||
|
* SPI frequency == 48MHz sample and change data on same edge.
|
||||||
|
* Mode 0: CPOL=0 CHPA=0 (CHPA_MISO=1 and CHPA_MOSI=0)
|
||||||
|
* Mode 3: CPOL=1 CHPA=1 (CHPA_MISO=0 and CHPA_MOSI=1)
|
||||||
|
*/
|
||||||
|
|
||||||
|
const u8_t smode_tbl[4] = {
|
||||||
|
0x00u, 0x06u, 0x01u, 0x07u
|
||||||
|
};
|
||||||
|
|
||||||
|
const u8_t smode48_tbl[4] = {
|
||||||
|
0x04u, 0x02u, 0x05u, 0x03u
|
||||||
|
};
|
||||||
|
|
||||||
|
static void qmspi_set_signalling_mode(QMSPI_Type *regs, u32_t smode)
|
||||||
|
{
|
||||||
|
const u8_t *ptbl;
|
||||||
|
u32_t m;
|
||||||
|
|
||||||
|
ptbl = smode_tbl;
|
||||||
|
if (((regs->MODE >> MCHP_QMSPI_M_FDIV_POS) &
|
||||||
|
MCHP_QMSPI_M_FDIV_MASK0) == 1) {
|
||||||
|
ptbl = smode48_tbl;
|
||||||
|
}
|
||||||
|
|
||||||
|
m = (u32_t)ptbl[smode & 0x03];
|
||||||
|
regs->MODE = (regs->MODE & ~(MCHP_QMSPI_M_SIG_MASK))
|
||||||
|
| (m << MCHP_QMSPI_M_SIG_POS);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* QMSPI HW support single, dual, and quad.
|
||||||
|
* Return QMSPI Control/Descriptor register encoded value.
|
||||||
|
*/
|
||||||
|
static u32_t qmspi_config_get_lines(const struct spi_config *config)
|
||||||
|
{
|
||||||
|
u32_t qlines;
|
||||||
|
|
||||||
|
switch (config->operation & SPI_LINES_MASK) {
|
||||||
|
case SPI_LINES_SINGLE:
|
||||||
|
qlines = MCHP_QMSPI_C_IFM_1X;
|
||||||
|
break;
|
||||||
|
#if DT_SPI_XEC_QMSPI_0_LINES > 1
|
||||||
|
case SPI_LINES_DUAL:
|
||||||
|
qlines = MCHP_QMSPI_C_IFM_2X;
|
||||||
|
break;
|
||||||
|
#endif
|
||||||
|
#if DT_SPI_XEC_QMSPI_0_LINES > 2
|
||||||
|
case SPI_LINES_QUAD:
|
||||||
|
qlines = MCHP_QMSPI_C_IFM_4X;
|
||||||
|
break;
|
||||||
|
#endif
|
||||||
|
default:
|
||||||
|
qlines = 0xffu;
|
||||||
|
}
|
||||||
|
|
||||||
|
return qlines;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Configure QMSPI.
|
||||||
|
* NOTE: QMSPI can control two chip selects. At this time we use CS0# only.
|
||||||
|
*/
|
||||||
|
static int qmspi_configure(struct device *dev,
|
||||||
|
const struct spi_config *config)
|
||||||
|
{
|
||||||
|
const struct spi_qmspi_config *cfg = dev->config->config_info;
|
||||||
|
struct spi_qmspi_data *data = dev->driver_data;
|
||||||
|
QMSPI_Type *regs = cfg->regs;
|
||||||
|
u32_t smode;
|
||||||
|
|
||||||
|
if (spi_context_configured(&data->ctx, config)) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (config->operation & (SPI_TRANSFER_LSB | SPI_OP_MODE_SLAVE
|
||||||
|
| SPI_MODE_LOOP)) {
|
||||||
|
return -ENOTSUP;
|
||||||
|
}
|
||||||
|
|
||||||
|
smode = qmspi_config_get_lines(config);
|
||||||
|
if (smode == 0xff) {
|
||||||
|
return -ENOTSUP;
|
||||||
|
}
|
||||||
|
|
||||||
|
regs->CTRL = smode;
|
||||||
|
|
||||||
|
/* Use the requested or next highest possible frequency */
|
||||||
|
qmspi_set_frequency(regs, config->frequency);
|
||||||
|
|
||||||
|
smode = 0;
|
||||||
|
if ((config->operation & SPI_MODE_CPHA) != 0U) {
|
||||||
|
smode |= (1ul << 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((config->operation & SPI_MODE_CPOL) != 0U) {
|
||||||
|
smode |= (1ul << 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
qmspi_set_signalling_mode(regs, smode);
|
||||||
|
|
||||||
|
if (SPI_WORD_SIZE_GET(config->operation) != 8) {
|
||||||
|
return -ENOTSUP;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* chip select */
|
||||||
|
smode = regs->MODE & ~(MCHP_QMSPI_M_CS_MASK);
|
||||||
|
#if DT_SPI_XEC_QMSPI_0_CHIP_SELECT == 0
|
||||||
|
smode |= MCHP_QMSPI_M_CS0;
|
||||||
|
#else
|
||||||
|
smode |= MCHP_QMSPI_M_CS1;
|
||||||
|
#endif
|
||||||
|
regs->MODE = smode;
|
||||||
|
|
||||||
|
/* chip select timing */
|
||||||
|
regs->CSTM = cfg->cs_timing;
|
||||||
|
|
||||||
|
data->ctx.config = config;
|
||||||
|
|
||||||
|
/* Add driver specific data to SPI context structure */
|
||||||
|
spi_context_cs_configure(&data->ctx);
|
||||||
|
|
||||||
|
regs->MODE |= MCHP_QMSPI_M_ACTIVATE;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Transmit dummy clocks - QMSPI will generate requested number of
|
||||||
|
* SPI clocks with I/O pins tri-stated.
|
||||||
|
* Single mode: 1 bit per clock -> IFM field = 00b. Max 0x7fff clocks
|
||||||
|
* Dual mode: 2 bits per clock -> IFM field = 01b. Max 0x3fff clocks
|
||||||
|
* Quad mode: 4 bits per clock -> IFM fiels = 1xb. Max 0x1fff clocks
|
||||||
|
* QMSPI unit size set to bits.
|
||||||
|
*/
|
||||||
|
static int qmspi_tx_dummy_clocks(QMSPI_Type *regs, u32_t nclocks)
|
||||||
|
{
|
||||||
|
u32_t descr, ifm, qstatus;
|
||||||
|
|
||||||
|
ifm = regs->CTRL & MCHP_QMSPI_C_IFM_MASK;
|
||||||
|
descr = ifm | MCHP_QMSPI_C_TX_DIS | MCHP_QMSPI_C_XFR_UNITS_BITS
|
||||||
|
| MCHP_QMSPI_C_DESCR_LAST | MCHP_QMSPI_C_DESCR0;
|
||||||
|
|
||||||
|
if (ifm & 0x01) {
|
||||||
|
nclocks <<= 1;
|
||||||
|
} else if (ifm & 0x02) {
|
||||||
|
nclocks <<= 2;
|
||||||
|
}
|
||||||
|
descr |= (nclocks << MCHP_QMSPI_C_XFR_NUNITS_POS);
|
||||||
|
|
||||||
|
descr_wr(regs, 0, descr);
|
||||||
|
|
||||||
|
regs->CTRL |= MCHP_QMSPI_C_DESCR_EN;
|
||||||
|
regs->IEN = 0;
|
||||||
|
regs->STS = 0xfffffffful;
|
||||||
|
|
||||||
|
regs->EXE = MCHP_QMSPI_EXE_START;
|
||||||
|
do {
|
||||||
|
qstatus = regs->STS;
|
||||||
|
if (qstatus & MCHP_QMSPI_STS_PROG_ERR) {
|
||||||
|
return -EIO;
|
||||||
|
}
|
||||||
|
} while ((qstatus & MCHP_QMSPI_STS_DONE) == 0);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Return unit size power of 2 given number of bytes to transfer.
|
||||||
|
*/
|
||||||
|
static u32_t qlen_shift(u32_t len)
|
||||||
|
{
|
||||||
|
u32_t ushift;
|
||||||
|
|
||||||
|
/* is len a multiple of 4 or 16? */
|
||||||
|
if ((len & 0x0F) == 0) {
|
||||||
|
ushift = 4;
|
||||||
|
} else if ((len & 0x03) == 0) {
|
||||||
|
ushift = 2;
|
||||||
|
} else {
|
||||||
|
ushift = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
return ushift;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Return QMSPI unit size of the number of units field in QMSPI
|
||||||
|
* control/descriptor register.
|
||||||
|
* Input: power of 2 unit size 4, 2, or 0(default) corresponding
|
||||||
|
* to 16, 4, or 1 byte units.
|
||||||
|
*/
|
||||||
|
static u32_t get_qunits(u32_t qshift)
|
||||||
|
{
|
||||||
|
if (qshift == 4) {
|
||||||
|
return MCHP_QMSPI_C_XFR_UNITS_16;
|
||||||
|
} else if (qshift == 2) {
|
||||||
|
return MCHP_QMSPI_C_XFR_UNITS_4;
|
||||||
|
} else {
|
||||||
|
return MCHP_QMSPI_C_XFR_UNITS_1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Allocate(build) one or more descriptors.
|
||||||
|
* QMSPI contains 16 32-bit descriptor registers used as a linked
|
||||||
|
* list of operations. Using only 32-bits there are limitations.
|
||||||
|
* Each descriptor is limited to 0x7FFF units where unit size can
|
||||||
|
* be 1, 4, or 16 bytes. A descriptor can perform transmit or receive
|
||||||
|
* but not both simultaneously. Order of descriptor processing is specified
|
||||||
|
* by the first descriptor field of the control register, the next descriptor
|
||||||
|
* fields in each descriptor, and the descriptors last flag.
|
||||||
|
*/
|
||||||
|
static int qmspi_descr_alloc(QMSPI_Type *regs, const struct spi_buf *txb,
|
||||||
|
int didx, bool is_tx)
|
||||||
|
{
|
||||||
|
u32_t descr, qshift, n, nu;
|
||||||
|
int dn;
|
||||||
|
|
||||||
|
if (didx >= MCHP_QMSPI_MAX_DESCR) {
|
||||||
|
return -EAGAIN;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (txb->len == 0) {
|
||||||
|
return didx; /* nothing to do */
|
||||||
|
}
|
||||||
|
|
||||||
|
/* b[1:0] IFM and b[3:2] transmit mode */
|
||||||
|
descr = (regs->CTRL & MCHP_QMSPI_C_IFM_MASK);
|
||||||
|
if (is_tx) {
|
||||||
|
descr |= MCHP_QMSPI_C_TX_DATA;
|
||||||
|
} else {
|
||||||
|
descr |= MCHP_QMSPI_C_RX_EN;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* b[11:10] unit size 1, 4, or 16 bytes */
|
||||||
|
qshift = qlen_shift(txb->len);
|
||||||
|
nu = txb->len >> qshift;
|
||||||
|
descr |= get_qunits(qshift);
|
||||||
|
|
||||||
|
do {
|
||||||
|
descr &= 0x0FFFul;
|
||||||
|
|
||||||
|
dn = didx + 1;
|
||||||
|
/* b[15:12] next descriptor pointer */
|
||||||
|
descr |= ((dn & MCHP_QMSPI_C_NEXT_DESCR_MASK0) <<
|
||||||
|
MCHP_QMSPI_C_NEXT_DESCR_POS);
|
||||||
|
|
||||||
|
n = nu;
|
||||||
|
if (n > MCHP_QMSPI_C_MAX_UNITS) {
|
||||||
|
n = MCHP_QMSPI_C_MAX_UNITS;
|
||||||
|
}
|
||||||
|
|
||||||
|
descr |= (n << MCHP_QMSPI_C_XFR_NUNITS_POS);
|
||||||
|
descr_wr(regs, didx, descr);
|
||||||
|
|
||||||
|
if (dn < MCHP_QMSPI_MAX_DESCR) {
|
||||||
|
didx++;
|
||||||
|
} else {
|
||||||
|
return -EAGAIN;
|
||||||
|
}
|
||||||
|
|
||||||
|
nu -= n;
|
||||||
|
} while (nu);
|
||||||
|
|
||||||
|
return dn;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int qmspi_tx(QMSPI_Type *regs, const struct spi_buf *tx_buf,
|
||||||
|
bool close)
|
||||||
|
{
|
||||||
|
const u8_t *p = tx_buf->buf;
|
||||||
|
size_t tlen = tx_buf->len;
|
||||||
|
u32_t descr;
|
||||||
|
int didx;
|
||||||
|
|
||||||
|
if (tlen == 0) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Buffer pointer is NULL and number of bytes != 0 ? */
|
||||||
|
if (p == NULL) {
|
||||||
|
return qmspi_tx_dummy_clocks(regs, tlen);
|
||||||
|
}
|
||||||
|
|
||||||
|
didx = qmspi_descr_alloc(regs, tx_buf, 0, true);
|
||||||
|
if (didx < 0) {
|
||||||
|
return didx;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* didx points to last allocated descriptor + 1 */
|
||||||
|
__ASSERT(didx > 0, "QMSPI descriptor index=%d expected > 0\n", didx);
|
||||||
|
didx--;
|
||||||
|
|
||||||
|
descr = descr_rd(regs, didx) | MCHP_QMSPI_C_DESCR_LAST;
|
||||||
|
if (close) {
|
||||||
|
descr |= MCHP_QMSPI_C_CLOSE;
|
||||||
|
}
|
||||||
|
descr_wr(regs, didx, descr);
|
||||||
|
|
||||||
|
regs->CTRL = (regs->CTRL & MCHP_QMSPI_C_IFM_MASK) |
|
||||||
|
MCHP_QMSPI_C_DESCR_EN | MCHP_QMSPI_C_DESCR0;
|
||||||
|
regs->IEN = 0;
|
||||||
|
regs->STS = 0xfffffffful;
|
||||||
|
|
||||||
|
/* preload TX_FIFO */
|
||||||
|
while (tlen) {
|
||||||
|
tlen--;
|
||||||
|
txb_wr8(regs, *p);
|
||||||
|
p++;
|
||||||
|
|
||||||
|
if (regs->STS & MCHP_QMSPI_STS_TXBF_RO) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
regs->EXE = MCHP_QMSPI_EXE_START;
|
||||||
|
|
||||||
|
if (regs->STS & MCHP_QMSPI_STS_PROG_ERR) {
|
||||||
|
return -EIO;
|
||||||
|
}
|
||||||
|
|
||||||
|
while (tlen) {
|
||||||
|
|
||||||
|
while (regs->STS & MCHP_QMSPI_STS_TXBF_RO) {
|
||||||
|
}
|
||||||
|
|
||||||
|
txb_wr8(regs, *p);
|
||||||
|
p++;
|
||||||
|
tlen--;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Wait for TX FIFO to drain and last byte to be clocked out */
|
||||||
|
for (;;) {
|
||||||
|
if (regs->STS & MCHP_QMSPI_STS_DONE) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int qmspi_rx(QMSPI_Type *regs, const struct spi_buf *rx_buf,
|
||||||
|
bool close)
|
||||||
|
{
|
||||||
|
u8_t *p = rx_buf->buf;
|
||||||
|
size_t rlen = rx_buf->len;
|
||||||
|
u32_t descr;
|
||||||
|
int didx;
|
||||||
|
u8_t data_byte;
|
||||||
|
|
||||||
|
if (rlen == 0) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
didx = qmspi_descr_alloc(regs, rx_buf, 0, false);
|
||||||
|
if (didx < 0) {
|
||||||
|
return didx;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* didx points to last allocated descriptor + 1 */
|
||||||
|
__ASSERT_NO_MSG(didx > 0);
|
||||||
|
didx--;
|
||||||
|
|
||||||
|
descr = descr_rd(regs, didx) | MCHP_QMSPI_C_DESCR_LAST;
|
||||||
|
if (close) {
|
||||||
|
descr |= MCHP_QMSPI_C_CLOSE;
|
||||||
|
}
|
||||||
|
descr_wr(regs, didx, descr);
|
||||||
|
|
||||||
|
regs->CTRL = (regs->CTRL & MCHP_QMSPI_C_IFM_MASK)
|
||||||
|
| MCHP_QMSPI_C_DESCR_EN | MCHP_QMSPI_C_DESCR0;
|
||||||
|
regs->IEN = 0;
|
||||||
|
regs->STS = 0xfffffffful;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Trigger read based on the descriptor(s) programmed above.
|
||||||
|
* QMSPI will generate clocks until the RX FIFO is filled.
|
||||||
|
* More clocks will be generated as we pull bytes from the RX FIFO.
|
||||||
|
* QMSPI Programming error will be triggered after start if
|
||||||
|
* descriptors were programmed options that cannot be enabled
|
||||||
|
* simultaneously.
|
||||||
|
*/
|
||||||
|
regs->EXE = MCHP_QMSPI_EXE_START;
|
||||||
|
if (regs->STS & MCHP_QMSPI_STS_PROG_ERR) {
|
||||||
|
return -EIO;
|
||||||
|
}
|
||||||
|
|
||||||
|
while (rlen) {
|
||||||
|
if (!(regs->STS & MCHP_QMSPI_STS_RXBE_RO)) {
|
||||||
|
data_byte = rxb_rd8(regs);
|
||||||
|
if (p != NULL) {
|
||||||
|
*p++ = data_byte;
|
||||||
|
}
|
||||||
|
rlen--;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int qmspi_transceive(struct device *dev,
|
||||||
|
const struct spi_config *config,
|
||||||
|
const struct spi_buf_set *tx_bufs,
|
||||||
|
const struct spi_buf_set *rx_bufs)
|
||||||
|
{
|
||||||
|
const struct spi_qmspi_config *cfg = dev->config->config_info;
|
||||||
|
struct spi_qmspi_data *data = dev->driver_data;
|
||||||
|
QMSPI_Type *regs = cfg->regs;
|
||||||
|
const struct spi_buf *ptx;
|
||||||
|
const struct spi_buf *prx;
|
||||||
|
size_t nb;
|
||||||
|
u32_t descr, last_didx;
|
||||||
|
int err;
|
||||||
|
|
||||||
|
spi_context_lock(&data->ctx, false, NULL);
|
||||||
|
|
||||||
|
err = qmspi_configure(dev, config);
|
||||||
|
if (err != 0) {
|
||||||
|
goto done;
|
||||||
|
}
|
||||||
|
|
||||||
|
spi_context_cs_control(&data->ctx, true);
|
||||||
|
|
||||||
|
if (tx_bufs != NULL) {
|
||||||
|
ptx = tx_bufs->buffers;
|
||||||
|
nb = tx_bufs->count;
|
||||||
|
while (nb--) {
|
||||||
|
err = qmspi_tx(regs, ptx, false);
|
||||||
|
if (err != 0) {
|
||||||
|
goto done;
|
||||||
|
}
|
||||||
|
ptx++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (rx_bufs != NULL) {
|
||||||
|
prx = rx_bufs->buffers;
|
||||||
|
nb = rx_bufs->count;
|
||||||
|
while (nb--) {
|
||||||
|
err = qmspi_rx(regs, prx, false);
|
||||||
|
if (err != 0) {
|
||||||
|
goto done;
|
||||||
|
}
|
||||||
|
prx++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* If caller doesn't need CS# held asserted then find the last
|
||||||
|
* descriptor, set its close flag, and set stop.
|
||||||
|
*/
|
||||||
|
if (!(config->operation & SPI_HOLD_ON_CS)) {
|
||||||
|
/* Get last descriptor from status register */
|
||||||
|
last_didx = (regs->STS >> MCHP_QMSPI_C_NEXT_DESCR_POS)
|
||||||
|
& MCHP_QMSPI_C_NEXT_DESCR_MASK0;
|
||||||
|
descr = descr_rd(regs, last_didx) | MCHP_QMSPI_C_CLOSE;
|
||||||
|
descr_wr(regs, last_didx, descr);
|
||||||
|
regs->EXE = MCHP_QMSPI_EXE_STOP;
|
||||||
|
}
|
||||||
|
|
||||||
|
spi_context_cs_control(&data->ctx, false);
|
||||||
|
|
||||||
|
done:
|
||||||
|
spi_context_release(&data->ctx, err);
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int qmspi_transceive_sync(struct device *dev,
|
||||||
|
const struct spi_config *config,
|
||||||
|
const struct spi_buf_set *tx_bufs,
|
||||||
|
const struct spi_buf_set *rx_bufs)
|
||||||
|
{
|
||||||
|
return qmspi_transceive(dev, config, tx_bufs, rx_bufs);
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifdef CONFIG_SPI_ASYNC
|
||||||
|
static int qmspi_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)
|
||||||
|
{
|
||||||
|
return -ENOTSUP;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
static int qmspi_release(struct device *dev,
|
||||||
|
const struct spi_config *config)
|
||||||
|
{
|
||||||
|
struct spi_qmspi_data *data = dev->driver_data;
|
||||||
|
const struct spi_qmspi_config *cfg = dev->config->config_info;
|
||||||
|
QMSPI_Type *regs = cfg->regs;
|
||||||
|
|
||||||
|
/* Force CS# to de-assert on next unit boundary */
|
||||||
|
regs->EXE = MCHP_QMSPI_EXE_STOP;
|
||||||
|
|
||||||
|
while (regs->STS & MCHP_QMSPI_STS_ACTIVE_RO) {
|
||||||
|
}
|
||||||
|
|
||||||
|
spi_context_unlock_unconditionally(&data->ctx);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Initialize QMSPI controller.
|
||||||
|
* Disable sleep control.
|
||||||
|
* Disable and clear interrupt status.
|
||||||
|
* Initialize SPI context.
|
||||||
|
* QMSPI will be configured and enabled when the transceive API is called.
|
||||||
|
*/
|
||||||
|
static int qmspi_init(struct device *dev)
|
||||||
|
{
|
||||||
|
const struct spi_qmspi_config *cfg = dev->config->config_info;
|
||||||
|
struct spi_qmspi_data *data = dev->driver_data;
|
||||||
|
QMSPI_Type *regs = cfg->regs;
|
||||||
|
|
||||||
|
mchp_pcr_periph_slp_ctrl(PCR_QMSPI, MCHP_PCR_SLEEP_DIS);
|
||||||
|
|
||||||
|
regs->MODE = MCHP_QMSPI_M_SRST;
|
||||||
|
|
||||||
|
MCHP_GIRQ_CLR_EN(cfg->girq, cfg->girq_pos);
|
||||||
|
MCHP_GIRQ_SRC_CLR(cfg->girq, cfg->girq_pos);
|
||||||
|
|
||||||
|
MCHP_GIRQ_BLK_CLREN(cfg->girq);
|
||||||
|
NVIC_ClearPendingIRQ(cfg->girq_nvic_direct);
|
||||||
|
|
||||||
|
spi_context_unlock_unconditionally(&data->ctx);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static const struct spi_driver_api spi_qmspi_driver_api = {
|
||||||
|
.transceive = qmspi_transceive_sync,
|
||||||
|
#ifdef CONFIG_SPI_ASYNC
|
||||||
|
.transceive_async = qmspi_transceive_async,
|
||||||
|
#endif
|
||||||
|
.release = qmspi_release,
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
#define XEC_QMSPI_CS_TIMING_VAL(a, b, c, d) (((a) & 0xFu) \
|
||||||
|
| (((b) & 0xFu) << 8) \
|
||||||
|
| (((c) & 0xFu) << 16) \
|
||||||
|
| (((d) & 0xFu) << 24))
|
||||||
|
|
||||||
|
|
||||||
|
#define XEC_QMSPI_0_CS_TIMING XEC_QMSPI_CS_TIMING_VAL( \
|
||||||
|
DT_SPI_XEC_QMSPI_0_DCSCKON, \
|
||||||
|
DT_SPI_XEC_QMSPI_0_DCKCSOFF, \
|
||||||
|
DT_SPI_XEC_QMSPI_0_DLDH, \
|
||||||
|
DT_SPI_XEC_QMSPI_0_DCSDA)
|
||||||
|
|
||||||
|
#ifdef DT_SPI_XEC_QMSPI_0_BASE_ADDRESS
|
||||||
|
|
||||||
|
static const struct spi_qmspi_config spi_qmspi_0_config = {
|
||||||
|
.regs = (QMSPI_Type *)DT_SPI_XEC_QMSPI_0_BASE_ADDRESS,
|
||||||
|
.cs_timing = XEC_QMSPI_0_CS_TIMING,
|
||||||
|
.girq = MCHP_QMSPI_GIRQ_NUM,
|
||||||
|
.girq_pos = MCHP_QMSPI_GIRQ_POS,
|
||||||
|
.girq_nvic_direct = MCHP_QMSPI_GIRQ_NVIC_DIRECT,
|
||||||
|
.irq_pri = DT_SPI_XEC_QMSPI_0_IRQ_PRI,
|
||||||
|
.chip_sel = DT_SPI_XEC_QMSPI_0_CHIP_SELECT,
|
||||||
|
.width = DT_SPI_XEC_QMSPI_0_LINES
|
||||||
|
};
|
||||||
|
|
||||||
|
static struct spi_qmspi_data spi_qmspi_0_dev_data = {
|
||||||
|
SPI_CONTEXT_INIT_LOCK(spi_qmspi_0_dev_data, ctx),
|
||||||
|
SPI_CONTEXT_INIT_SYNC(spi_qmspi_0_dev_data, ctx)
|
||||||
|
};
|
||||||
|
|
||||||
|
DEVICE_AND_API_INIT(spi_xec_qmspi_0,
|
||||||
|
DT_SPI_XEC_QMSPI_0_LABEL,
|
||||||
|
&qmspi_init, &spi_qmspi_0_dev_data,
|
||||||
|
&spi_qmspi_0_config, POST_KERNEL,
|
||||||
|
CONFIG_SPI_INIT_PRIORITY, &spi_qmspi_driver_api);
|
||||||
|
|
||||||
|
#endif /* DT_SPI_XEC_QMSPI_0_BASE_ADDRESS */
|
|
@ -298,6 +298,24 @@
|
||||||
#address-cells = <1>;
|
#address-cells = <1>;
|
||||||
#size-cells = <0>;
|
#size-cells = <0>;
|
||||||
};
|
};
|
||||||
|
spi0: spi@40070000 {
|
||||||
|
compatible = "microchip,xec-qmspi";
|
||||||
|
reg = <0x40070000 0x400>;
|
||||||
|
interrupts = <91 2>;
|
||||||
|
clock-frequency = <12000000>;
|
||||||
|
label = "SPI_0";
|
||||||
|
rxdma = <11>;
|
||||||
|
txdma = <10>;
|
||||||
|
lines = <1>;
|
||||||
|
chip_select = <0>;
|
||||||
|
dcsckon = <6>;
|
||||||
|
dckcsoff = <4>;
|
||||||
|
dldh = <6>;
|
||||||
|
dcsda = <6>;
|
||||||
|
#address-cells = <1>;
|
||||||
|
#size-cells = <0>;
|
||||||
|
status = "disabled";
|
||||||
|
};
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
63
dts/bindings/spi/microchip,xec-qmspi.yaml
Normal file
63
dts/bindings/spi/microchip,xec-qmspi.yaml
Normal file
|
@ -0,0 +1,63 @@
|
||||||
|
#
|
||||||
|
# Copyright (c) 2018, Google LLC.
|
||||||
|
#
|
||||||
|
# SPDX-License-Identifier: Apache-2.0
|
||||||
|
#
|
||||||
|
|
||||||
|
title: Microchip XEC Quad Master SPI driver
|
||||||
|
|
||||||
|
description: >
|
||||||
|
This binding gives a base representation of the Microchip XEC QMSPI controller
|
||||||
|
|
||||||
|
compatible: "microchip,xec-qmspi"
|
||||||
|
|
||||||
|
include: spi-controller.yaml
|
||||||
|
|
||||||
|
properties:
|
||||||
|
reg:
|
||||||
|
required: true
|
||||||
|
|
||||||
|
port_sel:
|
||||||
|
type: int
|
||||||
|
required: true
|
||||||
|
description: SPI Port 0 or 1.
|
||||||
|
|
||||||
|
rxdma:
|
||||||
|
type: int
|
||||||
|
required: true
|
||||||
|
description: Receive DMA channel
|
||||||
|
|
||||||
|
txdma:
|
||||||
|
type: int
|
||||||
|
required: true
|
||||||
|
description: Transmit DMA channel
|
||||||
|
|
||||||
|
lines:
|
||||||
|
type: int
|
||||||
|
required: true
|
||||||
|
description: QMSPI lines 1, 2, or 4
|
||||||
|
|
||||||
|
chip_select:
|
||||||
|
type: int
|
||||||
|
required: true
|
||||||
|
description: Use QMSPI CS0# or CS1#
|
||||||
|
|
||||||
|
dcsckon:
|
||||||
|
type: int
|
||||||
|
required: true
|
||||||
|
description: Delay in system clocks from CS# assertion to first clock edge
|
||||||
|
|
||||||
|
dckcsoff:
|
||||||
|
type: int
|
||||||
|
required: true
|
||||||
|
description: Delay in system clocks from last clock edge to CS# de-assertion
|
||||||
|
|
||||||
|
dldh:
|
||||||
|
type: int
|
||||||
|
required: true
|
||||||
|
description: Delay in system clocks from CS# de-assertion to driving HOLD# and WP#
|
||||||
|
|
||||||
|
dcsda:
|
||||||
|
type: int
|
||||||
|
required: true
|
||||||
|
description: Delay in system clocks from CS# de-assertion to CS# assertion
|
|
@ -77,4 +77,11 @@ config KSCAN_XEC
|
||||||
|
|
||||||
endif # KSCAN
|
endif # KSCAN
|
||||||
|
|
||||||
|
if SPI
|
||||||
|
|
||||||
|
config SPI_XEC_QMSPI
|
||||||
|
def_bool y
|
||||||
|
|
||||||
|
endif # SPI
|
||||||
|
|
||||||
endif # SOC_MEC1501_HSZ
|
endif # SOC_MEC1501_HSZ
|
||||||
|
|
|
@ -154,3 +154,35 @@
|
||||||
#define DT_PS2_XEC_1_LABEL DT_MICROCHIP_XEC_PS2_40009040_LABEL
|
#define DT_PS2_XEC_1_LABEL DT_MICROCHIP_XEC_PS2_40009040_LABEL
|
||||||
#define DT_PS2_XEC_1_SIZE DT_MICROCHIP_XEC_PS2_40009040_SIZE
|
#define DT_PS2_XEC_1_SIZE DT_MICROCHIP_XEC_PS2_40009040_SIZE
|
||||||
|
|
||||||
|
#define DT_SPI_XEC_QMSPI_0_LABEL \
|
||||||
|
DT_MICROCHIP_XEC_QMSPI_40070000_LABEL
|
||||||
|
#define DT_SPI_XEC_QMSPI_0_BASE_ADDRESS \
|
||||||
|
DT_MICROCHIP_XEC_QMSPI_40070000_BASE_ADDRESS
|
||||||
|
#define DT_SPI_XEC_QMSPI_0_IRQ \
|
||||||
|
DT_MICROCHIP_XEC_QMSPI_40070000_IRQ_0
|
||||||
|
#define DT_SPI_XEC_QMSPI_0_IRQ_PRI \
|
||||||
|
DT_MICROCHIP_XEC_QMSPI_40070000_IRQ_0_PRIORITY
|
||||||
|
#define DT_SPI_XEC_QMSPI_0_PORT_SEL \
|
||||||
|
DT_MICROCHIP_XEC_QMSPI_40070000_PORT_SEL
|
||||||
|
#define DT_SPI_XEC_QMSPI_0_LINES \
|
||||||
|
DT_MICROCHIP_XEC_QMSPI_40070000_LINES
|
||||||
|
#define DT_SPI_XEC_QMSPI_0_RXDMA \
|
||||||
|
DT_MICROCHIP_XEC_QMSPI_40070000_RXDMA
|
||||||
|
#define DT_SPI_XEC_QMSPI_0_TXDMA \
|
||||||
|
DT_MICROCHIP_XEC_QMSPI_40070000_TXDMA
|
||||||
|
#define DT_SPI_XEC_QMSPI_0_GIRQ \
|
||||||
|
DT_MICROCHIP_XEC_QMSPI_40070000_GIRQ
|
||||||
|
#define DT_SPI_XEC_QMSPI_0_GIRQ_POS \
|
||||||
|
DT_MICROCHIP_XEC_QMSPI_40070000_GIRQ_POS
|
||||||
|
#define DT_SPI_XEC_QMSPI_0_CLOCK_FREQUENCY \
|
||||||
|
DT_MICROCHIP_XEC_QMSPI_40070000_CLOCK_FREQUENCY
|
||||||
|
#define DT_SPI_XEC_QMSPI_0_CHIP_SELECT \
|
||||||
|
DT_MICROCHIP_XEC_QMSPI_40070000_CHIP_SELECT
|
||||||
|
#define DT_SPI_XEC_QMSPI_0_DCSCKON \
|
||||||
|
DT_MICROCHIP_XEC_QMSPI_40070000_DCSCKON
|
||||||
|
#define DT_SPI_XEC_QMSPI_0_DCKCSOFF \
|
||||||
|
DT_MICROCHIP_XEC_QMSPI_40070000_DCKCSOFF
|
||||||
|
#define DT_SPI_XEC_QMSPI_0_DLDH \
|
||||||
|
DT_MICROCHIP_XEC_QMSPI_40070000_DLDH
|
||||||
|
#define DT_SPI_XEC_QMSPI_0_DCSDA \
|
||||||
|
DT_MICROCHIP_XEC_QMSPI_40070000_DCSDA
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue