spi: stm32: add STM32F7 support
The STM32F7 SPI peripheral is similar to the STM32F4, except it allows arbitrary word lengths between 4 and 16 bits, and has a small 32-bit FIFO that allows two 8-bit or smaller words to be transferred with a single 16-bit read/write. Signed-off-by: Ben Wolsieffer <ben.wolsieffer@hefring.com> Link: https://lore.kernel.org/r/20231102193722.3042245-5-ben.wolsieffer@hefring.com Signed-off-by: Mark Brown <broonie@kernel.org>
This commit is contained in:
parent
247ba5ea05
commit
a84dcb410b
@ -41,6 +41,7 @@
|
||||
#define STM32FX_SPI_CR1_SSM BIT(9)
|
||||
#define STM32FX_SPI_CR1_RXONLY BIT(10)
|
||||
#define STM32F4_SPI_CR1_DFF BIT(11)
|
||||
#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)
|
||||
@ -56,6 +57,10 @@
|
||||
#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)
|
||||
|
||||
/* STM32FX_SPI_SR bit fields */
|
||||
#define STM32FX_SPI_SR_RXNE BIT(0)
|
||||
@ -67,6 +72,8 @@
|
||||
#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)
|
||||
|
||||
/* STM32FX_SPI_I2SCFGR bit fields */
|
||||
#define STM32FX_SPI_I2SCFGR_I2SMOD BIT(11)
|
||||
@ -413,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
|
||||
@ -526,6 +543,35 @@ static void stm32f4_spi_write_tx(struct stm32_spi *spi)
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
dev_dbg(spi->dev, "%s: %d bytes left\n", __func__, spi->tx_len);
|
||||
}
|
||||
|
||||
/**
|
||||
* stm32h7_spi_write_txfifo - Write bytes in Transmit Data Register
|
||||
* @spi: pointer to the spi controller data structure
|
||||
@ -590,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
|
||||
@ -1224,6 +1310,22 @@ static void stm32fx_spi_transfer_one_dma_start(struct stm32_spi *spi)
|
||||
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
|
||||
@ -1362,6 +1464,31 @@ static void stm32f4_spi_set_bpw(struct stm32_spi *spi)
|
||||
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);
|
||||
}
|
||||
|
||||
/**
|
||||
* stm32h7_spi_set_bpw - configure bits per word
|
||||
* @spi: pointer to the spi controller data structure
|
||||
@ -1771,6 +1898,27 @@ static const struct stm32_spi_cfg stm32f4_spi_cfg = {
|
||||
.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,
|
||||
@ -1800,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