Merge tag 'pm+acpi-4.1-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/rafael...
[firefly-linux-kernel-4.4.55.git] / drivers / spi / spi-dw.c
index 4847afba89f4e933e5a5d778c5f94e1a14ffe156..8d67d03c71ebcdec375023f8db910d3d0d8469ec 100644 (file)
 #include <linux/debugfs.h>
 #endif
 
-#define START_STATE    ((void *)0)
-#define RUNNING_STATE  ((void *)1)
-#define DONE_STATE     ((void *)2)
-#define ERROR_STATE    ((void *)-1)
-
 /* Slave spi_dev related */
 struct chip_data {
        u16 cr0;
@@ -143,13 +138,26 @@ static inline void dw_spi_debugfs_remove(struct dw_spi *dws)
 }
 #endif /* CONFIG_DEBUG_FS */
 
+static void dw_spi_set_cs(struct spi_device *spi, bool enable)
+{
+       struct dw_spi *dws = spi_master_get_devdata(spi->master);
+       struct chip_data *chip = spi_get_ctldata(spi);
+
+       /* Chip select logic is inverted from spi_set_cs() */
+       if (chip && chip->cs_control)
+               chip->cs_control(!enable);
+
+       if (!enable)
+               dw_writel(dws, DW_SPI_SER, BIT(spi->chip_select));
+}
+
 /* Return the max entries we can fill into tx fifo */
 static inline u32 tx_max(struct dw_spi *dws)
 {
        u32 tx_left, tx_room, rxtx_gap;
 
        tx_left = (dws->tx_end - dws->tx) / dws->n_bytes;
-       tx_room = dws->fifo_len - dw_readw(dws, DW_SPI_TXFLR);
+       tx_room = dws->fifo_len - dw_readl(dws, DW_SPI_TXFLR);
 
        /*
         * Another concern is about the tx/rx mismatch, we
@@ -170,7 +178,7 @@ static inline u32 rx_max(struct dw_spi *dws)
 {
        u32 rx_left = (dws->rx_end - dws->rx) / dws->n_bytes;
 
-       return min_t(u32, rx_left, dw_readw(dws, DW_SPI_RXFLR));
+       return min_t(u32, rx_left, dw_readl(dws, DW_SPI_RXFLR));
 }
 
 static void dw_writer(struct dw_spi *dws)
@@ -186,7 +194,7 @@ static void dw_writer(struct dw_spi *dws)
                        else
                                txw = *(u16 *)(dws->tx);
                }
-               dw_writew(dws, DW_SPI_DR, txw);
+               dw_writel(dws, DW_SPI_DR, txw);
                dws->tx += dws->n_bytes;
        }
 }
@@ -197,7 +205,7 @@ static void dw_reader(struct dw_spi *dws)
        u16 rxw;
 
        while (max--) {
-               rxw = dw_readw(dws, DW_SPI_DR);
+               rxw = dw_readl(dws, DW_SPI_DR);
                /* Care rx only if the transfer's original "rx" is not null */
                if (dws->rx_end - dws->len) {
                        if (dws->n_bytes == 1)
@@ -209,103 +217,22 @@ static void dw_reader(struct dw_spi *dws)
        }
 }
 
-static void *next_transfer(struct dw_spi *dws)
-{
-       struct spi_message *msg = dws->cur_msg;
-       struct spi_transfer *trans = dws->cur_transfer;
-
-       /* Move to next transfer */
-       if (trans->transfer_list.next != &msg->transfers) {
-               dws->cur_transfer =
-                       list_entry(trans->transfer_list.next,
-                                       struct spi_transfer,
-                                       transfer_list);
-               return RUNNING_STATE;
-       }
-
-       return DONE_STATE;
-}
-
-/*
- * Note: first step is the protocol driver prepares
- * a dma-capable memory, and this func just need translate
- * the virt addr to physical
- */
-static int map_dma_buffers(struct dw_spi *dws)
-{
-       if (!dws->cur_msg->is_dma_mapped
-               || !dws->dma_inited
-               || !dws->cur_chip->enable_dma
-               || !dws->dma_ops)
-               return 0;
-
-       if (dws->cur_transfer->tx_dma)
-               dws->tx_dma = dws->cur_transfer->tx_dma;
-
-       if (dws->cur_transfer->rx_dma)
-               dws->rx_dma = dws->cur_transfer->rx_dma;
-
-       return 1;
-}
-
-/* Caller already set message->status; dma and pio irqs are blocked */
-static void giveback(struct dw_spi *dws)
-{
-       struct spi_transfer *last_transfer;
-       struct spi_message *msg;
-
-       msg = dws->cur_msg;
-       dws->cur_msg = NULL;
-       dws->cur_transfer = NULL;
-       dws->prev_chip = dws->cur_chip;
-       dws->cur_chip = NULL;
-       dws->dma_mapped = 0;
-
-       last_transfer = list_last_entry(&msg->transfers, struct spi_transfer,
-                                       transfer_list);
-
-       if (!last_transfer->cs_change)
-               spi_chip_sel(dws, msg->spi, 0);
-
-       spi_finalize_current_message(dws->master);
-}
-
 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;
