forked from Minki/linux
spi: stm32: introduce compatible data cfg
Prepare support for STM32F4 spi variant by introducing compatible configuration data. Move STM32H7 specific stuff to compatible data structure: - registers & bit fields - routines to control driver - baud rate divisor definitions - fifo availability - split IRQ functions to parts to be called when the IRQ occurs and for threaded interrupt what helps to provide less discontinuous mode for drivers without FIFO. Signed-off-by: Cezary Gapinski <cezary.gapinski@gmail.com> Signed-off-by: Mark Brown <broonie@kernel.org>
This commit is contained in:
parent
f8bb12f2fa
commit
55166853b2
@ -116,10 +116,96 @@
|
||||
|
||||
#define SPI_1HZ_NS 1000000000
|
||||
|
||||
/**
|
||||
* stm32_spi_reg - stm32 SPI register & bitfield desc
|
||||
* @reg: register offset
|
||||
* @mask: bitfield mask
|
||||
* @shift: left shift
|
||||
*/
|
||||
struct stm32_spi_reg {
|
||||
int reg;
|
||||
int mask;
|
||||
int shift;
|
||||
};
|
||||
|
||||
/**
|
||||
* stm32_spi_regspec - stm32 registers definition, compatible dependent data
|
||||
* en: enable register and SPI enable bit
|
||||
* dma_rx_en: SPI DMA RX enable register end SPI DMA RX enable bit
|
||||
* dma_tx_en: SPI DMA TX enable register end SPI DMA TX enable bit
|
||||
* cpol: clock polarity register and polarity bit
|
||||
* cpha: clock phase register and phase bit
|
||||
* lsb_first: LSB transmitted first register and bit
|
||||
* br: baud rate register and bitfields
|
||||
* rx: SPI RX data register
|
||||
* tx: SPI TX data register
|
||||
*/
|
||||
struct stm32_spi_regspec {
|
||||
const struct stm32_spi_reg en;
|
||||
const struct stm32_spi_reg dma_rx_en;
|
||||
const struct stm32_spi_reg dma_tx_en;
|
||||
const struct stm32_spi_reg cpol;
|
||||
const struct stm32_spi_reg cpha;
|
||||
const struct stm32_spi_reg lsb_first;
|
||||
const struct stm32_spi_reg br;
|
||||
const struct stm32_spi_reg rx;
|
||||
const struct stm32_spi_reg tx;
|
||||
};
|
||||
|
||||
struct stm32_spi;
|
||||
|
||||
/**
|
||||
* stm32_spi_cfg - stm32 compatible configuration data
|
||||
* @regs: registers descriptions
|
||||
* @get_fifo_size: routine to get fifo size
|
||||
* @get_bpw_mask: routine to get bits per word mask
|
||||
* @disable: routine to disable controller
|
||||
* @config: routine to configure controller as SPI Master
|
||||
* @set_bpw: routine to configure registers to for bits per word
|
||||
* @set_mode: routine to configure registers to desired mode
|
||||
* @set_data_idleness: optional routine to configure registers to desired idle
|
||||
* 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)
|
||||
* @can_dma: routine to determine if the transfer is eligible for DMA use
|
||||
* @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
|
||||
* @dma_tx cb: routine to call after DMA TX channel operation is complete
|
||||
* @transfer_one_irq: routine to configure interrupts for driver
|
||||
* @irq_handler_event: Interrupt handler for SPI controller events
|
||||
* @irq_handler_thread: thread of interrupt handler for SPI controller
|
||||
* @baud_rate_div_min: minimum baud rate divisor
|
||||
* @baud_rate_div_max: maximum baud rate divisor
|
||||
* @has_fifo: boolean to know if fifo is used for driver
|
||||
* @has_startbit: boolean to know if start bit is used to start transfer
|
||||
*/
|
||||
struct stm32_spi_cfg {
|
||||
const struct stm32_spi_regspec *regs;
|
||||
int (*get_fifo_size)(struct stm32_spi *spi);
|
||||
int (*get_bpw_mask)(struct stm32_spi *spi);
|
||||
void (*disable)(struct stm32_spi *spi);
|
||||
int (*config)(struct stm32_spi *spi);
|
||||
void (*set_bpw)(struct stm32_spi *spi);
|
||||
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 (*transfer_one_dma_start)(struct stm32_spi *spi);
|
||||
void (*dma_rx_cb)(void *data);
|
||||
void (*dma_tx_cb)(void *data);
|
||||
int (*transfer_one_irq)(struct stm32_spi *spi);
|
||||
irqreturn_t (*irq_handler_event)(int irq, void *dev_id);
|
||||
irqreturn_t (*irq_handler_thread)(int irq, void *dev_id);
|
||||
unsigned int baud_rate_div_min;
|
||||
unsigned int baud_rate_div_max;
|
||||
bool has_fifo;
|
||||
};
|
||||
|
||||
/**
|
||||
* struct stm32_spi - private data of the SPI controller
|
||||
* @dev: driver model representation of the controller
|
||||
* @master: controller master interface
|
||||
* @cfg: compatible configuration data
|
||||
* @base: virtual memory area
|
||||
* @clk: hw kernel clock feeding the SPI clock generator
|
||||
* @clk_rate: rate of the hw kernel clock feeding the SPI clock generator
|
||||
@ -145,6 +231,7 @@
|
||||
struct stm32_spi {
|
||||
struct device *dev;
|
||||
struct spi_master *master;
|
||||
const struct stm32_spi_cfg *cfg;
|
||||
void __iomem *base;
|
||||
struct clk *clk;
|
||||
u32 clk_rate;
|
||||
@ -170,6 +257,25 @@ struct stm32_spi {
|
||||
dma_addr_t phys_addr;
|
||||
};
|
||||
|
||||
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.
|
||||
*/
|
||||
.en = { STM32H7_SPI_CR1, STM32H7_SPI_CR1_SPE },
|
||||
|
||||
.dma_rx_en = { STM32H7_SPI_CFG1, STM32H7_SPI_CFG1_RXDMAEN },
|
||||
.dma_tx_en = { STM32H7_SPI_CFG1, STM32H7_SPI_CFG1_TXDMAEN },
|
||||
|
||||
.cpol = { STM32H7_SPI_CFG2, STM32H7_SPI_CFG2_CPOL },
|
||||
.cpha = { STM32H7_SPI_CFG2, STM32H7_SPI_CFG2_CPHA },
|
||||
.lsb_first = { STM32H7_SPI_CFG2, STM32H7_SPI_CFG2_LSBFRST },
|
||||
.br = { STM32H7_SPI_CFG1, STM32H7_SPI_CFG1_MBR,
|
||||
STM32H7_SPI_CFG1_MBR_SHIFT },
|
||||
|
||||
.rx = { STM32H7_SPI_RXDR },
|
||||
.tx = { STM32H7_SPI_TXDR },
|
||||
};
|
||||
|
||||
static inline void stm32_spi_set_bits(struct stm32_spi *spi,
|
||||
u32 offset, u32 bits)
|
||||
{
|
||||
@ -185,10 +291,10 @@ static inline void stm32_spi_clr_bits(struct stm32_spi *spi,
|
||||
}
|
||||
|
||||
/**
|
||||
* stm32_spi_get_fifo_size - Return fifo size
|
||||
* stm32h7_spi_get_fifo_size - Return fifo size
|
||||
* @spi: pointer to the spi controller data structure
|
||||
*/
|
||||
static int stm32_spi_get_fifo_size(struct stm32_spi *spi)
|
||||
static int stm32h7_spi_get_fifo_size(struct stm32_spi *spi)
|
||||
{
|
||||
unsigned long flags;
|
||||
u32 count = 0;
|
||||
@ -210,10 +316,10 @@ static int stm32_spi_get_fifo_size(struct stm32_spi *spi)
|
||||
}
|
||||
|
||||
/**
|
||||
* stm32_spi_get_bpw_mask - Return bits per word mask
|
||||
* stm32h7_spi_get_bpw_mask - Return bits per word mask
|
||||
* @spi: pointer to the spi controller data structure
|
||||
*/
|
||||
static int stm32_spi_get_bpw_mask(struct stm32_spi *spi)
|
||||
static int stm32h7_spi_get_bpw_mask(struct stm32_spi *spi)
|
||||
{
|
||||
unsigned long flags;
|
||||
u32 cfg1, max_bpw;
|
||||
@ -276,10 +382,10 @@ static int stm32_spi_prepare_mbr(struct stm32_spi *spi, u32 speed_hz,
|
||||
}
|
||||
|
||||
/**
|
||||
* stm32_spi_prepare_fthlv - Determine FIFO threshold level
|
||||
* stm32h7_spi_prepare_fthlv - Determine FIFO threshold level
|
||||
* @spi: pointer to the spi controller data structure
|
||||
*/
|
||||
static u32 stm32_spi_prepare_fthlv(struct stm32_spi *spi)
|
||||
static u32 stm32h7_spi_prepare_fthlv(struct stm32_spi *spi)
|
||||
{
|
||||
u32 fthlv, half_fifo;
|
||||
|
||||
@ -303,13 +409,13 @@ static u32 stm32_spi_prepare_fthlv(struct stm32_spi *spi)
|
||||
}
|
||||
|
||||
/**
|
||||
* stm32_spi_write_txfifo - Write bytes in Transmit Data Register
|
||||
* stm32h7_spi_write_txfifo - Write bytes in 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 stm32_spi_write_txfifo(struct stm32_spi *spi)
|
||||
static void stm32h7_spi_write_txfifo(struct stm32_spi *spi)
|
||||
{
|
||||
while ((spi->tx_len > 0) &&
|
||||
(readl_relaxed(spi->base + STM32H7_SPI_SR) &
|
||||
@ -338,13 +444,13 @@ static void stm32_spi_write_txfifo(struct stm32_spi *spi)
|
||||
}
|
||||
|
||||
/**
|
||||
* stm32_spi_read_rxfifo - Read bytes in Receive Data Register
|
||||
* stm32h7_spi_read_rxfifo - Read bytes in 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 stm32_spi_read_rxfifo(struct stm32_spi *spi, bool flush)
|
||||
static void stm32h7_spi_read_rxfifo(struct stm32_spi *spi, bool flush)
|
||||
{
|
||||
u32 sr = readl_relaxed(spi->base + STM32H7_SPI_SR);
|
||||
u32 rxplvl = (sr & STM32H7_SPI_SR_RXPLVL) >>
|
||||
@ -386,26 +492,28 @@ static void stm32_spi_read_rxfifo(struct stm32_spi *spi, bool flush)
|
||||
/**
|
||||
* stm32_spi_enable - Enable SPI controller
|
||||
* @spi: pointer to the spi controller data structure
|
||||
*
|
||||
* SPI data transfer is enabled but spi_ker_ck is idle.
|
||||
* SPI_CFG1 and SPI_CFG2 are now write protected.
|
||||
*/
|
||||
static void stm32_spi_enable(struct stm32_spi *spi)
|
||||
{
|
||||
dev_dbg(spi->dev, "enable controller\n");
|
||||
|
||||
stm32_spi_set_bits(spi, STM32H7_SPI_CR1, STM32H7_SPI_CR1_SPE);
|
||||
stm32_spi_set_bits(spi, spi->cfg->regs->en.reg,
|
||||
spi->cfg->regs->en.mask);
|
||||
}
|
||||
|
||||
/**
|
||||
* stm32_spi_disable - Disable SPI controller
|
||||
* stm32h7_spi_disable - Disable SPI controller
|
||||
* @spi: pointer to the spi controller data structure
|
||||
*
|
||||
* RX-Fifo is flushed when SPI controller is disabled. To prevent any data
|
||||
* loss, use stm32_spi_read_rxfifo(flush) to read the remaining bytes in
|
||||
* loss, use stm32h7_spi_read_rxfifo(flush) to read the remaining bytes in
|
||||
* RX-Fifo.
|
||||
* Normally, if TSIZE has been configured, we should relax the hardware at the
|
||||
* reception of the EOT interrupt. But in case of error, EOT will not be
|
||||
* raised. So the subsystem unprepare_message call allows us to properly
|
||||
* complete the transfer from an hardware point of view.
|
||||
*/
|
||||
static void stm32_spi_disable(struct stm32_spi *spi)
|
||||
static void stm32h7_spi_disable(struct stm32_spi *spi)
|
||||
{
|
||||
unsigned long flags;
|
||||
u32 cr1, sr;
|
||||
@ -438,7 +546,7 @@ static void stm32_spi_disable(struct stm32_spi *spi)
|
||||
}
|
||||
|
||||
if (!spi->cur_usedma && spi->rx_buf && (spi->rx_len > 0))
|
||||
stm32_spi_read_rxfifo(spi, true);
|
||||
stm32h7_spi_read_rxfifo(spi, true);
|
||||
|
||||
if (spi->cur_usedma && spi->dma_tx)
|
||||
dmaengine_terminate_all(spi->dma_tx);
|
||||
@ -475,11 +583,11 @@ static bool stm32_spi_can_dma(struct spi_master *master,
|
||||
}
|
||||
|
||||
/**
|
||||
* stm32_spi_irq_thread - Thread of interrupt handler for SPI controller
|
||||
* stm32h7_spi_irq_thread - Thread of interrupt handler for SPI controller
|
||||
* @irq: interrupt line
|
||||
* @dev_id: SPI controller master interface
|
||||
*/
|
||||
static irqreturn_t stm32_spi_irq_thread(int irq, void *dev_id)
|
||||
static irqreturn_t stm32h7_spi_irq_thread(int irq, void *dev_id)
|
||||
{
|
||||
struct spi_master *master = dev_id;
|
||||
struct stm32_spi *spi = spi_master_get_devdata(master);
|
||||
@ -513,7 +621,7 @@ static irqreturn_t stm32_spi_irq_thread(int irq, void *dev_id)
|
||||
if (sr & STM32H7_SPI_SR_SUSP) {
|
||||
dev_warn(spi->dev, "Communication suspended\n");
|
||||
if (!spi->cur_usedma && (spi->rx_buf && (spi->rx_len > 0)))
|
||||
stm32_spi_read_rxfifo(spi, false);
|
||||
stm32h7_spi_read_rxfifo(spi, false);
|
||||
/*
|
||||
* If communication is suspended while using DMA, it means
|
||||
* that something went wrong, so stop the current transfer
|
||||
@ -530,7 +638,7 @@ static irqreturn_t stm32_spi_irq_thread(int irq, void *dev_id)
|
||||
if (sr & STM32H7_SPI_SR_OVR) {
|
||||
dev_warn(spi->dev, "Overrun: received value discarded\n");
|
||||
if (!spi->cur_usedma && (spi->rx_buf && (spi->rx_len > 0)))
|
||||
stm32_spi_read_rxfifo(spi, false);
|
||||
stm32h7_spi_read_rxfifo(spi, false);
|
||||
/*
|
||||
* If overrun is detected while using DMA, it means that
|
||||
* something went wrong, so stop the current transfer
|
||||
@ -541,17 +649,17 @@ static irqreturn_t stm32_spi_irq_thread(int irq, void *dev_id)
|
||||
|
||||
if (sr & STM32H7_SPI_SR_EOT) {
|
||||
if (!spi->cur_usedma && (spi->rx_buf && (spi->rx_len > 0)))
|
||||
stm32_spi_read_rxfifo(spi, true);
|
||||
stm32h7_spi_read_rxfifo(spi, true);
|
||||
end = true;
|
||||
}
|
||||
|
||||
if (sr & STM32H7_SPI_SR_TXP)
|
||||
if (!spi->cur_usedma && (spi->tx_buf && (spi->tx_len > 0)))
|
||||
stm32_spi_write_txfifo(spi);
|
||||
stm32h7_spi_write_txfifo(spi);
|
||||
|
||||
if (sr & STM32H7_SPI_SR_RXP)
|
||||
if (!spi->cur_usedma && (spi->rx_buf && (spi->rx_len > 0)))
|
||||
stm32_spi_read_rxfifo(spi, false);
|
||||
stm32h7_spi_read_rxfifo(spi, false);
|
||||
|
||||
writel_relaxed(mask, spi->base + STM32H7_SPI_IFCR);
|
||||
|
||||
@ -559,7 +667,7 @@ static irqreturn_t stm32_spi_irq_thread(int irq, void *dev_id)
|
||||
|
||||
if (end) {
|
||||
spi_finalize_current_transfer(master);
|
||||
stm32_spi_disable(spi);
|
||||
stm32h7_spi_disable(spi);
|
||||
}
|
||||
|
||||
return IRQ_HANDLED;
|
||||
@ -598,7 +706,7 @@ static int stm32_spi_prepare_msg(struct spi_master *master,
|
||||
struct spi_device *spi_dev = msg->spi;
|
||||
struct device_node *np = spi_dev->dev.of_node;
|
||||
unsigned long flags;
|
||||
u32 cfg2_clrb = 0, cfg2_setb = 0;
|
||||
u32 clrb = 0, setb = 0;
|
||||
|
||||
/* SPI slave device may need time between data frames */
|
||||
spi->cur_midi = 0;
|
||||
@ -606,19 +714,19 @@ static int stm32_spi_prepare_msg(struct spi_master *master,
|
||||
dev_dbg(spi->dev, "%dns inter-data idleness\n", spi->cur_midi);
|
||||
|
||||
if (spi_dev->mode & SPI_CPOL)
|
||||
cfg2_setb |= STM32H7_SPI_CFG2_CPOL;
|
||||
setb |= spi->cfg->regs->cpol.mask;
|
||||
else
|
||||
cfg2_clrb |= STM32H7_SPI_CFG2_CPOL;
|
||||
clrb |= spi->cfg->regs->cpol.mask;
|
||||
|
||||
if (spi_dev->mode & SPI_CPHA)
|
||||
cfg2_setb |= STM32H7_SPI_CFG2_CPHA;
|
||||
setb |= spi->cfg->regs->cpha.mask;
|
||||
else
|
||||
cfg2_clrb |= STM32H7_SPI_CFG2_CPHA;
|
||||
clrb |= spi->cfg->regs->cpha.mask;
|
||||
|
||||
if (spi_dev->mode & SPI_LSB_FIRST)
|
||||
cfg2_setb |= STM32H7_SPI_CFG2_LSBFRST;
|
||||
setb |= spi->cfg->regs->lsb_first.mask;
|
||||
else
|
||||
cfg2_clrb |= STM32H7_SPI_CFG2_LSBFRST;
|
||||
clrb |= spi->cfg->regs->lsb_first.mask;
|
||||
|
||||
dev_dbg(spi->dev, "cpol=%d cpha=%d lsb_first=%d cs_high=%d\n",
|
||||
spi_dev->mode & SPI_CPOL,
|
||||
@ -628,11 +736,12 @@ static int stm32_spi_prepare_msg(struct spi_master *master,
|
||||
|
||||
spin_lock_irqsave(&spi->lock, flags);
|
||||
|
||||
if (cfg2_clrb || cfg2_setb)
|
||||
/* CPOL, CPHA and LSB FIRST bits have common register */
|
||||
if (clrb || setb)
|
||||
writel_relaxed(
|
||||
(readl_relaxed(spi->base + STM32H7_SPI_CFG2) &
|
||||
~cfg2_clrb) | cfg2_setb,
|
||||
spi->base + STM32H7_SPI_CFG2);
|
||||
(readl_relaxed(spi->base + spi->cfg->regs->cpol.reg) &
|
||||
~clrb) | setb,
|
||||
spi->base + spi->cfg->regs->cpol.reg);
|
||||
|
||||
spin_unlock_irqrestore(&spi->lock, flags);
|
||||
|
||||
@ -640,12 +749,12 @@ static int stm32_spi_prepare_msg(struct spi_master *master,
|
||||
}
|
||||
|
||||
/**
|
||||
* stm32_spi_dma_cb - dma callback
|
||||
* stm32h7_spi_dma_cb - dma callback
|
||||
*
|
||||
* DMA callback is called when the transfer is complete or when an error
|
||||
* occurs. If the transfer is complete, EOT flag is raised.
|
||||
*/
|
||||
static void stm32_spi_dma_cb(void *data)
|
||||
static void stm32h7_spi_dma_cb(void *data)
|
||||
{
|
||||
struct stm32_spi *spi = data;
|
||||
unsigned long flags;
|
||||
@ -690,14 +799,14 @@ static void stm32_spi_dma_config(struct stm32_spi *spi,
|
||||
memset(dma_conf, 0, sizeof(struct dma_slave_config));
|
||||
dma_conf->direction = dir;
|
||||
if (dma_conf->direction == DMA_DEV_TO_MEM) { /* RX */
|
||||
dma_conf->src_addr = spi->phys_addr + STM32H7_SPI_RXDR;
|
||||
dma_conf->src_addr = spi->phys_addr + spi->cfg->regs->rx.reg;
|
||||
dma_conf->src_addr_width = buswidth;
|
||||
dma_conf->src_maxburst = maxburst;
|
||||
|
||||
dev_dbg(spi->dev, "Rx DMA config buswidth=%d, maxburst=%d\n",
|
||||
buswidth, maxburst);
|
||||
} else if (dma_conf->direction == DMA_MEM_TO_DEV) { /* TX */
|
||||
dma_conf->dst_addr = spi->phys_addr + STM32H7_SPI_TXDR;
|
||||
dma_conf->dst_addr = spi->phys_addr + spi->cfg->regs->tx.reg;
|
||||
dma_conf->dst_addr_width = buswidth;
|
||||
dma_conf->dst_maxburst = maxburst;
|
||||
|
||||
@ -707,13 +816,13 @@ static void stm32_spi_dma_config(struct stm32_spi *spi,
|
||||
}
|
||||
|
||||
/**
|
||||
* stm32_spi_transfer_one_irq - transfer a single spi_transfer using
|
||||
* interrupts
|
||||
* stm32h7_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 stm32_spi_transfer_one_irq(struct stm32_spi *spi)
|
||||
static int stm32h7_spi_transfer_one_irq(struct stm32_spi *spi)
|
||||
{
|
||||
unsigned long flags;
|
||||
u32 ier = 0;
|
||||
@ -736,7 +845,7 @@ static int stm32_spi_transfer_one_irq(struct stm32_spi *spi)
|
||||
|
||||
/* Be sure to have data in fifo before starting data transfer */
|
||||
if (spi->tx_buf)
|
||||
stm32_spi_write_txfifo(spi);
|
||||
stm32h7_spi_write_txfifo(spi);
|
||||
|
||||
stm32_spi_set_bits(spi, STM32H7_SPI_CR1, STM32H7_SPI_CR1_CSTART);
|
||||
|
||||
@ -748,10 +857,10 @@ static int stm32_spi_transfer_one_irq(struct stm32_spi *spi)
|
||||
}
|
||||
|
||||
/**
|
||||
* stm32_spi_transfer_one_dma_start - Set SPI driver registers to start transfer
|
||||
* using DMA
|
||||
* stm32h7_spi_transfer_one_dma_start - Set SPI driver registers to start
|
||||
* transfer using DMA
|
||||
*/
|
||||
static void stm32_spi_transfer_one_dma_start(struct stm32_spi *spi)
|
||||
static void stm32h7_spi_transfer_one_dma_start(struct stm32_spi *spi)
|
||||
{
|
||||
/* Enable the interrupts relative to the end of transfer */
|
||||
stm32_spi_set_bits(spi, STM32H7_SPI_IER, STM32H7_SPI_IER_EOTIE |
|
||||
@ -785,8 +894,8 @@ static int stm32_spi_transfer_one_dma(struct stm32_spi *spi,
|
||||
dmaengine_slave_config(spi->dma_rx, &rx_dma_conf);
|
||||
|
||||
/* Enable Rx DMA request */
|
||||
stm32_spi_set_bits(spi, STM32H7_SPI_CFG1,
|
||||
STM32H7_SPI_CFG1_RXDMAEN);
|
||||
stm32_spi_set_bits(spi, spi->cfg->regs->dma_rx_en.reg,
|
||||
spi->cfg->regs->dma_rx_en.mask);
|
||||
|
||||
rx_dma_desc = dmaengine_prep_slave_sg(
|
||||
spi->dma_rx, xfer->rx_sg.sgl,
|
||||
@ -815,7 +924,7 @@ static int stm32_spi_transfer_one_dma(struct stm32_spi *spi,
|
||||
goto dma_desc_error;
|
||||
|
||||
if (rx_dma_desc) {
|
||||
rx_dma_desc->callback = stm32_spi_dma_cb;
|
||||
rx_dma_desc->callback = spi->cfg->dma_rx_cb;
|
||||
rx_dma_desc->callback_param = spi;
|
||||
|
||||
if (dma_submit_error(dmaengine_submit(rx_dma_desc))) {
|
||||
@ -829,7 +938,7 @@ static int stm32_spi_transfer_one_dma(struct stm32_spi *spi,
|
||||
if (tx_dma_desc) {
|
||||
if (spi->cur_comm == SPI_SIMPLEX_TX ||
|
||||
spi->cur_comm == SPI_3WIRE_TX) {
|
||||
tx_dma_desc->callback = stm32_spi_dma_cb;
|
||||
tx_dma_desc->callback = spi->cfg->dma_tx_cb;
|
||||
tx_dma_desc->callback_param = spi;
|
||||
}
|
||||
|
||||
@ -841,11 +950,11 @@ static int stm32_spi_transfer_one_dma(struct stm32_spi *spi,
|
||||
dma_async_issue_pending(spi->dma_tx);
|
||||
|
||||
/* Enable Tx DMA request */
|
||||
stm32_spi_set_bits(spi, STM32H7_SPI_CFG1,
|
||||
STM32H7_SPI_CFG1_TXDMAEN);
|
||||
stm32_spi_set_bits(spi, spi->cfg->regs->dma_tx_en.reg,
|
||||
spi->cfg->regs->dma_tx_en.mask);
|
||||
}
|
||||
|
||||
stm32_spi_transfer_one_dma_start(spi);
|
||||
spi->cfg->transfer_one_dma_start(spi);
|
||||
|
||||
spin_unlock_irqrestore(&spi->lock, flags);
|
||||
|
||||
@ -856,21 +965,22 @@ dma_submit_error:
|
||||
dmaengine_terminate_all(spi->dma_rx);
|
||||
|
||||
dma_desc_error:
|
||||
stm32_spi_clr_bits(spi, STM32H7_SPI_CFG1, STM32H7_SPI_CFG1_RXDMAEN);
|
||||
stm32_spi_clr_bits(spi, spi->cfg->regs->dma_rx_en.reg,
|
||||
spi->cfg->regs->dma_rx_en.mask);
|
||||
|
||||
spin_unlock_irqrestore(&spi->lock, flags);
|
||||
|
||||
dev_info(spi->dev, "DMA issue: fall back to irq transfer\n");
|
||||
|
||||
spi->cur_usedma = false;
|
||||
return stm32_spi_transfer_one_irq(spi);
|
||||
return spi->cfg->transfer_one_irq(spi);
|
||||
}
|
||||
|
||||
/**
|
||||
* stm32_spi_set_bpw - configure bits per word
|
||||
* stm32h7_spi_set_bpw - configure bits per word
|
||||
* @spi: pointer to the spi controller data structure
|
||||
*/
|
||||
static void stm32_spi_set_bpw(struct stm32_spi *spi)
|
||||
static void stm32h7_spi_set_bpw(struct stm32_spi *spi)
|
||||
{
|
||||
u32 bpw, fthlv;
|
||||
u32 cfg1_clrb = 0, cfg1_setb = 0;
|
||||
@ -881,7 +991,7 @@ static void stm32_spi_set_bpw(struct stm32_spi *spi)
|
||||
cfg1_setb |= (bpw << STM32H7_SPI_CFG1_DSIZE_SHIFT) &
|
||||
STM32H7_SPI_CFG1_DSIZE;
|
||||
|
||||
spi->cur_fthlv = stm32_spi_prepare_fthlv(spi);
|
||||
spi->cur_fthlv = stm32h7_spi_prepare_fthlv(spi);
|
||||
fthlv = spi->cur_fthlv - 1;
|
||||
|
||||
cfg1_clrb |= STM32H7_SPI_CFG1_FTHLV;
|
||||
@ -901,15 +1011,15 @@ static void stm32_spi_set_bpw(struct stm32_spi *spi)
|
||||
*/
|
||||
static void stm32_spi_set_mbr(struct stm32_spi *spi, u32 mbrdiv)
|
||||
{
|
||||
u32 cfg1_clrb = 0, cfg1_setb = 0;
|
||||
u32 clrb = 0, setb = 0;
|
||||
|
||||
cfg1_clrb |= STM32H7_SPI_CFG1_MBR;
|
||||
cfg1_setb |= ((u32)mbrdiv << STM32H7_SPI_CFG1_MBR_SHIFT) &
|
||||
STM32H7_SPI_CFG1_MBR;
|
||||
clrb |= spi->cfg->regs->br.mask;
|
||||
setb |= ((u32)mbrdiv << spi->cfg->regs->br.shift) &
|
||||
spi->cfg->regs->br.mask;
|
||||
|
||||
writel_relaxed((readl_relaxed(spi->base + STM32H7_SPI_CFG1) &
|
||||
~cfg1_clrb) | cfg1_setb,
|
||||
spi->base + STM32H7_SPI_CFG1);
|
||||
writel_relaxed((readl_relaxed(spi->base + spi->cfg->regs->br.reg) &
|
||||
~clrb) | setb,
|
||||
spi->base + spi->cfg->regs->br.reg);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -944,11 +1054,11 @@ static unsigned int stm32_spi_communication_type(struct spi_device *spi_dev,
|
||||
}
|
||||
|
||||
/**
|
||||
* stm32_spi_set_mode - configure communication mode
|
||||
* stm32h7_spi_set_mode - configure communication mode
|
||||
* @spi: pointer to the spi controller data structure
|
||||
* @comm_type: type of communication to configure
|
||||
*/
|
||||
static int stm32_spi_set_mode(struct stm32_spi *spi, unsigned int comm_type)
|
||||
static int stm32h7_spi_set_mode(struct stm32_spi *spi, unsigned int comm_type)
|
||||
{
|
||||
u32 mode;
|
||||
u32 cfg2_clrb = 0, cfg2_setb = 0;
|
||||
@ -980,12 +1090,12 @@ static int stm32_spi_set_mode(struct stm32_spi *spi, unsigned int comm_type)
|
||||
}
|
||||
|
||||
/**
|
||||
* stm32_spi_data_idleness - configure minimum time delay inserted between two
|
||||
* consecutive data frames in master mode
|
||||
* stm32h7_spi_data_idleness - configure minimum time delay inserted between two
|
||||
* consecutive data frames in master mode
|
||||
* @spi: pointer to the spi controller data structure
|
||||
* @len: transfer len
|
||||
*/
|
||||
static void stm32_spi_data_idleness(struct stm32_spi *spi, u32 len)
|
||||
static void stm32h7_spi_data_idleness(struct stm32_spi *spi, u32 len)
|
||||
{
|
||||
u32 cfg2_clrb = 0, cfg2_setb = 0;
|
||||
|
||||
@ -1008,11 +1118,11 @@ static void stm32_spi_data_idleness(struct stm32_spi *spi, u32 len)
|
||||
}
|
||||
|
||||
/**
|
||||
* stm32_spi_number_of_data - configure number of data at current transfer
|
||||
* stm32h7_spi_number_of_data - configure number of data at current transfer
|
||||
* @spi: pointer to the spi controller data structure
|
||||
* @len: transfer length
|
||||
*/
|
||||
static int stm32_spi_number_of_data(struct stm32_spi *spi, u32 nb_words)
|
||||
static int stm32h7_spi_number_of_data(struct stm32_spi *spi, u32 nb_words)
|
||||
{
|
||||
u32 cr2_clrb = 0, cr2_setb = 0;
|
||||
|
||||
@ -1047,7 +1157,7 @@ static int stm32_spi_transfer_one_setup(struct stm32_spi *spi,
|
||||
|
||||
if (spi->cur_bpw != transfer->bits_per_word) {
|
||||
spi->cur_bpw = transfer->bits_per_word;
|
||||
stm32_spi_set_bpw(spi);
|
||||
spi->cfg->set_bpw(spi);
|
||||
}
|
||||
|
||||
if (spi->cur_speed != transfer->speed_hz) {
|
||||
@ -1055,8 +1165,8 @@ static int stm32_spi_transfer_one_setup(struct stm32_spi *spi,
|
||||
|
||||
/* Update spi->cur_speed with real clock speed */
|
||||
mbr = stm32_spi_prepare_mbr(spi, transfer->speed_hz,
|
||||
STM32H7_SPI_MBR_DIV_MIN,
|
||||
STM32H7_SPI_MBR_DIV_MAX);
|
||||
spi->cfg->baud_rate_div_min,
|
||||
spi->cfg->baud_rate_div_max);
|
||||
if (mbr < 0) {
|
||||
ret = mbr;
|
||||
goto out;
|
||||
@ -1068,7 +1178,7 @@ static int stm32_spi_transfer_one_setup(struct stm32_spi *spi,
|
||||
|
||||
comm_type = stm32_spi_communication_type(spi_dev, transfer);
|
||||
if (spi->cur_comm != comm_type) {
|
||||
stm32_spi_set_mode(spi, comm_type);
|
||||
ret = spi->cfg->set_mode(spi, comm_type);
|
||||
|
||||
if (ret < 0)
|
||||
goto out;
|
||||
@ -1076,7 +1186,8 @@ static int stm32_spi_transfer_one_setup(struct stm32_spi *spi,
|
||||
spi->cur_comm = comm_type;
|
||||
}
|
||||
|
||||
stm32_spi_data_idleness(spi, transfer->len);
|
||||
if (spi->cfg->set_data_idleness)
|
||||
spi->cfg->set_data_idleness(spi, transfer->len);
|
||||
|
||||
if (spi->cur_bpw <= 8)
|
||||
nb_words = transfer->len;
|
||||
@ -1085,9 +1196,11 @@ static int stm32_spi_transfer_one_setup(struct stm32_spi *spi,
|
||||
else
|
||||
nb_words = DIV_ROUND_UP(transfer->len * 8, 32);
|
||||
|
||||
ret = stm32_spi_number_of_data(spi, nb_words);
|
||||
if (ret < 0)
|
||||
goto out;
|
||||
if (spi->cfg->set_number_of_data) {
|
||||
ret = spi->cfg->set_number_of_data(spi, nb_words);
|
||||
if (ret < 0)
|
||||
goto out;
|
||||
}
|
||||
|
||||
spi->cur_xferlen = transfer->len;
|
||||
|
||||
@ -1138,31 +1251,26 @@ static int stm32_spi_transfer_one(struct spi_master *master,
|
||||
if (spi->cur_usedma)
|
||||
return stm32_spi_transfer_one_dma(spi, transfer);
|
||||
else
|
||||
return stm32_spi_transfer_one_irq(spi);
|
||||
return spi->cfg->transfer_one_irq(spi);
|
||||
}
|
||||
|
||||
/**
|
||||
* stm32_spi_unprepare_msg - relax the hardware
|
||||
*
|
||||
* Normally, if TSIZE has been configured, we should relax the hardware at the
|
||||
* reception of the EOT interrupt. But in case of error, EOT will not be
|
||||
* raised. So the subsystem unprepare_message call allows us to properly
|
||||
* complete the transfer from an hardware point of view.
|
||||
*/
|
||||
static int stm32_spi_unprepare_msg(struct spi_master *master,
|
||||
struct spi_message *msg)
|
||||
{
|
||||
struct stm32_spi *spi = spi_master_get_devdata(master);
|
||||
|
||||
stm32_spi_disable(spi);
|
||||
spi->cfg->disable(spi);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* stm32_spi_config - Configure SPI controller as SPI master
|
||||
* stm32h7_spi_config - Configure SPI controller as SPI master
|
||||
*/
|
||||
static int stm32_spi_config(struct stm32_spi *spi)
|
||||
static int stm32h7_spi_config(struct stm32_spi *spi)
|
||||
{
|
||||
unsigned long flags;
|
||||
|
||||
@ -1196,8 +1304,28 @@ static int stm32_spi_config(struct stm32_spi *spi)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct stm32_spi_cfg stm32h7_spi_cfg = {
|
||||
.regs = &stm32h7_spi_regspec,
|
||||
.get_fifo_size = stm32h7_spi_get_fifo_size,
|
||||
.get_bpw_mask = stm32h7_spi_get_bpw_mask,
|
||||
.disable = stm32h7_spi_disable,
|
||||
.config = stm32h7_spi_config,
|
||||
.set_bpw = stm32h7_spi_set_bpw,
|
||||
.set_mode = stm32h7_spi_set_mode,
|
||||
.set_data_idleness = stm32h7_spi_data_idleness,
|
||||
.set_number_of_data = stm32h7_spi_number_of_data,
|
||||
.transfer_one_dma_start = stm32h7_spi_transfer_one_dma_start,
|
||||
.dma_rx_cb = stm32h7_spi_dma_cb,
|
||||
.dma_tx_cb = stm32h7_spi_dma_cb,
|
||||
.transfer_one_irq = stm32h7_spi_transfer_one_irq,
|
||||
.irq_handler_thread = stm32h7_spi_irq_thread,
|
||||
.baud_rate_div_min = STM32H7_SPI_MBR_DIV_MIN,
|
||||
.baud_rate_div_max = STM32H7_SPI_MBR_DIV_MAX,
|
||||
.has_fifo = true,
|
||||
};
|
||||
|
||||
static const struct of_device_id stm32_spi_of_match[] = {
|
||||
{ .compatible = "st,stm32h7-spi", },
|
||||
{ .compatible = "st,stm32h7-spi", .data = (void *)&stm32h7_spi_cfg },
|
||||
{},
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, stm32_spi_of_match);
|
||||
@ -1221,12 +1349,17 @@ static int stm32_spi_probe(struct platform_device *pdev)
|
||||
spi->master = master;
|
||||
spin_lock_init(&spi->lock);
|
||||
|
||||
spi->cfg = (const struct stm32_spi_cfg *)
|
||||
of_match_device(pdev->dev.driver->of_match_table,
|
||||
&pdev->dev)->data;
|
||||
|
||||
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
|
||||
spi->base = devm_ioremap_resource(&pdev->dev, res);
|
||||
if (IS_ERR(spi->base)) {
|
||||
ret = PTR_ERR(spi->base);
|
||||
goto err_master_put;
|
||||
}
|
||||
|
||||
spi->phys_addr = (dma_addr_t)res->start;
|
||||
|
||||
spi->irq = platform_get_irq(pdev, 0);
|
||||
@ -1235,9 +1368,10 @@ static int stm32_spi_probe(struct platform_device *pdev)
|
||||
ret = -ENOENT;
|
||||
goto err_master_put;
|
||||
}
|
||||
ret = devm_request_threaded_irq(&pdev->dev, spi->irq, NULL,
|
||||
stm32_spi_irq_thread, IRQF_ONESHOT,
|
||||
pdev->name, master);
|
||||
ret = devm_request_threaded_irq(&pdev->dev, spi->irq,
|
||||
spi->cfg->irq_handler_event,
|
||||
spi->cfg->irq_handler_thread,
|
||||
IRQF_ONESHOT, pdev->name, master);
|
||||
if (ret) {
|
||||
dev_err(&pdev->dev, "irq%d request failed: %d\n", spi->irq,
|
||||
ret);
|
||||
@ -1270,9 +1404,10 @@ static int stm32_spi_probe(struct platform_device *pdev)
|
||||
reset_control_deassert(spi->rst);
|
||||
}
|
||||
|
||||
spi->fifo_size = stm32_spi_get_fifo_size(spi);
|
||||
if (spi->cfg->has_fifo)
|
||||
spi->fifo_size = spi->cfg->get_fifo_size(spi);
|
||||
|
||||
ret = stm32_spi_config(spi);
|
||||
ret = spi->cfg->config(spi);
|
||||
if (ret) {
|
||||
dev_err(&pdev->dev, "controller configuration failed: %d\n",
|
||||
ret);
|
||||
@ -1284,9 +1419,9 @@ static int stm32_spi_probe(struct platform_device *pdev)
|
||||
master->bus_num = pdev->id;
|
||||
master->mode_bits = SPI_CPHA | SPI_CPOL | SPI_CS_HIGH | SPI_LSB_FIRST |
|
||||
SPI_3WIRE;
|
||||
master->bits_per_word_mask = stm32_spi_get_bpw_mask(spi);
|
||||
master->max_speed_hz = spi->clk_rate / STM32H7_SPI_MBR_DIV_MIN;
|
||||
master->min_speed_hz = spi->clk_rate / STM32H7_SPI_MBR_DIV_MAX;
|
||||
master->bits_per_word_mask = spi->cfg->get_bpw_mask(spi);
|
||||
master->max_speed_hz = spi->clk_rate / spi->cfg->baud_rate_div_min;
|
||||
master->min_speed_hz = spi->clk_rate / spi->cfg->baud_rate_div_max;
|
||||
master->setup = stm32_spi_setup;
|
||||
master->prepare_message = stm32_spi_prepare_msg;
|
||||
master->transfer_one = stm32_spi_transfer_one;
|
||||
@ -1364,7 +1499,7 @@ static int stm32_spi_remove(struct platform_device *pdev)
|
||||
struct spi_master *master = platform_get_drvdata(pdev);
|
||||
struct stm32_spi *spi = spi_master_get_devdata(master);
|
||||
|
||||
stm32_spi_disable(spi);
|
||||
spi->cfg->disable(spi);
|
||||
|
||||
if (master->dma_tx)
|
||||
dma_release_channel(master->dma_tx);
|
||||
|
Loading…
Reference in New Issue
Block a user