spi.c revision 1.8.38.1 1 /* $NetBSD: spi.c,v 1.8.38.1 2019/06/10 22:07:32 christos Exp $ */
2
3 /*-
4 * Copyright (c) 2006 Urbana-Champaign Independent Media Center.
5 * Copyright (c) 2006 Garrett D'Amore.
6 * All rights reserved.
7 *
8 * Portions of this code were written by Garrett D'Amore for the
9 * Champaign-Urbana Community Wireless Network Project.
10 *
11 * Redistribution and use in source and binary forms, with or
12 * without modification, are permitted provided that the following
13 * conditions are met:
14 * 1. Redistributions of source code must retain the above copyright
15 * notice, this list of conditions and the following disclaimer.
16 * 2. Redistributions in binary form must reproduce the above
17 * copyright notice, this list of conditions and the following
18 * disclaimer in the documentation and/or other materials provided
19 * with the distribution.
20 * 3. All advertising materials mentioning features or use of this
21 * software must display the following acknowledgements:
22 * This product includes software developed by the Urbana-Champaign
23 * Independent Media Center.
24 * This product includes software developed by Garrett D'Amore.
25 * 4. Urbana-Champaign Independent Media Center's name and Garrett
26 * D'Amore's name may not be used to endorse or promote products
27 * derived from this software without specific prior written permission.
28 *
29 * THIS SOFTWARE IS PROVIDED BY THE URBANA-CHAMPAIGN INDEPENDENT
30 * MEDIA CENTER AND GARRETT D'AMORE ``AS IS'' AND ANY EXPRESS OR
31 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
32 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
33 * ARE DISCLAIMED. IN NO EVENT SHALL THE URBANA-CHAMPAIGN INDEPENDENT
34 * MEDIA CENTER OR GARRETT D'AMORE BE LIABLE FOR ANY DIRECT, INDIRECT,
35 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
36 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
37 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
38 * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
39 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
40 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
41 * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
42 */
43
44 #include <sys/cdefs.h>
45 __KERNEL_RCSID(0, "$NetBSD: spi.c,v 1.8.38.1 2019/06/10 22:07:32 christos Exp $");
46
47 #include "locators.h"
48
49 #include <sys/param.h>
50 #include <sys/systm.h>
51 #include <sys/device.h>
52 #include <sys/conf.h>
53 #include <sys/malloc.h>
54 #include <sys/mutex.h>
55 #include <sys/condvar.h>
56 #include <sys/errno.h>
57
58 #include <dev/spi/spivar.h>
59 #include <dev/spi/spi_io.h>
60
61 #include "ioconf.h"
62 #include "locators.h"
63
64 struct spi_softc {
65 struct spi_controller sc_controller;
66 int sc_mode;
67 int sc_speed;
68 int sc_slave;
69 int sc_nslaves;
70 struct spi_handle *sc_slaves;
71 kmutex_t sc_lock;
72 kcondvar_t sc_cv;
73 int sc_flags;
74 #define SPIC_BUSY 1
75 };
76
77 static dev_type_open(spi_open);
78 static dev_type_close(spi_close);
79 static dev_type_ioctl(spi_ioctl);
80
81 const struct cdevsw spi_cdevsw = {
82 .d_open = spi_open,
83 .d_close = spi_close,
84 .d_read = noread,
85 .d_write = nowrite,
86 .d_ioctl = spi_ioctl,
87 .d_stop = nostop,
88 .d_tty = notty,
89 .d_poll = nopoll,
90 .d_mmap = nommap,
91 .d_kqfilter = nokqfilter,
92 .d_discard = nodiscard,
93 .d_flag = D_OTHER
94 };
95
96 /*
97 * SPI slave device. We have one of these per slave.
98 */
99 struct spi_handle {
100 struct spi_softc *sh_sc;
101 struct spi_controller *sh_controller;
102 int sh_slave;
103 int sh_mode;
104 int sh_speed;
105 };
106
107 #define SPI_MAXDATA 4096
108
109 /*
110 * API for bus drivers.
111 */
112
113 int
114 spibus_print(void *aux, const char *pnp)
115 {
116
117 if (pnp != NULL)
118 aprint_normal("spi at %s", pnp);
119
120 return (UNCONF);
121 }
122
123
124 static int
125 spi_match(device_t parent, cfdata_t cf, void *aux)
126 {
127
128 return 1;
129 }
130
131 static int
132 spi_print(void *aux, const char *pnp)
133 {
134 struct spi_attach_args *sa = aux;
135
136 if (sa->sa_handle->sh_slave != -1)
137 aprint_normal(" slave %d", sa->sa_handle->sh_slave);
138
139 return (UNCONF);
140 }
141
142 static int
143 spi_search(device_t parent, cfdata_t cf, const int *ldesc, void *aux)
144 {
145 struct spi_softc *sc = device_private(parent);
146 struct spi_attach_args sa;
147 int addr;
148
149 addr = cf->cf_loc[SPICF_SLAVE];
150 if ((addr < 0) || (addr >= sc->sc_controller.sct_nslaves)) {
151 return -1;
152 }
153
154 sa.sa_handle = &sc->sc_slaves[addr];
155
156 if (config_match(parent, cf, &sa) > 0)
157 config_attach(parent, cf, &sa, spi_print);
158
159 return 0;
160 }
161
162 /*
163 * API for device drivers.
164 *
165 * We provide wrapper routines to decouple the ABI for the SPI
166 * device drivers from the ABI for the SPI bus drivers.
167 */
168 static void
169 spi_attach(device_t parent, device_t self, void *aux)
170 {
171 struct spi_softc *sc = device_private(self);
172 struct spibus_attach_args *sba = aux;
173 int i;
174
175 aprint_naive(": SPI bus\n");
176 aprint_normal(": SPI bus\n");
177
178 mutex_init(&sc->sc_lock, MUTEX_DEFAULT, IPL_BIO);
179 cv_init(&sc->sc_cv, "spictl");
180
181 sc->sc_controller = *sba->sba_controller;
182 sc->sc_nslaves = sba->sba_controller->sct_nslaves;
183 /* allocate slave structures */
184 sc->sc_slaves = malloc(sizeof (struct spi_handle) * sc->sc_nslaves,
185 M_DEVBUF, M_WAITOK | M_ZERO);
186
187 sc->sc_speed = 0;
188 sc->sc_mode = -1;
189 sc->sc_slave = -1;
190
191 /*
192 * Initialize slave handles
193 */
194 for (i = 0; i < sc->sc_nslaves; i++) {
195 sc->sc_slaves[i].sh_slave = i;
196 sc->sc_slaves[i].sh_sc = sc;
197 sc->sc_slaves[i].sh_controller = &sc->sc_controller;
198 }
199
200 /*
201 * Locate and attach child devices
202 */
203 config_search_ia(spi_search, self, "spi", NULL);
204 }
205
206 static int
207 spi_open(dev_t dev, int flag, int fmt, lwp_t *l)
208 {
209 struct spi_softc *sc = device_lookup_private(&spi_cd, minor(dev));
210
211 if (sc == NULL)
212 return ENXIO;
213
214 return 0;
215 }
216
217 static int
218 spi_close(dev_t dev, int flag, int fmt, lwp_t *l)
219 {
220
221 return 0;
222 }
223
224 static int
225 spi_ioctl(dev_t dev, u_long cmd, void *data, int flag, lwp_t *l)
226 {
227 struct spi_softc *sc = device_lookup_private(&spi_cd, minor(dev));
228 struct spi_handle *sh;
229 spi_ioctl_configure_t *sic;
230 spi_ioctl_transfer_t *sit;
231 uint8_t *sbuf, *rbuf;
232 int error;
233
234 if (sc == NULL)
235 return ENXIO;
236
237 switch (cmd) {
238 case SPI_IOCTL_CONFIGURE:
239 sic = (spi_ioctl_configure_t *)data;
240 if (sic->sic_addr < 0 || sic->sic_addr >= sc->sc_nslaves) {
241 error = EINVAL;
242 break;
243 }
244 sh = &sc->sc_slaves[sic->sic_addr];
245 error = spi_configure(sh, sic->sic_mode, sic->sic_speed);
246 break;
247 case SPI_IOCTL_TRANSFER:
248 sit = (spi_ioctl_transfer_t *)data;
249 if (sit->sit_addr < 0 || sit->sit_addr >= sc->sc_nslaves) {
250 error = EINVAL;
251 break;
252 }
253 if ((sit->sit_send && sit->sit_sendlen == 0)
254 || (sit->sit_recv && sit->sit_recv == 0)) {
255 error = EINVAL;
256 break;
257 }
258 sh = &sc->sc_slaves[sit->sit_addr];
259 sbuf = rbuf = NULL;
260 error = 0;
261 if (sit->sit_send && sit->sit_sendlen <= SPI_MAXDATA) {
262 sbuf = malloc(sit->sit_sendlen, M_DEVBUF, M_WAITOK);
263 error = copyin(sit->sit_send, sbuf, sit->sit_sendlen);
264 }
265 if (sit->sit_recv && sit->sit_recvlen <= SPI_MAXDATA) {
266 rbuf = malloc(sit->sit_recvlen, M_DEVBUF, M_WAITOK);
267 }
268 if (error == 0) {
269 if (sbuf && rbuf)
270 error = spi_send_recv(sh,
271 sit->sit_sendlen, sbuf,
272 sit->sit_recvlen, rbuf);
273 else if (sbuf)
274 error = spi_send(sh,
275 sit->sit_sendlen, sbuf);
276 else if (rbuf)
277 error = spi_recv(sh,
278 sit->sit_recvlen, rbuf);
279 }
280 if (rbuf) {
281 if (error == 0)
282 error = copyout(rbuf, sit->sit_recv,
283 sit->sit_recvlen);
284 free(rbuf, M_DEVBUF);
285 }
286 if (sbuf) {
287 free(sbuf, M_DEVBUF);
288 }
289 break;
290 default:
291 error = ENODEV;
292 break;
293 }
294
295 return error;
296 }
297
298 CFATTACH_DECL_NEW(spi, sizeof(struct spi_softc),
299 spi_match, spi_attach, NULL, NULL);
300
301 /*
302 * Configure. This should be the first thing that the SPI driver
303 * should do, to configure which mode (e.g. SPI_MODE_0, which is the
304 * same as Philips Microwire mode), and speed. If the bus driver
305 * cannot run fast enough, then it should just configure the fastest
306 * mode that it can support. If the bus driver cannot run slow
307 * enough, then the device is incompatible and an error should be
308 * returned.
309 */
310 int
311 spi_configure(struct spi_handle *sh, int mode, int speed)
312 {
313
314 sh->sh_mode = mode;
315 sh->sh_speed = speed;
316 return 0;
317 }
318
319 /*
320 * Acquire controller
321 */
322 static void
323 spi_acquire(struct spi_handle *sh)
324 {
325 struct spi_softc *sc = sh->sh_sc;
326
327 mutex_enter(&sc->sc_lock);
328 while ((sc->sc_flags & SPIC_BUSY) != 0)
329 cv_wait(&sc->sc_cv, &sc->sc_lock);
330 sc->sc_flags |= SPIC_BUSY;
331 mutex_exit(&sc->sc_lock);
332 }
333
334 /*
335 * Release controller
336 */
337 static void
338 spi_release(struct spi_handle *sh)
339 {
340 struct spi_softc *sc = sh->sh_sc;
341
342 mutex_enter(&sc->sc_lock);
343 sc->sc_flags &= ~SPIC_BUSY;
344 cv_broadcast(&sc->sc_cv);
345 mutex_exit(&sc->sc_lock);
346 }
347
348 void
349 spi_transfer_init(struct spi_transfer *st)
350 {
351
352 mutex_init(&st->st_lock, MUTEX_DEFAULT, IPL_BIO);
353 cv_init(&st->st_cv, "spixfr");
354
355 st->st_flags = 0;
356 st->st_errno = 0;
357 st->st_done = NULL;
358 st->st_chunks = NULL;
359 st->st_private = NULL;
360 st->st_slave = -1;
361 }
362
363 void
364 spi_chunk_init(struct spi_chunk *chunk, int cnt, const uint8_t *wptr,
365 uint8_t *rptr)
366 {
367
368 chunk->chunk_write = chunk->chunk_wptr = wptr;
369 chunk->chunk_read = chunk->chunk_rptr = rptr;
370 chunk->chunk_rresid = chunk->chunk_wresid = chunk->chunk_count = cnt;
371 chunk->chunk_next = NULL;
372 }
373
374 void
375 spi_transfer_add(struct spi_transfer *st, struct spi_chunk *chunk)
376 {
377 struct spi_chunk **cpp;
378
379 /* this is an O(n) insert -- perhaps we should use a simpleq? */
380 for (cpp = &st->st_chunks; *cpp; cpp = &(*cpp)->chunk_next);
381 *cpp = chunk;
382 }
383
384 int
385 spi_transfer(struct spi_handle *sh, struct spi_transfer *st)
386 {
387 struct spi_softc *sc = sh->sh_sc;
388 struct spi_controller *tag = sh->sh_controller;
389 struct spi_chunk *chunk;
390 int error;
391
392 /*
393 * Initialize "resid" counters and pointers, so that callers
394 * and bus drivers don't have to.
395 */
396 for (chunk = st->st_chunks; chunk; chunk = chunk->chunk_next) {
397 chunk->chunk_wresid = chunk->chunk_rresid = chunk->chunk_count;
398 chunk->chunk_wptr = chunk->chunk_write;
399 chunk->chunk_rptr = chunk->chunk_read;
400 }
401
402 /*
403 * Match slave and parameters to handle
404 */
405 st->st_slave = sh->sh_slave;
406
407 /*
408 * Reserve controller during transaction
409 */
410 spi_acquire(sh);
411
412 st->st_spiprivate = (void *)sh;
413
414 /*
415 * Reconfigure controller
416 *
417 * XXX backends don't configure per-slave parameters
418 * Whenever we switch slaves or change mode or speed, we
419 * need to tell the backend.
420 */
421 if (sc->sc_slave != sh->sh_slave
422 || sc->sc_mode != sh->sh_mode
423 || sc->sc_speed != sh->sh_speed) {
424 error = (*tag->sct_configure)(tag->sct_cookie,
425 sh->sh_slave, sh->sh_mode, sh->sh_speed);
426 if (error)
427 return error;
428 }
429 sc->sc_mode = sh->sh_mode;
430 sc->sc_speed = sh->sh_speed;
431 sc->sc_slave = sh->sh_slave;
432
433 error = (*tag->sct_transfer)(tag->sct_cookie, st);
434
435 return error;
436 }
437
438 void
439 spi_wait(struct spi_transfer *st)
440 {
441 struct spi_handle *sh = st->st_spiprivate;
442
443 mutex_enter(&st->st_lock);
444 while (!(st->st_flags & SPI_F_DONE)) {
445 cv_wait(&st->st_cv, &st->st_lock);
446 }
447 mutex_exit(&st->st_lock);
448 cv_destroy(&st->st_cv);
449 mutex_destroy(&st->st_lock);
450
451 /*
452 * End transaction
453 */
454 spi_release(sh);
455 }
456
457 void
458 spi_done(struct spi_transfer *st, int err)
459 {
460
461 mutex_enter(&st->st_lock);
462 if ((st->st_errno = err) != 0) {
463 st->st_flags |= SPI_F_ERROR;
464 }
465 st->st_flags |= SPI_F_DONE;
466 if (st->st_done != NULL) {
467 (*st->st_done)(st);
468 } else {
469 cv_broadcast(&st->st_cv);
470 }
471 mutex_exit(&st->st_lock);
472 }
473
474 /*
475 * Some convenience routines. These routines block until the work
476 * is done.
477 *
478 * spi_recv - receives data from the bus
479 *
480 * spi_send - sends data to the bus
481 *
482 * spi_send_recv - sends data to the bus, and then receives. Note that this is
483 * done synchronously, i.e. send a command and get the response. This is
484 * not full duplex. If you wnat full duplex, you can't use these convenience
485 * wrappers.
486 */
487 int
488 spi_recv(struct spi_handle *sh, int cnt, uint8_t *data)
489 {
490 struct spi_transfer trans;
491 struct spi_chunk chunk;
492
493 spi_transfer_init(&trans);
494 spi_chunk_init(&chunk, cnt, NULL, data);
495 spi_transfer_add(&trans, &chunk);
496
497 /* enqueue it and wait for it to complete */
498 spi_transfer(sh, &trans);
499 spi_wait(&trans);
500
501 if (trans.st_flags & SPI_F_ERROR)
502 return trans.st_errno;
503
504 return 0;
505 }
506
507 int
508 spi_send(struct spi_handle *sh, int cnt, const uint8_t *data)
509 {
510 struct spi_transfer trans;
511 struct spi_chunk chunk;
512
513 spi_transfer_init(&trans);
514 spi_chunk_init(&chunk, cnt, data, NULL);
515 spi_transfer_add(&trans, &chunk);
516
517 /* enqueue it and wait for it to complete */
518 spi_transfer(sh, &trans);
519 spi_wait(&trans);
520
521 if (trans.st_flags & SPI_F_ERROR)
522 return trans.st_errno;
523
524 return 0;
525 }
526
527 int
528 spi_send_recv(struct spi_handle *sh, int scnt, const uint8_t *snd,
529 int rcnt, uint8_t *rcv)
530 {
531 struct spi_transfer trans;
532 struct spi_chunk chunk1, chunk2;
533
534 spi_transfer_init(&trans);
535 spi_chunk_init(&chunk1, scnt, snd, NULL);
536 spi_chunk_init(&chunk2, rcnt, NULL, rcv);
537 spi_transfer_add(&trans, &chunk1);
538 spi_transfer_add(&trans, &chunk2);
539
540 /* enqueue it and wait for it to complete */
541 spi_transfer(sh, &trans);
542 spi_wait(&trans);
543
544 if (trans.st_flags & SPI_F_ERROR)
545 return trans.st_errno;
546
547 return 0;
548 }
549
550