Home | History | Annotate | Line # | Download | only in xscale
pxa2x0_i2s.c revision 1.10
      1  1.10  jmcneill /*	$NetBSD: pxa2x0_i2s.c,v 1.10 2011/11/23 23:07:29 jmcneill 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.10  jmcneill __KERNEL_RCSID(0, "$NetBSD: pxa2x0_i2s.c,v 1.10 2011/11/23 23:07:29 jmcneill 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.1     peter pxa2x0_i2s_setspeed(struct pxa2x0_i2s_softc *sc, u_int *argp)
    144   1.1     peter {
    145   1.1     peter 	/*
    146   1.1     peter 	 * The available speeds are in the following table.
    147   1.1     peter 	 * Keep the speeds in increasing order.
    148   1.1     peter 	 */
    149   1.1     peter 	static const struct speed_struct {
    150   1.1     peter 		int	speed;
    151   1.1     peter 		int	div;
    152   1.1     peter 	} speed_table[] = {
    153   1.1     peter 		{8000,	SADIV_513_25kHz},
    154   1.1     peter 		{11025,	SADIV_702_75kHz},
    155   1.1     peter 		{16000,	SADIV_1_026MHz},
    156   1.1     peter 		{22050,	SADIV_1_405MHz},
    157   1.1     peter 		{44100,	SADIV_2_836MHz},
    158   1.1     peter 		{48000,	SADIV_3_058MHz},
    159   1.1     peter 	};
    160   1.5    nonaka 	const int n = (int)__arraycount(speed_table);
    161   1.1     peter 	u_int arg = (u_int)*argp;
    162   1.1     peter 	int selected = -1;
    163   1.1     peter 	int i;
    164   1.1     peter 
    165   1.1     peter 	if (arg < speed_table[0].speed)
    166   1.1     peter 		selected = 0;
    167   1.1     peter 	if (arg > speed_table[n - 1].speed)
    168   1.1     peter 		selected = n - 1;
    169   1.1     peter 
    170   1.1     peter 	for (i = 1; selected == -1 && i < n; i++) {
    171   1.1     peter 		if (speed_table[i].speed == arg)
    172   1.1     peter 			selected = i;
    173   1.1     peter 		else if (speed_table[i].speed > arg) {
    174   1.1     peter 			int diff1, diff2;
    175   1.1     peter 
    176   1.1     peter 			diff1 = arg - speed_table[i - 1].speed;
    177   1.1     peter 			diff2 = speed_table[i].speed - arg;
    178   1.1     peter 			if (diff1 < diff2)
    179   1.1     peter 				selected = i - 1;
    180   1.1     peter 			else
    181   1.1     peter 				selected = i;
    182   1.1     peter 		}
    183   1.1     peter 	}
    184   1.1     peter 
    185   1.1     peter 	if (selected == -1)
    186   1.1     peter 		selected = 0;
    187   1.1     peter 
    188   1.1     peter 	*argp = speed_table[selected].speed;
    189   1.1     peter 
    190   1.1     peter 	sc->sc_sadiv = speed_table[selected].div;
    191   1.1     peter 	bus_space_write_4(sc->sc_iot, sc->sc_ioh, I2S_SADIV, sc->sc_sadiv);
    192   1.1     peter }
    193   1.1     peter 
    194   1.1     peter void *
    195  1.10  jmcneill pxa2x0_i2s_allocm(void *hdl, int direction, size_t size)
    196   1.1     peter {
    197   1.1     peter 	struct pxa2x0_i2s_softc *sc = hdl;
    198   1.1     peter 	struct pxa2x0_i2s_dma *p;
    199   1.1     peter 	struct dmac_xfer *dx;
    200   1.1     peter 	int error;
    201   1.1     peter 
    202  1.10  jmcneill 	p = kmem_alloc(sizeof(*p), KM_SLEEP);
    203   1.1     peter 	if (p == NULL)
    204   1.1     peter 		return NULL;
    205   1.1     peter 
    206  1.10  jmcneill 	dx = pxa2x0_dmac_allocate_xfer();
    207   1.1     peter 	if (dx == NULL) {
    208   1.1     peter 		goto fail_alloc;
    209   1.1     peter 	}
    210   1.1     peter 	p->dx = dx;
    211   1.1     peter 
    212   1.1     peter 	p->size = size;
    213   1.1     peter 	if ((error = bus_dmamem_alloc(sc->sc_dmat, size, NBPG, 0, p->segs,
    214  1.10  jmcneill 	    I2S_N_SEGS, &p->nsegs, BUS_DMA_WAITOK)) != 0) {
    215   1.1     peter 		goto fail_xfer;
    216   1.1     peter 	}
    217   1.1     peter 
    218   1.1     peter 	if ((error = bus_dmamem_map(sc->sc_dmat, p->segs, p->nsegs, size,
    219  1.10  jmcneill 	    &p->addr, BUS_DMA_WAITOK | BUS_DMA_COHERENT)) != 0) {
    220   1.1     peter 		goto fail_map;
    221   1.1     peter 	}
    222   1.1     peter 
    223   1.1     peter 	if ((error = bus_dmamap_create(sc->sc_dmat, size, 1, size, 0,
    224  1.10  jmcneill 	    BUS_DMA_WAITOK, &p->map)) != 0) {
    225   1.1     peter 		goto fail_create;
    226   1.1     peter 	}
    227   1.1     peter 
    228   1.1     peter 	if ((error = bus_dmamap_load(sc->sc_dmat, p->map, p->addr, size, NULL,
    229  1.10  jmcneill 	    BUS_DMA_WAITOK)) != 0) {
    230   1.1     peter 		goto fail_load;
    231   1.1     peter 	}
    232   1.1     peter 
    233   1.1     peter 	dx->dx_cookie = sc;
    234   1.1     peter 	dx->dx_priority = DMAC_PRIORITY_NORMAL;
    235   1.8    nonaka 	dx->dx_dev_width = DMAC_DEV_WIDTH_4;
    236   1.8    nonaka 	dx->dx_burst_size = DMAC_BURST_SIZE_32;
    237   1.1     peter 
    238   1.1     peter 	p->next = sc->sc_dmas;
    239   1.1     peter 	sc->sc_dmas = p;
    240   1.1     peter 
    241   1.1     peter 	return p->addr;
    242   1.1     peter 
    243   1.1     peter fail_load:
    244   1.1     peter 	bus_dmamap_destroy(sc->sc_dmat, p->map);
    245   1.1     peter fail_create:
    246   1.1     peter 	bus_dmamem_unmap(sc->sc_dmat, p->addr, size);
    247   1.1     peter fail_map:
    248   1.1     peter 	bus_dmamem_free(sc->sc_dmat, p->segs, p->nsegs);
    249   1.1     peter fail_xfer:
    250   1.1     peter 	pxa2x0_dmac_free_xfer(dx);
    251   1.1     peter fail_alloc:
    252  1.10  jmcneill 	kmem_free(p, sizeof(*p));
    253   1.1     peter 	return NULL;
    254   1.1     peter }
    255   1.1     peter 
    256   1.1     peter void
    257  1.10  jmcneill pxa2x0_i2s_freem(void *hdl, void *ptr, size_t size)
    258   1.1     peter {
    259   1.1     peter 	struct pxa2x0_i2s_softc *sc = hdl;
    260   1.1     peter 	struct pxa2x0_i2s_dma **pp, *p;
    261   1.1     peter 
    262   1.8    nonaka 	for (pp = &sc->sc_dmas; (p = *pp) != NULL; pp = &p->next) {
    263   1.1     peter 		if (p->addr == ptr) {
    264   1.1     peter 			pxa2x0_dmac_abort_xfer(p->dx);
    265   1.1     peter 			pxa2x0_dmac_free_xfer(p->dx);
    266   1.1     peter 			p->segs[0].ds_len = p->size;	/* XXX */
    267   1.1     peter 			bus_dmamap_unload(sc->sc_dmat, p->map);
    268   1.1     peter 			bus_dmamap_destroy(sc->sc_dmat, p->map);
    269   1.1     peter 			bus_dmamem_unmap(sc->sc_dmat, p->addr, p->size);
    270   1.1     peter 			bus_dmamem_free(sc->sc_dmat, p->segs, p->nsegs);
    271   1.1     peter 
    272   1.1     peter 			*pp = p->next;
    273  1.10  jmcneill 			kmem_free(p, sizeof(*p));
    274   1.1     peter 			return;
    275   1.1     peter 		}
    276   1.1     peter 	}
    277   1.1     peter 	panic("pxa2x0_i2s_freem: trying to free unallocated memory");
    278   1.1     peter }
    279   1.1     peter 
    280   1.1     peter paddr_t
    281   1.1     peter pxa2x0_i2s_mappage(void *hdl, void *mem, off_t off, int prot)
    282   1.1     peter {
    283   1.1     peter 	struct pxa2x0_i2s_softc *sc = hdl;
    284   1.1     peter 	struct pxa2x0_i2s_dma *p;
    285   1.1     peter 
    286   1.1     peter 	if (off < 0)
    287   1.1     peter 		return -1;
    288   1.1     peter 
    289   1.1     peter 	for (p = sc->sc_dmas; p && p->addr != mem; p = p->next)
    290   1.1     peter 		continue;
    291   1.1     peter 	if (p == NULL)
    292   1.1     peter 		return -1;
    293   1.1     peter 
    294   1.1     peter 	if (off > p->size)
    295   1.1     peter 		return -1;
    296   1.1     peter 
    297   1.1     peter 	return bus_dmamem_mmap(sc->sc_dmat, p->segs, p->nsegs, off, prot,
    298   1.1     peter 	    BUS_DMA_WAITOK);
    299   1.1     peter }
    300   1.1     peter 
    301   1.1     peter int
    302   1.1     peter pxa2x0_i2s_round_blocksize(void *hdl, int bs, int mode,
    303   1.1     peter     const struct audio_params *param)
    304   1.1     peter {
    305   1.1     peter 
    306   1.1     peter 	/* Enforce individual DMA block size limit */
    307   1.1     peter 	if (bs > DCMD_LENGTH_MASK)
    308   1.8    nonaka 		return (DCMD_LENGTH_MASK & ~0x07);
    309   1.1     peter 
    310   1.8    nonaka 	return (bs + 0x07) & ~0x07;	/* XXX: 64-bit multiples */
    311   1.1     peter }
    312   1.1     peter 
    313   1.1     peter size_t
    314   1.1     peter pxa2x0_i2s_round_buffersize(void *hdl, int direction, size_t bufsize)
    315   1.1     peter {
    316   1.1     peter 
    317   1.1     peter 	return bufsize;
    318   1.1     peter }
    319   1.1     peter 
    320   1.1     peter int
    321   1.1     peter pxa2x0_i2s_halt_output(void *hdl)
    322   1.1     peter {
    323   1.1     peter 	struct pxa2x0_i2s_softc *sc = hdl;
    324   1.1     peter 
    325  1.10  jmcneill 	mutex_spin_enter(sc->sc_intr_lock);
    326   1.1     peter 	if (sc->sc_txdma) {
    327   1.1     peter 		pxa2x0_dmac_abort_xfer(sc->sc_txdma->dx);
    328   1.1     peter 		sc->sc_txdma = NULL;
    329   1.1     peter 	}
    330  1.10  jmcneill 	mutex_spin_exit(sc->sc_intr_lock);
    331   1.1     peter 
    332   1.1     peter 	return 0;
    333   1.1     peter }
    334   1.1     peter 
    335   1.1     peter int
    336   1.1     peter pxa2x0_i2s_halt_input(void *hdl)
    337   1.1     peter {
    338   1.1     peter 	struct pxa2x0_i2s_softc *sc = hdl;
    339   1.1     peter 
    340  1.10  jmcneill 	mutex_spin_enter(sc->sc_intr_lock);
    341   1.1     peter 	if (sc->sc_rxdma) {
    342   1.1     peter 		pxa2x0_dmac_abort_xfer(sc->sc_rxdma->dx);
    343   1.1     peter 		sc->sc_rxdma = NULL;
    344   1.1     peter 	}
    345  1.10  jmcneill 	mutex_spin_exit(sc->sc_intr_lock);
    346   1.1     peter 
    347   1.1     peter 	return 0;
    348   1.1     peter }
    349   1.1     peter 
    350   1.1     peter int
    351   1.1     peter pxa2x0_i2s_start_output(void *hdl, void *block, int bsize,
    352   1.1     peter     void (*tx_func)(void *), void *tx_arg)
    353   1.1     peter {
    354   1.1     peter 	struct pxa2x0_i2s_softc *sc = hdl;
    355   1.1     peter 	struct pxa2x0_i2s_dma *p;
    356   1.1     peter 	struct dmac_xfer *dx;
    357   1.1     peter 
    358   1.1     peter 	if (sc->sc_txdma)
    359   1.1     peter 		return EBUSY;
    360   1.1     peter 
    361   1.1     peter 	/* Find mapping which contains block completely */
    362   1.8    nonaka 	for (p = sc->sc_dmas;
    363   1.8    nonaka 	     p != NULL &&
    364   1.8    nonaka 	       (((char*)block < (char *)p->addr) ||
    365   1.8    nonaka 	        ((char *)block + bsize > (char *)p->addr + p->size));
    366   1.8    nonaka 	     p = p->next) {
    367   1.1     peter 		continue;	/* Nothing */
    368   1.8    nonaka 	}
    369   1.1     peter 	if (p == NULL) {
    370   1.8    nonaka 		aprint_error("pxa2x0_i2s_start_output: "
    371   1.8    nonaka 		    "request with bad start address: %p, size: %d)\n",
    372   1.8    nonaka 		    block, bsize);
    373   1.1     peter 		return ENXIO;
    374   1.1     peter 	}
    375   1.1     peter 	sc->sc_txdma = p;
    376   1.1     peter 
    377   1.8    nonaka 	p->segs[0].ds_addr = p->map->dm_segs[0].ds_addr +
    378   1.8    nonaka 	                         ((char *)block - (char *)p->addr);
    379   1.1     peter 	p->segs[0].ds_len = bsize;
    380   1.1     peter 
    381   1.1     peter 	dx = p->dx;
    382   1.1     peter 	dx->dx_done = pxa2x0_i2s_dmac_ointr;
    383   1.1     peter 	dx->dx_peripheral = DMAC_PERIPH_I2STX;
    384   1.1     peter 	dx->dx_flow = DMAC_FLOW_CTRL_DEST;
    385   1.1     peter 	dx->dx_loop_notify = DMAC_DONT_LOOP;
    386   1.2   thorpej 	dx->dx_desc[DMAC_DESC_SRC].xd_addr_hold = false;
    387   1.1     peter 	dx->dx_desc[DMAC_DESC_SRC].xd_nsegs = p->nsegs;
    388   1.1     peter 	dx->dx_desc[DMAC_DESC_SRC].xd_dma_segs = p->segs;
    389   1.2   thorpej 	dx->dx_desc[DMAC_DESC_DST].xd_addr_hold = true;
    390   1.1     peter 	dx->dx_desc[DMAC_DESC_DST].xd_nsegs = 1;
    391   1.1     peter 	dx->dx_desc[DMAC_DESC_DST].xd_dma_segs = &sc->sc_dr;
    392   1.1     peter 
    393   1.8    nonaka 	sc->sc_txfunc = tx_func;
    394   1.8    nonaka 	sc->sc_txarg = tx_arg;
    395   1.8    nonaka 
    396   1.1     peter 	/* Start DMA */
    397   1.8    nonaka 	return pxa2x0_dmac_start_xfer(dx);
    398   1.1     peter }
    399   1.1     peter 
    400   1.1     peter int
    401   1.1     peter pxa2x0_i2s_start_input(void *hdl, void *block, int bsize,
    402   1.1     peter     void (*rx_func)(void *), void *rx_arg)
    403   1.1     peter {
    404   1.1     peter 	struct pxa2x0_i2s_softc *sc = hdl;
    405   1.1     peter 	struct pxa2x0_i2s_dma *p;
    406   1.1     peter 	struct dmac_xfer *dx;
    407   1.1     peter 
    408   1.1     peter 	if (sc->sc_rxdma)
    409   1.1     peter 		return EBUSY;
    410   1.1     peter 
    411   1.1     peter 	/* Find mapping which contains block completely */
    412   1.8    nonaka 	for (p = sc->sc_dmas;
    413   1.8    nonaka 	     p != NULL &&
    414   1.8    nonaka 	       (((char*)block < (char *)p->addr) ||
    415   1.8    nonaka 	        ((char *)block + bsize > (char *)p->addr + p->size));
    416   1.8    nonaka 	     p = p->next) {
    417   1.1     peter 		continue;	/* Nothing */
    418   1.8    nonaka 	}
    419   1.1     peter 	if (p == NULL) {
    420   1.8    nonaka 		aprint_error("pxa2x0_i2s_start_input: "
    421   1.8    nonaka 		    "request with bad start address: %p, size: %d)\n",
    422   1.8    nonaka 		    block, bsize);
    423   1.1     peter 		return ENXIO;
    424   1.1     peter 	}
    425   1.8    nonaka 	sc->sc_rxdma = p;
    426   1.1     peter 
    427   1.8    nonaka 	p->segs[0].ds_addr = p->map->dm_segs[0].ds_addr +
    428   1.8    nonaka 	                         ((char *)block - (char *)p->addr);
    429   1.1     peter 	p->segs[0].ds_len = bsize;
    430   1.1     peter 
    431   1.1     peter 	dx = p->dx;
    432   1.1     peter 	dx->dx_done = pxa2x0_i2s_dmac_iintr;
    433   1.1     peter 	dx->dx_peripheral = DMAC_PERIPH_I2SRX;
    434   1.1     peter 	dx->dx_flow = DMAC_FLOW_CTRL_SRC;
    435   1.1     peter 	dx->dx_loop_notify = DMAC_DONT_LOOP;
    436   1.2   thorpej 	dx->dx_desc[DMAC_DESC_SRC].xd_addr_hold = true;
    437   1.1     peter 	dx->dx_desc[DMAC_DESC_SRC].xd_nsegs = 1;
    438   1.1     peter 	dx->dx_desc[DMAC_DESC_SRC].xd_dma_segs = &sc->sc_dr;
    439   1.2   thorpej 	dx->dx_desc[DMAC_DESC_DST].xd_addr_hold = false;
    440   1.1     peter 	dx->dx_desc[DMAC_DESC_DST].xd_nsegs = p->nsegs;
    441   1.1     peter 	dx->dx_desc[DMAC_DESC_DST].xd_dma_segs = p->segs;
    442   1.1     peter 
    443   1.8    nonaka 	sc->sc_rxfunc = rx_func;
    444   1.8    nonaka 	sc->sc_rxarg = rx_arg;
    445   1.8    nonaka 
    446   1.1     peter 	/* Start DMA */
    447   1.8    nonaka 	return pxa2x0_dmac_start_xfer(dx);
    448   1.1     peter }
    449   1.1     peter 
    450   1.1     peter static void
    451   1.1     peter pxa2x0_i2s_dmac_ointr(struct dmac_xfer *dx, int status)
    452   1.1     peter {
    453   1.1     peter 	struct pxa2x0_i2s_softc *sc = dx->dx_cookie;
    454   1.1     peter 
    455   1.8    nonaka 	if (sc->sc_txdma == NULL) {
    456   1.1     peter 		panic("pxa2x_i2s_dmac_ointr: bad TX DMA descriptor!");
    457   1.1     peter 	}
    458   1.8    nonaka 	if (sc->sc_txdma->dx != dx) {
    459   1.1     peter 		panic("pxa2x_i2s_dmac_ointr: xfer mismatch!");
    460   1.1     peter 	}
    461   1.8    nonaka 	sc->sc_txdma = NULL;
    462   1.1     peter 
    463   1.1     peter 	if (status) {
    464   1.8    nonaka 		aprint_error("pxa2x0_i2s_dmac_ointr: "
    465   1.8    nonaka 		    "non-zero completion status %d\n", status);
    466   1.1     peter 	}
    467   1.1     peter 
    468  1.10  jmcneill 	mutex_spin_enter(sc->sc_intr_lock);
    469   1.1     peter 	(sc->sc_txfunc)(sc->sc_txarg);
    470  1.10  jmcneill 	mutex_spin_exit(sc->sc_intr_lock);
    471   1.1     peter }
    472   1.1     peter 
    473   1.1     peter static void
    474   1.1     peter pxa2x0_i2s_dmac_iintr(struct dmac_xfer *dx, int status)
    475   1.1     peter {
    476   1.1     peter 	struct pxa2x0_i2s_softc *sc = dx->dx_cookie;
    477   1.1     peter 
    478   1.8    nonaka 	if (sc->sc_rxdma == NULL) {
    479   1.1     peter 		panic("pxa2x_i2s_dmac_iintr: bad RX DMA descriptor!");
    480   1.1     peter 	}
    481   1.8    nonaka 	if (sc->sc_rxdma->dx != dx) {
    482   1.1     peter 		panic("pxa2x_i2s_dmac_iintr: xfer mismatch!");
    483   1.1     peter 	}
    484   1.8    nonaka 	sc->sc_rxdma = NULL;
    485   1.1     peter 
    486   1.1     peter 	if (status) {
    487   1.8    nonaka 		aprint_error("pxa2x0_i2s_dmac_iintr: "
    488   1.8    nonaka 		    "non-zero completion status %d\n", status);
    489   1.1     peter 	}
    490   1.1     peter 
    491   1.8    nonaka 
    492  1.10  jmcneill 	mutex_spin_enter(sc->sc_intr_lock);
    493   1.1     peter 	(sc->sc_rxfunc)(sc->sc_rxarg);
    494  1.10  jmcneill 	mutex_spin_exit(sc->sc_intr_lock);
    495   1.1     peter }
    496