Home | History | Annotate | Line # | Download | only in spi
      1 
      2 /*	$NetBSD: scmdspi.c,v 1.7 2025/09/13 14:10:44 thorpej Exp $	*/
      3 
      4 /*
      5  * Copyright (c) 2021 Brad Spencer <brad (at) anduin.eldar.org>
      6  *
      7  * Permission to use, copy, modify, and distribute this software for any
      8  * purpose with or without fee is hereby granted, provided that the above
      9  * copyright notice and this permission notice appear in all copies.
     10  *
     11  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
     12  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
     13  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
     14  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
     15  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
     16  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
     17  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
     18  */
     19 
     20 #include <sys/cdefs.h>
     21 __KERNEL_RCSID(0, "$NetBSD: scmdspi.c,v 1.7 2025/09/13 14:10:44 thorpej Exp $");
     22 
     23 /*
     24  * SPI driver for the Sparkfun Serial motor controller.
     25  * Uses the common scmd driver to do the real work.
     26 */
     27 
     28 #include <sys/param.h>
     29 #include <sys/systm.h>
     30 #include <sys/kernel.h>
     31 #include <sys/device.h>
     32 #include <sys/module.h>
     33 #include <sys/conf.h>
     34 #include <sys/sysctl.h>
     35 #include <sys/mutex.h>
     36 #include <sys/condvar.h>
     37 #include <sys/pool.h>
     38 #include <sys/kmem.h>
     39 
     40 #include <dev/i2c/i2cvar.h>
     41 #include <dev/spi/spivar.h>
     42 #include <dev/ic/scmdreg.h>
     43 #include <dev/ic/scmdvar.h>
     44 
     45 static const struct device_compatible_entry compat_data[] = {
     46 	{ .compat = "sparkfun,scmd-motor-driver" },
     47 
     48 	DEVICE_COMPAT_EOL
     49 };
     50 
     51 extern void	scmd_attach(struct scmd_sc *);
     52 
     53 static int 	scmdspi_match(device_t, cfdata_t, void *);
     54 static void 	scmdspi_attach(device_t, device_t, void *);
     55 static int 	scmdspi_detach(device_t, int);
     56 static int	scmdspi_activate(device_t, enum devact);
     57 
     58 #define SCMD_DEBUG
     59 #ifdef SCMD_DEBUG
     60 #define DPRINTF(s, l, x) \
     61     do { \
     62 	if (l <= s->sc_scmddebug) \
     63 	    printf x; \
     64     } while (/*CONSTCOND*/0)
     65 #else
     66 #define DPRINTF(s, l, x)
     67 #endif
     68 
     69 CFATTACH_DECL_NEW(scmdspi, sizeof(struct scmd_sc),
     70     scmdspi_match, scmdspi_attach, scmdspi_detach, scmdspi_activate);
     71 
     72 /* For the SPI interface on this device, the reads are done in an odd
     73  * manner.  The first part is normal enough, you send the register binary
     74  * or'ed with 0x80 and then the receive the data.  However, you MUST also
     75  * then receive a dummy value, otherwise everything gets out of sync and
     76  * no further reads appear to work unless you do a SPI receive all by itself.
     77  * This is documented in the data sheet for this device.
     78  *
     79  * Please note that the Ardunio code does this a little differently.  What is
     80  * below works on a Raspberry PI 3 without any apparent problems.
     81  *
     82  * The delays are also mentioned in the datasheet as being 20us, however, the
     83  * Ardunio code does 50us, so do likewise.
     84  */
     85 static int
     86 scmdspi_read_reg_direct(spi_handle_t sh, uint8_t reg, uint8_t *buf)
     87 {
     88 	int err;
     89 	uint8_t b;
     90 	uint8_t rreg = reg | 0x80;
     91 
     92 	err = spi_send(sh, 1, &rreg);
     93 	if (err)
     94 		return err;
     95 
     96 	delay(50);
     97 
     98 	b = SCMD_HOLE_VALUE;
     99 	err = spi_recv(sh, 1, &b);
    100 	if (err)
    101 		return err;
    102 
    103 	*buf = b;
    104 
    105 	delay(50);
    106 
    107 	b = SCMD_HOLE_VALUE;
    108 	err = spi_recv(sh, 1, &b);
    109 	delay(50);
    110 
    111 	return err;
    112 }
    113 
    114 static int
    115 scmdspi_read_reg(struct scmd_sc *sc, uint8_t reg, uint8_t *buf)
    116 {
    117 	return scmdspi_read_reg_direct(sc->sc_sh, reg, buf);
    118 }
    119 
    120 /* SPI writes to this device are normal enough.  You send the register
    121  * you want making sure that the high bit, 0x80, is clear and then the
    122  * data.
    123  *
    124  * The rule about waiting between operations appears to not apply, however.
    125  * This does more or less what the Ardunio code does.
    126  */
    127 static int
    128 scmdspi_write_reg_direct(spi_handle_t sh, uint8_t reg, uint8_t buf)
    129 {
    130 	uint8_t rreg = reg & 0x7F;
    131 	int err;
    132 
    133 	err = spi_send(sh, 1, &rreg);
    134 	if (err)
    135 		return err;
    136 
    137 	err = spi_send(sh, 1, &buf);
    138 	if (err)
    139 		return err;
    140 
    141 	delay(50);
    142 
    143 	return err;
    144 }
    145 
    146 static int
    147 scmdspi_write_reg(struct scmd_sc *sc, uint8_t reg, uint8_t buf)
    148 {
    149 	return scmdspi_write_reg_direct(sc->sc_sh, reg, buf);
    150 }
    151 
    152 /* These are to satisfy the common code */
    153 static int
    154 scmdspi_acquire_bus(struct scmd_sc *sc)
    155 {
    156 	return 0;
    157 }
    158 
    159 static void
    160 scmdspi_release_bus(struct scmd_sc *sc)
    161 {
    162 	return;
    163 }
    164 
    165 /* Nothing more is done here. It would be nice if the device was
    166  * actually checked to make sure it was there, but at least on the
    167  * Raspberry PI 3 the SPI pins were not set up in ALT0 mode yet and
    168  * everything acts like it succeeds.  No errors are ever produced while
    169  * in that state.
    170  */
    171 static int
    172 scmdspi_match(device_t parent, cfdata_t match, void *aux)
    173 {
    174 	struct spi_attach_args *sa = aux;
    175 	int match_result;
    176 
    177 	if (spi_use_direct_match(sa, compat_data, &match_result)) {
    178 		return match_result;
    179 	}
    180 
    181 	return SPI_MATCH_DEFAULT;
    182 }
    183 
    184 static void
    185 scmdspi_attach(device_t parent, device_t self, void *aux)
    186 {
    187 	struct scmd_sc *sc;
    188 	struct spi_attach_args *sa;
    189 	int error;
    190 
    191 	sa = aux;
    192 	sc = device_private(self);
    193 
    194 	sc->sc_dev = self;
    195 	sc->sc_sh = sa->sa_handle;
    196 	sc->sc_scmddebug = 0;
    197 	sc->sc_topaddr = 0xff;
    198 	sc->sc_opened = false;
    199 	sc->sc_dying = false;
    200 	sc->sc_func_acquire_bus = &scmdspi_acquire_bus;
    201 	sc->sc_func_release_bus = &scmdspi_release_bus;
    202 	sc->sc_func_read_register = &scmdspi_read_reg;
    203 	sc->sc_func_write_register = &scmdspi_write_reg;
    204 
    205 	mutex_init(&sc->sc_mutex, MUTEX_DEFAULT, IPL_NONE);
    206 	mutex_init(&sc->sc_condmutex, MUTEX_DEFAULT, IPL_NONE);
    207 	mutex_init(&sc->sc_dying_mutex, MUTEX_DEFAULT, IPL_NONE);
    208 	cv_init(&sc->sc_condvar, "scmdspicv");
    209 	cv_init(&sc->sc_cond_dying, "scmdspidc");
    210 
    211 	/* configure for 1MHz and SPI mode 0 according to the data sheet */
    212 	error = spi_configure(self, sa->sa_handle, SPI_MODE_0, SPI_FREQ_MHz(1));
    213 	if (error) {
    214 		return;
    215 	}
    216 
    217 	/* Please note that if the pins are not set up for SPI, the attachment
    218 	 * will work, but it will not figure out that there are slave modules.
    219 	 * It is likely required that a re-enumeration be performed after the pins
    220 	 * are set.  This can be done from userland later.
    221 	 */
    222 	scmd_attach(sc);
    223 
    224 	return;
    225 }
    226 
    227 /* These really do not do a whole lot, as SPI devices do not seem to work
    228  * as modules.
    229  */
    230 static int
    231 scmdspi_detach(device_t self, int flags)
    232 {
    233 	struct scmd_sc *sc;
    234 
    235 	sc = device_private(self);
    236 
    237 	mutex_enter(&sc->sc_mutex);
    238 	sc->sc_dying = true;
    239 	/* If this is true we are still open, destroy the condvar */
    240 	if (sc->sc_opened) {
    241 		mutex_enter(&sc->sc_dying_mutex);
    242 		DPRINTF(sc, 2, ("%s: Will wait for anything to exit\n",
    243 		    device_xname(sc->sc_dev)));
    244 		/* In the worst case this will time out after 5 seconds.
    245 		 * It really should not take that long for the drain / whatever
    246 		 * to happen
    247 		 */
    248 		cv_timedwait_sig(&sc->sc_cond_dying,
    249 		    &sc->sc_dying_mutex, mstohz(5000));
    250 		mutex_exit(&sc->sc_dying_mutex);
    251 		cv_destroy(&sc->sc_cond_dying);
    252 	}
    253 	cv_destroy(&sc->sc_condvar);
    254 	mutex_exit(&sc->sc_mutex);
    255 
    256 	mutex_destroy(&sc->sc_mutex);
    257 	mutex_destroy(&sc->sc_condmutex);
    258 
    259 	return 0;
    260 }
    261 
    262 int
    263 scmdspi_activate(device_t self, enum devact act)
    264 {
    265 	struct scmd_sc *sc = device_private(self);
    266 
    267 	switch (act) {
    268 	case DVACT_DEACTIVATE:
    269 		sc->sc_dying = true;
    270 		return 0;
    271 	default:
    272 		return EOPNOTSUPP;
    273 	}
    274 }
    275