Commit 529ba0d9 authored by David Brownell's avatar David Brownell Committed by Linus Torvalds

spi: bitbang bugfix in message setup

Bugfix to spi_bitbang infrastructure: make sure to always set transfer
parameters on the first pass through the message's per-transfer loop.
This can matter with drivers that replace the per-word or per-buffer
transfer primitives, on busses with multiple SPI devices.

Previously, this could have started messages using the settings left after
previous messages.  The problem was observed when a high speed chip
(m25p80 type flash) was running very slowly because a low speed device
(avr8 microcontroller) had previously used the bus.  Similar faults could
have driven the low speed device too fast, or used an unexpected word
size.
Acked-by: default avatarSteven A. Falco <sfalco@harris.com>
Signed-off-by: default avatarDavid Brownell <dbrownell@users.sourceforge.net>
Signed-off-by: default avatarAndrew Morton <akpm@linux-foundation.org>
Signed-off-by: default avatarLinus Torvalds <torvalds@linux-foundation.org>
parent 537a1bf0
...@@ -258,6 +258,11 @@ static void bitbang_work(struct work_struct *work) ...@@ -258,6 +258,11 @@ static void bitbang_work(struct work_struct *work)
struct spi_bitbang *bitbang = struct spi_bitbang *bitbang =
container_of(work, struct spi_bitbang, work); container_of(work, struct spi_bitbang, work);
unsigned long flags; unsigned long flags;
int do_setup = -1;
int (*setup_transfer)(struct spi_device *,
struct spi_transfer *);
setup_transfer = bitbang->setup_transfer;
spin_lock_irqsave(&bitbang->lock, flags); spin_lock_irqsave(&bitbang->lock, flags);
bitbang->busy = 1; bitbang->busy = 1;
...@@ -269,8 +274,6 @@ static void bitbang_work(struct work_struct *work) ...@@ -269,8 +274,6 @@ static void bitbang_work(struct work_struct *work)
unsigned tmp; unsigned tmp;
unsigned cs_change; unsigned cs_change;
int status; int status;
int (*setup_transfer)(struct spi_device *,
struct spi_transfer *);
m = container_of(bitbang->queue.next, struct spi_message, m = container_of(bitbang->queue.next, struct spi_message,
queue); queue);
...@@ -287,19 +290,19 @@ static void bitbang_work(struct work_struct *work) ...@@ -287,19 +290,19 @@ static void bitbang_work(struct work_struct *work)
tmp = 0; tmp = 0;
cs_change = 1; cs_change = 1;
status = 0; status = 0;
setup_transfer = NULL;
list_for_each_entry (t, &m->transfers, transfer_list) { list_for_each_entry (t, &m->transfers, transfer_list) {
/* override or restore speed and wordsize */ /* override speed or wordsize? */
if (t->speed_hz || t->bits_per_word) { if (t->speed_hz || t->bits_per_word)
setup_transfer = bitbang->setup_transfer; do_setup = 1;
/* init (-1) or override (1) transfer params */
if (do_setup != 0) {
if (!setup_transfer) { if (!setup_transfer) {
status = -ENOPROTOOPT; status = -ENOPROTOOPT;
break; break;
} }
}
if (setup_transfer) {
status = setup_transfer(spi, t); status = setup_transfer(spi, t);
if (status < 0) if (status < 0)
break; break;
...@@ -363,9 +366,10 @@ static void bitbang_work(struct work_struct *work) ...@@ -363,9 +366,10 @@ static void bitbang_work(struct work_struct *work)
m->status = status; m->status = status;
m->complete(m->context); m->complete(m->context);
/* restore speed and wordsize */ /* restore speed and wordsize if it was overridden */
if (setup_transfer) if (do_setup == 1)
setup_transfer(spi, NULL); setup_transfer(spi, NULL);
do_setup = 0;
/* normally deactivate chipselect ... unless no error and /* normally deactivate chipselect ... unless no error and
* cs_change has hinted that the next message will probably * cs_change has hinted that the next message will probably
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment