diff options
Diffstat (limited to 'include/linux')
-rw-r--r-- | include/linux/spi/spi.h | 92 | ||||
-rw-r--r-- | include/linux/spi/spi_bitbang.h | 7 |
2 files changed, 70 insertions, 29 deletions
diff --git a/include/linux/spi/spi.h b/include/linux/spi/spi.h index 6a41e26..939afd3 100644 --- a/include/linux/spi/spi.h +++ b/include/linux/spi/spi.h @@ -263,15 +263,16 @@ extern struct spi_master *spi_busnum_to_master(u16 busnum); /** * struct spi_transfer - a read/write buffer pair - * @tx_buf: data to be written (dma-safe address), or NULL - * @rx_buf: data to be read (dma-safe address), or NULL - * @tx_dma: DMA address of buffer, if spi_message.is_dma_mapped - * @rx_dma: DMA address of buffer, if spi_message.is_dma_mapped + * @tx_buf: data to be written (dma-safe memory), or NULL + * @rx_buf: data to be read (dma-safe memory), or NULL + * @tx_dma: DMA address of tx_buf, if spi_message.is_dma_mapped + * @rx_dma: DMA address of rx_buf, if spi_message.is_dma_mapped * @len: size of rx and tx buffers (in bytes) * @cs_change: affects chipselect after this transfer completes * @delay_usecs: microseconds to delay after this transfer before * (optionally) changing the chipselect status, then starting * the next transfer or completing this spi_message. + * @transfer_list: transfers are sequenced through spi_message.transfers * * SPI transfers always write the same number of bytes as they read. * Protocol drivers should always provide rx_buf and/or tx_buf. @@ -279,11 +280,16 @@ extern struct spi_master *spi_busnum_to_master(u16 busnum); * the data being transferred; that may reduce overhead, when the * underlying driver uses dma. * - * All SPI transfers start with the relevant chipselect active. Drivers - * can change behavior of the chipselect after the transfer finishes - * (including any mandatory delay). The normal behavior is to leave it - * selected, except for the last transfer in a message. Setting cs_change - * allows two additional behavior options: + * If the transmit buffer is null, undefined data will be shifted out + * while filling rx_buf. If the receive buffer is null, the data + * shifted in will be discarded. Only "len" bytes shift out (or in). + * It's an error to try to shift out a partial word. (For example, by + * shifting out three bytes with word size of sixteen or twenty bits; + * the former uses two bytes per word, the latter uses four bytes.) + * + * All SPI transfers start with the relevant chipselect active. Normally + * it stays selected until after the last transfer in a message. Drivers + * can affect the chipselect signal using cs_change: * * (i) If the transfer isn't the last one in the message, this flag is * used to make the chipselect briefly go inactive in the middle of the @@ -299,7 +305,8 @@ extern struct spi_master *spi_busnum_to_master(u16 busnum); * The code that submits an spi_message (and its spi_transfers) * to the lower layers is responsible for managing its memory. * Zero-initialize every field you don't set up explicitly, to - * insulate against future API updates. + * insulate against future API updates. After you submit a message + * and its transfers, ignore them until its completion callback. */ struct spi_transfer { /* it's ok if tx_buf == rx_buf (right?) @@ -316,12 +323,13 @@ struct spi_transfer { unsigned cs_change:1; u16 delay_usecs; + + struct list_head transfer_list; }; /** * struct spi_message - one multi-segment SPI transaction - * @transfers: the segements of the transaction - * @n_transfer: how many segments + * @transfers: list of transfer segments in this transaction * @spi: SPI device to which the transaction is queued * @is_dma_mapped: if true, the caller provided both dma and cpu virtual * addresses for each transfer buffer @@ -333,14 +341,22 @@ struct spi_transfer { * @queue: for use by whichever driver currently owns the message * @state: for use by whichever driver currently owns the message * + * An spi_message is used to execute an atomic sequence of data transfers, + * each represented by a struct spi_transfer. The sequence is "atomic" + * in the sense that no other spi_message may use that SPI bus until that + * sequence completes. On some systems, many such sequences can execute as + * as single programmed DMA transfer. On all systems, these messages are + * queued, and might complete after transactions to other devices. Messages + * sent to a given spi_device are alway executed in FIFO order. + * * The code that submits an spi_message (and its spi_transfers) * to the lower layers is responsible for managing its memory. * Zero-initialize every field you don't set up explicitly, to - * insulate against future API updates. + * insulate against future API updates. After you submit a message + * and its transfers, ignore them until its completion callback. */ struct spi_message { - struct spi_transfer *transfers; - unsigned n_transfer; + struct list_head transfers; struct spi_device *spi; @@ -371,6 +387,24 @@ struct spi_message { void *state; }; +static inline void spi_message_init(struct spi_message *m) +{ + memset(m, 0, sizeof *m); + INIT_LIST_HEAD(&m->transfers); +} + +static inline void +spi_message_add_tail(struct spi_transfer *t, struct spi_message *m) +{ + list_add_tail(&t->transfer_list, &m->transfers); +} + +static inline void +spi_transfer_del(struct spi_transfer *t) +{ + list_del(&t->transfer_list); +} + /* It's fine to embed message and transaction structures in other data * structures so long as you don't free them while they're in use. */ @@ -383,8 +417,12 @@ static inline struct spi_message *spi_message_alloc(unsigned ntrans, gfp_t flags + ntrans * sizeof(struct spi_transfer), flags); if (m) { - m->transfers = (void *)(m + 1); - m->n_transfer = ntrans; + int i; + struct spi_transfer *t = (struct spi_transfer *)(m + 1); + + INIT_LIST_HEAD(&m->transfers); + for (i = 0; i < ntrans; i++, t++) + spi_message_add_tail(t, m); } return m; } @@ -402,6 +440,8 @@ static inline void spi_message_free(struct spi_message *m) * device doesn't work with the mode 0 default. They may likewise need * to update clock rates or word sizes from initial values. This function * changes those settings, and must be called from a context that can sleep. + * The changes take effect the next time the device is selected and data + * is transferred to or from it. */ static inline int spi_setup(struct spi_device *spi) @@ -468,15 +508,12 @@ spi_write(struct spi_device *spi, const u8 *buf, size_t len) { struct spi_transfer t = { .tx_buf = buf, - .rx_buf = NULL, .len = len, - .cs_change = 0, - }; - struct spi_message m = { - .transfers = &t, - .n_transfer = 1, }; + struct spi_message m; + spi_message_init(&m); + spi_message_add_tail(&t, &m); return spi_sync(spi, &m); } @@ -493,16 +530,13 @@ static inline int spi_read(struct spi_device *spi, u8 *buf, size_t len) { struct spi_transfer t = { - .tx_buf = NULL, .rx_buf = buf, .len = len, - .cs_change = 0, - }; - struct spi_message m = { - .transfers = &t, - .n_transfer = 1, }; + struct spi_message m; + spi_message_init(&m); + spi_message_add_tail(&t, &m); return spi_sync(spi, &m); } diff --git a/include/linux/spi/spi_bitbang.h b/include/linux/spi/spi_bitbang.h index 8dfe61a..c961fe9 100644 --- a/include/linux/spi/spi_bitbang.h +++ b/include/linux/spi/spi_bitbang.h @@ -31,8 +31,15 @@ struct spi_bitbang { struct spi_master *master; void (*chipselect)(struct spi_device *spi, int is_on); +#define BITBANG_CS_ACTIVE 1 /* normally nCS, active low */ +#define BITBANG_CS_INACTIVE 0 + /* txrx_bufs() may handle dma mapping for transfers that don't + * already have one (transfer.{tx,rx}_dma is zero), or use PIO + */ int (*txrx_bufs)(struct spi_device *spi, struct spi_transfer *t); + + /* txrx_word[SPI_MODE_*]() just looks like a shift register */ u32 (*txrx_word[4])(struct spi_device *spi, unsigned nsecs, u32 word, u8 bits); |