lkml.org 
[lkml]   [2007]   [Jan]   [25]   [last100]   RSS Feed
Views: [wrap][no wrap]   [headers]  [forward] 
 
Messages in this thread
    Patch in this message
    /
    Date
    From
    Subject[PATCH] 3/5: Updates to SPI and mmc_spi: tx_default, kernel 2.6.19
    (Please CC me on replies, I'm not subscribed to LKML or the SPI list.  Thanks.)

    The SD/MMC SPI-based protocol isn't really duplex. In the
    normal case there's either information transmitted or received,
    not both simultaneously. The unused data is always 0xff; ones.
    Unfortunately, the SPI framework leaves outgoing data for a
    left-out tx_buf just as "undefined" with no other way to send
    constant data than to actually pass a buffer full of ones. I
    imagine other SPI-based protocols being in the same situation so
    here's a feature implementation: a controller can say it
    supports a default value for the bit being shifted out whenever
    there's no tx_buf. I measured it to improve read performance by
    3% for SD/MMC SPI (timing "dd" of the MMC block device) for a
    DMA-based controller. As with the cs_interactive patch, the
    functionality is optional for a driver/controller, but I include
    an update for the spi_bitbang framework, for clients that don't
    implement their own bitbang->txrx_bufs function. I don't expect
    it to save much performance for bitbanged transfers (though the
    lessened memory and cache footprint might be nice); it's mostly
    to provide an example implementation. (To make sure, I did
    measure it for spi_crisv32_gpio and found no measurable
    difference; less than .5% difference with same difference
    between equal samples).

    Tested together with the other patches on the spi_crisv32_sser
    and spi_crisv32_gpio drivers (not yet in the kernel, will IIUC
    be submitted as part of the usual arch-maintainer-pushes).

    This patch is intended to be applied on top of the cs_inactive
    patch (the previous one, 2/5).

    Signed-off-by: Hans-Peter Nilsson <hp@axis.com>

    diff -upr a/include/linux/spi/spi.h b/include/linux/spi/spi.h
    --- a/include/linux/spi/spi.h 2007-01-24 07:10:09.000000000 +0100
    +++ b/include/linux/spi/spi.h 2007-01-24 03:58:32.000000000 +0100
    @@ -153,6 +153,9 @@ static inline void spi_unregister_driver
    * SPI slaves, and are numbered from zero to num_chipselects.
    * each slave has a chipselect signal, but it's common that not
    * every chipselect is connected to a slave.
    + * @can_tx_default: the controller can specify the "default" bit value:
    + * if this bit is set and there's no tx data in a message,
    + * spi_transfer.tx_default then controls the data shifted out.
    * @can_cs_inactive: the controller can send data (or at least toggle the
    * clock with undefined data output) while having chipselect inactive.
    * @setup: updates the device mode and clocking records used by a
    @@ -187,6 +190,11 @@ struct spi_master {
    */
    u16 num_chipselect;

    + /* clients can check this to see if they can avoid passing
    + * transfers where the tx buffer is just zero or is just ones.
    + */
    + unsigned can_tx_default:1;
    +
    /* clients that want to toggle the clock while chipselect is
    * inactive (has different polarity compared to when data is
    * output) must test this bit.
    @@ -296,6 +304,9 @@ extern struct spi_master *spi_busnum_to_
    * important information, and it's ok to pass NULL for both tx_buf
    * and rx_buf. It is an error to set this bit if spi_device
    * .can_cs_inactive == 0.
    + * @tx_default: tx data value (0 or 1) in absence of tx_buf, *iff* the
    + * master controller supports it (see spi_master.can_tx_default),
    + * otherwise the tx data is undefined and this bit is unused.
    * @delay_usecs: microseconds to delay after this transfer before
    * (optionally) changing the chipselect status, then starting
    * the next transfer or completing this spi_message.
    @@ -308,7 +319,9 @@ extern struct spi_master *spi_busnum_to_
    * underlying driver uses dma.
    *
    * If the transmit buffer is null, undefined data will be shifted out
    - * while filling rx_buf. If the receive buffer is null, the data
    + * while filling rx_buf, unless the master controller has indicated
    + * can_tx_default = 1, in which case the data shifted out is specified by
    + * spi_message.tx_default. 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;
    @@ -351,6 +364,7 @@ struct spi_transfer {

    unsigned cs_change:1;
    unsigned cs_inactive:1;
    + unsigned tx_default:1;
    u8 bits_per_word;
    u16 delay_usecs;
    u32 speed_hz;
    diff -upr a/drivers/spi/spi_bitbang.c b/drivers/spi/spi_bitbang.c
    --- a/drivers/spi/spi_bitbang.c 2007-01-24 07:14:12.000000000 +0100
    +++ b/drivers/spi/spi_bitbang.c 2007-01-24 06:15:56.000000000 +0100
    @@ -77,6 +77,8 @@ static unsigned bitbang_txrx_8(

    if (tx)
    word = *tx++;
    + else if (t->tx_default)
    + word = 0xff;
    word = txrx_word(spi, ns, word, bits);
    if (rx)
    *rx++ = word;
    @@ -103,6 +105,8 @@ static unsigned bitbang_txrx_16(

    if (tx)
    word = *tx++;
    + else if (t->tx_default)
    + word = 0xffff;
    word = txrx_word(spi, ns, word, bits);
    if (rx)
    *rx++ = word;
    @@ -129,6 +133,8 @@ static unsigned bitbang_txrx_32(

    if (tx)
    word = *tx++;
    + else if (t->tx_default)
    + word = 0xffffffffu;
    word = txrx_word(spi, ns, word, bits);
    if (rx)
    *rx++ = word;
    @@ -305,6 +311,7 @@ static void bitbang_work(void *_bitbang)
    list_for_each_entry (t, &m->transfers, transfer_list) {
    cs_inactive = t->cs_inactive;
    BUG_ON(cs_inactive && !spi->master->can_cs_inactive);
    + BUG_ON(t->tx_default && !spi->master->can_tx_default);

    if (bitbang->shutdown) {
    status = -ESHUTDOWN;
    @@ -481,6 +488,17 @@ int spi_bitbang_start(struct spi_bitbang
    if (!bitbang->txrx_bufs) {
    bitbang->use_dma = 0;
    bitbang->txrx_bufs = spi_bitbang_bufs;
    +
    + /*
    + * Because we use spi_bitbang_bufs, spi_bitbang_setup
    + * must been called (at least from the function
    + * overriding it) to set cs->txrx_bufs, so the
    + * function looping over the transfer bytes must be
    + * one of bitbang_txrx_(8|16|32) where we implement
    + * tx_default.
    + */
    + bitbang->master->can_tx_default = 1;
    +
    if (!bitbang->master->setup) {
    if (!bitbang->setup_transfer)
    bitbang->setup_transfer =

    brgds, H-P
    -
    To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
    the body of a message to majordomo@vger.kernel.org
    More majordomo info at http://vger.kernel.org/majordomo-info.html
    Please read the FAQ at http://www.tux.org/lkml/

    \
     
     \ /
      Last update: 2007-01-25 07:01    [W:0.068 / U:2.284 seconds]
    ©2003-2016 Jasper Spaans. hosted at Digital OceanAdvertise on this site