mirror of
https://github.com/adulau/aha.git
synced 2024-12-27 19:26:25 +00:00
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>
This commit is contained in:
parent
7869c0b9ed
commit
568d0697f4
2 changed files with 62 additions and 36 deletions
|
@ -663,6 +663,65 @@ int spi_setup(struct spi_device *spi)
|
|||
}
|
||||
EXPORT_SYMBOL_GPL(spi_setup);
|
||||
|
||||
/**
|
||||
* spi_async - asynchronous SPI transfer
|
||||
* @spi: device with which data will be exchanged
|
||||
* @message: describes the data transfers, including completion callback
|
||||
* Context: any (irqs may be blocked, etc)
|
||||
*
|
||||
* This call may be used in_irq and other contexts which can't sleep,
|
||||
* as well as from task contexts which can sleep.
|
||||
*
|
||||
* The completion callback is invoked in a context which can't sleep.
|
||||
* Before that invocation, the value of message->status is undefined.
|
||||
* When the callback is issued, message->status holds either zero (to
|
||||
* indicate complete success) or a negative error code. After that
|
||||
* callback returns, the driver which issued the transfer request may
|
||||
* deallocate the associated memory; it's no longer in use by any SPI
|
||||
* core or controller driver code.
|
||||
*
|
||||
* Note that although all messages to a spi_device are handled in
|
||||
* FIFO order, messages may go to different devices in other orders.
|
||||
* Some device might be higher priority, or have various "hard" access
|
||||
* time requirements, for example.
|
||||
*
|
||||
* On detection of any fault during the transfer, processing of
|
||||
* the entire message is aborted, and the device is deselected.
|
||||
* Until returning from the associated message completion callback,
|
||||
* no other spi_message queued to that device will be processed.
|
||||
* (This rule applies equally to all the synchronous transfer calls,
|
||||
* which are wrappers around this core asynchronous primitive.)
|
||||
*/
|
||||
int spi_async(struct spi_device *spi, struct spi_message *message)
|
||||
{
|
||||
struct spi_master *master = spi->master;
|
||||
|
||||
/* Half-duplex links include original MicroWire, and ones with
|
||||
* only one data pin like SPI_3WIRE (switches direction) or where
|
||||
* either MOSI or MISO is missing. They can also be caused by
|
||||
* software limitations.
|
||||
*/
|
||||
if ((master->flags & SPI_MASTER_HALF_DUPLEX)
|
||||
|| (spi->mode & SPI_3WIRE)) {
|
||||
struct spi_transfer *xfer;
|
||||
unsigned flags = master->flags;
|
||||
|
||||
list_for_each_entry(xfer, &message->transfers, transfer_list) {
|
||||
if (xfer->rx_buf && xfer->tx_buf)
|
||||
return -EINVAL;
|
||||
if ((flags & SPI_MASTER_NO_TX) && xfer->tx_buf)
|
||||
return -EINVAL;
|
||||
if ((flags & SPI_MASTER_NO_RX) && xfer->rx_buf)
|
||||
return -EINVAL;
|
||||
}
|
||||
}
|
||||
|
||||
message->spi = spi;
|
||||
message->status = -EINPROGRESS;
|
||||
return master->transfer(spi, message);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(spi_async);
|
||||
|
||||
|
||||
/*-------------------------------------------------------------------------*/
|
||||
|
||||
|
|
|
@ -258,6 +258,8 @@ struct spi_master {
|
|||
/* other constraints relevant to this driver */
|
||||
u16 flags;
|
||||
#define SPI_MASTER_HALF_DUPLEX BIT(0) /* can't do full duplex */
|
||||
#define SPI_MASTER_NO_RX BIT(1) /* can't do buffer read */
|
||||
#define SPI_MASTER_NO_TX BIT(2) /* can't do buffer write */
|
||||
|
||||
/* Setup mode and clock, etc (spi driver may call many times).
|
||||
*
|
||||
|
@ -538,42 +540,7 @@ static inline void spi_message_free(struct spi_message *m)
|
|||
}
|
||||
|
||||
extern int spi_setup(struct spi_device *spi);
|
||||
|
||||
/**
|
||||
* spi_async - asynchronous SPI transfer
|
||||
* @spi: device with which data will be exchanged
|
||||
* @message: describes the data transfers, including completion callback
|
||||
* Context: any (irqs may be blocked, etc)
|
||||
*
|
||||
* This call may be used in_irq and other contexts which can't sleep,
|
||||
* as well as from task contexts which can sleep.
|
||||
*
|
||||
* The completion callback is invoked in a context which can't sleep.
|
||||
* Before that invocation, the value of message->status is undefined.
|
||||
* When the callback is issued, message->status holds either zero (to
|
||||
* indicate complete success) or a negative error code. After that
|
||||
* callback returns, the driver which issued the transfer request may
|
||||
* deallocate the associated memory; it's no longer in use by any SPI
|
||||
* core or controller driver code.
|
||||
*
|
||||
* Note that although all messages to a spi_device are handled in
|
||||
* FIFO order, messages may go to different devices in other orders.
|
||||
* Some device might be higher priority, or have various "hard" access
|
||||
* time requirements, for example.
|
||||
*
|
||||
* On detection of any fault during the transfer, processing of
|
||||
* the entire message is aborted, and the device is deselected.
|
||||
* Until returning from the associated message completion callback,
|
||||
* no other spi_message queued to that device will be processed.
|
||||
* (This rule applies equally to all the synchronous transfer calls,
|
||||
* which are wrappers around this core asynchronous primitive.)
|
||||
*/
|
||||
static inline int
|
||||
spi_async(struct spi_device *spi, struct spi_message *message)
|
||||
{
|
||||
message->spi = spi;
|
||||
return spi->master->transfer(spi, message);
|
||||
}
|
||||
extern int spi_async(struct spi_device *spi, struct spi_message *message);
|
||||
|
||||
/*---------------------------------------------------------------------------*/
|
||||
|
||||
|
|
Loading…
Reference in a new issue