dm: spi: zynq_spi: Convert to driver model
authorJagan Teki <jteki@openedev.com>
Fri, 26 Jun 2015 19:21:31 +0000 (00:51 +0530)
committerJagan Teki <jteki@openedev.com>
Wed, 1 Jul 2015 15:45:03 +0000 (21:15 +0530)
This converts the zynq spi driver to use the driver model.

Minimal functional changes like using meaningful name on
structure members wrt mainlined dm spi drivers.
- input_hz -> frequency
- req_hz -> freq
- base -> regs

Signed-off-by: Jagan Teki <jteki@openedev.com>
Acked-by: Simon Glass <sjg@chromium.org>
Cc: Michal Simek <michal.simek@xilinx.com>
Cc: Siva Durga Prasad Paladugu <sivadur@xilinx.com>
Tested-by: Jagan Teki <jteki@openedev.com>
drivers/spi/zynq_spi.c

index e9129da79d99825b9d88c7bc893d3de0f9700feb..50fb1aa479060e643f69c529371de507473d9e2e 100644 (file)
@@ -1,5 +1,6 @@
 /*
  * (C) Copyright 2013 Inc.
+ * (C) Copyright 2015 Jagan Teki <jteki@openedev.com>
  *
  * Xilinx Zynq PS SPI controller driver (master mode only)
  *
@@ -8,6 +9,8 @@
 
 #include <config.h>
 #include <common.h>
+#include <dm.h>
+#include <errno.h>
 #include <malloc.h>
 #include <spi.h>
 #include <asm/io.h>
@@ -44,180 +47,141 @@ struct zynq_spi_regs {
        u32 rxdr;       /* 0x20 */
 };
 
-/* zynq spi slave */
-struct zynq_spi_slave {
-       struct spi_slave slave;
-       struct zynq_spi_regs *base;
-       u8 mode;
-       u8 fifo_depth;
+
+/* zynq spi platform data */
+struct zynq_spi_platdata {
+       struct zynq_spi_regs *regs;
+       u32 frequency;          /* input frequency */
        u32 speed_hz;
-       u32 input_hz;
-       u32 req_hz;
 };
 
-static inline struct zynq_spi_slave *to_zynq_spi_slave(struct spi_slave *slave)
-{
-       return container_of(slave, struct zynq_spi_slave, slave);
-}
+/* zynq spi priv */
+struct zynq_spi_priv {
+       struct zynq_spi_regs *regs;
+       u8 mode;
+       u8 fifo_depth;
+       u32 freq;               /* required frequency */
+};
 
-static inline struct zynq_spi_regs *get_zynq_spi_base(int dev)
+static inline struct zynq_spi_regs *get_zynq_spi_regs(struct udevice *bus)
 {
-       if (dev)
+       if (bus->seq)
                return (struct zynq_spi_regs *)ZYNQ_SPI_BASEADDR1;
        else
                return (struct zynq_spi_regs *)ZYNQ_SPI_BASEADDR0;
 }
 
-static void zynq_spi_init_hw(struct zynq_spi_slave *zslave)
+static int zynq_spi_ofdata_to_platdata(struct udevice *bus)
 {
+       struct zynq_spi_platdata *plat = bus->platdata;
+
+       plat->regs = get_zynq_spi_regs(bus);
+       plat->frequency = 166666700;
+       plat->speed_hz = plat->frequency / 2;
+
+       return 0;
+}
+
+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);
+       writel(~ZYNQ_SPI_ENR_SPI_EN_MASK, &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, uint cs)
 {
-       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 cr;
 
-       debug("spi_cs_activate: 0x%08x\n", (u32)slave);
-
-       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);
+       cr |= (~(0x1 << cs) << 10) & ZYNQ_SPI_CR_CS_MASK;
+       writel(cr, &regs->cr);
 }
 
-void spi_cs_deactivate(struct spi_slave *slave)
+static void spi_cs_deactivate(struct udevice *dev)
 {
-       struct zynq_spi_slave *zslave = to_zynq_spi_slave(slave);
-
-       debug("spi_cs_deactivate: 0x%08x\n", (u32)slave);
+       struct udevice *bus = dev->parent;
+       struct zynq_spi_priv *priv = dev_get_priv(bus);
+       struct zynq_spi_regs *regs = priv->regs;
 
-       setbits_le32(&zslave->base->cr, ZYNQ_SPI_CR_CS_MASK);
+       setbits_le32(&regs->cr, ZYNQ_SPI_CR_CS_MASK);
 }
 
-void spi_init()
+static int zynq_spi_claim_bus(struct udevice *dev)
 {
-       /* nothing to do */
-}
+       struct udevice *bus = dev->parent;
+       struct zynq_spi_priv *priv = dev_get_priv(bus);
+       struct zynq_spi_regs *regs = priv->regs;
 
-struct spi_slave *spi_setup_slave(unsigned int bus, unsigned int cs,
-               unsigned int max_hz, unsigned int mode)
-{
-       struct zynq_spi_slave *zslave;
+       writel(ZYNQ_SPI_ENR_SPI_EN_MASK, &regs->enr);
 
-       if (!spi_cs_is_valid(bus, cs))
-               return NULL;
-
-       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;
-}
-
-void spi_free_slave(struct spi_slave *slave)
-{
-       struct zynq_spi_slave *zslave = to_zynq_spi_slave(slave);
-
-       debug("spi_free_slave: 0x%08x\n", (u32)slave);
-       free(zslave);
+       return 0;
 }
 
-int spi_claim_bus(struct spi_slave *slave)
+static int zynq_spi_release_bus(struct udevice *dev)
 {
-       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);
+       struct udevice *bus = dev->parent;
+       struct zynq_spi_priv *priv = dev_get_priv(bus);
+       struct zynq_spi_regs *regs = priv->regs;
 
-       /* 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_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);
-
-       debug("spi_release_bus: 0x%08x\n", (u32)slave);
-       writel(~ZYNQ_SPI_ENR_SPI_EN_MASK, &zslave->base->enr);
-}
-
-int spi_xfer(struct spi_slave *slave, 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,7 +189,7 @@ 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");
@@ -233,45 +197,126 @@ int spi_xfer(struct spi_slave *slave, unsigned int bitlen, const void *dout,
        }
 
        if (flags & SPI_XFER_BEGIN)
-               spi_cs_activate(slave);
+               spi_cs_activate(dev, slave_plat->cs);
 
        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);
+               status = readl(&regs->isr);
                while (status & ZYNQ_SPI_IXR_RXNEMPTY_MASK) {
-                       buf = readl(&zslave->base->rxdr);
+                       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 < 8) &&
+                               ((plat->frequency /
+                               (2 << baud_rate_val)) > speed))
+                       baud_rate_val++;
+               plat->speed_hz = speed / (2 << baud_rate_val);
+       }
+       confr &= ~ZYNQ_SPI_CR_BRD_MASK;
+       confr |= (baud_rate_val << 3);
+
+       writel(confr, &regs->cr);
+       priv->freq = speed;
+
+       debug("zynq_spi_set_speed: regs=%p, mode=%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 (priv->mode & SPI_CPHA)
+               confr |= ZYNQ_SPI_CR_CPHA_MASK;
+       if (priv->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" },
+       { }
+};
+
+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,
+};