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: Steven A. Falco <sfalco@harris.com> Signed-off-by: David Brownell <dbrownell@users.sourceforge.net> Signed-off-by: Andrew Morton <akpm@linux-foundation.org> Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
This commit is contained in:
parent
537a1bf059
commit
529ba0d966
|
@ -258,6 +258,11 @@ static void bitbang_work(struct work_struct *work)
|
|||
struct spi_bitbang *bitbang =
|
||||
container_of(work, struct spi_bitbang, work);
|
||||
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);
|
||||
bitbang->busy = 1;
|
||||
|
@ -269,8 +274,6 @@ static void bitbang_work(struct work_struct *work)
|
|||
unsigned tmp;
|
||||
unsigned cs_change;
|
||||
int status;
|
||||
int (*setup_transfer)(struct spi_device *,
|
||||
struct spi_transfer *);
|
||||
|
||||
m = container_of(bitbang->queue.next, struct spi_message,
|
||||
queue);
|
||||
|
@ -287,19 +290,19 @@ static void bitbang_work(struct work_struct *work)
|
|||
tmp = 0;
|
||||
cs_change = 1;
|
||||
status = 0;
|
||||
setup_transfer = NULL;
|
||||
|
||||
list_for_each_entry (t, &m->transfers, transfer_list) {
|
||||
|
||||
/* override or restore speed and wordsize */
|
||||
if (t->speed_hz || t->bits_per_word) {
|
||||
setup_transfer = bitbang->setup_transfer;
|
||||
/* override speed or wordsize? */
|
||||
if (t->speed_hz || t->bits_per_word)
|
||||
do_setup = 1;
|
||||
|
||||
/* init (-1) or override (1) transfer params */
|
||||
if (do_setup != 0) {
|
||||
if (!setup_transfer) {
|
||||
status = -ENOPROTOOPT;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (setup_transfer) {
|
||||
status = setup_transfer(spi, t);
|
||||
if (status < 0)
|
||||
break;
|
||||
|
@ -363,9 +366,10 @@ static void bitbang_work(struct work_struct *work)
|
|||
m->status = status;
|
||||
m->complete(m->context);
|
||||
|
||||
/* restore speed and wordsize */
|
||||
if (setup_transfer)
|
||||
/* restore speed and wordsize if it was overridden */
|
||||
if (do_setup == 1)
|
||||
setup_transfer(spi, NULL);
|
||||
do_setup = 0;
|
||||
|
||||
/* normally deactivate chipselect ... unless no error and
|
||||
* cs_change has hinted that the next message will probably
|
||||
|
|
Loading…
Reference in New Issue