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