spi: spi_register_controller(): free bus id on error paths
[linux-2.6-microblaze.git] / drivers / spi / spi-ti-qspi.c
index 3cb6537..366a3e5 100644 (file)
@@ -62,6 +62,7 @@ struct ti_qspi {
        u32 dc;
 
        bool mmap_enabled;
+       int current_cs;
 };
 
 #define QSPI_PID                       (0x0)
@@ -79,8 +80,6 @@ struct ti_qspi {
 
 #define QSPI_COMPLETION_TIMEOUT                msecs_to_jiffies(2000)
 
-#define QSPI_FCLK                      192000000
-
 /* Clock Control */
 #define QSPI_CLK_EN                    (1 << 31)
 #define QSPI_CLK_DIV_MAX               0xffff
@@ -315,6 +314,8 @@ static int qspi_read_msg(struct ti_qspi *qspi, struct spi_transfer *t,
 {
        int wlen;
        unsigned int cmd;
+       u32 rx;
+       u8 rxlen, rx_wlen;
        u8 *rxbuf;
 
        rxbuf = t->rx_buf;
@@ -331,20 +332,67 @@ static int qspi_read_msg(struct ti_qspi *qspi, struct spi_transfer *t,
                break;
        }
        wlen = t->bits_per_word >> 3;   /* in bytes */
+       rx_wlen = wlen;
 
        while (count) {
                dev_dbg(qspi->dev, "rx cmd %08x dc %08x\n", cmd, qspi->dc);
                if (qspi_is_busy(qspi))
                        return -EBUSY;
 
+               switch (wlen) {
+               case 1:
+                       /*
+                        * Optimize the 8-bit words transfers, as used by
+                        * the SPI flash devices.
+                        */
+                       if (count >= QSPI_WLEN_MAX_BYTES) {
+                               rxlen = QSPI_WLEN_MAX_BYTES;
+                       } else {
+                               rxlen = min(count, 4);
+                       }
+                       rx_wlen = rxlen << 3;
+                       cmd &= ~QSPI_WLEN_MASK;
+                       cmd |= QSPI_WLEN(rx_wlen);
+                       break;
+               default:
+                       rxlen = wlen;
+                       break;
+               }
+
                ti_qspi_write(qspi, cmd, QSPI_SPI_CMD_REG);
                if (ti_qspi_poll_wc(qspi)) {
                        dev_err(qspi->dev, "read timed out\n");
                        return -ETIMEDOUT;
                }
+
                switch (wlen) {
                case 1:
-                       *rxbuf = readb(qspi->base + QSPI_SPI_DATA_REG);
+                       /*
+                        * Optimize the 8-bit words transfers, as used by
+                        * the SPI flash devices.
+                        */
+                       if (count >= QSPI_WLEN_MAX_BYTES) {
+                               u32 *rxp = (u32 *) rxbuf;
+                               rx = readl(qspi->base + QSPI_SPI_DATA_REG_3);
+                               *rxp++ = be32_to_cpu(rx);
+                               rx = readl(qspi->base + QSPI_SPI_DATA_REG_2);
+                               *rxp++ = be32_to_cpu(rx);
+                               rx = readl(qspi->base + QSPI_SPI_DATA_REG_1);
+                               *rxp++ = be32_to_cpu(rx);
+                               rx = readl(qspi->base + QSPI_SPI_DATA_REG);
+                               *rxp++ = be32_to_cpu(rx);
+                       } else {
+                               u8 *rxp = rxbuf;
+                               rx = readl(qspi->base + QSPI_SPI_DATA_REG);
+                               if (rx_wlen >= 8)
+                                       *rxp++ = rx >> (rx_wlen - 8);
+                               if (rx_wlen >= 16)
+                                       *rxp++ = rx >> (rx_wlen - 16);
+                               if (rx_wlen >= 24)
+                                       *rxp++ = rx >> (rx_wlen - 24);
+                               if (rx_wlen >= 32)
+                                       *rxp++ = rx;
+                       }
                        break;
                case 2:
                        *((u16 *)rxbuf) = readw(qspi->base + QSPI_SPI_DATA_REG);
@@ -353,8 +401,8 @@ static int qspi_read_msg(struct ti_qspi *qspi, struct spi_transfer *t,
                        *((u32 *)rxbuf) = readl(qspi->base + QSPI_SPI_DATA_REG);
                        break;
                }
-               rxbuf += wlen;
-               count -= wlen;
+               rxbuf += rxlen;
+               count -= rxlen;
        }
 
        return 0;
@@ -487,6 +535,7 @@ static void ti_qspi_enable_memory_map(struct spi_device *spi)
                                   MEM_CS_EN(spi->chip_select));
        }
        qspi->mmap_enabled = true;
+       qspi->current_cs = spi->chip_select;
 }
 
 static void ti_qspi_disable_memory_map(struct spi_device *spi)
@@ -498,6 +547,7 @@ static void ti_qspi_disable_memory_map(struct spi_device *spi)
                regmap_update_bits(qspi->ctrl_base, qspi->ctrl_reg,
                                   MEM_CS_MASK, 0);
        qspi->mmap_enabled = false;
+       qspi->current_cs = -1;
 }
 
 static void ti_qspi_setup_mmap_read(struct spi_device *spi, u8 opcode,
@@ -524,6 +574,35 @@ static void ti_qspi_setup_mmap_read(struct spi_device *spi, u8 opcode,
                      QSPI_SPI_SETUP_REG(spi->chip_select));
 }
 
