xref: /netbsd-src/sys/dev/spi/spi.c (revision f3cfa6f6ce31685c6c4a758bc430e69eb99f50a4)
1 /* $NetBSD: spi.c,v 1.11 2019/03/09 07:53:12 mlelstv 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.11 2019/03/09 07:53:12 mlelstv 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