diff options
Diffstat (limited to 'drivers/spi/spi.c')
| -rw-r--r-- | drivers/spi/spi.c | 92 |
1 files changed, 81 insertions, 11 deletions
diff --git a/drivers/spi/spi.c b/drivers/spi/spi.c index 643908b74bc0..70845ccd85c3 100644 --- a/drivers/spi/spi.c +++ b/drivers/spi/spi.c @@ -265,7 +265,7 @@ int spi_add_device(struct spi_device *spi) * normally rely on the device being setup. Devices * using SPI_CS_HIGH can't coexist well otherwise... */ - status = spi->master->setup(spi); + status = spi_setup(spi); if (status < 0) { dev_err(dev, "can't %s %s, status %d\n", "setup", dev_name(&spi->dev), status); @@ -583,6 +583,70 @@ EXPORT_SYMBOL_GPL(spi_busnum_to_master); /*-------------------------------------------------------------------------*/ +/* Core methods for SPI master protocol drivers. Some of the + * other core methods are currently defined as inline functions. + */ + +/** + * spi_setup - setup SPI mode and clock rate + * @spi: the device whose settings are being modified + * Context: can sleep, and no requests are queued to the device + * + * SPI protocol drivers may need to update the transfer mode if the + * device doesn't work with its 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. + * Except for SPI_CS_HIGH, which takes effect immediately, the changes take + * effect the next time the device is selected and data is transferred to + * or from it. When this function returns, the spi device is deselected. + * + * Note that this call will fail if the protocol driver specifies an option + * that the underlying controller or its driver does not support. For + * example, not all hardware supports wire transfers using nine bit words, + * LSB-first wire encoding, or active-high chipselects. + */ +int spi_setup(struct spi_device *spi) +{ + unsigned bad_bits; + int status; + + /* help drivers fail *cleanly* when they need options + * that aren't supported with their current master + */ + bad_bits = spi->mode & ~spi->master->mode_bits; + if (bad_bits) { + dev_dbg(&spi->dev, "setup: unsupported mode bits %x\n", + bad_bits); + return -EINVAL; + } + + if (!spi->bits_per_word) + spi->bits_per_word = 8; + + status = spi->master->setup(spi); + + dev_dbg(&spi->dev, "setup mode %d, %s%s%s%s" + "%u bits/w, %u Hz max --> %d\n", + (int) (spi->mode & (SPI_CPOL | SPI_CPHA)), + (spi->mode & SPI_CS_HIGH) ? "cs_high, " : "", + (spi->mode & SPI_LSB_FIRST) ? "lsb, " : "", + (spi->mode & SPI_3WIRE) ? "3wire, " : "", + (spi->mode & SPI_LOOP) ? "loopback, " : "", + spi->bits_per_word, spi->max_speed_hz, + status); + + return status; +} +EXPORT_SYMBOL_GPL(spi_setup); + + +/*-------------------------------------------------------------------------*/ + +/* Utility methods for SPI master protocol drivers, layered on + * top of the core. Some other utility methods are defined as + * inline functions. + */ + static void spi_complete(void *arg) { complete(arg); @@ -636,8 +700,8 @@ static u8 *buf; * @spi: device with which data will be exchanged * @txbuf: data to be written (need not be dma-safe) * @n_tx: size of txbuf, in bytes - * @rxbuf: buffer into which data will be read - * @n_rx: size of rxbuf, in bytes (need not be dma-safe) + * @rxbuf: buffer into which data will be read (need not be dma-safe) + * @n_rx: size of rxbuf, in bytes * Context: can sleep * * This performs a half duplex MicroWire style transaction with the @@ -658,7 +722,7 @@ int spi_write_then_read(struct spi_device *spi, int status; struct spi_message message; - struct spi_transfer x; + struct spi_transfer x[2]; u8 *local_buf; /* Use preallocated DMA-safe buffer. We can't avoid copying here, @@ -669,9 +733,15 @@ int spi_write_then_read(struct spi_device *spi, return -EINVAL; spi_message_init(&message); - memset(&x, 0, sizeof x); - x.len = n_tx + n_rx; - spi_message_add_tail(&x, &message); + memset(x, 0, sizeof x); + if (n_tx) { + x[0].len = n_tx; + spi_message_add_tail(&x[0], &message); + } + if (n_rx) { + x[1].len = n_rx; + spi_message_add_tail(&x[1], &message); + } /* ... unless someone else is using the pre-allocated buffer */ if (!mutex_trylock(&lock)) { @@ -682,15 +752,15 @@ int spi_write_then_read(struct spi_device *spi, local_buf = buf; memcpy(local_buf, txbuf, n_tx); - x.tx_buf = local_buf; - x.rx_buf = local_buf; + x[0].tx_buf = local_buf; + x[1].rx_buf = local_buf + n_tx; /* do the i/o */ status = spi_sync(spi, &message); if (status == 0) - memcpy(rxbuf, x.rx_buf + n_tx, n_rx); + memcpy(rxbuf, x[1].rx_buf, n_rx); - if (x.tx_buf == buf) + if (x[0].tx_buf == buf) mutex_unlock(&lock); else kfree(local_buf); |
