summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--drivers/spi/spi-dw.c61
-rw-r--r--drivers/spi/spi-dw.h12
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