diff options
author | David Brownell <dbrownell@users.sourceforge.net> | 2009-09-22 19:46:18 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2009-09-23 10:39:44 -0400 |
commit | 568d0697f42771425ae9f1e9a3db769fef7e10b6 (patch) | |
tree | 8f4d1178b88481e3d3daba3e049c700a3cef72e4 | |
parent | 7869c0b9ed44404bbc675ef76f8ccb3be5496f39 (diff) |
spi: handle TX-only/RX-only
Support two new half-duplex SPI implementation restrictions, for links
that talk to TX-only or RX-only devices. (Existing half-duplex flavors
support both transfer directions, just not at the same time.)
Move spi_async() into the spi.c core, and stop inlining it. Then make
that function perform error checks and reject messages that demand more
than the underlying controller can support.
Based on a patch from Marek Szyprowski which did this only for the
bitbanged GPIO driver.
Cc: Marek Szyprowski <m.szyprowski@samsung.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>
-rw-r--r-- | drivers/spi/spi.c | 59 | ||||
-rw-r--r-- | include/linux/spi/spi.h | 39 |
2 files changed, 62 insertions, 36 deletions
diff --git a/drivers/spi/spi.c b/drivers/spi/spi.c index 49e84860c8da..b76f2468a84a 100644 --- a/drivers/spi/spi.c +++ b/drivers/spi/spi.c | |||
@@ -663,6 +663,65 @@ int spi_setup(struct spi_device *spi) | |||
663 | } | 663 | } |
664 | EXPORT_SYMBOL_GPL(spi_setup); | 664 | EXPORT_SYMBOL_GPL(spi_setup); |
665 | 665 | ||
666 | /** | ||
667 | * spi_async - asynchronous SPI transfer | ||
668 | * @spi: device with which data will be exchanged | ||
669 | * @message: describes the data transfers, including completion callback | ||
670 | * Context: any (irqs may be blocked, etc) | ||
671 | * | ||
672 | * This call may be used in_irq and other contexts which can't sleep, | ||
673 | * as well as from task contexts which can sleep. | ||
674 | * | ||
675 | * The completion callback is invoked in a context which can't sleep. | ||
676 | * Before that invocation, the value of message->status is undefined. | ||
677 | * When the callback is issued, message->status holds either zero (to | ||
678 | * indicate complete success) or a negative error code. After that | ||
679 | * callback returns, the driver which issued the transfer request may | ||
680 | * deallocate the associated memory; it's no longer in use by any SPI | ||
681 | * core or controller driver code. | ||
682 | * | ||
683 | * Note that although all messages to a spi_device are handled in | ||
684 | * FIFO order, messages may go to different devices in other orders. | ||
685 | * Some device might be higher priority, or have various "hard" access | ||
686 | * time requirements, for example. | ||
687 | * | ||
688 | * On detection of any fault during the transfer, processing of | ||
689 | * the entire message is aborted, and the device is deselected. | ||
690 | * Until returning from the associated message completion callback, | ||
691 | * no other spi_message queued to that device will be processed. | ||
692 | * (This rule applies equally to all the synchronous transfer calls, | ||
693 | * which are wrappers around this core asynchronous primitive.) | ||
694 | */ | ||
695 | int spi_async(struct spi_device *spi, struct spi_message *message) | ||
696 | { | ||
697 | struct spi_master *master = spi->master; | ||
698 | |||
699 | /* Half-duplex links include original MicroWire, and ones with | ||
700 | * only one data pin like SPI_3WIRE (switches direction) or where | ||
701 | * either MOSI or MISO is missing. They can also be caused by | ||
702 | * software limitations. | ||
703 | */ | ||
704 | if ((master->flags & SPI_MASTER_HALF_DUPLEX) | ||
705 | || (spi->mode & SPI_3WIRE)) { | ||
706 | struct spi_transfer *xfer; | ||
707 | unsigned flags = master->flags; | ||
708 | |||
709 | list_for_each_entry(xfer, &message->transfers, transfer_list) { | ||
710 | if (xfer->rx_buf && xfer->tx_buf) | ||
711 | return -EINVAL; | ||
712 | if ((flags & SPI_MASTER_NO_TX) && xfer->tx_buf) | ||
713 | return -EINVAL; | ||
714 | if ((flags & SPI_MASTER_NO_RX) && xfer->rx_buf) | ||
715 | return -EINVAL; | ||
716 | } | ||
717 | } | ||
718 | |||
719 | message->spi = spi; | ||
720 | message->status = -EINPROGRESS; | ||
721 | return master->transfer(spi, message); | ||
722 | } | ||
723 | EXPORT_SYMBOL_GPL(spi_async); | ||
724 | |||
666 | 725 | ||
667 | /*-------------------------------------------------------------------------*/ | 726 | /*-------------------------------------------------------------------------*/ |
668 | 727 | ||
diff --git a/include/linux/spi/spi.h b/include/linux/spi/spi.h index e2051f39f6a8..97b60b37f445 100644 --- a/include/linux/spi/spi.h +++ b/include/linux/spi/spi.h | |||
@@ -258,6 +258,8 @@ struct spi_master { | |||
258 | /* other constraints relevant to this driver */ | 258 | /* other constraints relevant to this driver */ |
259 | u16 flags; | 259 | u16 flags; |
260 | #define SPI_MASTER_HALF_DUPLEX BIT(0) /* can't do full duplex */ | 260 | #define SPI_MASTER_HALF_DUPLEX BIT(0) /* can't do full duplex */ |
261 | #define SPI_MASTER_NO_RX BIT(1) /* can't do buffer read */ | ||
262 | #define SPI_MASTER_NO_TX BIT(2) /* can't do buffer write */ | ||
261 | 263 | ||
262 | /* Setup mode and clock, etc (spi driver may call many times). | 264 | /* Setup mode and clock, etc (spi driver may call many times). |
263 | * | 265 | * |
@@ -538,42 +540,7 @@ static inline void spi_message_free(struct spi_message *m) | |||
538 | } | 540 | } |
539 | 541 | ||
540 | extern int spi_setup(struct spi_device *spi); | 542 | extern int spi_setup(struct spi_device *spi); |
541 | 543 | extern int spi_async(struct spi_device *spi, struct spi_message *message); | |
542 | /** | ||
543 | * spi_async - asynchronous SPI transfer | ||
544 | * @spi: device with which data will be exchanged | ||
545 | * @message: describes the data transfers, including completion callback | ||
546 | * Context: any (irqs may be blocked, etc) | ||
547 | * | ||
548 | * This call may be used in_irq and other contexts which can't sleep, | ||
549 | * as well as from task contexts which can sleep. | ||
550 | * | ||
551 | * The completion callback is invoked in a context which can't sleep. | ||
552 | * Before that invocation, the value of message->status is undefined. | ||
553 | * When the callback is issued, message->status holds either zero (to | ||
554 | * indicate complete success) or a negative error code. After that | ||
555 | * callback returns, the driver which issued the transfer request may | ||
556 | * deallocate the associated memory; it's no longer in use by any SPI | ||
557 | * core or controller driver code. | ||
558 | * | ||
559 | * Note that although all messages to a spi_device are handled in | ||
560 | * FIFO order, messages may go to different devices in other orders. | ||
561 | * Some device might be higher priority, or have various "hard" access | ||
562 | * time requirements, for example. | ||
563 | * | ||
564 | * On detection of any fault during the transfer, processing of | ||
565 | * the entire message is aborted, and the device is deselected. | ||
566 | * Until returning from the associated message completion callback, | ||
567 | * no other spi_message queued to that device will be processed. | ||
568 | * (This rule applies equally to all the synchronous transfer calls, | ||
569 | * which are wrappers around this core asynchronous primitive.) | ||
570 | */ | ||
571 | static inline int | ||
572 | spi_async(struct spi_device *spi, struct spi_message *message) | ||
573 | { | ||
574 | message->spi = spi; | ||
575 | return spi->master->transfer(spi, message); | ||
576 | } | ||
577 | 544 | ||
578 | /*---------------------------------------------------------------------------*/ | 545 | /*---------------------------------------------------------------------------*/ |
579 | 546 | ||