Home | History | Annotate | Line # | Download | only in xscale
      1  1.13     isaki /*	$NetBSD: pxa2x0_i2s.c,v 1.13 2019/05/08 13:40:14 isaki Exp $	*/
      2   1.1     peter /*	$OpenBSD: pxa2x0_i2s.c,v 1.7 2006/04/04 11:45:40 pascoe Exp $	*/
      3   1.1     peter 
      4   1.1     peter /*
      5   1.1     peter  * Copyright (c) 2005 Christopher Pascoe <pascoe (at) openbsd.org>
      6   1.1     peter  *
      7   1.1     peter  * Permission to use, copy, modify, and distribute this software for any
      8   1.1     peter  * purpose with or without fee is hereby granted, provided that the above
      9   1.1     peter  * copyright notice and this permission notice appear in all copies.
     10   1.1     peter  *
     11   1.1     peter  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
     12   1.1     peter  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
     13   1.1     peter  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
     14   1.1     peter  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
     15   1.1     peter  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
     16   1.1     peter  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
     17   1.1     peter  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
     18   1.1     peter  */
     19   1.1     peter 
     20   1.1     peter #include <sys/cdefs.h>
     21  1.13     isaki __KERNEL_RCSID(0, "$NetBSD: pxa2x0_i2s.c,v 1.13 2019/05/08 13:40:14 isaki Exp $");
     22   1.1     peter 
     23   1.1     peter #include <sys/param.h>
     24   1.1     peter #include <sys/systm.h>
     25   1.1     peter #include <sys/device.h>
     26  1.10  jmcneill #include <sys/kmem.h>
     27   1.9    dyoung #include <sys/bus.h>
     28   1.1     peter 
     29   1.1     peter #include <arm/xscale/pxa2x0reg.h>
     30   1.1     peter #include <arm/xscale/pxa2x0var.h>
     31   1.1     peter #include <arm/xscale/pxa2x0_gpio.h>
     32   1.1     peter #include <arm/xscale/pxa2x0_i2s.h>
     33   1.1     peter #include <arm/xscale/pxa2x0_dmac.h>
     34   1.1     peter 
     35   1.1     peter struct pxa2x0_i2s_dma {
     36   1.1     peter 	struct pxa2x0_i2s_dma *next;
     37   1.3  christos 	void *addr;
     38   1.1     peter 	size_t size;
     39   1.1     peter 	bus_dmamap_t map;
     40   1.1     peter #define	I2S_N_SEGS	1
     41   1.1     peter 	bus_dma_segment_t segs[I2S_N_SEGS];
     42   1.1     peter 	int nsegs;
     43   1.1     peter 	struct dmac_xfer *dx;
     44   1.1     peter };
     45   1.1     peter 
     46   1.1     peter static void pxa2x0_i2s_dmac_ointr(struct dmac_xfer *, int);
     47   1.1     peter static void pxa2x0_i2s_dmac_iintr(struct dmac_xfer *, int);
     48   1.1     peter 
     49   1.1     peter void
     50   1.1     peter pxa2x0_i2s_init(struct pxa2x0_i2s_softc *sc)
     51   1.1     peter {
     52   1.1     peter 
     53   1.1     peter 	bus_space_write_4(sc->sc_iot, sc->sc_ioh, I2S_SACR0, SACR0_RST);
     54   1.1     peter 	delay(100);
     55   1.1     peter 	bus_space_write_4(sc->sc_iot, sc->sc_ioh, I2S_SACR0,
     56   1.1     peter 	    SACR0_BCKD | SACR0_SET_TFTH(7) | SACR0_SET_RFTH(7));
     57   1.1     peter 	bus_space_write_4(sc->sc_iot, sc->sc_ioh, I2S_SACR1, 0);
     58   1.1     peter 	bus_space_write_4(sc->sc_iot, sc->sc_ioh, I2S_SADR, 0);
     59   1.1     peter 	bus_space_write_4(sc->sc_iot, sc->sc_ioh, I2S_SADIV, sc->sc_sadiv);
     60   1.1     peter 	bus_space_write_4(sc->sc_iot, sc->sc_ioh, I2S_SACR0,
     61   1.1     peter 		SACR0_BCKD | SACR0_SET_TFTH(7) | SACR0_SET_RFTH(7) | SACR0_ENB);
     62   1.1     peter }
     63   1.1     peter 
     64   1.1     peter int
     65   1.1     peter pxa2x0_i2s_attach_sub(struct pxa2x0_i2s_softc *sc)
     66   1.1     peter {
     67   1.1     peter 	int rv;
     68   1.1     peter 
     69  1.10  jmcneill 	KASSERT(sc->sc_intr_lock != NULL);
     70  1.10  jmcneill 
     71   1.1     peter 	rv = bus_space_map(sc->sc_iot, PXA2X0_I2S_BASE, PXA2X0_I2S_SIZE, 0,
     72   1.1     peter 	    &sc->sc_ioh);
     73   1.1     peter 	if (rv) {
     74   1.1     peter 		sc->sc_size = 0;
     75   1.1     peter 		return 1;
     76   1.1     peter 	}
     77   1.1     peter 
     78   1.1     peter 	sc->sc_dr.ds_addr = PXA2X0_I2S_BASE + I2S_SADR;
     79   1.1     peter 	sc->sc_dr.ds_len = 4;
     80   1.1     peter 
     81   1.1     peter 	sc->sc_sadiv = SADIV_3_058MHz;
     82   1.1     peter 
     83   1.1     peter 	bus_space_barrier(sc->sc_iot, sc->sc_ioh, 0, sc->sc_size,
     84   1.1     peter 	    BUS_SPACE_BARRIER_READ|BUS_SPACE_BARRIER_WRITE);
     85   1.1     peter 
     86   1.1     peter 	pxa2x0_i2s_init(sc);
     87   1.1     peter 
     88   1.1     peter 	return 0;
     89   1.1     peter }
     90   1.1     peter 
     91   1.1     peter void
     92   1.1     peter pxa2x0_i2s_open(struct pxa2x0_i2s_softc *sc)
     93   1.1     peter {
     94   1.1     peter 
     95   1.1     peter 	if (sc->sc_open++ == 0) {
     96   1.1     peter 		pxa2x0_clkman_config(CKEN_I2S, 1);
     97   1.1     peter 	}
     98   1.1     peter }
     99   1.1     peter 
    100   1.1     peter void
    101   1.1     peter pxa2x0_i2s_close(struct pxa2x0_i2s_softc *sc)
    102   1.1     peter {
    103   1.1     peter 
    104   1.1     peter 	if (--sc->sc_open == 0) {
    105   1.1     peter 		pxa2x0_clkman_config(CKEN_I2S, 0);
    106   1.1     peter 	}
    107   1.1     peter }
    108   1.1     peter 
    109   1.1     peter int
    110   1.1     peter pxa2x0_i2s_detach_sub(struct pxa2x0_i2s_softc *sc)
    111   1.1     peter {
    112   1.1     peter 
    113   1.1     peter 	if (sc->sc_size > 0) {
    114   1.1     peter 		bus_space_unmap(sc->sc_iot, sc->sc_ioh, sc->sc_size);
    115   1.1     peter 		sc->sc_size = 0;
    116   1.1     peter 	}
    117   1.1     peter 	pxa2x0_clkman_config(CKEN_I2S, 0);
    118   1.1     peter 
    119   1.1     peter 	return 0;
    120   1.1     peter }
    121   1.1     peter 
    122   1.1     peter void
    123   1.1     peter pxa2x0_i2s_write(struct pxa2x0_i2s_softc *sc, uint32_t data)
    124   1.1     peter {
    125   1.1     peter 
    126   1.1     peter 	if (sc->sc_open == 0)
    127   1.1     peter 		return;
    128   1.1     peter 
    129   1.1     peter 	/* Clear intr and underrun bit if set. */
    130   1.1     peter 	if (bus_space_read_4(sc->sc_iot, sc->sc_ioh, I2S_SASR0) & SASR0_TUR)
    131   1.1     peter 		bus_space_write_4(sc->sc_iot, sc->sc_ioh, I2S_SAICR, SAICR_TUR);
    132   1.1     peter 
    133   1.1     peter 	/* Wait for transmit fifo to have space. */
    134   1.1     peter 	while ((bus_space_read_4(sc->sc_iot, sc->sc_ioh, I2S_SASR0) & SASR0_TNF)
    135   1.1     peter 	     == 0)
    136   1.1     peter 		continue;	/* nothing */
    137   1.1     peter 
    138   1.1     peter 	/* Queue data */
    139   1.1     peter 	bus_space_write_4(sc->sc_iot, sc->sc_ioh, I2S_SADR, data);
    140   1.1     peter }
    141   1.1     peter 
    142   1.1     peter void
    143  1.13     isaki pxa2x0_i2s_setspeed(struct pxa2x0_i2s_softc *sc, u_int arg)
    144   1.1     peter {
    145   1.1     peter 	/*
    146   1.1     peter 	 * The available speeds are in the following table.
    147   1.1     peter 	 */
    148   1.1     peter 	static const struct speed_struct {
    149   1.1     peter 		int	speed;
    150   1.1     peter 		int	div;
    151   1.1     peter 	} speed_table[] = {
    152   1.1     peter 		{8000,	SADIV_513_25kHz},
    153   1.1     peter 		{11025,	SADIV_702_75kHz},
    154   1.1     peter 		{16000,	SADIV_1_026MHz},
    155   1.1     peter 		{22050,	SADIV_1_405MHz},
    156   1.1     peter 		{44100,	SADIV_2_836MHz},
    157   1.1     peter 		{48000,	SADIV_3_058MHz},
    158   1.1     peter 	};
    159   1.5    nonaka 	const int n = (int)__arraycount(speed_table);
    160   1.1     peter 	int selected = -1;
    161   1.1     peter 	int i;
    162   1.1     peter 
    163   1.1     peter 	if (arg < speed_table[0].speed)
    164   1.1     peter 		selected = 0;
    165   1.1     peter 	if (arg > speed_table[n - 1].speed)
    166   1.1     peter 		selected = n - 1;
    167   1.1     peter 
    168  1.13     isaki 	for (i = 0; selected == -1 && i < n; i++) {
    169   1.1     peter 		if (speed_table[i].speed == arg)
    170   1.1     peter 			selected = i;
    171   1.1     peter 	}
    172  1.13     isaki 	KASSERT(selected != -1);
    173   1.1     peter 
    174   1.1     peter 	sc->sc_sadiv = speed_table[selected].div;
    175   1.1     peter 	bus_space_write_4(sc->sc_iot, sc->sc_ioh, I2S_SADIV, sc->sc_sadiv);
    176   1.1     peter }
    177   1.1     peter 
    178   1.1     peter void *
    179  1.10  jmcneill pxa2x0_i2s_allocm(void *hdl, int direction, size_t size)
    180   1.1     peter {
    181   1.1     peter 	struct pxa2x0_i2s_softc *sc = hdl;
    182   1.1     peter 	struct pxa2x0_i2s_dma *p;
    183   1.1     peter 	struct dmac_xfer *dx;
    184   1.1     peter 	int error;
    185   1.1     peter 
    186  1.10  jmcneill 	p = kmem_alloc(sizeof(*p), KM_SLEEP);
    187   1.1     peter 
    188  1.10  jmcneill 	dx = pxa2x0_dmac_allocate_xfer();
    189   1.1     peter 	if (dx == NULL) {
    190   1.1     peter 		goto fail_alloc;
    191   1.1     peter 	}
    192   1.1     peter 	p->dx = dx;
    193   1.1     peter 
    194   1.1     peter 	p->size = size;
    195   1.1     peter 	if ((error = bus_dmamem_alloc(sc->sc_dmat, size, NBPG, 0, p->segs,
    196  1.10  jmcneill 	    I2S_N_SEGS, &p->nsegs, BUS_DMA_WAITOK)) != 0) {
    197   1.1     peter 		goto fail_xfer;
    198   1.1     peter 	}
    199   1.1     peter 
    200   1.1     peter 	if ((error = bus_dmamem_map(sc->sc_dmat, p->segs, p->nsegs, size,
    201  1.10  jmcneill 	    &p->addr, BUS_DMA_WAITOK | BUS_DMA_COHERENT)) != 0) {
    202   1.1     peter 		goto fail_map;
    203   1.1     peter 	}
    204   1.1     peter 
    205   1.1     peter 	if ((error = bus_dmamap_create(sc->sc_dmat, size, 1, size, 0,
    206  1.10  jmcneill 	    BUS_DMA_WAITOK, &p->map)) != 0) {
    207   1.1     peter 		goto fail_create;
    208   1.1     peter 	}
    209   1.1     peter 
    210   1.1     peter 	if ((error = bus_dmamap_load(sc->sc_dmat, p->map, p->addr, size, NULL,
    211  1.10  jmcneill 	    BUS_DMA_WAITOK)) != 0) {
    212   1.1     peter 		goto fail_load;
    213   1.1     peter 	}
    214   1.1     peter 
    215   1.1     peter 	dx->dx_cookie = sc;
    216   1.1     peter 	dx->dx_priority = DMAC_PRIORITY_NORMAL;
    217   1.8    nonaka 	dx->dx_dev_width = DMAC_DEV_WIDTH_4;
    218   1.8    nonaka 	dx->dx_burst_size = DMAC_BURST_SIZE_32;
    219   1.1     peter 
    220   1.1     peter 	p->next = sc->sc_dmas;
    221   1.1     peter 	sc->sc_dmas = p;
    222   1.1     peter 
    223   1.1     peter 	return p->addr;
    224   1.1     peter 
    225   1.1     peter fail_load:
    226   1.1     peter 	bus_dmamap_destroy(sc->sc_dmat, p->map);
    227   1.1     peter fail_create:
    228   1.1     peter 	bus_dmamem_unmap(sc->sc_dmat, p->addr, size);
    229   1.1     peter fail_map:
    230   1.1     peter 	bus_dmamem_free(sc->sc_dmat, p->segs, p->nsegs);
    231   1.1     peter fail_xfer:
    232   1.1     peter 	pxa2x0_dmac_free_xfer(dx);
    233   1.1     peter fail_alloc:
    234  1.10  jmcneill 	kmem_free(p, sizeof(*p));
    235   1.1     peter 	return NULL;
    236   1.1     peter }
    237   1.1     peter 
    238   1.1     peter void
    239  1.10  jmcneill pxa2x0_i2s_freem(void *hdl, void *ptr, size_t size)
    240   1.1     peter {
    241   1.1     peter 	struct pxa2x0_i2s_softc *sc = hdl;
    242   1.1     peter 	struct pxa2x0_i2s_dma **pp, *p;
    243   1.1     peter 
    244   1.8    nonaka 	for (pp = &sc->sc_dmas; (p = *pp) != NULL; pp = &p->next) {
    245   1.1     peter 		if (p->addr == ptr) {
    246   1.1     peter 			pxa2x0_dmac_abort_xfer(p->dx);
    247   1.1     peter 			pxa2x0_dmac_free_xfer(p->dx);
    248   1.1     peter 			p->segs[0].ds_len = p->size;	/* XXX */
    249   1.1     peter 			bus_dmamap_unload(sc->sc_dmat, p->map);
    250   1.1     peter 			bus_dmamap_destroy(sc->sc_dmat, p->map);
    251   1.1     peter 			bus_dmamem_unmap(sc->sc_dmat, p->addr, p->size);
    252   1.1     peter 			bus_dmamem_free(sc->sc_dmat, p->segs, p->nsegs);
    253   1.1     peter 
    254   1.1     peter 			*pp = p->next;
    255  1.10  jmcneill 			kmem_free(p, sizeof(*p));
    256   1.1     peter 			return;
    257   1.1     peter 		}
    258   1.1     peter 	}
    259   1.1     peter 	panic("pxa2x0_i2s_freem: trying to free unallocated memory");
    260   1.1     peter }
    261   1.1     peter 
    262   1.1     peter int
    263   1.1     peter pxa2x0_i2s_round_blocksize(void *hdl, int bs, int mode,
    264   1.1     peter     const struct audio_params *param)
    265   1.1     peter {
    266   1.1     peter 
    267   1.1     peter 	/* Enforce individual DMA block size limit */
    268   1.1     peter 	if (bs > DCMD_LENGTH_MASK)
    269   1.8    nonaka 		return (DCMD_LENGTH_MASK & ~0x07);
    270   1.1     peter 
    271   1.8    nonaka 	return (bs + 0x07) & ~0x07;	/* XXX: 64-bit multiples */
    272   1.1     peter }
    273   1.1     peter 
    274   1.1     peter size_t
    275   1.1     peter pxa2x0_i2s_round_buffersize(void *hdl, int direction, size_t bufsize)
    276   1.1     peter {
    277   1.1     peter 
    278   1.1     peter 	return bufsize;
    279   1.1     peter }
    280   1.1     peter 
    281   1.1     peter int
    282   1.1     peter pxa2x0_i2s_halt_output(void *hdl)
    283   1.1     peter {
    284   1.1     peter 	struct pxa2x0_i2s_softc *sc = hdl;
    285   1.1     peter 
    286   1.1     peter 	if (sc->sc_txdma) {
    287   1.1     peter 		pxa2x0_dmac_abort_xfer(sc->sc_txdma->dx);
    288   1.1     peter 		sc->sc_txdma = NULL;
    289   1.1     peter 	}
    290   1.1     peter 
    291   1.1     peter 	return 0;
    292   1.1     peter }
    293   1.1     peter 
    294   1.1     peter int
    295   1.1     peter pxa2x0_i2s_halt_input(void *hdl)
    296   1.1     peter {
    297   1.1     peter 	struct pxa2x0_i2s_softc *sc = hdl;
    298   1.1     peter 
    299   1.1     peter 	if (sc->sc_rxdma) {
    300   1.1     peter 		pxa2x0_dmac_abort_xfer(sc->sc_rxdma->dx);
    301   1.1     peter 		sc->sc_rxdma = NULL;
    302   1.1     peter 	}
    303   1.1     peter 
    304   1.1     peter 	return 0;
    305   1.1     peter }
    306   1.1     peter 
    307   1.1     peter int
    308   1.1     peter pxa2x0_i2s_start_output(void *hdl, void *block, int bsize,
    309   1.1     peter     void (*tx_func)(void *), void *tx_arg)
    310   1.1     peter {
    311   1.1     peter 	struct pxa2x0_i2s_softc *sc = hdl;
    312   1.1     peter 	struct pxa2x0_i2s_dma *p;
    313   1.1     peter 	struct dmac_xfer *dx;
    314   1.1     peter 
    315   1.1     peter 	if (sc->sc_txdma)
    316   1.1     peter 		return EBUSY;
    317   1.1     peter 
    318   1.1     peter 	/* Find mapping which contains block completely */
    319   1.8    nonaka 	for (p = sc->sc_dmas;
    320   1.8    nonaka 	     p != NULL &&
    321   1.8    nonaka 	       (((char*)block < (char *)p->addr) ||
    322   1.8    nonaka 	        ((char *)block + bsize > (char *)p->addr + p->size));
    323   1.8    nonaka 	     p = p->next) {
    324   1.1     peter 		continue;	/* Nothing */
    325   1.8    nonaka 	}
    326   1.1     peter 	if (p == NULL) {
    327   1.8    nonaka 		aprint_error("pxa2x0_i2s_start_output: "
    328  1.11    nonaka 		    "request with bad start address: %p, size: %d\n",
    329   1.8    nonaka 		    block, bsize);
    330   1.1     peter 		return ENXIO;
    331   1.1     peter 	}
    332   1.1     peter 	sc->sc_txdma = p;
    333   1.1     peter 
    334   1.8    nonaka 	p->segs[0].ds_addr = p->map->dm_segs[0].ds_addr +
    335   1.8    nonaka 	                         ((char *)block - (char *)p->addr);
    336   1.1     peter 	p->segs[0].ds_len = bsize;
    337   1.1     peter 
    338   1.1     peter 	dx = p->dx;
    339   1.1     peter 	dx->dx_done = pxa2x0_i2s_dmac_ointr;
    340   1.1     peter 	dx->dx_peripheral = DMAC_PERIPH_I2STX;
    341   1.1     peter 	dx->dx_flow = DMAC_FLOW_CTRL_DEST;
    342   1.1     peter 	dx->dx_loop_notify = DMAC_DONT_LOOP;
    343   1.2   thorpej 	dx->dx_desc[DMAC_DESC_SRC].xd_addr_hold = false;
    344   1.1     peter 	dx->dx_desc[DMAC_DESC_SRC].xd_nsegs = p->nsegs;
    345   1.1     peter 	dx->dx_desc[DMAC_DESC_SRC].xd_dma_segs = p->segs;
    346   1.2   thorpej 	dx->dx_desc[DMAC_DESC_DST].xd_addr_hold = true;
    347   1.1     peter 	dx->dx_desc[DMAC_DESC_DST].xd_nsegs = 1;
    348   1.1     peter 	dx->dx_desc[DMAC_DESC_DST].xd_dma_segs = &sc->sc_dr;
    349   1.1     peter 
    350   1.8    nonaka 	sc->sc_txfunc = tx_func;
    351   1.8    nonaka 	sc->sc_txarg = tx_arg;
    352   1.8    nonaka 
    353   1.1     peter 	/* Start DMA */
    354   1.8    nonaka 	return pxa2x0_dmac_start_xfer(dx);
    355   1.1     peter }
    356   1.1     peter 
    357   1.1     peter int
    358   1.1     peter pxa2x0_i2s_start_input(void *hdl, void *block, int bsize,
    359   1.1     peter     void (*rx_func)(void *), void *rx_arg)
    360   1.1     peter {
    361   1.1     peter 	struct pxa2x0_i2s_softc *sc = hdl;
    362   1.1     peter 	struct pxa2x0_i2s_dma *p;
    363   1.1     peter 	struct dmac_xfer *dx;
    364   1.1     peter 
    365   1.1     peter 	if (sc->sc_rxdma)
    366   1.1     peter 		return EBUSY;
    367   1.1     peter 
    368   1.1     peter 	/* Find mapping which contains block completely */
    369   1.8    nonaka 	for (p = sc->sc_dmas;
    370   1.8    nonaka 	     p != NULL &&
    371   1.8    nonaka 	       (((char*)block < (char *)p->addr) ||
    372   1.8    nonaka 	        ((char *)block + bsize > (char *)p->addr + p->size));
    373   1.8    nonaka 	     p = p->next) {
    374   1.1     peter 		continue;	/* Nothing */
    375   1.8    nonaka 	}
    376   1.1     peter 	if (p == NULL) {
    377   1.8    nonaka 		aprint_error("pxa2x0_i2s_start_input: "
    378  1.11    nonaka 		    "request with bad start address: %p, size: %d\n",
    379   1.8    nonaka 		    block, bsize);
    380   1.1     peter 		return ENXIO;
    381   1.1     peter 	}
    382   1.8    nonaka 	sc->sc_rxdma = p;
    383   1.1     peter 
    384   1.8    nonaka 	p->segs[0].ds_addr = p->map->dm_segs[0].ds_addr +
    385   1.8    nonaka 	                         ((char *)block - (char *)p->addr);
    386   1.1     peter 	p->segs[0].ds_len = bsize;
    387   1.1     peter 
    388   1.1     peter 	dx = p->dx;
    389   1.1     peter 	dx->dx_done = pxa2x0_i2s_dmac_iintr;
    390   1.1     peter 	dx->dx_peripheral = DMAC_PERIPH_I2SRX;
    391   1.1     peter 	dx->dx_flow = DMAC_FLOW_CTRL_SRC;
    392   1.1     peter 	dx->dx_loop_notify = DMAC_DONT_LOOP;
    393   1.2   thorpej 	dx->dx_desc[DMAC_DESC_SRC].xd_addr_hold = true;
    394   1.1     peter 	dx->dx_desc[DMAC_DESC_SRC].xd_nsegs = 1;
    395   1.1     peter 	dx->dx_desc[DMAC_DESC_SRC].xd_dma_segs = &sc->sc_dr;
    396   1.2   thorpej 	dx->dx_desc[DMAC_DESC_DST].xd_addr_hold = false;
    397   1.1     peter 	dx->dx_desc[DMAC_DESC_DST].xd_nsegs = p->nsegs;
    398   1.1     peter 	dx->dx_desc[DMAC_DESC_DST].xd_dma_segs = p->segs;
    399   1.1     peter 
    400   1.8    nonaka 	sc->sc_rxfunc = rx_func;
    401   1.8    nonaka 	sc->sc_rxarg = rx_arg;
    402   1.8    nonaka 
    403   1.1     peter 	/* Start DMA */
    404   1.8    nonaka 	return pxa2x0_dmac_start_xfer(dx);
    405   1.1     peter }
    406   1.1     peter 
    407   1.1     peter static void
    408   1.1     peter pxa2x0_i2s_dmac_ointr(struct dmac_xfer *dx, int status)
    409   1.1     peter {
    410   1.1     peter 	struct pxa2x0_i2s_softc *sc = dx->dx_cookie;
    411   1.1     peter 
    412   1.8    nonaka 	if (sc->sc_txdma == NULL) {
    413   1.1     peter 		panic("pxa2x_i2s_dmac_ointr: bad TX DMA descriptor!");
    414   1.1     peter 	}
    415   1.8    nonaka 	if (sc->sc_txdma->dx != dx) {
    416   1.1     peter 		panic("pxa2x_i2s_dmac_ointr: xfer mismatch!");
    417   1.1     peter 	}
    418   1.8    nonaka 	sc->sc_txdma = NULL;
    419   1.1     peter 
    420   1.1     peter 	if (status) {
    421   1.8    nonaka 		aprint_error("pxa2x0_i2s_dmac_ointr: "
    422   1.8    nonaka 		    "non-zero completion status %d\n", status);
    423   1.1     peter 	}
    424   1.1     peter 
    425  1.10  jmcneill 	mutex_spin_enter(sc->sc_intr_lock);
    426   1.1     peter 	(sc->sc_txfunc)(sc->sc_txarg);
    427  1.10  jmcneill 	mutex_spin_exit(sc->sc_intr_lock);
    428   1.1     peter }
    429   1.1     peter 
    430   1.1     peter static void
    431   1.1     peter pxa2x0_i2s_dmac_iintr(struct dmac_xfer *dx, int status)
    432   1.1     peter {
    433   1.1     peter 	struct pxa2x0_i2s_softc *sc = dx->dx_cookie;
    434   1.1     peter 
    435   1.8    nonaka 	if (sc->sc_rxdma == NULL) {
    436   1.1     peter 		panic("pxa2x_i2s_dmac_iintr: bad RX DMA descriptor!");
    437   1.1     peter 	}
    438   1.8    nonaka 	if (sc->sc_rxdma->dx != dx) {
    439   1.1     peter 		panic("pxa2x_i2s_dmac_iintr: xfer mismatch!");
    440   1.1     peter 	}
    441   1.8    nonaka 	sc->sc_rxdma = NULL;
    442   1.1     peter 
    443   1.1     peter 	if (status) {
    444   1.8    nonaka 		aprint_error("pxa2x0_i2s_dmac_iintr: "
    445   1.8    nonaka 		    "non-zero completion status %d\n", status);
    446   1.1     peter 	}
    447   1.1     peter 
    448   1.8    nonaka 
    449  1.10  jmcneill 	mutex_spin_enter(sc->sc_intr_lock);
    450   1.1     peter 	(sc->sc_rxfunc)(sc->sc_rxarg);
    451  1.10  jmcneill 	mutex_spin_exit(sc->sc_intr_lock);
    452   1.1     peter }
    453