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