mirror of
https://github.com/torvalds/linux.git
synced 2025-01-01 15:51:46 +00:00
Add STM32F7 SPI support
Merge series from Ben Wolsieffer <ben.wolsieffer@hefring.com>: This series adds support for SPI on STM32F7 processors. The STM32F7 SPI peripheral is nearly identical to the STM32F4, with the only significant differences being that it supports a wider range of word sizes, and the addition of 32-bit transmit and receive FIFOs. v2: - Add missing commit body Ben Wolsieffer (5): spi: stm32: rename stm32f4_* to stm32fx_* spi: stm32: use callbacks for read_rx and write_tx dt-bindings: spi: add stm32f7-spi compatible spi: stm32: add STM32F7 support ARM: dts: stm32: add SPI support on STM32F746 .../devicetree/bindings/spi/st,stm32-spi.yaml | 1 + arch/arm/boot/dts/st/stm32f746.dtsi | 60 +++ drivers/spi/spi-stm32.c | 455 ++++++++++++------ 3 files changed, 367 insertions(+), 149 deletions(-) -- 2.42.0
This commit is contained in:
commit
6f9da18171
@ -23,6 +23,7 @@ properties:
|
||||
compatible:
|
||||
enum:
|
||||
- st,stm32f4-spi
|
||||
- st,stm32f7-spi
|
||||
- st,stm32h7-spi
|
||||
|
||||
reg:
|
||||
|
@ -22,58 +22,65 @@
|
||||
|
||||
#define DRIVER_NAME "spi_stm32"
|
||||
|
||||
/* STM32F4 SPI registers */
|
||||
#define STM32F4_SPI_CR1 0x00
|
||||
#define STM32F4_SPI_CR2 0x04
|
||||
#define STM32F4_SPI_SR 0x08
|
||||
#define STM32F4_SPI_DR 0x0C
|
||||
#define STM32F4_SPI_I2SCFGR 0x1C
|
||||
/* STM32F4/7 SPI registers */
|
||||
#define STM32FX_SPI_CR1 0x00
|
||||
#define STM32FX_SPI_CR2 0x04
|
||||
#define STM32FX_SPI_SR 0x08
|
||||
#define STM32FX_SPI_DR 0x0C
|
||||
#define STM32FX_SPI_I2SCFGR 0x1C
|
||||
|
||||
/* STM32F4_SPI_CR1 bit fields */
|
||||
#define STM32F4_SPI_CR1_CPHA BIT(0)
|
||||
#define STM32F4_SPI_CR1_CPOL BIT(1)
|
||||
#define STM32F4_SPI_CR1_MSTR BIT(2)
|
||||
#define STM32F4_SPI_CR1_BR_SHIFT 3
|
||||
#define STM32F4_SPI_CR1_BR GENMASK(5, 3)
|
||||
#define STM32F4_SPI_CR1_SPE BIT(6)
|
||||
#define STM32F4_SPI_CR1_LSBFRST BIT(7)
|
||||
#define STM32F4_SPI_CR1_SSI BIT(8)
|
||||
#define STM32F4_SPI_CR1_SSM BIT(9)
|
||||
#define STM32F4_SPI_CR1_RXONLY BIT(10)
|
||||
/* STM32FX_SPI_CR1 bit fields */
|
||||
#define STM32FX_SPI_CR1_CPHA BIT(0)
|
||||
#define STM32FX_SPI_CR1_CPOL BIT(1)
|
||||
#define STM32FX_SPI_CR1_MSTR BIT(2)
|
||||
#define STM32FX_SPI_CR1_BR_SHIFT 3
|
||||
#define STM32FX_SPI_CR1_BR GENMASK(5, 3)
|
||||
#define STM32FX_SPI_CR1_SPE BIT(6)
|
||||
#define STM32FX_SPI_CR1_LSBFRST BIT(7)
|
||||
#define STM32FX_SPI_CR1_SSI BIT(8)
|
||||
#define STM32FX_SPI_CR1_SSM BIT(9)
|
||||
#define STM32FX_SPI_CR1_RXONLY BIT(10)
|
||||
#define STM32F4_SPI_CR1_DFF BIT(11)
|
||||
#define STM32F4_SPI_CR1_CRCNEXT BIT(12)
|
||||
#define STM32F4_SPI_CR1_CRCEN BIT(13)
|
||||
#define STM32F4_SPI_CR1_BIDIOE BIT(14)
|
||||
#define STM32F4_SPI_CR1_BIDIMODE BIT(15)
|
||||
#define STM32F4_SPI_CR1_BR_MIN 0
|
||||
#define STM32F4_SPI_CR1_BR_MAX (GENMASK(5, 3) >> 3)
|
||||
#define STM32F7_SPI_CR1_CRCL BIT(11)
|
||||
#define STM32FX_SPI_CR1_CRCNEXT BIT(12)
|
||||
#define STM32FX_SPI_CR1_CRCEN BIT(13)
|
||||
#define STM32FX_SPI_CR1_BIDIOE BIT(14)
|
||||
#define STM32FX_SPI_CR1_BIDIMODE BIT(15)
|
||||
#define STM32FX_SPI_CR1_BR_MIN 0
|
||||
#define STM32FX_SPI_CR1_BR_MAX (GENMASK(5, 3) >> 3)
|
||||
|
||||
/* STM32F4_SPI_CR2 bit fields */
|
||||
#define STM32F4_SPI_CR2_RXDMAEN BIT(0)
|
||||
#define STM32F4_SPI_CR2_TXDMAEN BIT(1)
|
||||
#define STM32F4_SPI_CR2_SSOE BIT(2)
|
||||
#define STM32F4_SPI_CR2_FRF BIT(4)
|
||||
#define STM32F4_SPI_CR2_ERRIE BIT(5)
|
||||
#define STM32F4_SPI_CR2_RXNEIE BIT(6)
|
||||
#define STM32F4_SPI_CR2_TXEIE BIT(7)
|
||||
/* STM32FX_SPI_CR2 bit fields */
|
||||
#define STM32FX_SPI_CR2_RXDMAEN BIT(0)
|
||||
#define STM32FX_SPI_CR2_TXDMAEN BIT(1)
|
||||
#define STM32FX_SPI_CR2_SSOE BIT(2)
|
||||
#define STM32FX_SPI_CR2_FRF BIT(4)
|
||||
#define STM32FX_SPI_CR2_ERRIE BIT(5)
|
||||
#define STM32FX_SPI_CR2_RXNEIE BIT(6)
|
||||
#define STM32FX_SPI_CR2_TXEIE BIT(7)
|
||||
#define STM32F7_SPI_CR2_DS GENMASK(11, 8)
|
||||
#define STM32F7_SPI_CR2_FRXTH BIT(12)
|
||||
#define STM32F7_SPI_CR2_LDMA_RX BIT(13)
|
||||
#define STM32F7_SPI_CR2_LDMA_TX BIT(14)
|
||||
|
||||
/* STM32F4_SPI_SR bit fields */
|
||||
#define STM32F4_SPI_SR_RXNE BIT(0)
|
||||
#define STM32F4_SPI_SR_TXE BIT(1)
|
||||
#define STM32F4_SPI_SR_CHSIDE BIT(2)
|
||||
#define STM32F4_SPI_SR_UDR BIT(3)
|
||||
#define STM32F4_SPI_SR_CRCERR BIT(4)
|
||||
#define STM32F4_SPI_SR_MODF BIT(5)
|
||||
#define STM32F4_SPI_SR_OVR BIT(6)
|
||||
#define STM32F4_SPI_SR_BSY BIT(7)
|
||||
#define STM32F4_SPI_SR_FRE BIT(8)
|
||||
/* STM32FX_SPI_SR bit fields */
|
||||
#define STM32FX_SPI_SR_RXNE BIT(0)
|
||||
#define STM32FX_SPI_SR_TXE BIT(1)
|
||||
#define STM32FX_SPI_SR_CHSIDE BIT(2)
|
||||
#define STM32FX_SPI_SR_UDR BIT(3)
|
||||
#define STM32FX_SPI_SR_CRCERR BIT(4)
|
||||
#define STM32FX_SPI_SR_MODF BIT(5)
|
||||
#define STM32FX_SPI_SR_OVR BIT(6)
|
||||
#define STM32FX_SPI_SR_BSY BIT(7)
|
||||
#define STM32FX_SPI_SR_FRE BIT(8)
|
||||
#define STM32F7_SPI_SR_FRLVL GENMASK(10, 9)
|
||||
#define STM32F7_SPI_SR_FTLVL GENMASK(12, 11)
|
||||
|
||||
/* STM32F4_SPI_I2SCFGR bit fields */
|
||||
#define STM32F4_SPI_I2SCFGR_I2SMOD BIT(11)
|
||||
/* STM32FX_SPI_I2SCFGR bit fields */
|
||||
#define STM32FX_SPI_I2SCFGR_I2SMOD BIT(11)
|
||||
|
||||
/* STM32F4 SPI Baud Rate min/max divisor */
|
||||
#define STM32F4_SPI_BR_DIV_MIN (2 << STM32F4_SPI_CR1_BR_MIN)
|
||||
#define STM32F4_SPI_BR_DIV_MAX (2 << STM32F4_SPI_CR1_BR_MAX)
|
||||
#define STM32FX_SPI_BR_DIV_MIN (2 << STM32FX_SPI_CR1_BR_MIN)
|
||||
#define STM32FX_SPI_BR_DIV_MAX (2 << STM32FX_SPI_CR1_BR_MAX)
|
||||
|
||||
/* STM32H7 SPI registers */
|
||||
#define STM32H7_SPI_CR1 0x00
|
||||
@ -229,6 +236,8 @@ struct stm32_spi;
|
||||
* time between frames (if driver has this functionality)
|
||||
* @set_number_of_data: optional routine to configure registers to desired
|
||||
* number of data (if driver has this functionality)
|
||||
* @write_tx: routine to write to transmit register/FIFO
|
||||
* @read_rx: routine to read from receive register/FIFO
|
||||
* @transfer_one_dma_start: routine to start transfer a single spi_transfer
|
||||
* using DMA
|
||||
* @dma_rx_cb: routine to call after DMA RX channel operation is complete
|
||||
@ -252,6 +261,8 @@ struct stm32_spi_cfg {
|
||||
int (*set_mode)(struct stm32_spi *spi, unsigned int comm_type);
|
||||
void (*set_data_idleness)(struct stm32_spi *spi, u32 length);
|
||||
int (*set_number_of_data)(struct stm32_spi *spi, u32 length);
|
||||
void (*write_tx)(struct stm32_spi *spi);
|
||||
void (*read_rx)(struct stm32_spi *spi);
|
||||
void (*transfer_one_dma_start)(struct stm32_spi *spi);
|
||||
void (*dma_rx_cb)(void *data);
|
||||
void (*dma_tx_cb)(void *data);
|
||||
@ -324,20 +335,20 @@ struct stm32_spi {
|
||||
bool device_mode;
|
||||
};
|
||||
|
||||
static const struct stm32_spi_regspec stm32f4_spi_regspec = {
|
||||
.en = { STM32F4_SPI_CR1, STM32F4_SPI_CR1_SPE },
|
||||
static const struct stm32_spi_regspec stm32fx_spi_regspec = {
|
||||
.en = { STM32FX_SPI_CR1, STM32FX_SPI_CR1_SPE },
|
||||
|
||||
.dma_rx_en = { STM32F4_SPI_CR2, STM32F4_SPI_CR2_RXDMAEN },
|
||||
.dma_tx_en = { STM32F4_SPI_CR2, STM32F4_SPI_CR2_TXDMAEN },
|
||||
.dma_rx_en = { STM32FX_SPI_CR2, STM32FX_SPI_CR2_RXDMAEN },
|
||||
.dma_tx_en = { STM32FX_SPI_CR2, STM32FX_SPI_CR2_TXDMAEN },
|
||||
|
||||
.cpol = { STM32F4_SPI_CR1, STM32F4_SPI_CR1_CPOL },
|
||||
.cpha = { STM32F4_SPI_CR1, STM32F4_SPI_CR1_CPHA },
|
||||
.lsb_first = { STM32F4_SPI_CR1, STM32F4_SPI_CR1_LSBFRST },
|
||||
.cpol = { STM32FX_SPI_CR1, STM32FX_SPI_CR1_CPOL },
|
||||
.cpha = { STM32FX_SPI_CR1, STM32FX_SPI_CR1_CPHA },
|
||||
.lsb_first = { STM32FX_SPI_CR1, STM32FX_SPI_CR1_LSBFRST },
|
||||
.cs_high = {},
|
||||
.br = { STM32F4_SPI_CR1, STM32F4_SPI_CR1_BR, STM32F4_SPI_CR1_BR_SHIFT },
|
||||
.br = { STM32FX_SPI_CR1, STM32FX_SPI_CR1_BR, STM32FX_SPI_CR1_BR_SHIFT },
|
||||
|
||||
.rx = { STM32F4_SPI_DR },
|
||||
.tx = { STM32F4_SPI_DR },
|
||||
.rx = { STM32FX_SPI_DR },
|
||||
.tx = { STM32FX_SPI_DR },
|
||||
};
|
||||
|
||||
static const struct stm32_spi_regspec stm32h7_spi_regspec = {
|
||||
@ -409,6 +420,16 @@ static int stm32f4_spi_get_bpw_mask(struct stm32_spi *spi)
|
||||
return SPI_BPW_MASK(8) | SPI_BPW_MASK(16);
|
||||
}
|
||||
|
||||
/**
|
||||
* stm32f7_spi_get_bpw_mask - Return bits per word mask
|
||||
* @spi: pointer to the spi controller data structure
|
||||
*/
|
||||
static int stm32f7_spi_get_bpw_mask(struct stm32_spi *spi)
|
||||
{
|
||||
dev_dbg(spi->dev, "16-bit maximum data frame\n");
|
||||
return SPI_BPW_RANGE_MASK(4, 16);
|
||||
}
|
||||
|
||||
/**
|
||||
* stm32h7_spi_get_bpw_mask - Return bits per word mask
|
||||
* @spi: pointer to the spi controller data structure
|
||||
@ -502,19 +523,48 @@ static u32 stm32h7_spi_prepare_fthlv(struct stm32_spi *spi, u32 xfer_len)
|
||||
*/
|
||||
static void stm32f4_spi_write_tx(struct stm32_spi *spi)
|
||||
{
|
||||
if ((spi->tx_len > 0) && (readl_relaxed(spi->base + STM32F4_SPI_SR) &
|
||||
STM32F4_SPI_SR_TXE)) {
|
||||
if ((spi->tx_len > 0) && (readl_relaxed(spi->base + STM32FX_SPI_SR) &
|
||||
STM32FX_SPI_SR_TXE)) {
|
||||
u32 offs = spi->cur_xferlen - spi->tx_len;
|
||||
|
||||
if (spi->cur_bpw == 16) {
|
||||
const u16 *tx_buf16 = (const u16 *)(spi->tx_buf + offs);
|
||||
|
||||
writew_relaxed(*tx_buf16, spi->base + STM32F4_SPI_DR);
|
||||
writew_relaxed(*tx_buf16, spi->base + STM32FX_SPI_DR);
|
||||
spi->tx_len -= sizeof(u16);
|
||||
} else {
|
||||
const u8 *tx_buf8 = (const u8 *)(spi->tx_buf + offs);
|
||||
|
||||
writeb_relaxed(*tx_buf8, spi->base + STM32F4_SPI_DR);
|
||||
writeb_relaxed(*tx_buf8, spi->base + STM32FX_SPI_DR);
|
||||
spi->tx_len -= sizeof(u8);
|
||||
}
|
||||
}
|
||||
|
||||
dev_dbg(spi->dev, "%s: %d bytes left\n", __func__, spi->tx_len);
|
||||
}
|
||||
|
||||
/**
|
||||
* stm32f7_spi_write_tx - Write bytes to Transmit Data Register
|
||||
* @spi: pointer to the spi controller data structure
|
||||
*
|
||||
* Read from tx_buf depends on remaining bytes to avoid to read beyond
|
||||
* tx_buf end.
|
||||
*/
|
||||
static void stm32f7_spi_write_tx(struct stm32_spi *spi)
|
||||
{
|
||||
if ((spi->tx_len > 0) && (readl_relaxed(spi->base + STM32FX_SPI_SR) &
|
||||
STM32FX_SPI_SR_TXE)) {
|
||||
u32 offs = spi->cur_xferlen - spi->tx_len;
|
||||
|
||||
if (spi->tx_len >= sizeof(u16)) {
|
||||
const u16 *tx_buf16 = (const u16 *)(spi->tx_buf + offs);
|
||||
|
||||
writew_relaxed(*tx_buf16, spi->base + STM32FX_SPI_DR);
|
||||
spi->tx_len -= sizeof(u16);
|
||||
} else {
|
||||
const u8 *tx_buf8 = (const u8 *)(spi->tx_buf + offs);
|
||||
|
||||
writeb_relaxed(*tx_buf8, spi->base + STM32FX_SPI_DR);
|
||||
spi->tx_len -= sizeof(u8);
|
||||
}
|
||||
}
|
||||
@ -566,19 +616,19 @@ static void stm32h7_spi_write_txfifo(struct stm32_spi *spi)
|
||||
*/
|
||||
static void stm32f4_spi_read_rx(struct stm32_spi *spi)
|
||||
{
|
||||
if ((spi->rx_len > 0) && (readl_relaxed(spi->base + STM32F4_SPI_SR) &
|
||||
STM32F4_SPI_SR_RXNE)) {
|
||||
if ((spi->rx_len > 0) && (readl_relaxed(spi->base + STM32FX_SPI_SR) &
|
||||
STM32FX_SPI_SR_RXNE)) {
|
||||
u32 offs = spi->cur_xferlen - spi->rx_len;
|
||||
|
||||
if (spi->cur_bpw == 16) {
|
||||
u16 *rx_buf16 = (u16 *)(spi->rx_buf + offs);
|
||||
|
||||
*rx_buf16 = readw_relaxed(spi->base + STM32F4_SPI_DR);
|
||||
*rx_buf16 = readw_relaxed(spi->base + STM32FX_SPI_DR);
|
||||
spi->rx_len -= sizeof(u16);
|
||||
} else {
|
||||
u8 *rx_buf8 = (u8 *)(spi->rx_buf + offs);
|
||||
|
||||
*rx_buf8 = readb_relaxed(spi->base + STM32F4_SPI_DR);
|
||||
*rx_buf8 = readb_relaxed(spi->base + STM32FX_SPI_DR);
|
||||
spi->rx_len -= sizeof(u8);
|
||||
}
|
||||
}
|
||||
@ -586,6 +636,46 @@ static void stm32f4_spi_read_rx(struct stm32_spi *spi)
|
||||
dev_dbg(spi->dev, "%s: %d bytes left\n", __func__, spi->rx_len);
|
||||
}
|
||||
|
||||
/**
|
||||
* stm32f7_spi_read_rx - Read bytes from Receive Data Register
|
||||
* @spi: pointer to the spi controller data structure
|
||||
*
|
||||
* Write in rx_buf depends on remaining bytes to avoid to write beyond
|
||||
* rx_buf end.
|
||||
*/
|
||||
static void stm32f7_spi_read_rx(struct stm32_spi *spi)
|
||||
{
|
||||
u32 sr = readl_relaxed(spi->base + STM32FX_SPI_SR);
|
||||
u32 frlvl = FIELD_GET(STM32F7_SPI_SR_FRLVL, sr);
|
||||
|
||||
while ((spi->rx_len > 0) && (frlvl > 0)) {
|
||||
u32 offs = spi->cur_xferlen - spi->rx_len;
|
||||
|
||||
if ((spi->rx_len >= sizeof(u16)) && (frlvl >= 2)) {
|
||||
u16 *rx_buf16 = (u16 *)(spi->rx_buf + offs);
|
||||
|
||||
*rx_buf16 = readw_relaxed(spi->base + STM32FX_SPI_DR);
|
||||
spi->rx_len -= sizeof(u16);
|
||||
} else {
|
||||
u8 *rx_buf8 = (u8 *)(spi->rx_buf + offs);
|
||||
|
||||
*rx_buf8 = readb_relaxed(spi->base + STM32FX_SPI_DR);
|
||||
spi->rx_len -= sizeof(u8);
|
||||
}
|
||||
|
||||
sr = readl_relaxed(spi->base + STM32FX_SPI_SR);
|
||||
frlvl = FIELD_GET(STM32F7_SPI_SR_FRLVL, sr);
|
||||
}
|
||||
|
||||
if (spi->rx_len >= sizeof(u16))
|
||||
stm32_spi_clr_bits(spi, STM32FX_SPI_CR2, STM32F7_SPI_CR2_FRXTH);
|
||||
else
|
||||
stm32_spi_set_bits(spi, STM32FX_SPI_CR2, STM32F7_SPI_CR2_FRXTH);
|
||||
|
||||
dev_dbg(spi->dev, "%s: %d bytes left (sr=%08x)\n",
|
||||
__func__, spi->rx_len, sr);
|
||||
}
|
||||
|
||||
/**
|
||||
* stm32h7_spi_read_rxfifo - Read bytes in Receive Data Register
|
||||
* @spi: pointer to the spi controller data structure
|
||||
@ -645,10 +735,10 @@ static void stm32_spi_enable(struct stm32_spi *spi)
|
||||
}
|
||||
|
||||
/**
|
||||
* stm32f4_spi_disable - Disable SPI controller
|
||||
* stm32fx_spi_disable - Disable SPI controller
|
||||
* @spi: pointer to the spi controller data structure
|
||||
*/
|
||||
static void stm32f4_spi_disable(struct stm32_spi *spi)
|
||||
static void stm32fx_spi_disable(struct stm32_spi *spi)
|
||||
{
|
||||
unsigned long flags;
|
||||
u32 sr;
|
||||
@ -657,20 +747,20 @@ static void stm32f4_spi_disable(struct stm32_spi *spi)
|
||||
|
||||
spin_lock_irqsave(&spi->lock, flags);
|
||||
|
||||
if (!(readl_relaxed(spi->base + STM32F4_SPI_CR1) &
|
||||
STM32F4_SPI_CR1_SPE)) {
|
||||
if (!(readl_relaxed(spi->base + STM32FX_SPI_CR1) &
|
||||
STM32FX_SPI_CR1_SPE)) {
|
||||
spin_unlock_irqrestore(&spi->lock, flags);
|
||||
return;
|
||||
}
|
||||
|
||||
/* Disable interrupts */
|
||||
stm32_spi_clr_bits(spi, STM32F4_SPI_CR2, STM32F4_SPI_CR2_TXEIE |
|
||||
STM32F4_SPI_CR2_RXNEIE |
|
||||
STM32F4_SPI_CR2_ERRIE);
|
||||
stm32_spi_clr_bits(spi, STM32FX_SPI_CR2, STM32FX_SPI_CR2_TXEIE |
|
||||
STM32FX_SPI_CR2_RXNEIE |
|
||||
STM32FX_SPI_CR2_ERRIE);
|
||||
|
||||
/* Wait until BSY = 0 */
|
||||
if (readl_relaxed_poll_timeout_atomic(spi->base + STM32F4_SPI_SR,
|
||||
sr, !(sr & STM32F4_SPI_SR_BSY),
|
||||
if (readl_relaxed_poll_timeout_atomic(spi->base + STM32FX_SPI_SR,
|
||||
sr, !(sr & STM32FX_SPI_SR_BSY),
|
||||
10, 100000) < 0) {
|
||||
dev_warn(spi->dev, "disabling condition timeout\n");
|
||||
}
|
||||
@ -680,14 +770,14 @@ static void stm32f4_spi_disable(struct stm32_spi *spi)
|
||||
if (spi->cur_usedma && spi->dma_rx)
|
||||
dmaengine_terminate_async(spi->dma_rx);
|
||||
|
||||
stm32_spi_clr_bits(spi, STM32F4_SPI_CR1, STM32F4_SPI_CR1_SPE);
|
||||
stm32_spi_clr_bits(spi, STM32FX_SPI_CR1, STM32FX_SPI_CR1_SPE);
|
||||
|
||||
stm32_spi_clr_bits(spi, STM32F4_SPI_CR2, STM32F4_SPI_CR2_TXDMAEN |
|
||||
STM32F4_SPI_CR2_RXDMAEN);
|
||||
stm32_spi_clr_bits(spi, STM32FX_SPI_CR2, STM32FX_SPI_CR2_TXDMAEN |
|
||||
STM32FX_SPI_CR2_RXDMAEN);
|
||||
|
||||
/* Sequence to clear OVR flag */
|
||||
readl_relaxed(spi->base + STM32F4_SPI_DR);
|
||||
readl_relaxed(spi->base + STM32F4_SPI_SR);
|
||||
readl_relaxed(spi->base + STM32FX_SPI_DR);
|
||||
readl_relaxed(spi->base + STM32FX_SPI_SR);
|
||||
|
||||
spin_unlock_irqrestore(&spi->lock, flags);
|
||||
}
|
||||
@ -763,11 +853,11 @@ static bool stm32_spi_can_dma(struct spi_controller *ctrl,
|
||||
}
|
||||
|
||||
/**
|
||||
* stm32f4_spi_irq_event - Interrupt handler for SPI controller events
|
||||
* stm32fx_spi_irq_event - Interrupt handler for SPI controller events
|
||||
* @irq: interrupt line
|
||||
* @dev_id: SPI controller ctrl interface
|
||||
*/
|
||||
static irqreturn_t stm32f4_spi_irq_event(int irq, void *dev_id)
|
||||
static irqreturn_t stm32fx_spi_irq_event(int irq, void *dev_id)
|
||||
{
|
||||
struct spi_controller *ctrl = dev_id;
|
||||
struct stm32_spi *spi = spi_controller_get_devdata(ctrl);
|
||||
@ -776,26 +866,26 @@ static irqreturn_t stm32f4_spi_irq_event(int irq, void *dev_id)
|
||||
|
||||
spin_lock(&spi->lock);
|
||||
|
||||
sr = readl_relaxed(spi->base + STM32F4_SPI_SR);
|
||||
sr = readl_relaxed(spi->base + STM32FX_SPI_SR);
|
||||
/*
|
||||
* BSY flag is not handled in interrupt but it is normal behavior when
|
||||
* this flag is set.
|
||||
*/
|
||||
sr &= ~STM32F4_SPI_SR_BSY;
|
||||
sr &= ~STM32FX_SPI_SR_BSY;
|
||||
|
||||
if (!spi->cur_usedma && (spi->cur_comm == SPI_SIMPLEX_TX ||
|
||||
spi->cur_comm == SPI_3WIRE_TX)) {
|
||||
/* OVR flag shouldn't be handled for TX only mode */
|
||||
sr &= ~(STM32F4_SPI_SR_OVR | STM32F4_SPI_SR_RXNE);
|
||||
mask |= STM32F4_SPI_SR_TXE;
|
||||
sr &= ~(STM32FX_SPI_SR_OVR | STM32FX_SPI_SR_RXNE);
|
||||
mask |= STM32FX_SPI_SR_TXE;
|
||||
}
|
||||
|
||||
if (!spi->cur_usedma && (spi->cur_comm == SPI_FULL_DUPLEX ||
|
||||
spi->cur_comm == SPI_SIMPLEX_RX ||
|
||||
spi->cur_comm == SPI_3WIRE_RX)) {
|
||||
/* TXE flag is set and is handled when RXNE flag occurs */
|
||||
sr &= ~STM32F4_SPI_SR_TXE;
|
||||
mask |= STM32F4_SPI_SR_RXNE | STM32F4_SPI_SR_OVR;
|
||||
sr &= ~STM32FX_SPI_SR_TXE;
|
||||
mask |= STM32FX_SPI_SR_RXNE | STM32FX_SPI_SR_OVR;
|
||||
}
|
||||
|
||||
if (!(sr & mask)) {
|
||||
@ -804,12 +894,12 @@ static irqreturn_t stm32f4_spi_irq_event(int irq, void *dev_id)
|
||||
return IRQ_NONE;
|
||||
}
|
||||
|
||||
if (sr & STM32F4_SPI_SR_OVR) {
|
||||
if (sr & STM32FX_SPI_SR_OVR) {
|
||||
dev_warn(spi->dev, "Overrun: received value discarded\n");
|
||||
|
||||
/* Sequence to clear OVR flag */
|
||||
readl_relaxed(spi->base + STM32F4_SPI_DR);
|
||||
readl_relaxed(spi->base + STM32F4_SPI_SR);
|
||||
readl_relaxed(spi->base + STM32FX_SPI_DR);
|
||||
readl_relaxed(spi->base + STM32FX_SPI_SR);
|
||||
|
||||
/*
|
||||
* If overrun is detected, it means that something went wrong,
|
||||
@ -820,28 +910,28 @@ static irqreturn_t stm32f4_spi_irq_event(int irq, void *dev_id)
|
||||
goto end_irq;
|
||||
}
|
||||
|
||||
if (sr & STM32F4_SPI_SR_TXE) {
|
||||
if (sr & STM32FX_SPI_SR_TXE) {
|
||||
if (spi->tx_buf)
|
||||
stm32f4_spi_write_tx(spi);
|
||||
spi->cfg->write_tx(spi);
|
||||
if (spi->tx_len == 0)
|
||||
end = true;
|
||||
}
|
||||
|
||||
if (sr & STM32F4_SPI_SR_RXNE) {
|
||||
stm32f4_spi_read_rx(spi);
|
||||
if (sr & STM32FX_SPI_SR_RXNE) {
|
||||
spi->cfg->read_rx(spi);
|
||||
if (spi->rx_len == 0)
|
||||
end = true;
|
||||
else if (spi->tx_buf)/* Load data for discontinuous mode */
|
||||
stm32f4_spi_write_tx(spi);
|
||||
spi->cfg->write_tx(spi);
|
||||
}
|
||||
|
||||
end_irq:
|
||||
if (end) {
|
||||
/* Immediately disable interrupts to do not generate new one */
|
||||
stm32_spi_clr_bits(spi, STM32F4_SPI_CR2,
|
||||
STM32F4_SPI_CR2_TXEIE |
|
||||
STM32F4_SPI_CR2_RXNEIE |
|
||||
STM32F4_SPI_CR2_ERRIE);
|
||||
stm32_spi_clr_bits(spi, STM32FX_SPI_CR2,
|
||||
STM32FX_SPI_CR2_TXEIE |
|
||||
STM32FX_SPI_CR2_RXNEIE |
|
||||
STM32FX_SPI_CR2_ERRIE);
|
||||
spin_unlock(&spi->lock);
|
||||
return IRQ_WAKE_THREAD;
|
||||
}
|
||||
@ -851,17 +941,17 @@ end_irq:
|
||||
}
|
||||
|
||||
/**
|
||||
* stm32f4_spi_irq_thread - Thread of interrupt handler for SPI controller
|
||||
* stm32fx_spi_irq_thread - Thread of interrupt handler for SPI controller
|
||||
* @irq: interrupt line
|
||||
* @dev_id: SPI controller interface
|
||||
*/
|
||||
static irqreturn_t stm32f4_spi_irq_thread(int irq, void *dev_id)
|
||||
static irqreturn_t stm32fx_spi_irq_thread(int irq, void *dev_id)
|
||||
{
|
||||
struct spi_controller *ctrl = dev_id;
|
||||
struct stm32_spi *spi = spi_controller_get_devdata(ctrl);
|
||||
|
||||
spi_finalize_current_transfer(ctrl);
|
||||
stm32f4_spi_disable(spi);
|
||||
stm32fx_spi_disable(spi);
|
||||
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
@ -1034,18 +1124,18 @@ static int stm32_spi_prepare_msg(struct spi_controller *ctrl,
|
||||
}
|
||||
|
||||
/**
|
||||
* stm32f4_spi_dma_tx_cb - dma callback
|
||||
* stm32fx_spi_dma_tx_cb - dma callback
|
||||
* @data: pointer to the spi controller data structure
|
||||
*
|
||||
* DMA callback is called when the transfer is complete for DMA TX channel.
|
||||
*/
|
||||
static void stm32f4_spi_dma_tx_cb(void *data)
|
||||
static void stm32fx_spi_dma_tx_cb(void *data)
|
||||
{
|
||||
struct stm32_spi *spi = data;
|
||||
|
||||
if (spi->cur_comm == SPI_SIMPLEX_TX || spi->cur_comm == SPI_3WIRE_TX) {
|
||||
spi_finalize_current_transfer(spi->ctrl);
|
||||
stm32f4_spi_disable(spi);
|
||||
stm32fx_spi_disable(spi);
|
||||
}
|
||||
}
|
||||
|
||||
@ -1114,21 +1204,21 @@ static void stm32_spi_dma_config(struct stm32_spi *spi,
|
||||
}
|
||||
|
||||
/**
|
||||
* stm32f4_spi_transfer_one_irq - transfer a single spi_transfer using
|
||||
* stm32fx_spi_transfer_one_irq - transfer a single spi_transfer using
|
||||
* interrupts
|
||||
* @spi: pointer to the spi controller data structure
|
||||
*
|
||||
* It must returns 0 if the transfer is finished or 1 if the transfer is still
|
||||
* in progress.
|
||||
*/
|
||||
static int stm32f4_spi_transfer_one_irq(struct stm32_spi *spi)
|
||||
static int stm32fx_spi_transfer_one_irq(struct stm32_spi *spi)
|
||||
{
|
||||
unsigned long flags;
|
||||
u32 cr2 = 0;
|
||||
|
||||
/* Enable the interrupts relative to the current communication mode */
|
||||
if (spi->cur_comm == SPI_SIMPLEX_TX || spi->cur_comm == SPI_3WIRE_TX) {
|
||||
cr2 |= STM32F4_SPI_CR2_TXEIE;
|
||||
cr2 |= STM32FX_SPI_CR2_TXEIE;
|
||||
} else if (spi->cur_comm == SPI_FULL_DUPLEX ||
|
||||
spi->cur_comm == SPI_SIMPLEX_RX ||
|
||||
spi->cur_comm == SPI_3WIRE_RX) {
|
||||
@ -1136,20 +1226,20 @@ static int stm32f4_spi_transfer_one_irq(struct stm32_spi *spi)
|
||||
* since the received data are never read. Therefore set OVR
|
||||
* interrupt only when rx buffer is available.
|
||||
*/
|
||||
cr2 |= STM32F4_SPI_CR2_RXNEIE | STM32F4_SPI_CR2_ERRIE;
|
||||
cr2 |= STM32FX_SPI_CR2_RXNEIE | STM32FX_SPI_CR2_ERRIE;
|
||||
} else {
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
spin_lock_irqsave(&spi->lock, flags);
|
||||
|
||||
stm32_spi_set_bits(spi, STM32F4_SPI_CR2, cr2);
|
||||
stm32_spi_set_bits(spi, STM32FX_SPI_CR2, cr2);
|
||||
|
||||
stm32_spi_enable(spi);
|
||||
|
||||
/* starting data transfer when buffer is loaded */
|
||||
if (spi->tx_buf)
|
||||
stm32f4_spi_write_tx(spi);
|
||||
spi->cfg->write_tx(spi);
|
||||
|
||||
spin_unlock_irqrestore(&spi->lock, flags);
|
||||
|
||||
@ -1200,11 +1290,11 @@ static int stm32h7_spi_transfer_one_irq(struct stm32_spi *spi)
|
||||
}
|
||||
|
||||
/**
|
||||
* stm32f4_spi_transfer_one_dma_start - Set SPI driver registers to start
|
||||
* stm32fx_spi_transfer_one_dma_start - Set SPI driver registers to start
|
||||
* transfer using DMA
|
||||
* @spi: pointer to the spi controller data structure
|
||||
*/
|
||||
static void stm32f4_spi_transfer_one_dma_start(struct stm32_spi *spi)
|
||||
static void stm32fx_spi_transfer_one_dma_start(struct stm32_spi *spi)
|
||||
{
|
||||
/* In DMA mode end of transfer is handled by DMA TX or RX callback. */
|
||||
if (spi->cur_comm == SPI_SIMPLEX_RX || spi->cur_comm == SPI_3WIRE_RX ||
|
||||
@ -1214,12 +1304,28 @@ static void stm32f4_spi_transfer_one_dma_start(struct stm32_spi *spi)
|
||||
* since the received data are never read. Therefore set OVR
|
||||
* interrupt only when rx buffer is available.
|
||||
*/
|
||||
stm32_spi_set_bits(spi, STM32F4_SPI_CR2, STM32F4_SPI_CR2_ERRIE);
|
||||
stm32_spi_set_bits(spi, STM32FX_SPI_CR2, STM32FX_SPI_CR2_ERRIE);
|
||||
}
|
||||
|
||||
stm32_spi_enable(spi);
|
||||
}
|
||||
|
||||
/**
|
||||
* stm32f7_spi_transfer_one_dma_start - Set SPI driver registers to start
|
||||
* transfer using DMA
|
||||
* @spi: pointer to the spi controller data structure
|
||||
*/
|
||||
static void stm32f7_spi_transfer_one_dma_start(struct stm32_spi *spi)
|
||||
{
|
||||
/* Configure DMA request trigger threshold according to DMA width */
|
||||
if (spi->cur_bpw <= 8)
|
||||
stm32_spi_set_bits(spi, STM32FX_SPI_CR2, STM32F7_SPI_CR2_FRXTH);
|
||||
else
|
||||
stm32_spi_clr_bits(spi, STM32FX_SPI_CR2, STM32F7_SPI_CR2_FRXTH);
|
||||
|
||||
stm32fx_spi_transfer_one_dma_start(spi);
|
||||
}
|
||||
|
||||
/**
|
||||
* stm32h7_spi_transfer_one_dma_start - Set SPI driver registers to start
|
||||
* transfer using DMA
|
||||
@ -1353,9 +1459,34 @@ dma_desc_error:
|
||||
static void stm32f4_spi_set_bpw(struct stm32_spi *spi)
|
||||
{
|
||||
if (spi->cur_bpw == 16)
|
||||
stm32_spi_set_bits(spi, STM32F4_SPI_CR1, STM32F4_SPI_CR1_DFF);
|
||||
stm32_spi_set_bits(spi, STM32FX_SPI_CR1, STM32F4_SPI_CR1_DFF);
|
||||
else
|
||||
stm32_spi_clr_bits(spi, STM32F4_SPI_CR1, STM32F4_SPI_CR1_DFF);
|
||||
stm32_spi_clr_bits(spi, STM32FX_SPI_CR1, STM32F4_SPI_CR1_DFF);
|
||||
}
|
||||
|
||||
/**
|
||||
* stm32f7_spi_set_bpw - Configure bits per word
|
||||
* @spi: pointer to the spi controller data structure
|
||||
*/
|
||||
static void stm32f7_spi_set_bpw(struct stm32_spi *spi)
|
||||
{
|
||||
u32 bpw;
|
||||
u32 cr2_clrb = 0, cr2_setb = 0;
|
||||
|
||||
bpw = spi->cur_bpw - 1;
|
||||
|
||||
cr2_clrb |= STM32F7_SPI_CR2_DS;
|
||||
cr2_setb |= FIELD_PREP(STM32F7_SPI_CR2_DS, bpw);
|
||||
|
||||
if (spi->rx_len >= sizeof(u16))
|
||||
cr2_clrb |= STM32F7_SPI_CR2_FRXTH;
|
||||
else
|
||||
cr2_setb |= STM32F7_SPI_CR2_FRXTH;
|
||||
|
||||
writel_relaxed(
|
||||
(readl_relaxed(spi->base + STM32FX_SPI_CR2) &
|
||||
~cr2_clrb) | cr2_setb,
|
||||
spi->base + STM32FX_SPI_CR2);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -1433,26 +1564,26 @@ static unsigned int stm32_spi_communication_type(struct spi_device *spi_dev,
|
||||
}
|
||||
|
||||
/**
|
||||
* stm32f4_spi_set_mode - configure communication mode
|
||||
* stm32fx_spi_set_mode - configure communication mode
|
||||
* @spi: pointer to the spi controller data structure
|
||||
* @comm_type: type of communication to configure
|
||||
*/
|
||||
static int stm32f4_spi_set_mode(struct stm32_spi *spi, unsigned int comm_type)
|
||||
static int stm32fx_spi_set_mode(struct stm32_spi *spi, unsigned int comm_type)
|
||||
{
|
||||
if (comm_type == SPI_3WIRE_TX || comm_type == SPI_SIMPLEX_TX) {
|
||||
stm32_spi_set_bits(spi, STM32F4_SPI_CR1,
|
||||
STM32F4_SPI_CR1_BIDIMODE |
|
||||
STM32F4_SPI_CR1_BIDIOE);
|
||||
stm32_spi_set_bits(spi, STM32FX_SPI_CR1,
|
||||
STM32FX_SPI_CR1_BIDIMODE |
|
||||
STM32FX_SPI_CR1_BIDIOE);
|
||||
} else if (comm_type == SPI_FULL_DUPLEX ||
|
||||
comm_type == SPI_SIMPLEX_RX) {
|
||||
stm32_spi_clr_bits(spi, STM32F4_SPI_CR1,
|
||||
STM32F4_SPI_CR1_BIDIMODE |
|
||||
STM32F4_SPI_CR1_BIDIOE);
|
||||
stm32_spi_clr_bits(spi, STM32FX_SPI_CR1,
|
||||
STM32FX_SPI_CR1_BIDIMODE |
|
||||
STM32FX_SPI_CR1_BIDIOE);
|
||||
} else if (comm_type == SPI_3WIRE_RX) {
|
||||
stm32_spi_set_bits(spi, STM32F4_SPI_CR1,
|
||||
STM32F4_SPI_CR1_BIDIMODE);
|
||||
stm32_spi_clr_bits(spi, STM32F4_SPI_CR1,
|
||||
STM32F4_SPI_CR1_BIDIOE);
|
||||
stm32_spi_set_bits(spi, STM32FX_SPI_CR1,
|
||||
STM32FX_SPI_CR1_BIDIMODE);
|
||||
stm32_spi_clr_bits(spi, STM32FX_SPI_CR1,
|
||||
STM32FX_SPI_CR1_BIDIOE);
|
||||
} else {
|
||||
return -EINVAL;
|
||||
}
|
||||
@ -1672,18 +1803,18 @@ static int stm32_spi_unprepare_msg(struct spi_controller *ctrl,
|
||||
}
|
||||
|
||||
/**
|
||||
* stm32f4_spi_config - Configure SPI controller as SPI master
|
||||
* stm32fx_spi_config - Configure SPI controller as SPI master
|
||||
* @spi: pointer to the spi controller data structure
|
||||
*/
|
||||
static int stm32f4_spi_config(struct stm32_spi *spi)
|
||||
static int stm32fx_spi_config(struct stm32_spi *spi)
|
||||
{
|
||||
unsigned long flags;
|
||||
|
||||
spin_lock_irqsave(&spi->lock, flags);
|
||||
|
||||
/* Ensure I2SMOD bit is kept cleared */
|
||||
stm32_spi_clr_bits(spi, STM32F4_SPI_I2SCFGR,
|
||||
STM32F4_SPI_I2SCFGR_I2SMOD);
|
||||
stm32_spi_clr_bits(spi, STM32FX_SPI_I2SCFGR,
|
||||
STM32FX_SPI_I2SCFGR_I2SMOD);
|
||||
|
||||
/*
|
||||
* - SS input value high
|
||||
@ -1692,10 +1823,10 @@ static int stm32f4_spi_config(struct stm32_spi *spi)
|
||||
* - Consider 1 master/n slaves configuration and
|
||||
* SS input value is determined by the SSI bit
|
||||
*/
|
||||
stm32_spi_set_bits(spi, STM32F4_SPI_CR1, STM32F4_SPI_CR1_SSI |
|
||||
STM32F4_SPI_CR1_BIDIOE |
|
||||
STM32F4_SPI_CR1_MSTR |
|
||||
STM32F4_SPI_CR1_SSM);
|
||||
stm32_spi_set_bits(spi, STM32FX_SPI_CR1, STM32FX_SPI_CR1_SSI |
|
||||
STM32FX_SPI_CR1_BIDIOE |
|
||||
STM32FX_SPI_CR1_MSTR |
|
||||
STM32FX_SPI_CR1_SSM);
|
||||
|
||||
spin_unlock_irqrestore(&spi->lock, flags);
|
||||
|
||||
@ -1746,25 +1877,48 @@ static int stm32h7_spi_config(struct stm32_spi *spi)
|
||||
}
|
||||
|
||||
static const struct stm32_spi_cfg stm32f4_spi_cfg = {
|
||||
.regs = &stm32f4_spi_regspec,
|
||||
.regs = &stm32fx_spi_regspec,
|
||||
.get_bpw_mask = stm32f4_spi_get_bpw_mask,
|
||||
.disable = stm32f4_spi_disable,
|
||||
.config = stm32f4_spi_config,
|
||||
.disable = stm32fx_spi_disable,
|
||||
.config = stm32fx_spi_config,
|
||||
.set_bpw = stm32f4_spi_set_bpw,
|
||||
.set_mode = stm32f4_spi_set_mode,
|
||||
.transfer_one_dma_start = stm32f4_spi_transfer_one_dma_start,
|
||||
.dma_tx_cb = stm32f4_spi_dma_tx_cb,
|
||||
.set_mode = stm32fx_spi_set_mode,
|
||||
.write_tx = stm32f4_spi_write_tx,
|
||||
.read_rx = stm32f4_spi_read_rx,
|
||||
.transfer_one_dma_start = stm32fx_spi_transfer_one_dma_start,
|
||||
.dma_tx_cb = stm32fx_spi_dma_tx_cb,
|
||||
.dma_rx_cb = stm32_spi_dma_rx_cb,
|
||||
.transfer_one_irq = stm32f4_spi_transfer_one_irq,
|
||||
.irq_handler_event = stm32f4_spi_irq_event,
|
||||
.irq_handler_thread = stm32f4_spi_irq_thread,
|
||||
.baud_rate_div_min = STM32F4_SPI_BR_DIV_MIN,
|
||||
.baud_rate_div_max = STM32F4_SPI_BR_DIV_MAX,
|
||||
.transfer_one_irq = stm32fx_spi_transfer_one_irq,
|
||||
.irq_handler_event = stm32fx_spi_irq_event,
|
||||
.irq_handler_thread = stm32fx_spi_irq_thread,
|
||||
.baud_rate_div_min = STM32FX_SPI_BR_DIV_MIN,
|
||||
.baud_rate_div_max = STM32FX_SPI_BR_DIV_MAX,
|
||||
.has_fifo = false,
|
||||
.has_device_mode = false,
|
||||
.flags = SPI_CONTROLLER_MUST_TX,
|
||||
};
|
||||
|
||||
static const struct stm32_spi_cfg stm32f7_spi_cfg = {
|
||||
.regs = &stm32fx_spi_regspec,
|
||||
.get_bpw_mask = stm32f7_spi_get_bpw_mask,
|
||||
.disable = stm32fx_spi_disable,
|
||||
.config = stm32fx_spi_config,
|
||||
.set_bpw = stm32f7_spi_set_bpw,
|
||||
.set_mode = stm32fx_spi_set_mode,
|
||||
.write_tx = stm32f7_spi_write_tx,
|
||||
.read_rx = stm32f7_spi_read_rx,
|
||||
.transfer_one_dma_start = stm32f7_spi_transfer_one_dma_start,
|
||||
.dma_tx_cb = stm32fx_spi_dma_tx_cb,
|
||||
.dma_rx_cb = stm32_spi_dma_rx_cb,
|
||||
.transfer_one_irq = stm32fx_spi_transfer_one_irq,
|
||||
.irq_handler_event = stm32fx_spi_irq_event,
|
||||
.irq_handler_thread = stm32fx_spi_irq_thread,
|
||||
.baud_rate_div_min = STM32FX_SPI_BR_DIV_MIN,
|
||||
.baud_rate_div_max = STM32FX_SPI_BR_DIV_MAX,
|
||||
.has_fifo = false,
|
||||
.flags = SPI_CONTROLLER_MUST_TX,
|
||||
};
|
||||
|
||||
static const struct stm32_spi_cfg stm32h7_spi_cfg = {
|
||||
.regs = &stm32h7_spi_regspec,
|
||||
.get_fifo_size = stm32h7_spi_get_fifo_size,
|
||||
@ -1775,6 +1929,8 @@ static const struct stm32_spi_cfg stm32h7_spi_cfg = {
|
||||
.set_mode = stm32h7_spi_set_mode,
|
||||
.set_data_idleness = stm32h7_spi_data_idleness,
|
||||
.set_number_of_data = stm32h7_spi_number_of_data,
|
||||
.write_tx = stm32h7_spi_write_txfifo,
|
||||
.read_rx = stm32h7_spi_read_rxfifo,
|
||||
.transfer_one_dma_start = stm32h7_spi_transfer_one_dma_start,
|
||||
.dma_rx_cb = stm32_spi_dma_rx_cb,
|
||||
/*
|
||||
@ -1792,6 +1948,7 @@ static const struct stm32_spi_cfg stm32h7_spi_cfg = {
|
||||
static const struct of_device_id stm32_spi_of_match[] = {
|
||||
{ .compatible = "st,stm32h7-spi", .data = (void *)&stm32h7_spi_cfg },
|
||||
{ .compatible = "st,stm32f4-spi", .data = (void *)&stm32f4_spi_cfg },
|
||||
{ .compatible = "st,stm32f7-spi", .data = (void *)&stm32f7_spi_cfg },
|
||||
{},
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, stm32_spi_of_match);
|
||||
|
Loading…
Reference in New Issue
Block a user