On Tue, 6 Jan 2009 23:20:55 -0500 "Nelson Castillo" <[email protected]> wrote:
> I've been reading this thread about the accelerometers and the SPI > problems. > > http://www.mail-archive.com/[email protected]/msg06231.html > > I would like check the issue. Great! (I see lots of good work from you!) > Is anyone working on this? > Has anything changed since then? No, I started looking at it, but my head went buzzing from looking into the SPI code (layers upon layers!). I guess you are already aware of this, but for other readers of the thread: It's not really a functionality issue but something needed to upstream the driver. Using the current SPI interface is too slow on the openmoko and also not really safe since it cannot be operated in interrupt mode. Andys implementation simply communicates with the accelerometers manually so everything is fine there. But not for upstream, which tends to dislike duplicated efforts. The idea we discussed was therefore to add a synchronous SPI transfer function, which can be called from interrupt context. It was posted further up in your thread: http://www.mail-archive.com/[email protected]/msg06227.html the problems which got me dizzy was the layering of SPI, which I never really got the hang of. Also, if you want to work on this, I've found the eclipse code navigation to be really, really nice (makes it easy to lookup all implementations of the interfaces etc). I've written a small guide for how to set it up for the kernel here: http://simonkagstrom.livejournal.com/33093.html The patch with what I got so far is below. It's not much really, the big function is just a copy of bitbang_work, and I think you can safely ignore it. // Simon From: Simon Kagstrom <[email protected]> Signed-off-by: Simon Kagstrom <[email protected]> --- drivers/spi/spi_bitbang.c | 117 +++++++++++++++++++++++++++++++++++++++++++++ include/linux/spi/spi.h | 6 ++ 2 files changed, 123 insertions(+), 0 deletions(-) diff --git a/drivers/spi/spi_bitbang.c b/drivers/spi/spi_bitbang.c index 96cc39e..44d74e0 100644 --- a/drivers/spi/spi_bitbang.c +++ b/drivers/spi/spi_bitbang.c @@ -421,6 +421,121 @@ int spi_bitbang_transfer(struct spi_device *spi, struct spi_message *m) } EXPORT_SYMBOL_GPL(spi_bitbang_transfer); +int spi_bitbang_transfer_sync(struct spi_device *spi, struct spi_message *m) +{ + struct spi_bitbang *bitbang = spi_master_get_devdata(spi->master); + struct spi_device *spi; + unsigned nsecs; + struct spi_transfer *t = NULL; + unsigned tmp; + unsigned cs_change; + int status; + int (*setup_transfer)(struct spi_device *, + struct spi_transfer *); + + list_del_init(&m->queue); + + /* 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; + setup_transfer = NULL; + + list_for_each_entry (t, &m->transfers, transfer_list) { + + /* override or restore speed and wordsize */ + if (t->speed_hz || t->bits_per_word) { + setup_transfer = bitbang->setup_transfer; + if (!setup_transfer) { + status = -ENOPROTOOPT; + break; + } + } + if (setup_transfer) { + status = setup_transfer(spi, t); + if (status < 0) + break; + } + + /* 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; + } + + /* 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; + break; + } + status = 0; + + /* protocol tweaks before next transfer */ + if (t->delay_usecs) + udelay(t->delay_usecs); + + if (!cs_change) + continue; + if (t->transfer_list.next == &m->transfers) + break; + + /* 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; + + /* restore speed and wordsize */ + if (setup_transfer) + setup_transfer(spi, NULL); + + /* 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; +} + /*----------------------------------------------------------------------*/ /** @@ -459,6 +574,8 @@ int spi_bitbang_start(struct spi_bitbang *bitbang) if (!bitbang->master->transfer) bitbang->master->transfer = spi_bitbang_transfer; + if (!bitbang->master->transfer_sync) + bitbang->master->transfer_sync = spi_bitbang_transfer_sync; if (!bitbang->txrx_bufs) { bitbang->use_dma = 0; bitbang->txrx_bufs = spi_bitbang_bufs; diff --git a/include/linux/spi/spi.h b/include/linux/spi/spi.h index 4be01bb..6147e57 100644 --- a/include/linux/spi/spi.h +++ b/include/linux/spi/spi.h @@ -262,6 +262,10 @@ struct spi_master { int (*transfer)(struct spi_device *spi, struct spi_message *mesg); + /* bidirectional bulk transfer, synchronous (no callback) */ + int (*transfer_sync)(struct spi_device *spi, + struct spi_message *mesg); + /* called on release() to free memory provided by spi_master */ void (*cleanup)(struct spi_device *spi); }; @@ -573,6 +577,8 @@ spi_async(struct spi_device *spi, struct spi_message *message) /*---------------------------------------------------------------------------*/ +extern int spi_sync_poll(struct spi_device *spi, struct spi_message *message); + /* All these synchronous SPI transfer routines are utilities layered * over the core async transfer primitive. Here, "synchronous" means * they will sleep uninterruptibly until the async transfer completes.
