Skip to content

Commit

Permalink
Merge tag 'spi-cs-word' into spi-4.20
Browse files Browse the repository at this point in the history
spi: Provide SPI_CS_WORD

This provides a SPI operation mode which changes chip select after every
word, used by some devices such as ADCs and DACs.
  • Loading branch information
Mark Brown committed Sep 17, 2018
2 parents 3356d9f + cbaa62e commit 9263696
Show file tree
Hide file tree
Showing 2 changed files with 31 additions and 2 deletions.
31 changes: 30 additions & 1 deletion drivers/spi/spi.c
Original file line number Diff line number Diff line change
Expand Up @@ -2774,8 +2774,10 @@ int spi_setup(struct spi_device *spi)
return -EINVAL;
/* help drivers fail *cleanly* when they need options
* that aren't supported with their current controller
* SPI_CS_WORD has a fallback software implementation,
* so it is ignored here.
*/
bad_bits = spi->mode & ~spi->controller->mode_bits;
bad_bits = spi->mode & ~(spi->controller->mode_bits | SPI_CS_WORD);
ugly_bits = bad_bits &
(SPI_TX_DUAL | SPI_TX_QUAD | SPI_RX_DUAL | SPI_RX_QUAD);
if (ugly_bits) {
Expand Down Expand Up @@ -2829,6 +2831,33 @@ static int __spi_validate(struct spi_device *spi, struct spi_message *message)
if (list_empty(&message->transfers))
return -EINVAL;

/* If an SPI controller does not support toggling the CS line on each
* transfer (indicated by the SPI_CS_WORD flag), we can emulate it by
* splitting transfers into one-word transfers and ensuring that
* cs_change is set for each transfer.
*/
if ((spi->mode & SPI_CS_WORD) && !(ctlr->mode_bits & SPI_CS_WORD)) {
size_t maxsize;
int ret;

maxsize = (spi->bits_per_word + 7) / 8;

/* spi_split_transfers_maxsize() requires message->spi */
message->spi = spi;

ret = spi_split_transfers_maxsize(ctlr, message, maxsize,
GFP_KERNEL);
if (ret)
return ret;

list_for_each_entry(xfer, &message->transfers, transfer_list) {
/* don't change cs_change on the last entry in the list */
if (list_is_last(&xfer->transfer_list, &message->transfers))
break;
xfer->cs_change = 1;
}
}

/* 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
Expand Down
2 changes: 1 addition & 1 deletion include/linux/spi/spi.h
Original file line number Diff line number Diff line change
Expand Up @@ -163,6 +163,7 @@ struct spi_device {
#define SPI_TX_QUAD 0x200 /* transmit with 4 wires */
#define SPI_RX_DUAL 0x400 /* receive with 2 wires */
#define SPI_RX_QUAD 0x800 /* receive with 4 wires */
#define SPI_CS_WORD 0x1000 /* toggle cs after each word */
int irq;
void *controller_state;
void *controller_data;
Expand All @@ -177,7 +178,6 @@ struct spi_device {
* the controller talks to each chip, like:
* - memory packing (12 bit samples into low bits, others zeroed)
* - priority
* - drop chipselect after each word
* - chipselect delays
* - ...
*/
Expand Down

0 comments on commit 9263696

Please sign in to comment.