regulator: wm8994: Switch to SPDX identifier
[linux-2.6-microblaze.git] / drivers / spi / spi-armada-3700.c
index d653453..7dcb14d 100644 (file)
@@ -27,6 +27,8 @@
 
 #define DRIVER_NAME                    "armada_3700_spi"
 
+#define A3700_SPI_MAX_SPEED_HZ         100000000
+#define A3700_SPI_MAX_PRESCALE         30
 #define A3700_SPI_TIMEOUT              10
 
 /* SPI Register Offest */
@@ -184,12 +186,15 @@ static int a3700_spi_pin_mode_set(struct a3700_spi *a3700_spi,
        return 0;
 }
 
-static void a3700_spi_fifo_mode_set(struct a3700_spi *a3700_spi)
+static void a3700_spi_fifo_mode_set(struct a3700_spi *a3700_spi, bool enable)
 {
        u32 val;
 
        val = spireg_read(a3700_spi, A3700_SPI_IF_CFG_REG);
-       val |= A3700_SPI_FIFO_MODE;
+       if (enable)
+               val |= A3700_SPI_FIFO_MODE;
+       else
+               val &= ~A3700_SPI_FIFO_MODE;
        spireg_write(a3700_spi, A3700_SPI_IF_CFG_REG, val);
 }
 
@@ -297,7 +302,7 @@ static int a3700_spi_init(struct a3700_spi *a3700_spi)
                a3700_spi_deactivate_cs(a3700_spi, i);
 
        /* Enable FIFO mode */
-       a3700_spi_fifo_mode_set(a3700_spi);
+       a3700_spi_fifo_mode_set(a3700_spi, true);
 
        /* Set SPI mode */
        a3700_spi_mode_set(a3700_spi, master->mode_bits);
@@ -416,15 +421,20 @@ static void a3700_spi_transfer_setup(struct spi_device *spi,
                                     struct spi_transfer *xfer)
 {
        struct a3700_spi *a3700_spi;
-       unsigned int byte_len;
 
        a3700_spi = spi_master_get_devdata(spi->master);
 
        a3700_spi_clock_set(a3700_spi, xfer->speed_hz);
 
-       byte_len = xfer->bits_per_word >> 3;
+       /* Use 4 bytes long transfers. Each transfer method has its way to deal
+        * with the remaining bytes for non 4-bytes aligned transfers.
+        */
+       a3700_spi_bytelen_set(a3700_spi, 4);
 
-       a3700_spi_fifo_thres_set(a3700_spi, byte_len);
+       /* Initialize the working buffers */
+       a3700_spi->tx_buf  = xfer->tx_buf;
+       a3700_spi->rx_buf  = xfer->rx_buf;
+       a3700_spi->buf_len = xfer->len;
 }
 
 static void a3700_spi_set_cs(struct spi_device *spi, bool enable)