+static int ti_qspi_adjust_op_size(struct spi_mem *mem, struct spi_mem_op *op)
+{
+       struct ti_qspi *qspi = spi_controller_get_devdata(mem->spi->master);
+       size_t max_len;
+
+       if (op->data.dir == SPI_MEM_DATA_IN) {
+               if (op->addr.val < qspi->mmap_size) {
+                       /* Limit MMIO to the mmaped region */
+                       if (op->addr.val + op->data.nbytes > qspi->mmap_size) {
+                               max_len = qspi->mmap_size - op->addr.val;
+                               op->data.nbytes = min((size_t) op->data.nbytes,
+                                                     max_len);
+                       }
+               } else {
+                       /*
+                        * Use fallback mode (SW generated transfers) above the
+                        * mmaped region.
+                        * Adjust size to comply with the QSPI max frame length.
+                        */
+                       max_len = QSPI_FRAME;
+                       max_len -= 1 + op->addr.nbytes + op->dummy.nbytes;
+                       op->data.nbytes = min((size_t) op->data.nbytes,
+                                             max_len);
+               }
+       }
+
+       return 0;
+}
+
 static int ti_qspi_exec_mem_op(struct spi_mem *mem,
                               const struct spi_mem_op *op)
 {
@@ -543,7 +622,7 @@ static int ti_qspi_exec_mem_op(struct spi_mem *mem,
 
        mutex_lock(&qspi->list_lock);
 
-       if (!qspi->mmap_enabled)
+       if (!qspi->mmap_enabled || qspi->current_cs != mem->spi->chip_select)
                ti_qspi_enable_memory_map(mem->spi);
        ti_qspi_setup_mmap_read(mem->spi, op->cmd.opcode, op->data.buswidth,
                                op->addr.nbytes, op->dummy.nbytes);
@@ -574,6 +653,7 @@ static int ti_qspi_exec_mem_op(struct spi_mem *mem,
 
 static const struct spi_controller_mem_ops ti_qspi_mem_ops = {
        .exec_op = ti_qspi_exec_mem_op,
+       .adjust_op_size = ti_qspi_adjust_op_size,
 };
 
 static int ti_qspi_start_transfer_one(struct spi_master *master,
@@ -799,6 +879,7 @@ no_dma:
                }
        }
        qspi->mmap_enabled = false;
+       qspi->current_cs = -1;
 
        ret = devm_spi_register_master(&pdev->dev, master);
        if (!ret)