diff options
author | Mark Brown <broonie@linaro.org> | 2013-07-05 12:06:44 +0100 |
---|---|---|
committer | Mark Brown <broonie@linaro.org> | 2013-07-15 11:29:53 +0100 |
commit | 91b308586793b48c590c9ac3528bbacb8ef53e15 (patch) | |
tree | e42c0f4510cea05fb7e262fe7d9caaab5811c0ed /drivers/spi/spi-bitbang.c | |
parent | 874b31585650afa6745de5133849365e7e6af418 (diff) | |
download | linux-91b308586793b48c590c9ac3528bbacb8ef53e15.tar.bz2 |
spi/bitbang: Factor out message transfer from message pump loop
In order to make it easier to convert to transfer_one_message() lift the
code that does the actual message transfer out of the work function that
implements the message pump. This should have no functional impact, it's
just a simple code motion patch.
Signed-off-by: Mark Brown <broonie@linaro.org>
Diffstat (limited to 'drivers/spi/spi-bitbang.c')
-rw-r--r-- | drivers/spi/spi-bitbang.c | 199 |
1 files changed, 104 insertions, 95 deletions
diff --git a/drivers/spi/spi-bitbang.c b/drivers/spi/spi-bitbang.c index 495ce0a51d2f..8b8487c9694e 100644 --- a/drivers/spi/spi-bitbang.c +++ b/drivers/spi/spi-bitbang.c @@ -255,117 +255,126 @@ static int spi_bitbang_bufs(struct spi_device *spi, struct spi_transfer *t) * Drivers can provide word-at-a-time i/o primitives, or provide * transfer-at-a-time ones to leverage dma or fifo hardware. */ -static void bitbang_work(struct work_struct *work) +static int spi_bitbang_transfer_one(struct spi_device *spi, + struct spi_message *m) { - struct spi_bitbang *bitbang = - container_of(work, struct spi_bitbang, work); - unsigned long flags; - struct spi_message *m, *_m; + struct spi_bitbang *bitbang; + unsigned nsecs; + struct spi_transfer *t = NULL; + unsigned tmp; + unsigned cs_change; + int status; + int do_setup = -1; - spin_lock_irqsave(&bitbang->lock, flags); - bitbang->busy = 1; - list_for_each_entry_safe(m, _m, &bitbang->queue, queue) { - struct spi_device *spi; - unsigned nsecs; - struct spi_transfer *t = NULL; - unsigned tmp; - unsigned cs_change; - int status; - int do_setup = -1; + bitbang = spi_master_get_devdata(spi->master); - list_del(&m->queue); - spin_unlock_irqrestore(&bitbang->lock, flags); + /* FIXME this is made-up ... the correct value is known to + * word-at-a-time bitbang code, and presumably chipselect() + * should enforce these requirements too? + */ + nsecs = 100; - /* FIXME this is made-up ... the correct value is known to - * word-at-a-time bitbang code, and presumably chipselect() - * should enforce these requirements too? - */ - nsecs = 100; + tmp = 0; + cs_change = 1; + status = 0; - spi = m->spi; - tmp = 0; - cs_change = 1; - status = 0; + list_for_each_entry (t, &m->transfers, transfer_list) { - list_for_each_entry (t, &m->transfers, transfer_list) { - - /* override speed or wordsize? */ - if (t->speed_hz || t->bits_per_word) - do_setup = 1; - - /* init (-1) or override (1) transfer params */ - if (do_setup != 0) { - status = bitbang->setup_transfer(spi, t); - if (status < 0) - break; - if (do_setup == -1) - do_setup = 0; - } - - /* set up default clock polarity, and activate chip; - * this implicitly updates clock and spi modes as - * previously recorded for this device via setup(). - * (and also deselects any other chip that might be - * selected ...) - */ - if (cs_change) { - bitbang->chipselect(spi, BITBANG_CS_ACTIVE); - ndelay(nsecs); - } - cs_change = t->cs_change; - if (!t->tx_buf && !t->rx_buf && t->len) { - status = -EINVAL; - break; - } + /* override speed or wordsize? */ + if (t->speed_hz || t->bits_per_word) + do_setup = 1; - /* transfer data. the lower level code handles any - * new dma mappings it needs. our caller always gave - * us dma-safe buffers. - */ - if (t->len) { - /* REVISIT dma API still needs a designated - * DMA_ADDR_INVALID; ~0 might be better. - */ - if (!m->is_dma_mapped) - t->rx_dma = t->tx_dma = 0; - status = bitbang->txrx_bufs(spi, t); - } - if (status > 0) - m->actual_length += status; - if (status != t->len) { - /* always report some kind of error */ - if (status >= 0) - status = -EREMOTEIO; + /* init (-1) or override (1) transfer params */ + if (do_setup != 0) { + status = bitbang->setup_transfer(spi, t); + if (status < 0) break; - } - status = 0; - - /* protocol tweaks before next transfer */ - if (t->delay_usecs) - udelay(t->delay_usecs); - - if (cs_change && !list_is_last(&t->transfer_list, &m->transfers)) { - /* sometimes a short mid-message deselect of the chip - * may be needed to terminate a mode or command - */ - ndelay(nsecs); - bitbang->chipselect(spi, BITBANG_CS_INACTIVE); - ndelay(nsecs); - } + if (do_setup == -1) + do_setup = 0; } - m->status = status; - m->complete(m->context); + /* set up default clock polarity, and activate chip; + * this implicitly updates clock and spi modes as + * previously recorded for this device via setup(). + * (and also deselects any other chip that might be + * selected ...) + */ + if (cs_change) { + bitbang->chipselect(spi, BITBANG_CS_ACTIVE); + ndelay(nsecs); + } + cs_change = t->cs_change; + if (!t->tx_buf && !t->rx_buf && t->len) { + status = -EINVAL; + break; + } - /* normally deactivate chipselect ... unless no error and - * cs_change has hinted that the next message will probably - * be for this chip too. + /* transfer data. the lower level code handles any + * new dma mappings it needs. our caller always gave + * us dma-safe buffers. */ - if (!(status == 0 && cs_change)) { + if (t->len) { + /* REVISIT dma API still needs a designated + * DMA_ADDR_INVALID; ~0 might be better. + */ + if (!m->is_dma_mapped) + t->rx_dma = t->tx_dma = 0; + status = bitbang->txrx_bufs(spi, t); + } + if (status > 0) + m->actual_length += status; + if (status != t->len) { + /* always report some kind of error */ + if (status >= 0) + status = -EREMOTEIO; + break; + } + status = 0; + + /* protocol tweaks before next transfer */ + if (t->delay_usecs) + udelay(t->delay_usecs); + + if (cs_change && !list_is_last(&t->transfer_list, &m->transfers)) { + /* sometimes a short mid-message deselect of the chip + * may be needed to terminate a mode or command + */ ndelay(nsecs); bitbang->chipselect(spi, BITBANG_CS_INACTIVE); ndelay(nsecs); } + } + + m->status = status; + m->complete(m->context); + + /* normally deactivate chipselect ... unless no error and + * cs_change has hinted that the next message will probably + * be for this chip too. + */ + if (!(status == 0 && cs_change)) { + ndelay(nsecs); + bitbang->chipselect(spi, BITBANG_CS_INACTIVE); + ndelay(nsecs); + } + + return status; +} + +static void bitbang_work(struct work_struct *work) +{ + struct spi_bitbang *bitbang = + container_of(work, struct spi_bitbang, work); + unsigned long flags; + struct spi_message *m, *_m; + + spin_lock_irqsave(&bitbang->lock, flags); + bitbang->busy = 1; + list_for_each_entry_safe(m, _m, &bitbang->queue, queue) { + list_del(&m->queue); + spin_unlock_irqrestore(&bitbang->lock, flags); + + spi_bitbang_transfer_one(m->spi, m); spin_lock_irqsave(&bitbang->lock, flags); } |