@@ -491,7 +501,7 @@ static int a3700_spi_fifo_write(struct a3700_spi *a3700_spi)
        u32 val;
 
        while (!a3700_is_wfifo_full(a3700_spi) && a3700_spi->buf_len) {
-               val = cpu_to_le32(*(u32 *)a3700_spi->tx_buf);
+               val = *(u32 *)a3700_spi->tx_buf;
                spireg_write(a3700_spi, A3700_SPI_DATA_OUT_REG, val);
                a3700_spi->buf_len -= 4;
                a3700_spi->tx_buf += 4;
@@ -514,9 +524,8 @@ static int a3700_spi_fifo_read(struct a3700_spi *a3700_spi)
        while (!a3700_is_rfifo_empty(a3700_spi) && a3700_spi->buf_len) {
                val = spireg_read(a3700_spi, A3700_SPI_DATA_IN_REG);
                if (a3700_spi->buf_len >= 4) {
-                       u32 data = le32_to_cpu(val);
 
-                       memcpy(a3700_spi->rx_buf, &data, 4);
+                       memcpy(a3700_spi->rx_buf, &val, 4);
 
                        a3700_spi->buf_len -= 4;
                        a3700_spi->rx_buf += 4;
@@ -579,27 +588,26 @@ static int a3700_spi_prepare_message(struct spi_master *master,
        if (ret)
                return ret;
 
-       a3700_spi_bytelen_set(a3700_spi, 4);
-
        a3700_spi_mode_set(a3700_spi, spi->mode);
 
        return 0;
 }
 
-static int a3700_spi_transfer_one(struct spi_master *master,
+static int a3700_spi_transfer_one_fifo(struct spi_master *master,
                                  struct spi_device *spi,
                                  struct spi_transfer *xfer)
 {
        struct a3700_spi *a3700_spi = spi_master_get_devdata(master);
        int ret = 0, timeout = A3700_SPI_TIMEOUT;
-       unsigned int nbits = 0;
+       unsigned int nbits = 0, byte_len;
        u32 val;
 
-       a3700_spi_transfer_setup(spi, xfer);
+       /* Make sure we use FIFO mode */
+       a3700_spi_fifo_mode_set(a3700_spi, true);
 
-       a3700_spi->tx_buf  = xfer->tx_buf;
-       a3700_spi->rx_buf  = xfer->rx_buf;
-       a3700_spi->buf_len = xfer->len;
+       /* Configure FIFO thresholds */
+       byte_len = xfer->bits_per_word >> 3;
+       a3700_spi_fifo_thres_set(a3700_spi, byte_len);
 
        if (xfer->tx_buf)
                nbits = xfer->tx_nbits;
@@ -615,6 +623,11 @@ static int a3700_spi_transfer_one(struct spi_master *master,
        a3700_spi_header_set(a3700_spi);
 
        if (xfer->rx_buf) {
+               /* Clear WFIFO, since it's last 2 bytes are shifted out during
+                * a read operation
+                */
+               spireg_write(a3700_spi, A3700_SPI_DATA_OUT_REG, 0);
+
                /* Set read data length */
                spireg_write(a3700_spi, A3700_SPI_IF_DIN_CNT_REG,
                             a3700_spi->buf_len);
@@ -729,6 +742,63 @@ out:
        return ret;
 }
 
+static int a3700_spi_transfer_one_full_duplex(struct spi_master *master,
+                                 struct spi_device *spi,
+                                 struct spi_transfer *xfer)
+{
+       struct a3700_spi *a3700_spi = spi_master_get_devdata(master);
+       u32 val;
+
+       /* Disable FIFO mode */
+       a3700_spi_fifo_mode_set(a3700_spi, false);
+
+       while (a3700_spi->buf_len) {
+
+               /* When we have less than 4 bytes to transfer, switch to 1 byte
+                * mode. This is reset after each transfer
+                */
+               if (a3700_spi->buf_len < 4)
+                       a3700_spi_bytelen_set(a3700_spi, 1);
+
+               if (a3700_spi->byte_len == 1)
+                       val = *a3700_spi->tx_buf;
+               else
+                       val = *(u32 *)a3700_spi->tx_buf;
+
+               spireg_write(a3700_spi, A3700_SPI_DATA_OUT_REG, val);
+
+               /* Wait for all the data to be shifted in / out */
+               while (!(spireg_read(a3700_spi, A3700_SPI_IF_CTRL_REG) &
+                               A3700_SPI_XFER_DONE))
+                       cpu_relax();
+
+               val = spireg_read(a3700_spi, A3700_SPI_DATA_IN_REG);
+
+               memcpy(a3700_spi->rx_buf, &val, a3700_spi->byte_len);
+
+               a3700_spi->buf_len -= a3700_spi->byte_len;
+               a3700_spi->tx_buf += a3700_spi->byte_len;
+               a3700_spi->rx_buf += a3700_spi->byte_len;
+
+       }
+
+       spi_finalize_current_transfer(master);
+
+       return 0;
+}
+
+static int a3700_spi_transfer_one(struct spi_master *master,
+                                 struct spi_device *spi,
+                                 struct spi_transfer *xfer)
+{
+       a3700_spi_transfer_setup(spi, xfer);
+
+       if (xfer->tx_buf && xfer->rx_buf)
+               return a3700_spi_transfer_one_full_duplex(master, spi, xfer);
+
+       return a3700_spi_transfer_one_fifo(master, spi, xfer);
+}
+
 static int a3700_spi_unprepare_message(struct spi_master *master,
                                       struct spi_message *message)
 {
@@ -778,7 +848,6 @@ static int a3700_spi_probe(struct platform_device *pdev)
        master->transfer_one = a3700_spi_transfer_one;
        master->unprepare_message = a3700_spi_unprepare_message;
        master->set_cs = a3700_spi_set_cs;
-       master->flags = SPI_MASTER_HALF_DUPLEX;
        master->mode_bits |= (SPI_RX_DUAL | SPI_TX_DUAL |
                              SPI_RX_QUAD | SPI_TX_QUAD);
 
@@ -818,6 +887,11 @@ static int a3700_spi_probe(struct platform_device *pdev)
                goto error;
        }
 
+       master->max_speed_hz = min_t(unsigned long, A3700_SPI_MAX_SPEED_HZ,
+                                       clk_get_rate(spi->clk));
+       master->min_speed_hz = DIV_ROUND_UP(clk_get_rate(spi->clk),
+                                               A3700_SPI_MAX_PRESCALE);
+
        ret = a3700_spi_init(spi);
        if (ret)
                goto error_clk;