1*c7fb772bSthorpej /* $NetBSD: auspi.c,v 1.11 2021/08/07 16:18:58 thorpej Exp $ */
2bcad0816Sgdamore
3bcad0816Sgdamore /*-
4bcad0816Sgdamore * Copyright (c) 2006 Urbana-Champaign Independent Media Center.
5bcad0816Sgdamore * Copyright (c) 2006 Garrett D'Amore.
6bcad0816Sgdamore * All rights reserved.
7bcad0816Sgdamore *
8bcad0816Sgdamore * Portions of this code were written by Garrett D'Amore for the
9bcad0816Sgdamore * Champaign-Urbana Community Wireless Network Project.
10bcad0816Sgdamore *
11bcad0816Sgdamore * Redistribution and use in source and binary forms, with or
12bcad0816Sgdamore * without modification, are permitted provided that the following
13bcad0816Sgdamore * conditions are met:
14bcad0816Sgdamore * 1. Redistributions of source code must retain the above copyright
15bcad0816Sgdamore * notice, this list of conditions and the following disclaimer.
16bcad0816Sgdamore * 2. Redistributions in binary form must reproduce the above
17bcad0816Sgdamore * copyright notice, this list of conditions and the following
18bcad0816Sgdamore * disclaimer in the documentation and/or other materials provided
19bcad0816Sgdamore * with the distribution.
20bcad0816Sgdamore * 3. All advertising materials mentioning features or use of this
21bcad0816Sgdamore * software must display the following acknowledgements:
22bcad0816Sgdamore * This product includes software developed by the Urbana-Champaign
23bcad0816Sgdamore * Independent Media Center.
24bcad0816Sgdamore * This product includes software developed by Garrett D'Amore.
25bcad0816Sgdamore * 4. Urbana-Champaign Independent Media Center's name and Garrett
26bcad0816Sgdamore * D'Amore's name may not be used to endorse or promote products
27bcad0816Sgdamore * derived from this software without specific prior written permission.
28bcad0816Sgdamore *
29bcad0816Sgdamore * THIS SOFTWARE IS PROVIDED BY THE URBANA-CHAMPAIGN INDEPENDENT
30bcad0816Sgdamore * MEDIA CENTER AND GARRETT D'AMORE ``AS IS'' AND ANY EXPRESS OR
31bcad0816Sgdamore * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
32bcad0816Sgdamore * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
33bcad0816Sgdamore * ARE DISCLAIMED. IN NO EVENT SHALL THE URBANA-CHAMPAIGN INDEPENDENT
34bcad0816Sgdamore * MEDIA CENTER OR GARRETT D'AMORE BE LIABLE FOR ANY DIRECT, INDIRECT,
35bcad0816Sgdamore * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
36bcad0816Sgdamore * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
37bcad0816Sgdamore * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
38bcad0816Sgdamore * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
39bcad0816Sgdamore * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
40bcad0816Sgdamore * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
41bcad0816Sgdamore * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
42bcad0816Sgdamore */
43bcad0816Sgdamore
44bcad0816Sgdamore #include <sys/cdefs.h>
45*c7fb772bSthorpej __KERNEL_RCSID(0, "$NetBSD: auspi.c,v 1.11 2021/08/07 16:18:58 thorpej Exp $");
46bcad0816Sgdamore
47bcad0816Sgdamore #include "locators.h"
48bcad0816Sgdamore
49bcad0816Sgdamore #include <sys/param.h>
50b6185cbdSmatt #include <sys/bus.h>
51b6185cbdSmatt #include <sys/cpu.h>
52bcad0816Sgdamore #include <sys/device.h>
53bcad0816Sgdamore #include <sys/errno.h>
54b6185cbdSmatt #include <sys/kernel.h>
55bcad0816Sgdamore #include <sys/proc.h>
56b6185cbdSmatt #include <sys/systm.h>
57bcad0816Sgdamore
58bcad0816Sgdamore #include <mips/alchemy/include/aubusvar.h>
59bcad0816Sgdamore #include <mips/alchemy/include/auvar.h>
60bcad0816Sgdamore
61bcad0816Sgdamore #include <mips/alchemy/dev/aupscreg.h>
62bcad0816Sgdamore #include <mips/alchemy/dev/aupscvar.h>
63bcad0816Sgdamore #include <mips/alchemy/dev/auspireg.h>
64bcad0816Sgdamore #include <mips/alchemy/dev/auspivar.h>
65bcad0816Sgdamore
66bcad0816Sgdamore #include <dev/spi/spivar.h>
67bcad0816Sgdamore
68bcad0816Sgdamore struct auspi_softc {
69f58fcf6aSkiyohara device_t sc_dev;
70bcad0816Sgdamore struct aupsc_controller sc_psc; /* parent controller ops */
71bcad0816Sgdamore struct spi_controller sc_spi; /* SPI implementation ops */
72bcad0816Sgdamore struct auspi_machdep sc_md; /* board-specific support */
73bcad0816Sgdamore struct auspi_job *sc_job; /* current job */
74bcad0816Sgdamore struct spi_chunk *sc_wchunk;
75bcad0816Sgdamore struct spi_chunk *sc_rchunk;
76bcad0816Sgdamore void *sc_ih; /* interrupt handler */
77bcad0816Sgdamore
78bcad0816Sgdamore struct spi_transfer *sc_transfer;
79712239e3Sthorpej bool sc_running; /* is it processing stuff? */
80bcad0816Sgdamore
81bcad0816Sgdamore SIMPLEQ_HEAD(,spi_transfer) sc_q;
82bcad0816Sgdamore };
83bcad0816Sgdamore
84bcad0816Sgdamore #define auspi_select(sc, slave) \
85bcad0816Sgdamore (sc)->sc_md.am_select((sc)->sc_md.am_cookie, (slave))
86bcad0816Sgdamore
87bcad0816Sgdamore #define STATIC
88bcad0816Sgdamore
89f58fcf6aSkiyohara STATIC int auspi_match(device_t, struct cfdata *, void *);
90f58fcf6aSkiyohara STATIC void auspi_attach(device_t, device_t, void *);
91bcad0816Sgdamore STATIC int auspi_intr(void *);
92bcad0816Sgdamore
93f58fcf6aSkiyohara CFATTACH_DECL_NEW(auspi, sizeof(struct auspi_softc),
94bcad0816Sgdamore auspi_match, auspi_attach, NULL, NULL);
95bcad0816Sgdamore
96bcad0816Sgdamore /* SPI service routines */
97bcad0816Sgdamore STATIC int auspi_configure(void *, int, int, int);
98bcad0816Sgdamore STATIC int auspi_transfer(void *, struct spi_transfer *);
99bcad0816Sgdamore
100bcad0816Sgdamore /* internal stuff */
101bcad0816Sgdamore STATIC void auspi_done(struct auspi_softc *, int);
102bcad0816Sgdamore STATIC void auspi_send(struct auspi_softc *);
103bcad0816Sgdamore STATIC void auspi_recv(struct auspi_softc *);
104bcad0816Sgdamore STATIC void auspi_sched(struct auspi_softc *);
105bcad0816Sgdamore
106bcad0816Sgdamore #define GETREG(sc, x) \
107bcad0816Sgdamore bus_space_read_4(sc->sc_psc.psc_bust, sc->sc_psc.psc_bush, x)
108bcad0816Sgdamore #define PUTREG(sc, x, v) \
109bcad0816Sgdamore bus_space_write_4(sc->sc_psc.psc_bust, sc->sc_psc.psc_bush, x, v)
110bcad0816Sgdamore
111bcad0816Sgdamore int
auspi_match(device_t parent,struct cfdata * cf,void * aux)112f58fcf6aSkiyohara auspi_match(device_t parent, struct cfdata *cf, void *aux)
113bcad0816Sgdamore {
114bcad0816Sgdamore struct aupsc_attach_args *aa = aux;
115bcad0816Sgdamore
116bcad0816Sgdamore if (strcmp(aa->aupsc_name, cf->cf_name) != 0)
117bcad0816Sgdamore return 0;
118bcad0816Sgdamore
119bcad0816Sgdamore return 1;
120bcad0816Sgdamore }
121bcad0816Sgdamore
122bcad0816Sgdamore void
auspi_attach(device_t parent,device_t self,void * aux)123f58fcf6aSkiyohara auspi_attach(device_t parent, device_t self, void *aux)
124bcad0816Sgdamore {
125bcad0816Sgdamore struct auspi_softc *sc = device_private(self);
126bcad0816Sgdamore struct aupsc_attach_args *aa = aux;
127bcad0816Sgdamore struct spibus_attach_args sba;
128bcad0816Sgdamore const struct auspi_machdep *md;
129bcad0816Sgdamore
130f58fcf6aSkiyohara sc->sc_dev = self;
131f58fcf6aSkiyohara
132bcad0816Sgdamore if ((md = auspi_machdep(aa->aupsc_addr)) != NULL) {
133bcad0816Sgdamore sc->sc_md = *md;
134bcad0816Sgdamore }
135bcad0816Sgdamore
136bcad0816Sgdamore aprint_normal(": Alchemy PSC SPI protocol\n");
137bcad0816Sgdamore
138bcad0816Sgdamore sc->sc_psc = aa->aupsc_ctrl;
139bcad0816Sgdamore
140bcad0816Sgdamore /*
141bcad0816Sgdamore * Initialize SPI controller
142bcad0816Sgdamore */
143bcad0816Sgdamore sc->sc_spi.sct_cookie = sc;
144bcad0816Sgdamore sc->sc_spi.sct_configure = auspi_configure;
145bcad0816Sgdamore sc->sc_spi.sct_transfer = auspi_transfer;
146bcad0816Sgdamore
147bcad0816Sgdamore /* fix this! */
148bcad0816Sgdamore sc->sc_spi.sct_nslaves = sc->sc_md.am_nslaves;
149bcad0816Sgdamore
1509555f417Stnn memset(&sba, 0, sizeof(sba));
151bcad0816Sgdamore sba.sba_controller = &sc->sc_spi;
152bcad0816Sgdamore
153bcad0816Sgdamore /* enable SPI mode */
154bcad0816Sgdamore sc->sc_psc.psc_enable(sc, AUPSC_SEL_SPI);
155bcad0816Sgdamore
156bcad0816Sgdamore /* initialize the queue */
157bcad0816Sgdamore SIMPLEQ_INIT(&sc->sc_q);
158bcad0816Sgdamore
159bcad0816Sgdamore /* make sure interrupts disabled at the SPI */
160bcad0816Sgdamore PUTREG(sc, AUPSC_SPIMSK, SPIMSK_ALL);
161bcad0816Sgdamore
162bcad0816Sgdamore /* enable device interrupts */
163b1d9d10dSrmind sc->sc_ih = au_intr_establish(aa->aupsc_irq, 0, IPL_BIO, IST_LEVEL,
164bcad0816Sgdamore auspi_intr, sc);
165bcad0816Sgdamore
166*c7fb772bSthorpej config_found(self, &sba, spibus_print, CFARGS_NONE);
167bcad0816Sgdamore }
168bcad0816Sgdamore
169bcad0816Sgdamore int
auspi_configure(void * arg,int slave,int mode,int speed)170bcad0816Sgdamore auspi_configure(void *arg, int slave, int mode, int speed)
171bcad0816Sgdamore {
172bcad0816Sgdamore struct auspi_softc *sc = arg;
173bcad0816Sgdamore int brg, i;
174bcad0816Sgdamore uint32_t reg;
175bcad0816Sgdamore
176bcad0816Sgdamore /* setup interrupt registers */
177bcad0816Sgdamore PUTREG(sc, AUPSC_SPIMSK, SPIMSK_NORM);
178bcad0816Sgdamore
179bcad0816Sgdamore reg = GETREG(sc, AUPSC_SPICFG);
180bcad0816Sgdamore
181bcad0816Sgdamore reg &= ~(SPICFG_BRG_MASK); /* clear BRG */
182bcad0816Sgdamore reg &= ~(SPICFG_DIV_MASK); /* use pscn_mainclock/2 */
183bcad0816Sgdamore reg &= ~(SPICFG_PSE); /* disable port swap */
184bcad0816Sgdamore reg &= ~(SPICFG_BI); /* clear bit clock invert */
185bcad0816Sgdamore reg &= ~(SPICFG_CDE); /* clear clock phase delay */
186bcad0816Sgdamore reg &= ~(SPICFG_CGE); /* clear clock gate enable */
187bcad0816Sgdamore //reg |= SPICFG_MO; /* master-only mode */
188bcad0816Sgdamore reg |= SPICFG_DE; /* device enable */
189bcad0816Sgdamore reg |= SPICFG_DD; /* disable DMA */
190bcad0816Sgdamore reg |= SPICFG_RT_1; /* 1 byte rx fifo threshold */
191bcad0816Sgdamore reg |= SPICFG_TT_1; /* 1 byte tx fifo threshold */
192bcad0816Sgdamore reg |= ((8-1) << SPICFG_LEN_SHIFT);/* always work in 8-bit chunks */
193bcad0816Sgdamore
194bcad0816Sgdamore /*
195bcad0816Sgdamore * We assume a base clock of 48MHz has been established by the
196bcad0816Sgdamore * platform code. The clock divider reduces this to 24MHz.
197bcad0816Sgdamore * Next we have to figure out the BRG
198bcad0816Sgdamore */
199bcad0816Sgdamore #define BASECLK 24000000
200bcad0816Sgdamore for (brg = 0; brg < 64; brg++) {
201bcad0816Sgdamore if (speed >= (BASECLK / ((brg + 1) * 2))) {
202bcad0816Sgdamore break;
203bcad0816Sgdamore }
204bcad0816Sgdamore }
205bcad0816Sgdamore
206bcad0816Sgdamore /*
207bcad0816Sgdamore * Does the device want to go even slower? Our minimum speed without
208bcad0816Sgdamore * changing other assumptions, and complicating the code even further,
209bcad0816Sgdamore * is 24MHz/128, or 187.5kHz. That should be slow enough for any
210bcad0816Sgdamore * device we're likely to encounter.
211bcad0816Sgdamore */
212bcad0816Sgdamore if (speed < (BASECLK / ((brg + 1) * 2))) {
213bcad0816Sgdamore return EINVAL;
214bcad0816Sgdamore }
215bcad0816Sgdamore reg &= ~SPICFG_BRG_MASK;
216bcad0816Sgdamore reg |= (brg << SPICFG_BRG_SHIFT);
217bcad0816Sgdamore
218bcad0816Sgdamore /*
219bcad0816Sgdamore * I'm not entirely confident that these values are correct.
220bcad0816Sgdamore * But at least mode 0 appears to work properly with the
221bcad0816Sgdamore * devices I have tested. The documentation seems to suggest
222bcad0816Sgdamore * that I have the meaning of the clock delay bit inverted.
223bcad0816Sgdamore */
224bcad0816Sgdamore switch (mode) {
225bcad0816Sgdamore case SPI_MODE_0:
226bcad0816Sgdamore reg |= 0; /* CPHA = 0, CPOL = 0 */
227bcad0816Sgdamore break;
228bcad0816Sgdamore case SPI_MODE_1:
229bcad0816Sgdamore reg |= SPICFG_CDE; /* CPHA = 1, CPOL = 0 */
230bcad0816Sgdamore break;
231bcad0816Sgdamore case SPI_MODE_2:
232bcad0816Sgdamore reg |= SPICFG_BI; /* CPHA = 0, CPOL = 1 */
233bcad0816Sgdamore break;
234bcad0816Sgdamore case SPI_MODE_3:
235bcad0816Sgdamore reg |= SPICFG_CDE | SPICFG_BI; /* CPHA = 1, CPOL = 1 */
236bcad0816Sgdamore break;
237bcad0816Sgdamore default:
238bcad0816Sgdamore return EINVAL;
239bcad0816Sgdamore }
240bcad0816Sgdamore
241bcad0816Sgdamore PUTREG(sc, AUPSC_SPICFG, reg);
242bcad0816Sgdamore
243bcad0816Sgdamore for (i = 1000000; i; i -= 10) {
244bcad0816Sgdamore if (GETREG(sc, AUPSC_SPISTAT) & SPISTAT_DR) {
245bcad0816Sgdamore return 0;
246bcad0816Sgdamore }
247bcad0816Sgdamore }
248bcad0816Sgdamore
249bcad0816Sgdamore return ETIMEDOUT;
250bcad0816Sgdamore }
251bcad0816Sgdamore
252bcad0816Sgdamore void
auspi_send(struct auspi_softc * sc)253bcad0816Sgdamore auspi_send(struct auspi_softc *sc)
254bcad0816Sgdamore {
255bcad0816Sgdamore uint32_t data;
256bcad0816Sgdamore struct spi_chunk *chunk;
257bcad0816Sgdamore
258bcad0816Sgdamore /* fill the fifo */
259bcad0816Sgdamore while ((chunk = sc->sc_wchunk) != NULL) {
260bcad0816Sgdamore
261bcad0816Sgdamore while (chunk->chunk_wresid) {
262bcad0816Sgdamore
263bcad0816Sgdamore /* transmit fifo full? */
264bcad0816Sgdamore if (GETREG(sc, AUPSC_SPISTAT) & SPISTAT_TF) {
265bcad0816Sgdamore return;
266bcad0816Sgdamore }
267bcad0816Sgdamore
268bcad0816Sgdamore if (chunk->chunk_wptr) {
269bcad0816Sgdamore data = *chunk->chunk_wptr++;
270bcad0816Sgdamore } else {
271bcad0816Sgdamore data = 0;
272bcad0816Sgdamore }
273bcad0816Sgdamore chunk->chunk_wresid--;
274bcad0816Sgdamore
275bcad0816Sgdamore /* if the last outbound character, mark it */
276bcad0816Sgdamore if ((chunk->chunk_wresid == 0) &&
277bcad0816Sgdamore (chunk->chunk_next == NULL)) {
278bcad0816Sgdamore data |= SPITXRX_LC;
279bcad0816Sgdamore }
280bcad0816Sgdamore PUTREG(sc, AUPSC_SPITXRX, data);
281bcad0816Sgdamore }
282bcad0816Sgdamore
283bcad0816Sgdamore /* advance to next transfer */
284bcad0816Sgdamore sc->sc_wchunk = sc->sc_wchunk->chunk_next;
285bcad0816Sgdamore }
286bcad0816Sgdamore }
287bcad0816Sgdamore
288bcad0816Sgdamore void
auspi_recv(struct auspi_softc * sc)289bcad0816Sgdamore auspi_recv(struct auspi_softc *sc)
290bcad0816Sgdamore {
291bcad0816Sgdamore uint32_t data;
292bcad0816Sgdamore struct spi_chunk *chunk;
293bcad0816Sgdamore
294bcad0816Sgdamore while ((chunk = sc->sc_rchunk) != NULL) {
295bcad0816Sgdamore while (chunk->chunk_rresid) {
296bcad0816Sgdamore
297bcad0816Sgdamore /* rx fifo empty? */
298bcad0816Sgdamore if ((GETREG(sc, AUPSC_SPISTAT) & SPISTAT_RE) != 0) {
299bcad0816Sgdamore return;
300bcad0816Sgdamore }
301bcad0816Sgdamore
302bcad0816Sgdamore /* collect rx data */
303bcad0816Sgdamore data = GETREG(sc, AUPSC_SPITXRX);
304bcad0816Sgdamore if (chunk->chunk_rptr) {
305bcad0816Sgdamore *chunk->chunk_rptr++ = data & 0xff;
306bcad0816Sgdamore }
307bcad0816Sgdamore
308bcad0816Sgdamore chunk->chunk_rresid--;
309bcad0816Sgdamore }
310bcad0816Sgdamore
311bcad0816Sgdamore /* advance next to next transfer */
312bcad0816Sgdamore sc->sc_rchunk = sc->sc_rchunk->chunk_next;
313bcad0816Sgdamore }
314bcad0816Sgdamore }
315bcad0816Sgdamore
316bcad0816Sgdamore void
auspi_sched(struct auspi_softc * sc)317bcad0816Sgdamore auspi_sched(struct auspi_softc *sc)
318bcad0816Sgdamore {
319bcad0816Sgdamore struct spi_transfer *st;
320bcad0816Sgdamore int err;
321bcad0816Sgdamore
322bcad0816Sgdamore while ((st = spi_transq_first(&sc->sc_q)) != NULL) {
323bcad0816Sgdamore
324bcad0816Sgdamore /* remove the item */
325bcad0816Sgdamore spi_transq_dequeue(&sc->sc_q);
326bcad0816Sgdamore
327bcad0816Sgdamore /* note that we are working on it */
328bcad0816Sgdamore sc->sc_transfer = st;
329bcad0816Sgdamore
330bcad0816Sgdamore if ((err = auspi_select(sc, st->st_slave)) != 0) {
331bcad0816Sgdamore spi_done(st, err);
332bcad0816Sgdamore continue;
333bcad0816Sgdamore }
334bcad0816Sgdamore
335bcad0816Sgdamore /* clear the fifos */
336bcad0816Sgdamore PUTREG(sc, AUPSC_SPIPCR, SPIPCR_RC | SPIPCR_TC);
337bcad0816Sgdamore /* setup chunks */
338bcad0816Sgdamore sc->sc_rchunk = sc->sc_wchunk = st->st_chunks;
339bcad0816Sgdamore auspi_send(sc);
340bcad0816Sgdamore /* now kick the master start to get the chip running */
341bcad0816Sgdamore PUTREG(sc, AUPSC_SPIPCR, SPIPCR_MS);
34209c5f9ccSthorpej sc->sc_running = true;
343bcad0816Sgdamore return;
344bcad0816Sgdamore }
345bcad0816Sgdamore auspi_select(sc, -1);
34609c5f9ccSthorpej sc->sc_running = false;
347bcad0816Sgdamore }
348bcad0816Sgdamore
349bcad0816Sgdamore void
auspi_done(struct auspi_softc * sc,int err)350bcad0816Sgdamore auspi_done(struct auspi_softc *sc, int err)
351bcad0816Sgdamore {
352bcad0816Sgdamore struct spi_transfer *st;
353bcad0816Sgdamore
354bcad0816Sgdamore /* called from interrupt handler */
355bcad0816Sgdamore if ((st = sc->sc_transfer) != NULL) {
356bcad0816Sgdamore sc->sc_transfer = NULL;
357bcad0816Sgdamore spi_done(st, err);
358bcad0816Sgdamore }
359bcad0816Sgdamore /* make sure we clear these bits out */
360bcad0816Sgdamore sc->sc_wchunk = sc->sc_rchunk = NULL;
361bcad0816Sgdamore auspi_sched(sc);
362bcad0816Sgdamore }
363bcad0816Sgdamore
364bcad0816Sgdamore int
auspi_intr(void * arg)365bcad0816Sgdamore auspi_intr(void *arg)
366bcad0816Sgdamore {
367bcad0816Sgdamore struct auspi_softc *sc = arg;
368bcad0816Sgdamore uint32_t ev;
369bcad0816Sgdamore int err = 0;
370bcad0816Sgdamore
371bcad0816Sgdamore
372bcad0816Sgdamore if ((GETREG(sc, AUPSC_SPISTAT) & SPISTAT_DI) == 0) {
373bcad0816Sgdamore return 0;
374bcad0816Sgdamore }
375bcad0816Sgdamore
376bcad0816Sgdamore ev = GETREG(sc, AUPSC_SPIEVNT);
377bcad0816Sgdamore
378bcad0816Sgdamore if (ev & SPIMSK_MM) {
379bcad0816Sgdamore printf("%s: multiple masters detected!\n",
380133bfd25Skiyohara device_xname(sc->sc_dev));
381bcad0816Sgdamore err = EIO;
382bcad0816Sgdamore }
383bcad0816Sgdamore if (ev & SPIMSK_RO) {
384133bfd25Skiyohara printf("%s: receive overflow\n", device_xname(sc->sc_dev));
385bcad0816Sgdamore err = EIO;
386bcad0816Sgdamore }
387bcad0816Sgdamore if (ev & SPIMSK_TU) {
388133bfd25Skiyohara printf("%s: transmit underflow\n", device_xname(sc->sc_dev));
389bcad0816Sgdamore err = EIO;
390bcad0816Sgdamore }
391bcad0816Sgdamore if (err) {
392bcad0816Sgdamore /* clear errors */
393bcad0816Sgdamore PUTREG(sc, AUPSC_SPIEVNT,
394bcad0816Sgdamore ev & (SPIMSK_MM | SPIMSK_RO | SPIMSK_TU));
395bcad0816Sgdamore /* clear the fifos */
396bcad0816Sgdamore PUTREG(sc, AUPSC_SPIPCR, SPIPCR_RC | SPIPCR_TC);
397bcad0816Sgdamore auspi_done(sc, err);
398bcad0816Sgdamore
399bcad0816Sgdamore } else {
400bcad0816Sgdamore
401bcad0816Sgdamore /* do all data exchanges */
402bcad0816Sgdamore auspi_send(sc);
403bcad0816Sgdamore auspi_recv(sc);
404bcad0816Sgdamore
405bcad0816Sgdamore /*
406bcad0816Sgdamore * if the master done bit is set, make sure we do the
407bcad0816Sgdamore * right processing.
408bcad0816Sgdamore */
409bcad0816Sgdamore if (ev & SPIMSK_MD) {
410bcad0816Sgdamore if ((sc->sc_wchunk != NULL) ||
411bcad0816Sgdamore (sc->sc_rchunk != NULL)) {
412bcad0816Sgdamore printf("%s: partial transfer?\n",
413133bfd25Skiyohara device_xname(sc->sc_dev));
414bcad0816Sgdamore err = EIO;
415bcad0816Sgdamore }
416bcad0816Sgdamore auspi_done(sc, err);
417bcad0816Sgdamore }
418bcad0816Sgdamore /* clear interrupts */
419bcad0816Sgdamore PUTREG(sc, AUPSC_SPIEVNT,
420bcad0816Sgdamore ev & (SPIMSK_TR | SPIMSK_RR | SPIMSK_MD));
421bcad0816Sgdamore }
422bcad0816Sgdamore
423bcad0816Sgdamore return 1;
424bcad0816Sgdamore }
425bcad0816Sgdamore
426bcad0816Sgdamore int
auspi_transfer(void * arg,struct spi_transfer * st)427bcad0816Sgdamore auspi_transfer(void *arg, struct spi_transfer *st)
428bcad0816Sgdamore {
429bcad0816Sgdamore struct auspi_softc *sc = arg;
430bcad0816Sgdamore int s;
431bcad0816Sgdamore
432bcad0816Sgdamore /* make sure we select the right chip */
433b1d9d10dSrmind s = splbio();
434bcad0816Sgdamore spi_transq_enqueue(&sc->sc_q, st);
435bcad0816Sgdamore if (sc->sc_running == 0) {
436bcad0816Sgdamore auspi_sched(sc);
437bcad0816Sgdamore }
438bcad0816Sgdamore splx(s);
439bcad0816Sgdamore return 0;
440bcad0816Sgdamore }
441bcad0816Sgdamore
442