mirror of
https://mirrors.bfsu.edu.cn/git/linux.git
synced 2024-11-25 05:04:09 +08:00
spi: stm32: add support for STM32F4
Add routines, registers & bitfield definition. Also baud rate divisor definitions for STM32F4 SPI. This version supports full-duplex, simplex TX and half-duplex TX communication with 8 or 16-bit per word. DMA capability is optionally supported for transfer longer than 16 bytes. For transfer less than 16 bytes frames can be send in discontinuous mode. Signed-off-by: Cezary Gapinski <cezary.gapinski@gmail.com> Signed-off-by: Mark Brown <broonie@kernel.org>
This commit is contained in:
parent
55166853b2
commit
00505edf95
@ -20,6 +20,59 @@
|
||||
|
||||
#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_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)
|
||||
#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)
|
||||
|
||||
/* 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)
|
||||
|
||||
/* 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)
|
||||
|
||||
/* STM32F4_SPI_I2SCFGR bit fields */
|
||||
#define STM32F4_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)
|
||||
|
||||
/* STM32H7 SPI registers */
|
||||
#define STM32H7_SPI_CR1 0x00
|
||||
#define STM32H7_SPI_CR2 0x04
|
||||
@ -116,6 +169,12 @@
|
||||
|
||||
#define SPI_1HZ_NS 1000000000
|
||||
|
||||
/*
|
||||
* use PIO for small transfers, avoiding DMA setup/teardown overhead for drivers
|
||||
* without fifo buffers.
|
||||
*/
|
||||
#define SPI_DMA_MIN_BYTES 16
|
||||
|
||||
/**
|
||||
* stm32_spi_reg - stm32 SPI register & bitfield desc
|
||||
* @reg: register offset
|
||||
@ -257,6 +316,21 @@ struct stm32_spi {
|
||||
dma_addr_t phys_addr;
|
||||
};
|
||||
|
||||
static const struct stm32_spi_regspec stm32f4_spi_regspec = {
|
||||
.en = { STM32F4_SPI_CR1, STM32F4_SPI_CR1_SPE },
|
||||
|
||||
.dma_rx_en = { STM32F4_SPI_CR2, STM32F4_SPI_CR2_RXDMAEN },
|
||||
.dma_tx_en = { STM32F4_SPI_CR2, STM32F4_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 },
|
||||
.br = { STM32F4_SPI_CR1, STM32F4_SPI_CR1_BR, STM32F4_SPI_CR1_BR_SHIFT },
|
||||
|
||||
.rx = { STM32F4_SPI_DR },
|
||||
.tx = { STM32F4_SPI_DR },
|
||||
};
|
||||
|
||||
static const struct stm32_spi_regspec stm32h7_spi_regspec = {
|
||||
/* SPI data transfer is enabled but spi_ker_ck is idle.
|
||||
* CFG1 and CFG2 registers are write protected when SPE is enabled.
|
||||
@ -315,6 +389,16 @@ static int stm32h7_spi_get_fifo_size(struct stm32_spi *spi)
|
||||
return count;
|
||||
}
|
||||
|
||||
/**
|
||||
* stm32f4_spi_get_bpw_mask - Return bits per word mask
|
||||
* @spi: pointer to the spi controller data structure
|
||||
*/
|
||||
static int stm32f4_spi_get_bpw_mask(struct stm32_spi *spi)
|
||||
{
|
||||
dev_dbg(spi->dev, "8-bit or 16-bit data frame supported\n");
|
||||
return SPI_BPW_MASK(8) | SPI_BPW_MASK(16);
|
||||
}
|
||||
|
||||
/**
|
||||
* stm32h7_spi_get_bpw_mask - Return bits per word mask
|
||||
* @spi: pointer to the spi controller data structure
|
||||
@ -408,6 +492,35 @@ static u32 stm32h7_spi_prepare_fthlv(struct stm32_spi *spi)
|
||||
return fthlv;
|
||||
}
|
||||
|
||||
/**
|
||||
* stm32f4_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 stm32f4_spi_write_tx(struct stm32_spi *spi)
|
||||
{
|
||||
if ((spi->tx_len > 0) && (readl_relaxed(spi->base + STM32F4_SPI_SR) &
|
||||
STM32F4_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);
|
||||
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);
|
||||
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
|
||||
@ -443,6 +556,35 @@ static void stm32h7_spi_write_txfifo(struct stm32_spi *spi)
|
||||
dev_dbg(spi->dev, "%s: %d bytes left\n", __func__, spi->tx_len);
|
||||
}
|
||||
|
||||
/**
|
||||
* stm32f4_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 stm32f4_spi_read_rx(struct stm32_spi *spi)
|
||||
{
|
||||
if ((spi->rx_len > 0) && (readl_relaxed(spi->base + STM32F4_SPI_SR) &
|
||||
STM32F4_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);
|
||||
spi->rx_len -= sizeof(u16);
|
||||
} else {
|
||||
u8 *rx_buf8 = (u8 *)(spi->rx_buf + offs);
|
||||
|
||||
*rx_buf8 = readb_relaxed(spi->base + STM32F4_SPI_DR);
|
||||
spi->rx_len -= sizeof(u8);
|
||||
}
|
||||
}
|
||||
|
||||
dev_dbg(spi->dev, "%s: %d bytes left\n", __func__, spi->rx_len);
|
||||
}
|
||||
|
||||
/**
|
||||
* stm32h7_spi_read_rxfifo - Read bytes in Receive Data Register
|
||||
* @spi: pointer to the spi controller data structure
|
||||
@ -501,6 +643,54 @@ static void stm32_spi_enable(struct stm32_spi *spi)
|
||||
spi->cfg->regs->en.mask);
|
||||
}
|
||||
|
||||
/**
|
||||
* stm32f4_spi_disable - Disable SPI controller
|
||||
* @spi: pointer to the spi controller data structure
|
||||
*/
|
||||
static void stm32f4_spi_disable(struct stm32_spi *spi)
|
||||
{
|
||||
unsigned long flags;
|
||||
u32 sr;
|
||||
|
||||
dev_dbg(spi->dev, "disable controller\n");
|
||||
|
||||
spin_lock_irqsave(&spi->lock, flags);
|
||||
|
||||
if (!(readl_relaxed(spi->base + STM32F4_SPI_CR1) &
|
||||
STM32F4_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);
|
||||
|
||||
/* Wait until BSY = 0 */
|
||||
if (readl_relaxed_poll_timeout_atomic(spi->base + STM32F4_SPI_SR,
|
||||
sr, !(sr & STM32F4_SPI_SR_BSY),
|
||||
10, 100000) < 0) {
|
||||
dev_warn(spi->dev, "disabling condition timeout\n");
|
||||
}
|
||||
|
||||
if (spi->cur_usedma && spi->dma_tx)
|
||||
dmaengine_terminate_all(spi->dma_tx);
|
||||
if (spi->cur_usedma && spi->dma_rx)
|
||||
dmaengine_terminate_all(spi->dma_rx);
|
||||
|
||||
stm32_spi_clr_bits(spi, STM32F4_SPI_CR1, STM32F4_SPI_CR1_SPE);
|
||||
|
||||
stm32_spi_clr_bits(spi, STM32F4_SPI_CR2, STM32F4_SPI_CR2_TXDMAEN |
|
||||
STM32F4_SPI_CR2_RXDMAEN);
|
||||
|
||||
/* Sequence to clear OVR flag */
|
||||
readl_relaxed(spi->base + STM32F4_SPI_DR);
|
||||
readl_relaxed(spi->base + STM32F4_SPI_SR);
|
||||
|
||||
spin_unlock_irqrestore(&spi->lock, flags);
|
||||
}
|
||||
|
||||
/**
|
||||
* stm32h7_spi_disable - Disable SPI controller
|
||||
* @spi: pointer to the spi controller data structure
|
||||
@ -568,18 +758,128 @@ static void stm32h7_spi_disable(struct stm32_spi *spi)
|
||||
/**
|
||||
* stm32_spi_can_dma - Determine if the transfer is eligible for DMA use
|
||||
*
|
||||
* If the current transfer size is greater than fifo size, use DMA.
|
||||
* If driver has fifo and the current transfer size is greater than fifo size,
|
||||
* use DMA. Otherwise use DMA for transfer longer than defined DMA min bytes.
|
||||
*/
|
||||
static bool stm32_spi_can_dma(struct spi_master *master,
|
||||
struct spi_device *spi_dev,
|
||||
struct spi_transfer *transfer)
|
||||
{
|
||||
unsigned int dma_size;
|
||||
struct stm32_spi *spi = spi_master_get_devdata(master);
|
||||
|
||||
dev_dbg(spi->dev, "%s: %s\n", __func__,
|
||||
(transfer->len > spi->fifo_size) ? "true" : "false");
|
||||
if (spi->cfg->has_fifo)
|
||||
dma_size = spi->fifo_size;
|
||||
else
|
||||
dma_size = SPI_DMA_MIN_BYTES;
|
||||
|
||||
return (transfer->len > spi->fifo_size);
|
||||
dev_dbg(spi->dev, "%s: %s\n", __func__,
|
||||
(transfer->len > dma_size) ? "true" : "false");
|
||||
|
||||
return (transfer->len > dma_size);
|
||||
}
|
||||
|
||||
/**
|
||||
* stm32f4_spi_irq_event - Interrupt handler for SPI controller events
|
||||
* @irq: interrupt line
|
||||
* @dev_id: SPI controller master interface
|
||||
*/
|
||||
static irqreturn_t stm32f4_spi_irq_event(int irq, void *dev_id)
|
||||
{
|
||||
struct spi_master *master = dev_id;
|
||||
struct stm32_spi *spi = spi_master_get_devdata(master);
|
||||
u32 sr, mask = 0;
|
||||
unsigned long flags;
|
||||
bool end = false;
|
||||
|
||||
spin_lock_irqsave(&spi->lock, flags);
|
||||
|
||||
sr = readl_relaxed(spi->base + STM32F4_SPI_SR);
|
||||
/*
|
||||
* BSY flag is not handled in interrupt but it is normal behavior when
|
||||
* this flag is set.
|
||||
*/
|
||||
sr &= ~STM32F4_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;
|
||||
}
|
||||
|
||||
if (!spi->cur_usedma && spi->cur_comm == SPI_FULL_DUPLEX) {
|
||||
/* 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;
|
||||
}
|
||||
|
||||
if (!(sr & mask)) {
|
||||
dev_dbg(spi->dev, "spurious IT (sr=0x%08x)\n", sr);
|
||||
spin_unlock_irqrestore(&spi->lock, flags);
|
||||
return IRQ_NONE;
|
||||
}
|
||||
|
||||
if (sr & STM32F4_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);
|
||||
|
||||
/*
|
||||
* If overrun is detected, it means that something went wrong,
|
||||
* so stop the current transfer. Transfer can wait for next
|
||||
* RXNE but DR is already read and end never happens.
|
||||
*/
|
||||
end = true;
|
||||
goto end_irq;
|
||||
}
|
||||
|
||||
if (sr & STM32F4_SPI_SR_TXE) {
|
||||
if (spi->tx_buf)
|
||||
stm32f4_spi_write_tx(spi);
|
||||
if (spi->tx_len == 0)
|
||||
end = true;
|
||||
}
|
||||
|
||||
if (sr & STM32F4_SPI_SR_RXNE) {
|
||||
stm32f4_spi_read_rx(spi);
|
||||
if (spi->rx_len == 0)
|
||||
end = true;
|
||||
else /* Load data for discontinuous mode */
|
||||
stm32f4_spi_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);
|
||||
spin_unlock_irqrestore(&spi->lock, flags);
|
||||
return IRQ_WAKE_THREAD;
|
||||
}
|
||||
|
||||
spin_unlock_irqrestore(&spi->lock, flags);
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
|
||||
/**
|
||||
* stm32f4_spi_irq_thread - Thread of interrupt handler for SPI controller
|
||||
* @irq: interrupt line
|
||||
* @dev_id: SPI controller master interface
|
||||
*/
|
||||
static irqreturn_t stm32f4_spi_irq_thread(int irq, void *dev_id)
|
||||
{
|
||||
struct spi_master *master = dev_id;
|
||||
struct stm32_spi *spi = spi_master_get_devdata(master);
|
||||
|
||||
spi_finalize_current_transfer(master);
|
||||
stm32f4_spi_disable(spi);
|
||||
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -748,6 +1048,34 @@ static int stm32_spi_prepare_msg(struct spi_master *master,
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* stm32f4_spi_dma_tx_cb - dma callback
|
||||
*
|
||||
* DMA callback is called when the transfer is complete for DMA TX channel.
|
||||
*/
|
||||
static void stm32f4_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->master);
|
||||
stm32f4_spi_disable(spi);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* stm32f4_spi_dma_rx_cb - dma callback
|
||||
*
|
||||
* DMA callback is called when the transfer is complete for DMA RX channel.
|
||||
*/
|
||||
static void stm32f4_spi_dma_rx_cb(void *data)
|
||||
{
|
||||
struct stm32_spi *spi = data;
|
||||
|
||||
spi_finalize_current_transfer(spi->master);
|
||||
stm32f4_spi_disable(spi);
|
||||
}
|
||||
|
||||
/**
|
||||
* stm32h7_spi_dma_cb - dma callback
|
||||
*
|
||||
@ -790,11 +1118,15 @@ static void stm32_spi_dma_config(struct stm32_spi *spi,
|
||||
else
|
||||
buswidth = DMA_SLAVE_BUSWIDTH_4_BYTES;
|
||||
|
||||
/* Valid for DMA Half or Full Fifo threshold */
|
||||
if (spi->cur_fthlv == 2)
|
||||
if (spi->cfg->has_fifo) {
|
||||
/* Valid for DMA Half or Full Fifo threshold */
|
||||
if (spi->cur_fthlv == 2)
|
||||
maxburst = 1;
|
||||
else
|
||||
maxburst = spi->cur_fthlv;
|
||||
} else {
|
||||
maxburst = 1;
|
||||
else
|
||||
maxburst = spi->cur_fthlv;
|
||||
}
|
||||
|
||||
memset(dma_conf, 0, sizeof(struct dma_slave_config));
|
||||
dma_conf->direction = dir;
|
||||
@ -815,6 +1147,46 @@ static void stm32_spi_dma_config(struct stm32_spi *spi,
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* stm32f4_spi_transfer_one_irq - transfer a single spi_transfer using
|
||||
* interrupts
|
||||
*
|
||||
* 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)
|
||||
{
|
||||
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;
|
||||
} else if (spi->cur_comm == SPI_FULL_DUPLEX) {
|
||||
/* In transmit-only mode, the OVR flag is set in the SR register
|
||||
* 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;
|
||||
} else {
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
spin_lock_irqsave(&spi->lock, flags);
|
||||
|
||||
stm32_spi_set_bits(spi, STM32F4_SPI_CR2, cr2);
|
||||
|
||||
stm32_spi_enable(spi);
|
||||
|
||||
/* starting data transfer when buffer is loaded */
|
||||
if (spi->tx_buf)
|
||||
stm32f4_spi_write_tx(spi);
|
||||
|
||||
spin_unlock_irqrestore(&spi->lock, flags);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
/**
|
||||
* stm32h7_spi_transfer_one_irq - transfer a single spi_transfer using
|
||||
* interrupts
|
||||
@ -856,6 +1228,26 @@ static int stm32h7_spi_transfer_one_irq(struct stm32_spi *spi)
|
||||
return 1;
|
||||
}
|
||||
|
||||
/**
|
||||
* stm32f4_spi_transfer_one_dma_start - Set SPI driver registers to start
|
||||
* transfer using DMA
|
||||
*/
|
||||
static void stm32f4_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 ||
|
||||
spi->cur_comm == SPI_FULL_DUPLEX) {
|
||||
/*
|
||||
* In transmit-only mode, the OVR flag is set in the SR register
|
||||
* 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_enable(spi);
|
||||
}
|
||||
|
||||
/**
|
||||
* stm32h7_spi_transfer_one_dma_start - Set SPI driver registers to start
|
||||
* transfer using DMA
|
||||
@ -976,6 +1368,18 @@ dma_desc_error:
|
||||
return spi->cfg->transfer_one_irq(spi);
|
||||
}
|
||||
|
||||
/**
|
||||
* stm32f4_spi_set_bpw - Configure bits per word
|
||||
* @spi: pointer to the spi controller data structure
|
||||
*/
|
||||
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);
|
||||
else
|
||||
stm32_spi_clr_bits(spi, STM32F4_SPI_CR1, STM32F4_SPI_CR1_DFF);
|
||||
}
|
||||
|
||||
/**
|
||||
* stm32h7_spi_set_bpw - configure bits per word
|
||||
* @spi: pointer to the spi controller data structure
|
||||
@ -1053,6 +1457,28 @@ static unsigned int stm32_spi_communication_type(struct spi_device *spi_dev,
|
||||
return type;
|
||||
}
|
||||
|
||||
/**
|
||||
* stm32f4_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)
|
||||
{
|
||||
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);
|
||||
} else if (comm_type == SPI_FULL_DUPLEX) {
|
||||
stm32_spi_clr_bits(spi, STM32F4_SPI_CR1,
|
||||
STM32F4_SPI_CR1_BIDIMODE |
|
||||
STM32F4_SPI_CR1_BIDIOE);
|
||||
} else {
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* stm32h7_spi_set_mode - configure communication mode
|
||||
* @spi: pointer to the spi controller data structure
|
||||
@ -1267,6 +1693,36 @@ static int stm32_spi_unprepare_msg(struct spi_master *master,
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* stm32f4_spi_config - Configure SPI controller as SPI master
|
||||
*/
|
||||
static int stm32f4_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);
|
||||
|
||||
/*
|
||||
* - SS input value high
|
||||
* - transmitter half duplex direction
|
||||
* - Set the master mode (default Motorola mode)
|
||||
* - 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);
|
||||
|
||||
spin_unlock_irqrestore(&spi->lock, flags);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* stm32h7_spi_config - Configure SPI controller as SPI master
|
||||
*/
|
||||
@ -1304,6 +1760,24 @@ static int stm32h7_spi_config(struct stm32_spi *spi)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct stm32_spi_cfg stm32f4_spi_cfg = {
|
||||
.regs = &stm32f4_spi_regspec,
|
||||
.get_bpw_mask = stm32f4_spi_get_bpw_mask,
|
||||
.disable = stm32f4_spi_disable,
|
||||
.config = stm32f4_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,
|
||||
.dma_rx_cb = stm32f4_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,
|
||||
.has_fifo = false,
|
||||
};
|
||||
|
||||
static const struct stm32_spi_cfg stm32h7_spi_cfg = {
|
||||
.regs = &stm32h7_spi_regspec,
|
||||
.get_fifo_size = stm32h7_spi_get_fifo_size,
|
||||
@ -1326,6 +1800,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 },
|
||||
{},
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, stm32_spi_of_match);
|
||||
|
Loading…
Reference in New Issue
Block a user