summaryrefslogtreecommitdiff
path: root/drivers
diff options
context:
space:
mode:
authorTodor I Mollov <tmollov@ucsd.edu>2009-04-04 06:53:06 -0400
committerMike Frysinger <vapier@gentoo.org>2009-04-06 03:49:31 -0400
commitd04371a116d102e587ba7aa4c329b441cdbea3f4 (patch)
tree3b8d8ff0416b3ae12abb2d9c463db37fc3a2b99a /drivers
parent712ac6a1a6909a58d6549fb220cc921a7e9f9979 (diff)
Blackfin: spi: make cs deassert function deterministic
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>
Diffstat (limited to 'drivers')
-rw-r--r--drivers/spi/bfin_spi.c16
1 files changed, 15 insertions, 1 deletions
diff --git a/drivers/spi/bfin_spi.c b/drivers/spi/bfin_spi.c
index bc3394ad59..bc255ccc82 100644
--- a/drivers/spi/bfin_spi.c
+++ b/drivers/spi/bfin_spi.c
@@ -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));
}