Expand PMF_FN_* macros.
[netbsd-mini2440.git] / sys / dev / spi / spi.c
blob90e74729b2ac2dab86ab4c2eb12044477db4c662
1 /* $NetBSD: spi.c,v 1.2 2006/10/07 07:21:13 gdamore Exp $ */
3 /*-
4 * Copyright (c) 2006 Urbana-Champaign Independent Media Center.
5 * Copyright (c) 2006 Garrett D'Amore.
6 * All rights reserved.
8 * Portions of this code were written by Garrett D'Amore for the
9 * Champaign-Urbana Community Wireless Network Project.
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.
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.
44 #include <sys/cdefs.h>
45 __KERNEL_RCSID(0, "$NetBSD: spi.c,v 1.2 2006/10/07 07:21:13 gdamore Exp $");
47 #include "locators.h"
49 #include <sys/param.h>
50 #include <sys/systm.h>
51 #include <sys/device.h>
52 #include <sys/malloc.h>
53 #include <sys/proc.h>
54 #include <sys/errno.h>
56 #include <dev/spi/spivar.h>
58 struct spi_softc {
59 struct spi_controller sc_controller;
60 int sc_mode;
61 int sc_speed;
62 int sc_nslaves;
63 struct spi_handle *sc_slaves;
67 * SPI slave device. We have one of these per slave.
69 struct spi_handle {
70 struct spi_softc *sh_sc;
71 struct spi_controller *sh_controller;
72 int sh_slave;
76 * API for bus drivers.
79 int
80 spibus_print(void *aux, const char *pnp)
83 if (pnp != NULL)
84 aprint_normal("spi at %s", pnp);
86 return (UNCONF);
90 static int
91 spi_match(device_t parent, cfdata_t cf, void *aux)
94 return 1;
97 static int
98 spi_print(void *aux, const char *pnp)
100 struct spi_attach_args *sa = aux;
102 if (sa->sa_handle->sh_slave != -1)
103 aprint_normal(" slave %d", sa->sa_handle->sh_slave);
105 return (UNCONF);
108 static int
109 spi_search(device_t parent, cfdata_t cf, const int *ldesc, void *aux)
111 struct spi_softc *sc = device_private(parent);
112 struct spi_attach_args sa;
113 int addr;
115 addr = cf->cf_loc[SPICF_SLAVE];
116 if ((addr < 0) || (addr >= sc->sc_controller.sct_nslaves)) {
117 return -1;
120 sa.sa_handle = &sc->sc_slaves[addr];
122 if (config_match(parent, cf, &sa) > 0)
123 config_attach(parent, cf, &sa, spi_print);
125 return 0;
129 * API for device drivers.
131 * We provide wrapper routines to decouple the ABI for the SPI
132 * device drivers from the ABI for the SPI bus drivers.
134 static void
135 spi_attach(device_t parent, device_t self, void *aux)
137 struct spi_softc *sc = device_private(self);
138 struct spibus_attach_args *sba = aux;
139 int i;
141 aprint_naive(": SPI bus\n");
142 aprint_normal(": SPI bus\n");
144 sc->sc_controller = *sba->sba_controller;
145 /* allocate slave structures */
146 sc->sc_slaves = malloc(sizeof (struct spi_handle) * sc->sc_nslaves,
147 M_DEVBUF, M_WAITOK | M_ZERO);
149 sc->sc_speed = 0;
150 sc->sc_mode = -1;
153 * Initialize slave handles
155 sc->sc_nslaves = sba->sba_controller->sct_nslaves;
156 for (i = 0; i < sc->sc_nslaves; i++) {
157 sc->sc_slaves[i].sh_slave = i;
158 sc->sc_slaves[i].sh_sc = sc;
159 sc->sc_slaves[i].sh_controller = &sc->sc_controller;
163 * Locate and attach child devices
165 config_search_ia(spi_search, self, "spi", NULL);
168 CFATTACH_DECL_NEW(spi, sizeof(struct spi_softc),
169 spi_match, spi_attach, NULL, NULL);
172 * Configure. This should be the first thing that the SPI driver
173 * should do, to configure which mode (e.g. SPI_MODE_0, which is the
174 * same as Philips Microwire mode), and speed. If the bus driver
175 * cannot run fast enough, then it should just configure the fastest
176 * mode that it can support. If the bus driver cannot run slow
177 * enough, then the device is incompatible and an error should be
178 * returned.
181 spi_configure(struct spi_handle *sh, int mode, int speed)
183 int s, rv;
184 struct spi_softc *sc = sh->sh_sc;
185 struct spi_controller *tag = sh->sh_controller;
187 /* ensure that request is compatible with other devices on the bus */
188 if ((sc->sc_mode >= 0) && (sc->sc_mode != mode))
189 return EINVAL;
191 s = splserial();
192 /* pick lowest configured speed */
193 if (speed == 0)
194 speed = sc->sc_speed;
195 if (sc->sc_speed)
196 speed = min(sc->sc_speed, speed);
198 rv = (*tag->sct_configure)(tag->sct_cookie, sh->sh_slave,
199 mode, speed);
201 if (rv == 0) {
202 sc->sc_mode = mode;
203 sc->sc_speed = speed;
205 splx(s);
206 return rv;
209 void
210 spi_transfer_init(struct spi_transfer *st)
213 simple_lock_init(&st->st_lock);
214 st->st_flags = 0;
215 st->st_errno = 0;
216 st->st_done = NULL;
217 st->st_chunks = NULL;
218 st->st_private = NULL;
219 st->st_slave = -1;
222 void
223 spi_chunk_init(struct spi_chunk *chunk, int cnt, const uint8_t *wptr,
224 uint8_t *rptr)
227 chunk->chunk_write = chunk->chunk_wptr = wptr;
228 chunk->chunk_read = chunk->chunk_read = rptr;
229 chunk->chunk_rresid = chunk->chunk_wresid = chunk->chunk_count = cnt;
230 chunk->chunk_next = NULL;
233 void
234 spi_transfer_add(struct spi_transfer *st, struct spi_chunk *chunk)
236 struct spi_chunk **cpp;
238 /* this is an O(n) insert -- perhaps we should use a simpleq? */
239 for (cpp = &st->st_chunks; *cpp; cpp = &(*cpp)->chunk_next);
240 *cpp = chunk;
244 spi_transfer(struct spi_handle *sh, struct spi_transfer *st)
246 struct spi_controller *tag = sh->sh_controller;
247 struct spi_chunk *chunk;
250 * Initialize "resid" counters and pointers, so that callers
251 * and bus drivers don't have to.
253 for (chunk = st->st_chunks; chunk; chunk = chunk->chunk_next) {
254 chunk->chunk_wresid = chunk->chunk_rresid = chunk->chunk_count;
255 chunk->chunk_wptr = chunk->chunk_write;
256 chunk->chunk_rptr = chunk->chunk_read;
260 * Match slave to handle's slave.
262 st->st_slave = sh->sh_slave;
264 return (*tag->sct_transfer)(tag->sct_cookie, st);
267 void
268 spi_wait(struct spi_transfer *st)
270 int s;
272 s = splserial();
273 simple_lock(&st->st_lock);
274 while (!st->st_flags & SPI_F_DONE) {
275 ltsleep(st, PWAIT, "spi_wait", 0, &st->st_lock);
277 simple_unlock(&st->st_lock);
278 splx(s);
281 void
282 spi_done(struct spi_transfer *st, int err)
284 int s;
286 s = splserial();
288 if ((st->st_errno = err) != 0) {
289 st->st_flags |= SPI_F_ERROR;
291 st->st_flags |= SPI_F_DONE;
292 if (st->st_done != NULL) {
293 (*st->st_done)(st);
294 } else {
296 simple_lock(&st->st_lock);
297 wakeup(st);
298 simple_unlock(&st->st_lock);
300 splx(s);
304 * Some convenience routines. These routines block until the work
305 * is done.
307 * spi_recv - receives data from the bus
309 * spi_send - sends data to the bus
311 * spi_send_recv - sends data to the bus, and then receives. Note that this is
312 * done synchronously, i.e. send a command and get the response. This is
313 * not full duplex. If you wnat full duplex, you can't use these convenience
314 * wrappers.
317 spi_recv(struct spi_handle *sh, int cnt, uint8_t *data)
319 struct spi_transfer trans;
320 struct spi_chunk chunk;
322 spi_transfer_init(&trans);
323 spi_chunk_init(&chunk, cnt, NULL, data);
324 spi_transfer_add(&trans, &chunk);
326 /* enqueue it and wait for it to complete */
327 spi_transfer(sh, &trans);
328 spi_wait(&trans);
330 if (trans.st_flags & SPI_F_ERROR)
331 return trans.st_errno;
333 return 0;
337 spi_send(struct spi_handle *sh, int cnt, const uint8_t *data)
339 struct spi_transfer trans;
340 struct spi_chunk chunk;
342 spi_transfer_init(&trans);
343 spi_chunk_init(&chunk, cnt, data, NULL);
344 spi_transfer_add(&trans, &chunk);
346 /* enqueue it and wait for it to complete */
347 spi_transfer(sh, &trans);
348 spi_wait(&trans);
350 if (trans.st_flags & SPI_F_ERROR)
351 return trans.st_errno;
353 return 0;
357 spi_send_recv(struct spi_handle *sh, int scnt, const uint8_t *snd,
358 int rcnt, uint8_t *rcv)
360 struct spi_transfer trans;
361 struct spi_chunk chunk1, chunk2;
363 spi_transfer_init(&trans);
364 spi_chunk_init(&chunk1, scnt, snd, NULL);
365 spi_chunk_init(&chunk2, rcnt, NULL, rcv);
366 spi_transfer_add(&trans, &chunk1);
367 spi_transfer_add(&trans, &chunk2);
369 /* enqueue it and wait for it to complete */
370 spi_transfer(sh, &trans);
371 spi_wait(&trans);
373 if (trans.st_flags & SPI_F_ERROR)
374 return trans.st_errno;
376 return 0;