Re: [PATCH 1/6] spi: add flow controll support

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 






On 01.03.2016 15:43, Oleksij Rempel wrote:
Different HW implement different variants of SPI based flow control (FC).
To flexible FC implementation a spited it to fallowing common parts:
Flow control: Request Sequence
Master CS   |-------2\_____________________|
Slave  FC   |-----1\_______________________|
DATA        |-----------3\_________________|

Flow control: Ready Sequence
Master CS   |-----1\_______________________|
Slave  FC   |--------2\____________________|
DATA        |-----------3\_________________|

Flow control: ACK End of Data
Master CS   |______________________/2------|
Slave  FC   |________________________/3----|
DATA        |__________________/1----------|

Flow control: Pause
Master CS   |_______________________/------|
Slave  FC   |_______1/-----\3______/-------|
DATA        |________2/------\4___/--------|

Flow control: Ready signal on MISO
Master CS   |-----1\_______________________|
MISO/DATA   |------2\____3/----------------|
CONV START  |       ^                      |
DATA READY  |             ^                |

One alternative idea:

I guess all of the above could also get implemented
without a single framework change like this only in
the spi_device driver that requires this:

* spi_bus_lock
* spi_sync_lock (but with cs_change = 1 on the last transfer,
   so that cs does not get de-asserted - maybe a 0 byte transfer)
* check for your gpio to be of the "expected" level
   (maybe via interrupt or polling)
* spi_sync_lock (continue your transfer)
* spi_bus_unlock

This could also get wrapped in a generic spi_* method.

Maybe another alternative to this approach could be a generic
callback after having finished the processing a specific spi_transfer.
(not the specific version that you propose)

E.g:
--- a/drivers/spi/spi.c
+++ b/drivers/spi/spi.c
@@ -1001,6 +1001,9 @@ static int spi_transfer_one_message(struct spi_master *master,
                if (msg->status != -EINPROGRESS)
                        goto out;

+               if (xfer->complete)
+                       xfer->complete(xfer->context);
+
                if (xfer->delay_usecs)
                        udelay(xfer->delay_usecs);

diff --git a/include/linux/spi/spi.h b/include/linux/spi/spi.h
index 520a23d..d2b53c4 100644
--- a/include/linux/spi/spi.h
+++ b/include/linux/spi/spi.h
@@ -753,6 +753,9 @@ struct spi_transfer {
        u16             delay_usecs;
        u32             speed_hz;

+       void                    (*complete)(void *context);
+       void                    *context;
+
        struct list_head transfer_list;
 };

Then all that is left is implementing that gpio logic as this
callback.

The complete_code could be just waiting for an GPIO-interrupt to wake up
the thread - so it could be as simple as:

void spi_transfer_complete_wait_for_completion(void *context)
{
    /* possibly enable interrupt */
    /* wait for interrupt to wake us up*/
    wait_for_completion(context);
    /* possibly disable interrupt */
    reinit_completion(context);
}

The creation of the GPIO interrupt and such could also be spi_* helper
methods which then could take some of the required info from the
device tree.

This way the whole thing would be orthogonal to the SPI_READY,
for which there is no spi_device driver besides spidev.
So there would be also no impact to out of tree/userland drivers.

Such an interface actually would allow for other (ab)uses -
e.g: read len, then read len bytes becomes easy:

void spi_transfer_complete_read_length_then_read(void *context)
{
   struct spi_transfer *xfer = context;
   struct spi_transfer *next =
        list_first_entry(list, typeof(*next), transfer_list);

   /* saturate on length given in original transfer */
   if (xfer->rx_buf && (xfer->len>0))
       /* this may require unmapping the dma-buffer */
       next->len = min_t(unsigned, len, ((char*)xfer->rx_buf)[0]);

    /* note that if we wanted the ability to abort a transfer,
      * then the complete method would need to return a status
      */
}

All that is required is that a spi_message is created with 2 transfers,
where the first has:
* len = 1
* complete = spi_transfer_complete_read_length_then_read;
* context = xfer[0]
and the second contains:
* len = 16;

Just some ideas of how it could be implemented in a more generic way
that would also allow other uses.

Martin
--
To unsubscribe from this list: send the line "unsubscribe devicetree" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at  http://vger.kernel.org/majordomo-info.html



[Index of Archives]     [Device Tree Compilter]     [Device Tree Spec]     [Linux Driver Backports]     [Video for Linux]     [Linux USB Devel]     [Linux PCI Devel]     [Linux Audio Users]     [Linux Kernel]     [Linux SCSI]     [XFree86]     [Yosemite Backpacking]
  Powered by Linux