]> git.kernelconcepts.de Git - karo-tx-uboot.git/blobdiff - drivers/spi/mxc_spi.c
arm: marvell: Move arch-kirkwood/spi.h to arch-mvebu/spi.h
[karo-tx-uboot.git] / drivers / spi / mxc_spi.c
index f3f029d634abd1f2045c20ba3e159bc1aecf7e4a..026f680d80d90e60591d04bb3b092058df371883 100644 (file)
@@ -25,11 +25,20 @@ static unsigned long spi_bases[] = {
        MXC_SPI_BASE_ADDRESSES
 };
 
+__weak int board_spi_cs_gpio(unsigned bus, unsigned cs)
+{
+       return -1;
+}
+
 #define OUT    MXC_GPIO_DIRECTION_OUT
 
 #define reg_read readl
 #define reg_write(a, v) writel(v, a)
 
+#if !defined(CONFIG_SYS_SPI_MXC_WAIT)
+#define CONFIG_SYS_SPI_MXC_WAIT                (CONFIG_SYS_HZ/100)     /* 10 ms */
+#endif
+
 struct mxc_spi_slave {
        struct spi_slave slave;
        unsigned long   base;
@@ -212,6 +221,8 @@ int spi_xchg_single(struct spi_slave *slave, unsigned int bitlen,
        int nbytes = DIV_ROUND_UP(bitlen, 8);
        u32 data, cnt, i;
        struct cspi_regs *regs = (struct cspi_regs *)mxcs->base;
+       u32 ts;
+       int status;
 
        debug("%s: bitlen %d dout 0x%x din 0x%x\n",
                __func__, bitlen, (u32)dout, (u32)din);
@@ -272,9 +283,16 @@ int spi_xchg_single(struct spi_slave *slave, unsigned int bitlen,
        reg_write(&regs->ctrl, mxcs->ctrl_reg |
                MXC_CSPICTRL_EN | MXC_CSPICTRL_XCH);
 
+       ts = get_timer(0);
+       status = reg_read(&regs->stat);
        /* Wait until the TC (Transfer completed) bit is set */
-       while ((reg_read(&regs->stat) & MXC_CSPICTRL_TC) == 0)
-               ;
+       while ((status & MXC_CSPICTRL_TC) == 0) {
+               if (get_timer(ts) > CONFIG_SYS_SPI_MXC_WAIT) {
+                       printf("spi_xchg_single: Timeout!\n");
+                       return -1;
+               }
+               status = reg_read(&regs->stat);
+       }
 
        /* Transfer completed, clear any pending request */
        reg_write(&regs->stat, MXC_CSPICTRL_TC | MXC_CSPICTRL_RXOVF);
@@ -358,31 +376,30 @@ void spi_init(void)
 {
 }
 
-static int decode_cs(struct mxc_spi_slave *mxcs, unsigned int cs)
+/*
+ * Some SPI devices require active chip-select over multiple
+ * transactions, we achieve this using a GPIO. Still, the SPI
+ * controller has to be configured to use one of its own chipselects.
+ * To use this feature you have to implement board_spi_cs_gpio() to assign
+ * a gpio value for each cs (-1 if cs doesn't need to use gpio).
+ * You must use some unused on this SPI controller cs between 0 and 3.
+ */
+static int setup_cs_gpio(struct mxc_spi_slave *mxcs,
+                        unsigned int bus, unsigned int cs)
 {
        int ret;
 
-       /*
-        * Some SPI devices require active chip-select over multiple
-        * transactions, we achieve this using a GPIO. Still, the SPI
-        * controller has to be configured to use one of its own chipselects.
-        * To use this feature you have to call spi_setup_slave() with
-        * cs = internal_cs | (gpio << 8), and you have to use some unused
-        * on this SPI controller cs between 0 and 3.
-        */
-       if (cs > 3) {
-               mxcs->gpio = cs >> 8;
-               cs &= 3;
-               ret = gpio_direction_output(mxcs->gpio, !(mxcs->ss_pol));
-               if (ret) {
-                       printf("mxc_spi: cannot setup gpio %d\n", mxcs->gpio);
-                       return -EINVAL;
-               }
-       } else {
-               mxcs->gpio = -1;
+       mxcs->gpio = board_spi_cs_gpio(bus, cs);
+       if (mxcs->gpio == -1)
+               return 0;
+
+       ret = gpio_direction_output(mxcs->gpio, !(mxcs->ss_pol));
+       if (ret) {
+               printf("mxc_spi: cannot setup gpio %d\n", mxcs->gpio);
+               return -EINVAL;
        }
 
-       return cs;
+       return 0;
 }
 
 struct spi_slave *spi_setup_slave(unsigned int bus, unsigned int cs,
@@ -402,14 +419,12 @@ struct spi_slave *spi_setup_slave(unsigned int bus, unsigned int cs,
 
        mxcs->ss_pol = (mode & SPI_CS_HIGH) ? 1 : 0;
 
-       ret = decode_cs(mxcs, cs);
+       ret = setup_cs_gpio(mxcs, bus, cs);
        if (ret < 0) {
                free(mxcs);
                return NULL;
        }
 
-       cs = ret;
-
        mxcs->base = spi_bases[bus];
 
        ret = spi_cfg_mxc(mxcs, cs, max_hz, mode);