diff options
-rw-r--r-- | drivers/spi/spi-dw.c | 61 | ||||
-rw-r--r-- | drivers/spi/spi-dw.h | 12 |
2 files changed, 35 insertions, 38 deletions
diff --git a/drivers/spi/spi-dw.c b/drivers/spi/spi-dw.c index 5a97a62b298a..9a855bb00694 100644 --- a/drivers/spi/spi-dw.c +++ b/drivers/spi/spi-dw.c @@ -272,8 +272,7 @@ static void giveback(struct dw_spi *dws) static void int_error_stop(struct dw_spi *dws, const char *msg) { - /* Stop the hw */ - spi_enable_chip(dws, 0); + spi_reset_chip(dws); dev_err(&dws->master->dev, "%s\n", msg); dws->cur_msg->state = ERROR_STATE; @@ -365,7 +364,7 @@ static void pump_transfers(unsigned long data) u8 bits = 0; u8 imask = 0; u8 cs_change = 0; - u16 txint_level = 0; + u16 txlevel = 0; u16 clk_div = 0; u32 speed = 0; u32 cr0 = 0; @@ -410,21 +409,24 @@ static void pump_transfers(unsigned long data) if (chip != dws->prev_chip) cs_change = 1; + spi_enable_chip(dws, 0); + cr0 = chip->cr0; /* Handle per transfer options for bpw and speed */ if (transfer->speed_hz) { speed = chip->speed_hz; - if ((transfer->speed_hz != speed) || (!chip->clk_div)) { + if ((transfer->speed_hz != speed) || !chip->clk_div) { speed = transfer->speed_hz; /* clk_div doesn't support odd number */ - clk_div = dws->max_freq / speed; - clk_div = (clk_div + 1) & 0xfffe; + clk_div = (dws->max_freq / speed + 1) & 0xfffe; chip->speed_hz = speed; chip->clk_div = clk_div; + + spi_set_clk(dws, chip->clk_div); } } if (transfer->bits_per_word) { @@ -453,50 +455,35 @@ static void pump_transfers(unsigned long data) cr0 |= (chip->tmode << SPI_TMOD_OFFSET); } + dw_writew(dws, DW_SPI_CTRL0, cr0); + spi_chip_sel(dws, spi, 1); + /* Check if current transfer is a DMA transaction */ dws->dma_mapped = map_dma_buffers(dws); + /* For poll mode just disable all interrupts */ + spi_mask_intr(dws, 0xff); + /* * Interrupt mode * we only need set the TXEI IRQ, as TX/RX always happen syncronizely */ if (!dws->dma_mapped && !chip->poll_mode) { - int templen = dws->len / dws->n_bytes; - - txint_level = dws->fifo_len / 2; - txint_level = (templen > txint_level) ? txint_level : templen; + txlevel = min_t(u16, dws->fifo_len / 2, dws->len / dws->n_bytes); + dw_writew(dws, DW_SPI_TXFLTR, txlevel); + /* Set the interrupt mask */ imask |= SPI_INT_TXEI | SPI_INT_TXOI | SPI_INT_RXUI | SPI_INT_RXOI; + spi_umask_intr(dws, imask); + dws->transfer_handler = interrupt_transfer; } - /* - * Reprogram registers only if - * 1. chip select changes - * 2. clk_div is changed - * 3. control value changes - */ - if (dw_readw(dws, DW_SPI_CTRL0) != cr0 || cs_change || clk_div || imask) { - spi_enable_chip(dws, 0); - - if (dw_readw(dws, DW_SPI_CTRL0) != cr0) - dw_writew(dws, DW_SPI_CTRL0, cr0); - - spi_set_clk(dws, clk_div ? clk_div : chip->clk_div); - spi_chip_sel(dws, spi, 1); + spi_enable_chip(dws, 1); - /* Set the interrupt mask, for poll mode just disable all int */ - spi_mask_intr(dws, 0xff); - if (imask) - spi_umask_intr(dws, imask); - if (txint_level) - dw_writew(dws, DW_SPI_TXFLTR, txint_level); - - spi_enable_chip(dws, 1); - if (cs_change) - dws->prev_chip = chip; - } + if (cs_change) + dws->prev_chip = chip; if (dws->dma_mapped) dws->dma_ops->dma_transfer(dws, cs_change); @@ -610,9 +597,7 @@ static void dw_spi_cleanup(struct spi_device *spi) /* Restart the controller, disable all interrupts, clean rx fifo */ static void spi_hw_init(struct device *dev, struct dw_spi *dws) { - spi_enable_chip(dws, 0); - spi_mask_intr(dws, 0xff); - spi_enable_chip(dws, 1); + spi_reset_chip(dws); /* * Try to detect the FIFO depth if not set by interface driver, diff --git a/drivers/spi/spi-dw.h b/drivers/spi/spi-dw.h index 3d32be68c142..1a7f083c2217 100644 --- a/drivers/spi/spi-dw.h +++ b/drivers/spi/spi-dw.h @@ -217,6 +217,18 @@ static inline void spi_umask_intr(struct dw_spi *dws, u32 mask) } /* + * This does disable the SPI controller, interrupts, and re-enable the + * controller back. Transmit and receive FIFO buffers are cleared when the + * device is disabled. + */ +static inline void spi_reset_chip(struct dw_spi *dws) +{ + spi_enable_chip(dws, 0); + spi_mask_intr(dws, 0xff); + spi_enable_chip(dws, 1); +} + +/* * Each SPI slave device to work with dw_api controller should * has such a structure claiming its working mode (PIO/DMA etc), * which can be save in the "controller_data" member of the |