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);
|
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 */
|
/* other constraints relevant to this driver */
|
||||||
u16 flags;
|
u16 flags;
|
||||||
#define SPI_MASTER_HALF_DUPLEX BIT(0) /* can't do full duplex */
|
#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).
|
/* 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);
|
extern int spi_setup(struct spi_device *spi);
|
||||||
|
extern int spi_async(struct spi_device *spi, struct spi_message *message);
|
||||||
/**
|
|
||||||
* 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);
|
|
||||||
}
|
|
||||||
|
|
||||||
/*---------------------------------------------------------------------------*/
|
/*---------------------------------------------------------------------------*/
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue