Extend the SPI bus API a bit. The config structure gets an sc_cs_delay
authorkettenis <kettenis@openbsd.org>
Sun, 31 Oct 2021 15:12:00 +0000 (15:12 +0000)
committerkettenis <kettenis@openbsd.org>
Sun, 31 Oct 2021 15:12:00 +0000 (15:12 +0000)
member to allow us to specify a delay between assert the CS# signal and
starting the clock.  And the transfer function gains a flags argument,
which can be used to specify a new SPI_KEEP_CS flag to keep CS# asserted
after the transfer.  This allows us to do another transfer immediately
afterwards without de-asserting CS# which is necessary for sending
commands to the upcoming Apple M1 keyboard/touchpad driver.

ok patrick@

sys/dev/fdt/imxspi.c
sys/dev/fdt/mvspi.c
sys/dev/spi/spivar.h

index 425c3cb..3c07fe6 100644 (file)
@@ -1,4 +1,4 @@
-/* $OpenBSD: imxspi.c,v 1.2 2021/10/24 17:52:26 mpi Exp $ */
+/* $OpenBSD: imxspi.c,v 1.3 2021/10/31 15:12:00 kettenis Exp $ */
 /*
  * Copyright (c) 2018 Patrick Wildt <patrick@blueri.se>
  *
@@ -99,6 +99,7 @@ struct imxspi_softc {
        int                      sc_ridx;
        int                      sc_widx;
        int                      sc_cs;
+       u_int                    sc_cs_delay;
 };
 
 int     imxspi_match(struct device *, void *, void *);
@@ -109,7 +110,7 @@ int  imxspi_intr(void *);
 
 void    imxspi_config(void *, struct spi_config *);
 uint32_t imxspi_clkdiv(struct imxspi_softc *, uint32_t);
-int     imxspi_transfer(void *, char *, char *, int);
+int     imxspi_transfer(void *, char *, char *, int, int);
 int     imxspi_acquire_bus(void *, int);
 void    imxspi_release_bus(void *, int);
 
@@ -235,6 +236,7 @@ imxspi_config(void *cookie, struct spi_config *conf)
                return;
        }
        sc->sc_cs = cs;
+       sc->sc_cs_delay = conf->sc_cs_delay;
 
        conreg = SPI_CONREG_EN;
        conreg |= SPI_CONREG_CHANNEL_MASTER;
@@ -322,7 +324,7 @@ imxspi_find_cs_gpio(struct imxspi_softc *sc, int cs)
 }
 
 int
-imxspi_transfer(void *cookie, char *out, char *in, int len)
+imxspi_transfer(void *cookie, char *out, char *in, int len, int flags)
 {
        struct imxspi_softc *sc = cookie;
        uint32_t *gpio;
@@ -335,6 +337,7 @@ imxspi_transfer(void *cookie, char *out, char *in, int len)
                gpio_controller_set_pin(gpio, 0);
                delay(1);
        }
+       delay(sc->sc_cs_delay);
 
        /* drain input buffer */
        while (HREAD4(sc, SPI_STATREG) & SPI_STATREG_RR)
@@ -370,10 +373,12 @@ imxspi_transfer(void *cookie, char *out, char *in, int len)
                HWRITE4(sc, SPI_STATREG, SPI_STATREG_TC);
        }
 
-       gpio = imxspi_find_cs_gpio(sc, sc->sc_cs);
-       if (gpio) {
-               gpio_controller_set_pin(gpio, 1);
-               delay(1);
+       if (!ISSET(flags, SPI_KEEP_CS)) {
+               gpio = imxspi_find_cs_gpio(sc, sc->sc_cs);
+               if (gpio) {
+                       gpio_controller_set_pin(gpio, 1);
+                       delay(1);
+               }
        }
 
        return 0;
index 4731e34..30b8831 100644 (file)
@@ -1,4 +1,4 @@
-/* $OpenBSD: mvspi.c,v 1.2 2021/10/24 17:52:26 mpi Exp $ */
+/* $OpenBSD: mvspi.c,v 1.3 2021/10/31 15:12:00 kettenis Exp $ */
 /*
  * Copyright (c) 2019 Patrick Wildt <patrick@blueri.se>
  *
@@ -60,6 +60,7 @@ struct mvspi_softc {
        struct spi_controller    sc_tag;
 
        int                      sc_cs;
+       u_int                    sc_cs_delay;
 };
 
 int     mvspi_match(struct device *, void *, void *);
@@ -68,7 +69,7 @@ int    mvspi_detach(struct device *, int);
 
 void    mvspi_config(void *, struct spi_config *);
 uint32_t mvspi_clkdiv(struct mvspi_softc *, uint32_t);
-int     mvspi_transfer(void *, char *, char *, int);
+int     mvspi_transfer(void *, char *, char *, int, int);
 int     mvspi_acquire_bus(void *, int);
 void    mvspi_release_bus(void *, int);
 
@@ -177,6 +178,7 @@ mvspi_config(void *cookie, struct spi_config *conf)
                return;
        }
        sc->sc_cs = cs;
+       sc->sc_cs_delay = conf->sc_cs_delay;
 
        HCLR4(sc, SPI_CFG, SPI_CFG_PRESCALE_MASK);
        HSET4(sc, SPI_CFG, mvspi_clkdiv(sc, conf->sc_freq));
@@ -229,12 +231,13 @@ mvspi_set_cs(struct mvspi_softc *sc, int cs, int on)
 }
 
 int
-mvspi_transfer(void *cookie, char *out, char *in, int len)
+mvspi_transfer(void *cookie, char *out, char *in, int len, int flags)
 {
        struct mvspi_softc *sc = cookie;
        int i = 0;
 
        mvspi_set_cs(sc, sc->sc_cs, 1);
+       delay(sc->sc_cs_delay);
 
        while (i < len) {
                if (mvspi_wait_state(sc, SPI_CTRL_XFER_READY,
@@ -255,7 +258,8 @@ mvspi_transfer(void *cookie, char *out, char *in, int len)
                i++;
        }
 
-       mvspi_set_cs(sc, sc->sc_cs, 0);
+       if (!ISSET(flags, SPI_KEEP_CS))
+               mvspi_set_cs(sc, sc->sc_cs, 0);
        return 0;
 
 err:
index 986bc7f..c56b840 100644 (file)
@@ -1,4 +1,4 @@
-/* $OpenBSD: spivar.h,v 1.1 2018/07/26 10:59:07 patrick Exp $ */
+/* $OpenBSD: spivar.h,v 1.2 2021/10/31 15:12:00 kettenis Exp $ */
 /*
  * Copyright (c) 2018 Patrick Wildt <patrick@blueri.se>
  *
@@ -23,14 +23,17 @@ struct spi_config {
 #define SPI_CONFIG_CS_HIGH     (1 << 2)
        int              sc_bpw;
        uint32_t         sc_freq;
+       u_int            sc_cs_delay;
 };
 
+#define SPI_KEEP_CS            (1 << 0)
+
 typedef struct spi_controller {
-       void                    *sc_cookie;
-       void                    (*sc_config)(void *, struct spi_config *);
-       int                     (*sc_transfer)(void *, char *, char *, int);
-       int                     (*sc_acquire_bus)(void *, int);
-       void                    (*sc_release_bus)(void *, int);
+       void            *sc_cookie;
+       void            (*sc_config)(void *, struct spi_config *);
+       int             (*sc_transfer)(void *, char *, char *, int, int);
+       int             (*sc_acquire_bus)(void *, int);
+       void            (*sc_release_bus)(void *, int);
 } *spi_tag_t;
 
 struct spi_attach_args {
@@ -42,11 +45,11 @@ struct spi_attach_args {
 #define        spi_config(sc, config)                                          \
        (*(sc)->sc_config)((sc)->sc_cookie, (config))
 #define        spi_read(sc, data, len)                                         \
-       (*(sc)->sc_transfer)((sc)->sc_cookie, NULL, (data), (len))
+       (*(sc)->sc_transfer)((sc)->sc_cookie, NULL, (data), (len), 0)
 #define        spi_write(sc, data, len)                                        \
-       (*(sc)->sc_transfer)((sc)->sc_cookie, (data), NULL, (len))
-#define        spi_transfer(sc, out, in, len)                                  \
-       (*(sc)->sc_transfer)((sc)->sc_cookie, (out), (in), (len))
+       (*(sc)->sc_transfer)((sc)->sc_cookie, (data), NULL, (len), 0)
+#define        spi_transfer(sc, out, in, len, flags)                           \
+       (*(sc)->sc_transfer)((sc)->sc_cookie, (out), (in), (len), (flags))
 #define        spi_acquire_bus(sc, flags)                                      \
        (*(sc)->sc_acquire_bus)((sc)->sc_cookie, (flags))
 #define        spi_release_bus(sc, flags)                                      \