-       tasklet_schedule(&dws->pump_transfers);
+       dws->master->cur_msg->status = -EIO;
+       spi_finalize_current_transfer(dws->master);
 }
 
-void dw_spi_xfer_done(struct dw_spi *dws)
-{
-       /* Update total byte transferred return count actual bytes read */
-       dws->cur_msg->actual_length += dws->len;
-
-       /* Move to next transfer */
-       dws->cur_msg->state = next_transfer(dws);
-
-       /* Handle end of message */
-       if (dws->cur_msg->state == DONE_STATE) {
-               dws->cur_msg->status = 0;
-               giveback(dws);
-       } else
-               tasklet_schedule(&dws->pump_transfers);
-}
-EXPORT_SYMBOL_GPL(dw_spi_xfer_done);
-
 static irqreturn_t interrupt_transfer(struct dw_spi *dws)
 {
-       u16 irq_status = dw_readw(dws, DW_SPI_ISR);
+       u16 irq_status = dw_readl(dws, DW_SPI_ISR);
 
        /* Error handling */
        if (irq_status & (SPI_INT_TXOI | SPI_INT_RXOI | SPI_INT_RXUI)) {
-               dw_readw(dws, DW_SPI_TXOICR);
-               dw_readw(dws, DW_SPI_RXOICR);
-               dw_readw(dws, DW_SPI_RXUICR);
+               dw_readl(dws, DW_SPI_ICR);
                int_error_stop(dws, "interrupt_transfer: fifo overrun/underrun");
                return IRQ_HANDLED;
        }
@@ -313,7 +240,7 @@ static irqreturn_t interrupt_transfer(struct dw_spi *dws)
        dw_reader(dws);
        if (dws->rx_end == dws->rx) {
                spi_mask_intr(dws, SPI_INT_TXEI);
-               dw_spi_xfer_done(dws);
+               spi_finalize_current_transfer(dws->master);
                return IRQ_HANDLED;
        }
        if (irq_status & SPI_INT_TXEI) {
@@ -328,13 +255,14 @@ static irqreturn_t interrupt_transfer(struct dw_spi *dws)
 
 static irqreturn_t dw_spi_irq(int irq, void *dev_id)
 {
-       struct dw_spi *dws = dev_id;
-       u16 irq_status = dw_readw(dws, DW_SPI_ISR) & 0x3f;
+       struct spi_master *master = dev_id;
+       struct dw_spi *dws = spi_master_get_devdata(master);
+       u16 irq_status = dw_readl(dws, DW_SPI_ISR) & 0x3f;
 
        if (!irq_status)
                return IRQ_NONE;
 
-       if (!dws->cur_msg) {
+       if (!master->cur_msg) {
                spi_mask_intr(dws, SPI_INT_TXEI);
                return IRQ_HANDLED;
        }
@@ -343,7 +271,7 @@ static irqreturn_t dw_spi_irq(int irq, void *dev_id)
 }
 
 /* Must be called inside pump_transfers() */
-static void poll_transfer(struct dw_spi *dws)
+static int poll_transfer(struct dw_spi *dws)
 {
        do {
                dw_writer(dws);
@@ -351,64 +279,32 @@ static void poll_transfer(struct dw_spi *dws)
                cpu_relax();
        } while (dws->rx_end > dws->rx);
 
-       dw_spi_xfer_done(dws);
+       return 0;
 }
 
-static void pump_transfers(unsigned long data)
+static int dw_spi_transfer_one(struct spi_master *master,
+               struct spi_device *spi, struct spi_transfer *transfer)
 {
-       struct dw_spi *dws = (struct dw_spi *)data;
-       struct spi_message *message = NULL;
-       struct spi_transfer *transfer = NULL;
-       struct spi_transfer *previous = NULL;
-       struct spi_device *spi = NULL;
-       struct chip_data *chip = NULL;
-       u8 bits = 0;
+       struct dw_spi *dws = spi_master_get_devdata(master);
+       struct chip_data *chip = spi_get_ctldata(spi);
        u8 imask = 0;
-       u8 cs_change = 0;
-       u16 txint_level = 0;
+       u16 txlevel = 0;
        u16 clk_div = 0;
        u32 speed = 0;
        u32 cr0 = 0;
+       int ret;
 
-       /* Get current state information */
-       message = dws->cur_msg;
-       transfer = dws->cur_transfer;
-       chip = dws->cur_chip;
-       spi = message->spi;
-
-       if (message->state == ERROR_STATE) {
-               message->status = -EIO;
-               goto early_exit;
-       }
-
-       /* Handle end of message */
-       if (message->state == DONE_STATE) {
-               message->status = 0;
-               goto early_exit;
-       }
-
-       /* Delay if requested at end of transfer */
-       if (message->state == RUNNING_STATE) {
-               previous = list_entry(transfer->transfer_list.prev,
-                                       struct spi_transfer,
-                                       transfer_list);
-               if (previous->delay_usecs)
-                       udelay(previous->delay_usecs);
-       }
-
+       dws->dma_mapped = 0;
        dws->n_bytes = chip->n_bytes;
        dws->dma_width = chip->dma_width;
-       dws->cs_control = chip->cs_control;
 
-       dws->rx_dma = transfer->rx_dma;
-       dws->tx_dma = transfer->tx_dma;
        dws->tx = (void *)transfer->tx_buf;
        dws->tx_end = dws->tx + transfer->len;
        dws->rx = transfer->rx_buf;
        dws->rx_end = dws->rx + transfer->len;
-       dws->len = dws->cur_transfer->len;
-       if (chip != dws->prev_chip)
-               cs_change = 1;
+       dws->len = transfer->len;
+
+       spi_enable_chip(dws, 0);
 
        cr0 = chip->cr0;
 
@@ -416,32 +312,37 @@ static void pump_transfers(unsigned long data)
        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) {
-               bits = transfer->bits_per_word;
-               dws->n_bytes = dws->dma_width = bits >> 3;
-               cr0 = (bits - 1)
+               if (transfer->bits_per_word == 8) {
+                       dws->n_bytes = 1;
+                       dws->dma_width = 1;
+               } else if (transfer->bits_per_word == 16) {
+                       dws->n_bytes = 2;
+                       dws->dma_width = 2;
+               }
+               cr0 = (transfer->bits_per_word - 1)
                        | (chip->type << SPI_FRF_OFFSET)
                        | (spi->mode << SPI_MODE_OFFSET)
                        | (chip->tmode << SPI_TMOD_OFFSET);
        }
-       message->state = RUNNING_STATE;
 
        /*
         * Adjust transfer mode if necessary. Requires platform dependent
         * chipselect mechanism.
         */
-       if (dws->cs_control) {
+       if (chip->cs_control) {
                if (dws->rx && dws->tx)
                        chip->tmode = SPI_TMOD_TR;
                else if (dws->rx)
@@ -453,80 +354,60 @@ static void pump_transfers(unsigned long data)
                cr0 |= (chip->tmode << SPI_TMOD_OFFSET);
        }
 
+       dw_writel(dws, DW_SPI_CTRL0, cr0);
+
        /* Check if current transfer is a DMA transaction */
-       dws->dma_mapped = map_dma_buffers(dws);
+       if (master->can_dma && master->can_dma(master, spi, transfer))
+               dws->dma_mapped = master->cur_msg_mapped;
+
+       /* 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;
+       if (dws->dma_mapped) {
+               ret = dws->dma_ops->dma_setup(dws, transfer);
+               if (ret < 0) {
+                       spi_enable_chip(dws, 1);
+                       return ret;
+               }
+       } else if (!chip->poll_mode) {
+               txlevel = min_t(u16, dws->fifo_len / 2, dws->len / dws->n_bytes);
+               dw_writel(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);
-
-               /* 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);
 
-               spi_enable_chip(dws, 1);
-               if (cs_change)
-                       dws->prev_chip = chip;
+       if (dws->dma_mapped) {
+               ret = dws->dma_ops->dma_transfer(dws, transfer);
+               if (ret < 0)
+                       return ret;
        }
 
-       if (dws->dma_mapped)
-               dws->dma_ops->dma_transfer(dws, cs_change);
-
        if (chip->poll_mode)
-               poll_transfer(dws);
-
-       return;
+               return poll_transfer(dws);
 
-early_exit:
-       giveback(dws);
+       return 1;
 }
 
-static int dw_spi_transfer_one_message(struct spi_master *master,
+static void dw_spi_handle_err(struct spi_master *master,
                struct spi_message *msg)
 {
        struct dw_spi *dws = spi_master_get_devdata(master);
 
-       dws->cur_msg = msg;
-       /* Initial message state */
-       dws->cur_msg->state = START_STATE;
-       dws->cur_transfer = list_entry(dws->cur_msg->transfers.next,
-                                               struct spi_transfer,
-                                               transfer_list);
-       dws->cur_chip = spi_get_ctldata(dws->cur_msg->spi);
-
-       /* Launch transfers */
-       tasklet_schedule(&dws->pump_transfers);
+       if (dws->dma_mapped)
+               dws->dma_ops->dma_stop(dws);
 
-       return 0;
+       spi_reset_chip(dws);
 }
 
 /* This may be called twice for each spi dev */
@@ -561,8 +442,6 @@ static int dw_spi_setup(struct spi_device *spi)
 
                chip->rx_threshold = 0;
                chip->tx_threshold = 0;
-
-               chip->enable_dma = chip_info->enable_dma;
        }
 
        if (spi->bits_per_word == 8) {
@@ -610,9 +489,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,
@@ -622,11 +499,11 @@ static void spi_hw_init(struct device *dev, struct dw_spi *dws)
                u32 fifo;
 
                for (fifo = 1; fifo < 256; fifo++) {
-                       dw_writew(dws, DW_SPI_TXFLTR, fifo);
-                       if (fifo != dw_readw(dws, DW_SPI_TXFLTR))
+                       dw_writel(dws, DW_SPI_TXFLTR, fifo);
+                       if (fifo != dw_readl(dws, DW_SPI_TXFLTR))
                                break;
                }
-               dw_writew(dws, DW_SPI_TXFLTR, 0);
+               dw_writel(dws, DW_SPI_TXFLTR, 0);
 
                dws->fifo_len = (fifo == 1) ? 0 : fifo;
                dev_dbg(dev, "Detected FIFO size: %u bytes\n", dws->fifo_len);
@@ -646,13 +523,12 @@ int dw_spi_add_host(struct device *dev, struct dw_spi *dws)
 
        dws->master = master;
        dws->type = SSI_MOTO_SPI;
-       dws->prev_chip = NULL;
        dws->dma_inited = 0;
        dws->dma_addr = (dma_addr_t)(dws->paddr + 0x60);
        snprintf(dws->name, sizeof(dws->name), "dw_spi%d", dws->bus_num);
 
        ret = devm_request_irq(dev, dws->irq, dw_spi_irq, IRQF_SHARED,
-                       dws->name, dws);
+                       dws->name, master);
        if (ret < 0) {
                dev_err(&master->dev, "can not get IRQ\n");
                goto err_free_master;
@@ -664,7 +540,9 @@ int dw_spi_add_host(struct device *dev, struct dw_spi *dws)
        master->num_chipselect = dws->num_cs;
        master->setup = dw_spi_setup;
        master->cleanup = dw_spi_cleanup;
-       master->transfer_one_message = dw_spi_transfer_one_message;
+       master->set_cs = dw_spi_set_cs;
+       master->transfer_one = dw_spi_transfer_one;
+       master->handle_err = dw_spi_handle_err;
        master->max_speed_hz = dws->max_freq;
        master->dev.of_node = dev->of_node;
 
@@ -676,11 +554,11 @@ int dw_spi_add_host(struct device *dev, struct dw_spi *dws)
                if (ret) {
                        dev_warn(dev, "DMA init failed\n");
                        dws->dma_inited = 0;
+               } else {
+                       master->can_dma = dws->dma_ops->can_dma;
                }
        }
 
-       tasklet_init(&dws->pump_transfers, pump_transfers, (unsigned long)dws);
-
        spi_master_set_devdata(master, dws);
        ret = devm_spi_register_master(dev, master);
        if (ret) {