Commit 4cff33f9 authored by Imre Deak's avatar Imre Deak Committed by Greg Kroah-Hartman

[PATCH] SPI: per-transfer overrides for wordsize and clocking

Some protocols (like one for some bitmap displays) require different clock
speed or word size settings for each transfer in an SPI message. This adds
those parameters to struct spi_transfer.  They are to be used when they are
nonzero; otherwise the defaults from spi_device are to be used.

The patch also adds a setup_transfer callback to spi_bitbang, uses it for
messages that use those overrides, and implements it so that the pure
bitbanging code can help resolve any questions about how it should work.
Signed-off-by: default avatarImre Deak <imre.deak@nokia.com>
Signed-off-by: default avatarDavid Brownell <dbrownell@users.sourceforge.net>
Signed-off-by: default avatarGreg Kroah-Hartman <gregkh@suse.de>
parent 716f8954
...@@ -138,6 +138,43 @@ static unsigned bitbang_txrx_32( ...@@ -138,6 +138,43 @@ static unsigned bitbang_txrx_32(
return t->len - count; return t->len - count;
} }
static int
bitbang_transfer_setup(struct spi_device *spi, struct spi_transfer *t)
{
struct spi_bitbang_cs *cs = spi->controller_state;
u8 bits_per_word;
u32 hz;
if (t) {
bits_per_word = t->bits_per_word;
hz = t->speed_hz;
} else {
bits_per_word = 0;
hz = 0;
}
/* spi_transfer level calls that work per-word */
if (!bits_per_word)
bits_per_word = spi->bits_per_word;
if (bits_per_word <= 8)
cs->txrx_bufs = bitbang_txrx_8;
else if (bits_per_word <= 16)
cs->txrx_bufs = bitbang_txrx_16;
else if (bits_per_word <= 32)
cs->txrx_bufs = bitbang_txrx_32;
else
return -EINVAL;
/* nsecs = (clock period)/2 */
if (!hz)
hz = spi->max_speed_hz;
cs->nsecs = (1000000000/2) / hz;
if (cs->nsecs > MAX_UDELAY_MS * 1000)
return -EINVAL;
return 0;
}
/** /**
* spi_bitbang_setup - default setup for per-word I/O loops * spi_bitbang_setup - default setup for per-word I/O loops
*/ */
...@@ -145,6 +182,7 @@ int spi_bitbang_setup(struct spi_device *spi) ...@@ -145,6 +182,7 @@ int spi_bitbang_setup(struct spi_device *spi)
{ {
struct spi_bitbang_cs *cs = spi->controller_state; struct spi_bitbang_cs *cs = spi->controller_state;
struct spi_bitbang *bitbang; struct spi_bitbang *bitbang;
int retval;
if (!spi->max_speed_hz) if (!spi->max_speed_hz)
return -EINVAL; return -EINVAL;
...@@ -160,25 +198,14 @@ int spi_bitbang_setup(struct spi_device *spi) ...@@ -160,25 +198,14 @@ int spi_bitbang_setup(struct spi_device *spi)
if (!spi->bits_per_word) if (!spi->bits_per_word)
spi->bits_per_word = 8; spi->bits_per_word = 8;
/* spi_transfer level calls that work per-word */
if (spi->bits_per_word <= 8)
cs->txrx_bufs = bitbang_txrx_8;
else if (spi->bits_per_word <= 16)
cs->txrx_bufs = bitbang_txrx_16;
else if (spi->bits_per_word <= 32)
cs->txrx_bufs = bitbang_txrx_32;
else
return -EINVAL;
/* per-word shift register access, in hardware or bitbanging */ /* per-word shift register access, in hardware or bitbanging */
cs->txrx_word = bitbang->txrx_word[spi->mode & (SPI_CPOL|SPI_CPHA)]; cs->txrx_word = bitbang->txrx_word[spi->mode & (SPI_CPOL|SPI_CPHA)];
if (!cs->txrx_word) if (!cs->txrx_word)
return -EINVAL; return -EINVAL;
/* nsecs = (clock period)/2 */ retval = bitbang_transfer_setup(spi, NULL);
cs->nsecs = (1000000000/2) / (spi->max_speed_hz); if (retval < 0)
if (cs->nsecs > MAX_UDELAY_MS * 1000) return retval;
return -EINVAL;
dev_dbg(&spi->dev, "%s, mode %d, %u bits/w, %u nsec\n", dev_dbg(&spi->dev, "%s, mode %d, %u bits/w, %u nsec\n",
__FUNCTION__, spi->mode & (SPI_CPOL | SPI_CPHA), __FUNCTION__, spi->mode & (SPI_CPOL | SPI_CPHA),
...@@ -246,6 +273,8 @@ static void bitbang_work(void *_bitbang) ...@@ -246,6 +273,8 @@ static void bitbang_work(void *_bitbang)
unsigned tmp; unsigned tmp;
unsigned cs_change; unsigned cs_change;
int status; int status;
int (*setup_transfer)(struct spi_device *,
struct spi_transfer *);
m = container_of(bitbang->queue.next, struct spi_message, m = container_of(bitbang->queue.next, struct spi_message,
queue); queue);
...@@ -262,6 +291,7 @@ static void bitbang_work(void *_bitbang) ...@@ -262,6 +291,7 @@ static void bitbang_work(void *_bitbang)
tmp = 0; tmp = 0;
cs_change = 1; cs_change = 1;
status = 0; status = 0;
setup_transfer = NULL;
list_for_each_entry (t, &m->transfers, transfer_list) { list_for_each_entry (t, &m->transfers, transfer_list) {
if (bitbang->shutdown) { if (bitbang->shutdown) {
...@@ -269,6 +299,20 @@ static void bitbang_work(void *_bitbang) ...@@ -269,6 +299,20 @@ static void bitbang_work(void *_bitbang)
break; break;
} }
/* 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; /* set up default clock polarity, and activate chip;
* this implicitly updates clock and spi modes as * this implicitly updates clock and spi modes as
* previously recorded for this device via setup(). * previously recorded for this device via setup().
...@@ -325,6 +369,10 @@ static void bitbang_work(void *_bitbang) ...@@ -325,6 +369,10 @@ static void bitbang_work(void *_bitbang)
m->status = status; m->status = status;
m->complete(m->context); m->complete(m->context);
/* restore speed and wordsize */
if (setup_transfer)
setup_transfer(spi, NULL);
/* normally deactivate chipselect ... unless no error and /* normally deactivate chipselect ... unless no error and
* cs_change has hinted that the next message will probably * cs_change has hinted that the next message will probably
* be for this chip too. * be for this chip too.
...@@ -406,6 +454,7 @@ int spi_bitbang_start(struct spi_bitbang *bitbang) ...@@ -406,6 +454,7 @@ int spi_bitbang_start(struct spi_bitbang *bitbang)
bitbang->use_dma = 0; bitbang->use_dma = 0;
bitbang->txrx_bufs = spi_bitbang_bufs; bitbang->txrx_bufs = spi_bitbang_bufs;
if (!bitbang->master->setup) { if (!bitbang->master->setup) {
bitbang->setup_transfer = bitbang_transfer_setup;
bitbang->master->setup = spi_bitbang_setup; bitbang->master->setup = spi_bitbang_setup;
bitbang->master->cleanup = spi_bitbang_cleanup; bitbang->master->cleanup = spi_bitbang_cleanup;
} }
......
...@@ -31,6 +31,7 @@ extern struct bus_type spi_bus_type; ...@@ -31,6 +31,7 @@ extern struct bus_type spi_bus_type;
* @master: SPI controller used with the device. * @master: SPI controller used with the device.
* @max_speed_hz: Maximum clock rate to be used with this chip * @max_speed_hz: Maximum clock rate to be used with this chip
* (on this board); may be changed by the device's driver. * (on this board); may be changed by the device's driver.
* The spi_transfer.speed_hz can override this for each transfer.
* @chip-select: Chipselect, distinguishing chips handled by "master". * @chip-select: Chipselect, distinguishing chips handled by "master".
* @mode: The spi mode defines how data is clocked out and in. * @mode: The spi mode defines how data is clocked out and in.
* This may be changed by the device's driver. * This may be changed by the device's driver.
...@@ -38,6 +39,7 @@ extern struct bus_type spi_bus_type; ...@@ -38,6 +39,7 @@ extern struct bus_type spi_bus_type;
* like eight or 12 bits are common. In-memory wordsizes are * like eight or 12 bits are common. In-memory wordsizes are
* powers of two bytes (e.g. 20 bit samples use 32 bits). * powers of two bytes (e.g. 20 bit samples use 32 bits).
* This may be changed by the device's driver. * This may be changed by the device's driver.
* The spi_transfer.bits_per_word can override this for each transfer.
* @irq: Negative, or the number passed to request_irq() to receive * @irq: Negative, or the number passed to request_irq() to receive
* interrupts from this device. * interrupts from this device.
* @controller_state: Controller's runtime state * @controller_state: Controller's runtime state
...@@ -268,6 +270,10 @@ extern struct spi_master *spi_busnum_to_master(u16 busnum); ...@@ -268,6 +270,10 @@ extern struct spi_master *spi_busnum_to_master(u16 busnum);
* @tx_dma: DMA address of tx_buf, if spi_message.is_dma_mapped * @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 * @rx_dma: DMA address of rx_buf, if spi_message.is_dma_mapped
* @len: size of rx and tx buffers (in bytes) * @len: size of rx and tx buffers (in bytes)
* @speed_hz: Select a speed other then the device default for this
* transfer. If 0 the default (from spi_device) is used.
* @bits_per_word: select a bits_per_word other then the device default
* for this transfer. If 0 the default (from spi_device) is used.
* @cs_change: affects chipselect after this transfer completes * @cs_change: affects chipselect after this transfer completes
* @delay_usecs: microseconds to delay after this transfer before * @delay_usecs: microseconds to delay after this transfer before
* (optionally) changing the chipselect status, then starting * (optionally) changing the chipselect status, then starting
...@@ -322,7 +328,9 @@ struct spi_transfer { ...@@ -322,7 +328,9 @@ struct spi_transfer {
dma_addr_t rx_dma; dma_addr_t rx_dma;
unsigned cs_change:1; unsigned cs_change:1;
u8 bits_per_word;
u16 delay_usecs; u16 delay_usecs;
u32 speed_hz;
struct list_head transfer_list; struct list_head transfer_list;
}; };
......
...@@ -30,6 +30,12 @@ struct spi_bitbang { ...@@ -30,6 +30,12 @@ struct spi_bitbang {
struct spi_master *master; struct spi_master *master;
/* setup_transfer() changes clock and/or wordsize to match settings
* for this transfer; zeroes restore defaults from spi_device.
*/
int (*setup_transfer)(struct spi_device *spi,
struct spi_transfer *t);
void (*chipselect)(struct spi_device *spi, int is_on); void (*chipselect)(struct spi_device *spi, int is_on);
#define BITBANG_CS_ACTIVE 1 /* normally nCS, active low */ #define BITBANG_CS_ACTIVE 1 /* normally nCS, active low */
#define BITBANG_CS_INACTIVE 0 #define BITBANG_CS_INACTIVE 0
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment