common: Drop linux/delay.h from common header
[oweals/u-boot.git] / drivers / spi / zynq_spi.c
index e9129da79d99825b9d88c7bc893d3de0f9700feb..e3bad5532a540162099fc04a2b13a4d6fa6f3e12 100644 (file)
@@ -1,30 +1,38 @@
+// SPDX-License-Identifier: GPL-2.0+
 /*
- * (C) Copyright 2013 Inc.
+ * (C) Copyright 2013 Xilinx, Inc.
+ * (C) Copyright 2015 Jagan Teki <jteki@openedev.com>
  *
  * Xilinx Zynq PS SPI controller driver (master mode only)
- *
- * SPDX-License-Identifier:     GPL-2.0+
  */
 
-#include <config.h>
 #include <common.h>
+#include <dm.h>
+#include <log.h>
 #include <malloc.h>
 #include <spi.h>
+#include <time.h>
 #include <asm/io.h>
-#include <asm/arch/hardware.h>
+#include <linux/delay.h>
+
+DECLARE_GLOBAL_DATA_PTR;
 
 /* zynq spi register bit masks ZYNQ_SPI_<REG>_<BIT>_MASK */
-#define ZYNQ_SPI_CR_MSA_MASK           (1 << 15)       /* Manual start enb */
-#define ZYNQ_SPI_CR_MCS_MASK           (1 << 14)       /* Manual chip select */
-#define ZYNQ_SPI_CR_CS_MASK            (0xF << 10)     /* Chip select */
-#define ZYNQ_SPI_CR_BRD_MASK           (0x7 << 3)      /* Baud rate div */
-#define ZYNQ_SPI_CR_CPHA_MASK          (1 << 2)        /* Clock phase */
-#define ZYNQ_SPI_CR_CPOL_MASK          (1 << 1)        /* Clock polarity */
-#define ZYNQ_SPI_CR_MSTREN_MASK                (1 << 0)        /* Mode select */
-#define ZYNQ_SPI_IXR_RXNEMPTY_MASK     (1 << 4)        /* RX_FIFO_not_empty */
-#define ZYNQ_SPI_IXR_TXOW_MASK         (1 << 2)        /* TX_FIFO_not_full */
-#define ZYNQ_SPI_IXR_ALL_MASK          0x7F            /* All IXR bits */
-#define ZYNQ_SPI_ENR_SPI_EN_MASK       (1 << 0)        /* SPI Enable */
+#define ZYNQ_SPI_CR_MSA_MASK           BIT(15) /* Manual start enb */
+#define ZYNQ_SPI_CR_MCS_MASK           BIT(14) /* Manual chip select */
+#define ZYNQ_SPI_CR_CS_MASK            GENMASK(13, 10) /* Chip select */
+#define ZYNQ_SPI_CR_BAUD_MASK          GENMASK(5, 3)   /* Baud rate div */
+#define ZYNQ_SPI_CR_CPHA_MASK          BIT(2)  /* Clock phase */
+#define ZYNQ_SPI_CR_CPOL_MASK          BIT(1)  /* Clock polarity */
+#define ZYNQ_SPI_CR_MSTREN_MASK                BIT(0)  /* Mode select */
+#define ZYNQ_SPI_IXR_RXNEMPTY_MASK     BIT(4)  /* RX_FIFO_not_empty */
+#define ZYNQ_SPI_IXR_TXOW_MASK         BIT(2)  /* TX_FIFO_not_full */
+#define ZYNQ_SPI_IXR_ALL_MASK          GENMASK(6, 0)   /* All IXR bits */
+#define ZYNQ_SPI_ENR_SPI_EN_MASK       BIT(0)  /* SPI Enable */
+
+#define ZYNQ_SPI_CR_BAUD_MAX           8       /* Baud rate divisor max val */
+#define ZYNQ_SPI_CR_BAUD_SHIFT         3       /* Baud rate divisor shift */
+#define ZYNQ_SPI_CR_SS_SHIFT           10      /* Slave select shift */
 
 #define ZYNQ_SPI_FIFO_DEPTH            128
 #ifndef CONFIG_SYS_ZYNQ_SPI_WAIT
@@ -44,180 +52,169 @@ struct zynq_spi_regs {
        u32 rxdr;       /* 0x20 */
 };
 
