]> git.sur5r.net Git - u-boot/commitdiff
Blackfin: spi: make cs deassert function deterministic
authorTodor I Mollov <tmollov@ucsd.edu>
Sat, 4 Apr 2009 10:53:06 +0000 (06:53 -0400)
committerMike Frysinger <vapier@gentoo.org>
Mon, 6 Apr 2009 07:49:31 +0000 (03:49 -0400)
Blackfin SPI driver was not driving the SPI chip-select high before
putting the chip-select signals into tri-state mode.  This is probably
something that slipped by unnoticed in most designs.  If the signals are
put directly into a tri-state mode, then the board is relying on the
pull-up resistors to pull up the chip-select before the next transaction.
Most of the time this is fine, except when you have two transactions that
follow each other very closely, such as the flash erase and read status
register commands.  In this case I was seeing a 500ns separation between
the transactions.  In my setup, with a 10kOhm pull-up, it would meet
timing spec about half the time and resulted in intermittent errors.  (A
stronger pull up would fix this, but our design is targeted for low power
consumption and a 3.3kOhm @ 3.3v is 3.3mW of needless power consumption.)
I modified the spi_cs_deactivate() function in bfin_spi.c to drive the
chip-selects high before putting them into tri-state.  For me, this
resulted in a rise time of 5ns instead of the previous rise time of about
1us, and fully satisfied the timing spec of the chip.

Signed-off-by: Todor I Mollov <tmollov@ucsd.edu>
Signed-off-by: Mike Frysinger <vapier@gentoo.org>
drivers/spi/bfin_spi.c

index bc3394ad59f76c8cda86baddc965606882ce989a..bc255ccc82d9f3d3335e64593993d67ef1a05675 100644 (file)
@@ -52,6 +52,7 @@ void spi_cs_activate(struct spi_slave *slave)
                (read_SPI_FLG(bss) &
                ~((!bss->flg << 8) << slave->cs)) |
                (1 << slave->cs));
+       SSYNC();
        debug("%s: SPI_FLG:%x\n", __func__, read_SPI_FLG(bss));
 }
 
@@ -59,7 +60,20 @@ __attribute__((weak))
 void spi_cs_deactivate(struct spi_slave *slave)
 {
        struct bfin_spi_slave *bss = to_bfin_spi_slave(slave);
-       write_SPI_FLG(bss, read_SPI_FLG(bss) & ~(1 << slave->cs));
+       u16 flg;
+
+       /* make sure we force the cs to deassert rather than let the
+        * pin float back up.  otherwise, exact timings may not be
+        * met some of the time leading to random behavior (ugh).
+        */
+       flg = read_SPI_FLG(bss) | ((!bss->flg << 8) << slave->cs);
+       write_SPI_FLG(bss, flg);
+       SSYNC();
+       debug("%s: SPI_FLG:%x\n", __func__, read_SPI_FLG(bss));
+
+       flg &= ~(1 << slave->cs);
+       write_SPI_FLG(bss, flg);
+       SSYNC();
        debug("%s: SPI_FLG:%x\n", __func__, read_SPI_FLG(bss));
 }