-/* zynq spi slave */
-struct zynq_spi_slave {
-       struct spi_slave slave;
-       struct zynq_spi_regs *base;
+
+/* zynq spi platform data */
+struct zynq_spi_platdata {
+       struct zynq_spi_regs *regs;
+       u32 frequency;          /* input frequency */
+       u32 speed_hz;
+       uint deactivate_delay_us;       /* Delay to wait after deactivate */
+       uint activate_delay_us;         /* Delay to wait after activate */
+};
+
+/* zynq spi priv */
+struct zynq_spi_priv {
+       struct zynq_spi_regs *regs;
+       u8 cs;
        u8 mode;
+       ulong last_transaction_us;      /* Time of last transaction end */
        u8 fifo_depth;
-       u32 speed_hz;
-       u32 input_hz;
-       u32 req_hz;
+       u32 freq;               /* required frequency */
 };
 
-static inline struct zynq_spi_slave *to_zynq_spi_slave(struct spi_slave *slave)
+static int zynq_spi_ofdata_to_platdata(struct udevice *bus)
 {
-       return container_of(slave, struct zynq_spi_slave, slave);
-}
+       struct zynq_spi_platdata *plat = bus->platdata;
+       const void *blob = gd->fdt_blob;
+       int node = dev_of_offset(bus);
 
-static inline struct zynq_spi_regs *get_zynq_spi_base(int dev)
-{
-       if (dev)
-               return (struct zynq_spi_regs *)ZYNQ_SPI_BASEADDR1;
-       else
-               return (struct zynq_spi_regs *)ZYNQ_SPI_BASEADDR0;
+       plat->regs = (struct zynq_spi_regs *)devfdt_get_addr(bus);
+
+       /* FIXME: Use 250MHz as a suitable default */
+       plat->frequency = fdtdec_get_int(blob, node, "spi-max-frequency",
+                                       250000000);
+       plat->deactivate_delay_us = fdtdec_get_int(blob, node,
+                                       "spi-deactivate-delay", 0);
+       plat->activate_delay_us = fdtdec_get_int(blob, node,
+                                                "spi-activate-delay", 0);
+       plat->speed_hz = plat->frequency / 2;
+
+       debug("%s: regs=%p max-frequency=%d\n", __func__,
+             plat->regs, plat->frequency);
+
+       return 0;
 }
 
-static void zynq_spi_init_hw(struct zynq_spi_slave *zslave)
+static void zynq_spi_init_hw(struct zynq_spi_priv *priv)
 {
+       struct zynq_spi_regs *regs = priv->regs;
        u32 confr;
 
        /* Disable SPI */
-       writel(~ZYNQ_SPI_ENR_SPI_EN_MASK, &zslave->base->enr);
+       confr = ZYNQ_SPI_ENR_SPI_EN_MASK;
+       writel(~confr, &regs->enr);
 
        /* Disable Interrupts */
-       writel(ZYNQ_SPI_IXR_ALL_MASK, &zslave->base->idr);
+       writel(ZYNQ_SPI_IXR_ALL_MASK, &regs->idr);
 
        /* Clear RX FIFO */
-       while (readl(&zslave->base->isr) &
+       while (readl(&regs->isr) &
                        ZYNQ_SPI_IXR_RXNEMPTY_MASK)
-               readl(&zslave->base->rxdr);
+               readl(&regs->rxdr);
 
        /* Clear Interrupts */
-       writel(ZYNQ_SPI_IXR_ALL_MASK, &zslave->base->isr);
+       writel(ZYNQ_SPI_IXR_ALL_MASK, &regs->isr);
 
        /* Manual slave select and Auto start */
        confr = ZYNQ_SPI_CR_MCS_MASK | ZYNQ_SPI_CR_CS_MASK |
                ZYNQ_SPI_CR_MSTREN_MASK;
        confr &= ~ZYNQ_SPI_CR_MSA_MASK;
-       writel(confr, &zslave->base->cr);
+       writel(confr, &regs->cr);
 
        /* Enable SPI */
-       writel(ZYNQ_SPI_ENR_SPI_EN_MASK, &zslave->base->enr);
+       writel(ZYNQ_SPI_ENR_SPI_EN_MASK, &regs->enr);
 }
 
-int spi_cs_is_valid(unsigned int bus, unsigned int cs)
+static int zynq_spi_probe(struct udevice *bus)
 {
-       /* 2 bus with 3 chipselect */
-       return bus < 2 && cs < 3;
+       struct zynq_spi_platdata *plat = dev_get_platdata(bus);
+       struct zynq_spi_priv *priv = dev_get_priv(bus);
+
+       priv->regs = plat->regs;
+       priv->fifo_depth = ZYNQ_SPI_FIFO_DEPTH;
+
+       /* init the zynq spi hw */
+       zynq_spi_init_hw(priv);
+
+       return 0;
 }
 
-void spi_cs_activate(struct spi_slave *slave)
+static void spi_cs_activate(struct udevice *dev)
 {
-       struct zynq_spi_slave *zslave = to_zynq_spi_slave(slave);
+       struct udevice *bus = dev->parent;
+       struct zynq_spi_platdata *plat = bus->platdata;
+       struct zynq_spi_priv *priv = dev_get_priv(bus);
+       struct zynq_spi_regs *regs = priv->regs;
        u32 cr;
 
-       debug("spi_cs_activate: 0x%08x\n", (u32)slave);
+       /* If it's too soon to do another transaction, wait */
+       if (plat->deactivate_delay_us && priv->last_transaction_us) {
+               ulong delay_us;         /* The delay completed so far */
+               delay_us = timer_get_us() - priv->last_transaction_us;
+               if (delay_us < plat->deactivate_delay_us)
+                       udelay(plat->deactivate_delay_us - delay_us);
+       }
 
-       clrbits_le32(&zslave->base->cr, ZYNQ_SPI_CR_CS_MASK);
-       cr = readl(&zslave->base->cr);
+       clrbits_le32(&regs->cr, ZYNQ_SPI_CR_CS_MASK);
+       cr = readl(&regs->cr);
        /*
         * CS cal logic: CS[13:10]
         * xxx0 - cs0
         * xx01 - cs1
         * x011 - cs2
         */
-       cr |= (~(0x1 << slave->cs) << 10) & ZYNQ_SPI_CR_CS_MASK;
-       writel(cr, &zslave->base->cr);
-}
-
-void spi_cs_deactivate(struct spi_slave *slave)
-{
-       struct zynq_spi_slave *zslave = to_zynq_spi_slave(slave);
-
-       debug("spi_cs_deactivate: 0x%08x\n", (u32)slave);
-
-       setbits_le32(&zslave->base->cr, ZYNQ_SPI_CR_CS_MASK);
-}
+       cr |= (~(1 << priv->cs) << ZYNQ_SPI_CR_SS_SHIFT) & ZYNQ_SPI_CR_CS_MASK;
+       writel(cr, &regs->cr);
 
-void spi_init()
-{
-       /* nothing to do */
+       if (plat->activate_delay_us)
+               udelay(plat->activate_delay_us);
 }
 
-struct spi_slave *spi_setup_slave(unsigned int bus, unsigned int cs,
-               unsigned int max_hz, unsigned int mode)
+static void spi_cs_deactivate(struct udevice *dev)
 {
-       struct zynq_spi_slave *zslave;
+       struct udevice *bus = dev->parent;
+       struct zynq_spi_platdata *plat = bus->platdata;
+       struct zynq_spi_priv *priv = dev_get_priv(bus);
+       struct zynq_spi_regs *regs = priv->regs;
 
-       if (!spi_cs_is_valid(bus, cs))
-               return NULL;
+       setbits_le32(&regs->cr, ZYNQ_SPI_CR_CS_MASK);
 
-       zslave = spi_alloc_slave(struct zynq_spi_slave, bus, cs);
-       if (!zslave) {
-               printf("SPI_error: Fail to allocate zynq_spi_slave\n");
-               return NULL;
-       }
-
-       zslave->base = get_zynq_spi_base(bus);
-       zslave->mode = mode;
-       zslave->fifo_depth = ZYNQ_SPI_FIFO_DEPTH;
-       zslave->input_hz = 166666700;
-       zslave->speed_hz = zslave->input_hz / 2;
-       zslave->req_hz = max_hz;
-
-       /* init the zynq spi hw */
-       zynq_spi_init_hw(zslave);
-
-       return &zslave->slave;
+       /* Remember time of this transaction so we can honour the bus delay */
+       if (plat->deactivate_delay_us)
+               priv->last_transaction_us = timer_get_us();
 }
 
-void spi_free_slave(struct spi_slave *slave)
+static int zynq_spi_claim_bus(struct udevice *dev)
 {
-       struct zynq_spi_slave *zslave = to_zynq_spi_slave(slave);
+       struct udevice *bus = dev->parent;
+       struct zynq_spi_priv *priv = dev_get_priv(bus);
+       struct zynq_spi_regs *regs = priv->regs;
 
-       debug("spi_free_slave: 0x%08x\n", (u32)slave);
-       free(zslave);
-}
-
-int spi_claim_bus(struct spi_slave *slave)
-{
-       struct zynq_spi_slave *zslave = to_zynq_spi_slave(slave);
-       u32 confr = 0;
-       u8 baud_rate_val = 0;
-
-       writel(~ZYNQ_SPI_ENR_SPI_EN_MASK, &zslave->base->enr);
-
-       /* Set the SPI Clock phase and polarities */
-       confr = readl(&zslave->base->cr);
-       confr &= ~(ZYNQ_SPI_CR_CPHA_MASK | ZYNQ_SPI_CR_CPOL_MASK);
-       if (zslave->mode & SPI_CPHA)
-               confr |= ZYNQ_SPI_CR_CPHA_MASK;
-       if (zslave->mode & SPI_CPOL)
-               confr |= ZYNQ_SPI_CR_CPOL_MASK;
-
-       /* Set the clock frequency */
-       if (zslave->req_hz == 0) {
-               /* Set baudrate x8, if the req_hz is 0 */
-               baud_rate_val = 0x2;
-       } else if (zslave->speed_hz != zslave->req_hz) {
-               while ((baud_rate_val < 8) &&
-                               ((zslave->input_hz /
-                               (2 << baud_rate_val)) > zslave->req_hz))
-                       baud_rate_val++;
-               zslave->speed_hz = zslave->req_hz / (2 << baud_rate_val);
-       }
-       confr &= ~ZYNQ_SPI_CR_BRD_MASK;
-       confr |= (baud_rate_val << 3);
-       writel(confr, &zslave->base->cr);
-
-       writel(ZYNQ_SPI_ENR_SPI_EN_MASK, &zslave->base->enr);
+       writel(ZYNQ_SPI_ENR_SPI_EN_MASK, &regs->enr);
 
        return 0;
 }
 
-void spi_release_bus(struct spi_slave *slave)
+static int zynq_spi_release_bus(struct udevice *dev)
 {
-       struct zynq_spi_slave *zslave = to_zynq_spi_slave(slave);
+       struct udevice *bus = dev->parent;
+       struct zynq_spi_priv *priv = dev_get_priv(bus);
+       struct zynq_spi_regs *regs = priv->regs;
+       u32 confr;
 
-       debug("spi_release_bus: 0x%08x\n", (u32)slave);
-       writel(~ZYNQ_SPI_ENR_SPI_EN_MASK, &zslave->base->enr);
+       confr = ZYNQ_SPI_ENR_SPI_EN_MASK;
+       writel(~confr, &regs->enr);
+
+       return 0;
 }
 
-int spi_xfer(struct spi_slave *slave, unsigned int bitlen, const void *dout,
-               void *din, unsigned long flags)
+static int zynq_spi_xfer(struct udevice *dev, unsigned int bitlen,
+                           const void *dout, void *din, unsigned long flags)
 {
-       struct zynq_spi_slave *zslave = to_zynq_spi_slave(slave);
+       struct udevice *bus = dev->parent;
+       struct zynq_spi_priv *priv = dev_get_priv(bus);
+       struct zynq_spi_regs *regs = priv->regs;
+       struct dm_spi_slave_platdata *slave_plat = dev_get_parent_platdata(dev);
        u32 len = bitlen / 8;
        u32 tx_len = len, rx_len = len, tx_tvl;
        const u8 *tx_buf = dout;
@@ -225,53 +222,137 @@ int spi_xfer(struct spi_slave *slave, unsigned int bitlen, const void *dout,
        u32 ts, status;
 
        debug("spi_xfer: bus:%i cs:%i bitlen:%i len:%i flags:%lx\n",
-             slave->bus, slave->cs, bitlen, len, flags);
+             bus->seq, slave_plat->cs, bitlen, len, flags);
 
        if (bitlen % 8) {
                debug("spi_xfer: Non byte aligned SPI transfer\n");
                return -1;
        }
 
+       priv->cs = slave_plat->cs;
        if (flags & SPI_XFER_BEGIN)
-               spi_cs_activate(slave);
+               spi_cs_activate(dev);
 
        while (rx_len > 0) {
                /* Write the data into TX FIFO - tx threshold is fifo_depth */
                tx_tvl = 0;
-               while ((tx_tvl < zslave->fifo_depth) && tx_len) {
+               while ((tx_tvl < priv->fifo_depth) && tx_len) {
                        if (tx_buf)
                                buf = *tx_buf++;
                        else
                                buf = 0;
-                       writel(buf, &zslave->base->txdr);
+                       writel(buf, &regs->txdr);
                        tx_len--;
                        tx_tvl++;
                }
 
                /* Check TX FIFO completion */
                ts = get_timer(0);
-               status = readl(&zslave->base->isr);
+               status = readl(&regs->isr);
                while (!(status & ZYNQ_SPI_IXR_TXOW_MASK)) {
                        if (get_timer(ts) > CONFIG_SYS_ZYNQ_SPI_WAIT) {
                                printf("spi_xfer: Timeout! TX FIFO not full\n");
                                return -1;
                        }
-                       status = readl(&zslave->base->isr);
+                       status = readl(&regs->isr);
                }
 
                /* Read the data from RX FIFO */
-               status = readl(&zslave->base->isr);
-               while (status & ZYNQ_SPI_IXR_RXNEMPTY_MASK) {
-                       buf = readl(&zslave->base->rxdr);
+               status = readl(&regs->isr);
+               while ((status & ZYNQ_SPI_IXR_RXNEMPTY_MASK) && rx_len) {
+                       buf = readl(&regs->rxdr);
                        if (rx_buf)
                                *rx_buf++ = buf;
-                       status = readl(&zslave->base->isr);
+                       status = readl(&regs->isr);
                        rx_len--;
                }
        }
 
        if (flags & SPI_XFER_END)
-               spi_cs_deactivate(slave);
+               spi_cs_deactivate(dev);
 
        return 0;
 }
+
+static int zynq_spi_set_speed(struct udevice *bus, uint speed)
+{
+       struct zynq_spi_platdata *plat = bus->platdata;
+       struct zynq_spi_priv *priv = dev_get_priv(bus);
+       struct zynq_spi_regs *regs = priv->regs;
+       uint32_t confr;
+       u8 baud_rate_val = 0;
+
+       if (speed > plat->frequency)
+               speed = plat->frequency;
+
+       /* Set the clock frequency */
+       confr = readl(&regs->cr);
+       if (speed == 0) {
+               /* Set baudrate x8, if the freq is 0 */
+               baud_rate_val = 0x2;
+       } else if (plat->speed_hz != speed) {
+               while ((baud_rate_val < ZYNQ_SPI_CR_BAUD_MAX) &&
+                               ((plat->frequency /
+                               (2 << baud_rate_val)) > speed))
+                       baud_rate_val++;
+               plat->speed_hz = speed / (2 << baud_rate_val);
+       }
+       confr &= ~ZYNQ_SPI_CR_BAUD_MASK;
+       confr |= (baud_rate_val << ZYNQ_SPI_CR_BAUD_SHIFT);
+
+       writel(confr, &regs->cr);
+       priv->freq = speed;
+
+       debug("zynq_spi_set_speed: regs=%p, speed=%d\n",
+             priv->regs, priv->freq);
+
+       return 0;
+}
+
+static int zynq_spi_set_mode(struct udevice *bus, uint mode)
+{
+       struct zynq_spi_priv *priv = dev_get_priv(bus);
+       struct zynq_spi_regs *regs = priv->regs;
+       uint32_t confr;
+
+       /* Set the SPI Clock phase and polarities */
+       confr = readl(&regs->cr);
+       confr &= ~(ZYNQ_SPI_CR_CPHA_MASK | ZYNQ_SPI_CR_CPOL_MASK);
+
+       if (mode & SPI_CPHA)
+               confr |= ZYNQ_SPI_CR_CPHA_MASK;
+       if (mode & SPI_CPOL)
+               confr |= ZYNQ_SPI_CR_CPOL_MASK;
+
+       writel(confr, &regs->cr);
+       priv->mode = mode;
+
+       debug("zynq_spi_set_mode: regs=%p, mode=%d\n", priv->regs, priv->mode);
+
+       return 0;
+}
+
+static const struct dm_spi_ops zynq_spi_ops = {
+       .claim_bus      = zynq_spi_claim_bus,
+       .release_bus    = zynq_spi_release_bus,
+       .xfer           = zynq_spi_xfer,
+       .set_speed      = zynq_spi_set_speed,
+       .set_mode       = zynq_spi_set_mode,
+};
+
+static const struct udevice_id zynq_spi_ids[] = {
+       { .compatible = "xlnx,zynq-spi-r1p6" },
+       { .compatible = "cdns,spi-r1p6" },
+       { }
+};
+
+U_BOOT_DRIVER(zynq_spi) = {
+       .name   = "zynq_spi",
+       .id     = UCLASS_SPI,
+       .of_match = zynq_spi_ids,
+       .ops    = &zynq_spi_ops,
+       .ofdata_to_platdata = zynq_spi_ofdata_to_platdata,
+       .platdata_auto_alloc_size = sizeof(struct zynq_spi_platdata),
+       .priv_auto_alloc_size = sizeof(struct zynq_spi_priv),
+       .probe  = zynq_spi_probe,
+};