Home | History | Annotate | Line # | Download | only in imx
imx23_digfilt.c revision 1.2
      1  1.2     isaki /* $Id: imx23_digfilt.c,v 1.2 2019/05/08 13:40:14 isaki Exp $ */
      2  1.1  jmcneill 
      3  1.1  jmcneill /*
      4  1.1  jmcneill  * Copyright (c) 2014 The NetBSD Foundation, Inc.
      5  1.1  jmcneill  * All rights reserved.
      6  1.1  jmcneill  *
      7  1.1  jmcneill  * This code is derived from software contributed to The NetBSD Foundation
      8  1.1  jmcneill  * by Petri Laakso.
      9  1.1  jmcneill  *
     10  1.1  jmcneill  * Redistribution and use in source and binary forms, with or without
     11  1.1  jmcneill  * modification, are permitted provided that the following conditions
     12  1.1  jmcneill  * are met:
     13  1.1  jmcneill  * 1. Redistributions of source code must retain the above copyright
     14  1.1  jmcneill  *    notice, this list of conditions and the following disclaimer.
     15  1.1  jmcneill  * 2. Redistributions in binary form must reproduce the above copyright
     16  1.1  jmcneill  *    notice, this list of conditions and the following disclaimer in the
     17  1.1  jmcneill  *    documentation and/or other materials provided with the distribution.
     18  1.1  jmcneill  *
     19  1.1  jmcneill  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
     20  1.1  jmcneill  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
     21  1.1  jmcneill  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
     22  1.1  jmcneill  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
     23  1.1  jmcneill  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
     24  1.1  jmcneill  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
     25  1.1  jmcneill  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
     26  1.1  jmcneill  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
     27  1.1  jmcneill  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
     28  1.1  jmcneill  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
     29  1.1  jmcneill  * POSSIBILITY OF SUCH DAMAGE.
     30  1.1  jmcneill  */
     31  1.1  jmcneill 
     32  1.1  jmcneill #include <sys/param.h>
     33  1.1  jmcneill #include <sys/cdefs.h>
     34  1.1  jmcneill #include <sys/types.h>
     35  1.1  jmcneill #include <sys/device.h>
     36  1.1  jmcneill #include <sys/errno.h>
     37  1.1  jmcneill #include <sys/systm.h>
     38  1.1  jmcneill #include <sys/bus.h>
     39  1.1  jmcneill #include <sys/mutex.h>
     40  1.1  jmcneill #include <sys/audioio.h>
     41  1.1  jmcneill #include <sys/mallocvar.h>
     42  1.2     isaki #include <dev/audio/audio_if.h>
     43  1.1  jmcneill #include <arm/imx/imx23_digfiltreg.h>
     44  1.1  jmcneill #include <arm/imx/imx23_rtcvar.h>
     45  1.1  jmcneill #include <arm/imx/imx23_clkctrlvar.h>
     46  1.1  jmcneill #include <arm/imx/imx23_apbdmavar.h>
     47  1.1  jmcneill #include <arm/imx/imx23_icollreg.h>
     48  1.1  jmcneill #include <arm/imx/imx23var.h>
     49  1.1  jmcneill 
     50  1.1  jmcneill #include <arm/pic/picvar.h>
     51  1.1  jmcneill 
     52  1.1  jmcneill /* Autoconf. */
     53  1.1  jmcneill static int digfilt_match(device_t, cfdata_t, void *);
     54  1.1  jmcneill static void digfilt_attach(device_t, device_t, void *);
     55  1.1  jmcneill static int digfilt_activate(device_t, enum devact);
     56  1.1  jmcneill 
     57  1.1  jmcneill /* Audio driver interface. */
     58  1.2     isaki static int digfilt_query_format(void *, audio_format_query_t *);
     59  1.2     isaki static int digfilt_set_format(void *, int,
     60  1.2     isaki     const audio_params_t *, const audio_params_t *,
     61  1.2     isaki     audio_filter_reg_t *, audio_filter_reg_t *);
     62  1.1  jmcneill static int digfilt_round_blocksize(void *, int, int, const audio_params_t *);
     63  1.1  jmcneill static int digfilt_init_output(void *, void *, int );
     64  1.1  jmcneill static int digfilt_start_output(void *, void *, int, void (*)(void *), void *);
     65  1.1  jmcneill static int digfilt_halt_output(void *);
     66  1.1  jmcneill static int digfilt_getdev(void *, struct audio_device *);
     67  1.1  jmcneill static int digfilt_set_port(void *, mixer_ctrl_t *);
     68  1.1  jmcneill static int digfilt_get_port(void *, mixer_ctrl_t *);
     69  1.1  jmcneill static int digfilt_query_devinfo(void *, mixer_devinfo_t *);
     70  1.1  jmcneill static void *digfilt_allocm(void *, int, size_t);
     71  1.1  jmcneill static void digfilt_freem(void *, void *, size_t);
     72  1.1  jmcneill static size_t digfilt_round_buffersize(void *, int, size_t);
     73  1.1  jmcneill static int digfilt_get_props(void *);
     74  1.1  jmcneill static void digfilt_get_locks(void *, kmutex_t **, kmutex_t **);
     75  1.1  jmcneill 
     76  1.1  jmcneill /* IRQs */
     77  1.1  jmcneill static int dac_error_intr(void *);
     78  1.1  jmcneill static int dac_dma_intr(void *);
     79  1.1  jmcneill 
     80  1.1  jmcneill struct digfilt_softc;
     81  1.1  jmcneill 
     82  1.1  jmcneill /* Audio out. */
     83  1.1  jmcneill static void *digfilt_ao_alloc_dmachain(void *, size_t);
     84  1.1  jmcneill static void digfilt_ao_apply_mutes(struct digfilt_softc *);
     85  1.1  jmcneill static void digfilt_ao_init(struct digfilt_softc *);
     86  1.1  jmcneill static void digfilt_ao_reset(struct digfilt_softc *);
     87  1.1  jmcneill static void digfilt_ao_set_rate(struct digfilt_softc *, int);
     88  1.1  jmcneill 
     89  1.1  jmcneill /* Audio in. */
     90  1.1  jmcneill #if 0
     91  1.1  jmcneill static void digfilt_ai_reset(struct digfilt_softc *);
     92  1.1  jmcneill #endif
     93  1.1  jmcneill 
     94  1.1  jmcneill #define DIGFILT_DMA_NSEGS 1
     95  1.1  jmcneill #define DIGFILT_BLOCKSIZE_MAX 4096
     96  1.1  jmcneill #define DIGFILT_BLOCKSIZE_ROUND 512
     97  1.1  jmcneill #define DIGFILT_DMA_CHAIN_LENGTH 3
     98  1.1  jmcneill #define DIGFILT_DMA_CHANNEL 1
     99  1.1  jmcneill #define DIGFILT_MUTE_DAC 1
    100  1.1  jmcneill #define DIGFILT_MUTE_HP 2
    101  1.1  jmcneill #define DIGFILT_MUTE_LINE 4
    102  1.1  jmcneill #define DIGFILT_SOFT_RST_LOOP 455	/* At least 1 us. */
    103  1.1  jmcneill 
    104  1.1  jmcneill #define AO_RD(sc, reg)							\
    105  1.1  jmcneill 	bus_space_read_4(sc->sc_iot, sc->sc_aohdl, (reg))
    106  1.1  jmcneill #define AO_WR(sc, reg, val)						\
    107  1.1  jmcneill 	bus_space_write_4(sc->sc_iot, sc->sc_aohdl, (reg), (val))
    108  1.1  jmcneill #define AI_RD(sc, reg)							\
    109  1.1  jmcneill 	bus_space_read_4(sc->sc_iot, sc->sc_aihdl, (reg))
    110  1.1  jmcneill #define AI_WR(sc, reg, val)						\
    111  1.1  jmcneill 	bus_space_write_4(sc->sc_iot, sc->sc_aihdl, (reg), (val))
    112  1.1  jmcneill 
    113  1.1  jmcneill struct digfilt_softc {
    114  1.1  jmcneill 	device_t sc_dev;
    115  1.1  jmcneill 	device_t sc_audiodev;
    116  1.1  jmcneill 	struct audio_format sc_format;
    117  1.1  jmcneill 	bus_space_handle_t sc_aihdl;
    118  1.1  jmcneill 	bus_space_handle_t sc_aohdl;
    119  1.1  jmcneill 	apbdma_softc_t sc_dmac;
    120  1.1  jmcneill 	bus_dma_tag_t sc_dmat;
    121  1.1  jmcneill 	bus_dmamap_t sc_dmamp;
    122  1.1  jmcneill 	bus_dmamap_t sc_c_dmamp;
    123  1.1  jmcneill 	bus_dma_segment_t sc_ds[DIGFILT_DMA_NSEGS];
    124  1.1  jmcneill 	bus_dma_segment_t sc_c_ds[DIGFILT_DMA_NSEGS];
    125  1.1  jmcneill 	bus_space_handle_t sc_hdl;
    126  1.1  jmcneill 	kmutex_t sc_intr_lock;
    127  1.1  jmcneill 	bus_space_tag_t	sc_iot;
    128  1.1  jmcneill 	kmutex_t sc_lock;
    129  1.1  jmcneill 	audio_params_t sc_pparam;
    130  1.1  jmcneill 	void *sc_buffer;
    131  1.1  jmcneill 	void *sc_dmachain;
    132  1.1  jmcneill 	void *sc_intarg;
    133  1.1  jmcneill 	void (*sc_intr)(void*);
    134  1.1  jmcneill 	uint8_t sc_mute;
    135  1.1  jmcneill 	uint8_t sc_cmd_index;
    136  1.1  jmcneill };
    137  1.1  jmcneill 
    138  1.1  jmcneill CFATTACH_DECL3_NEW(digfilt,
    139  1.1  jmcneill 	sizeof(struct digfilt_softc),
    140  1.1  jmcneill 	digfilt_match,
    141  1.1  jmcneill 	digfilt_attach,
    142  1.1  jmcneill 	NULL,
    143  1.1  jmcneill 	digfilt_activate,
    144  1.1  jmcneill 	NULL,
    145  1.1  jmcneill 	NULL,
    146  1.1  jmcneill 	0);
    147  1.1  jmcneill 
    148  1.1  jmcneill static const struct audio_hw_if digfilt_hw_if = {
    149  1.1  jmcneill 	.open = NULL,
    150  1.1  jmcneill 	.close = NULL,
    151  1.2     isaki 	.query_format = digfilt_query_format,
    152  1.2     isaki 	.set_format = digfilt_set_format,
    153  1.1  jmcneill 	.round_blocksize = digfilt_round_blocksize,
    154  1.1  jmcneill 	.commit_settings = NULL,
    155  1.1  jmcneill 	.init_output = digfilt_init_output,
    156  1.1  jmcneill 	.init_input = NULL,
    157  1.1  jmcneill 	.start_output = digfilt_start_output,
    158  1.1  jmcneill 	.start_input = NULL,
    159  1.1  jmcneill 	.halt_output = digfilt_halt_output,
    160  1.1  jmcneill 	.speaker_ctl = NULL,
    161  1.1  jmcneill 	.getdev = digfilt_getdev,
    162  1.1  jmcneill 	.set_port = digfilt_set_port,
    163  1.1  jmcneill 	.get_port = digfilt_get_port,
    164  1.1  jmcneill 	.query_devinfo = digfilt_query_devinfo,
    165  1.1  jmcneill 	.allocm = digfilt_allocm,
    166  1.1  jmcneill 	.freem = digfilt_freem,
    167  1.1  jmcneill 	.round_buffersize = digfilt_round_buffersize,
    168  1.1  jmcneill 	.get_props = digfilt_get_props,
    169  1.1  jmcneill 	.trigger_output = NULL,
    170  1.1  jmcneill 	.trigger_input = NULL,
    171  1.1  jmcneill 	.dev_ioctl = NULL,
    172  1.1  jmcneill 	.get_locks = digfilt_get_locks
    173  1.1  jmcneill };
    174  1.1  jmcneill 
    175  1.1  jmcneill enum {
    176  1.1  jmcneill 	DIGFILT_OUTPUT_CLASS,
    177  1.1  jmcneill 	DIGFILT_OUTPUT_DAC_VOLUME,
    178  1.1  jmcneill 	DIGFILT_OUTPUT_DAC_MUTE,
    179  1.1  jmcneill 	DIGFILT_OUTPUT_HP_VOLUME,
    180  1.1  jmcneill 	DIGFILT_OUTPUT_HP_MUTE,
    181  1.1  jmcneill 	DIGFILT_OUTPUT_LINE_VOLUME,
    182  1.1  jmcneill 	DIGFILT_OUTPUT_LINE_MUTE,
    183  1.1  jmcneill 	DIGFILT_ENUM_LAST
    184  1.1  jmcneill };
    185  1.1  jmcneill 
    186  1.1  jmcneill static int
    187  1.1  jmcneill digfilt_match(device_t parent, cfdata_t match, void *aux)
    188  1.1  jmcneill {
    189  1.1  jmcneill 	struct apb_attach_args *aa = aux;
    190  1.1  jmcneill 
    191  1.1  jmcneill 	if (aa->aa_addr == HW_DIGFILT_BASE && aa->aa_size == HW_DIGFILT_SIZE)
    192  1.1  jmcneill 		return 1;
    193  1.1  jmcneill 	else
    194  1.1  jmcneill 		return 0;
    195  1.1  jmcneill }
    196  1.1  jmcneill 
    197  1.1  jmcneill static void
    198  1.1  jmcneill digfilt_attach(device_t parent, device_t self, void *aux)
    199  1.1  jmcneill {
    200  1.1  jmcneill 	struct apb_softc *sc_parent = device_private(parent);
    201  1.1  jmcneill 	struct digfilt_softc *sc = device_private(self);
    202  1.1  jmcneill 	struct apb_attach_args *aa = aux;
    203  1.1  jmcneill 	static int digfilt_attached = 0;
    204  1.1  jmcneill 	int error;
    205  1.1  jmcneill 	uint32_t v;
    206  1.1  jmcneill 	void *intr;
    207  1.1  jmcneill 
    208  1.1  jmcneill 	sc->sc_dev = self;
    209  1.1  jmcneill 	sc->sc_iot = aa->aa_iot;
    210  1.1  jmcneill 	sc->sc_dmat = aa->aa_dmat;
    211  1.1  jmcneill 
    212  1.1  jmcneill 	/* This driver requires DMA functionality from the bus.
    213  1.1  jmcneill 	 * Parent bus passes handle to the DMA controller instance. */
    214  1.1  jmcneill 	if (sc_parent->dmac == NULL) {
    215  1.1  jmcneill 		aprint_error_dev(sc->sc_dev, "DMA functionality missing\n");
    216  1.1  jmcneill 		return;
    217  1.1  jmcneill 	}
    218  1.1  jmcneill 	sc->sc_dmac = device_private(sc_parent->dmac);
    219  1.1  jmcneill 
    220  1.1  jmcneill 	if (aa->aa_addr == HW_DIGFILT_BASE && digfilt_attached) {
    221  1.1  jmcneill 		aprint_error_dev(sc->sc_dev, "DIGFILT already attached\n");
    222  1.1  jmcneill 		return;
    223  1.1  jmcneill 	}
    224  1.1  jmcneill 
    225  1.1  jmcneill 	/* Allocate DMA for audio buffer. */
    226  1.1  jmcneill 	error = bus_dmamap_create(sc->sc_dmat, MAXPHYS, DIGFILT_DMA_NSEGS,
    227  1.1  jmcneill 		MAXPHYS, 0, BUS_DMA_NOWAIT|BUS_DMA_ALLOCNOW, &sc->sc_dmamp);
    228  1.1  jmcneill 	if (error) {
    229  1.1  jmcneill 		aprint_error_dev(sc->sc_dev,
    230  1.1  jmcneill 		    "Unable to allocate DMA handle\n");
    231  1.1  jmcneill 		return;
    232  1.1  jmcneill 	}
    233  1.1  jmcneill 
    234  1.1  jmcneill 	/* Allocate for DMA chain. */
    235  1.1  jmcneill 	error = bus_dmamap_create(sc->sc_dmat, MAXPHYS, DIGFILT_DMA_NSEGS,
    236  1.1  jmcneill 		MAXPHYS, 0, BUS_DMA_NOWAIT|BUS_DMA_ALLOCNOW, &sc->sc_c_dmamp);
    237  1.1  jmcneill 	if (error) {
    238  1.1  jmcneill 		aprint_error_dev(sc->sc_dev,
    239  1.1  jmcneill 		    "Unable to allocate DMA handle\n");
    240  1.1  jmcneill 		return;
    241  1.1  jmcneill 	}
    242  1.1  jmcneill 
    243  1.1  jmcneill 	/* Map DIGFILT bus space. */
    244  1.1  jmcneill 	if (bus_space_map(sc->sc_iot, HW_DIGFILT_BASE, HW_DIGFILT_SIZE, 0,
    245  1.1  jmcneill 	    &sc->sc_hdl)) {
    246  1.1  jmcneill 		aprint_error_dev(sc->sc_dev,
    247  1.1  jmcneill 		    "Unable to map DIGFILT bus space\n");
    248  1.1  jmcneill 		return;
    249  1.1  jmcneill 	}
    250  1.1  jmcneill 
    251  1.1  jmcneill 	/* Map AUDIOOUT subregion from parent bus space. */
    252  1.1  jmcneill 	if (bus_space_subregion(sc->sc_iot, sc->sc_hdl,
    253  1.1  jmcneill 	    (HW_AUDIOOUT_BASE - HW_DIGFILT_BASE), HW_AUDIOOUT_SIZE,
    254  1.1  jmcneill 	    &sc->sc_aohdl)) {
    255  1.1  jmcneill 		aprint_error_dev(sc->sc_dev,
    256  1.1  jmcneill 			"Unable to submap AUDIOOUT bus space\n");
    257  1.1  jmcneill 		return;
    258  1.1  jmcneill 	}
    259  1.1  jmcneill 
    260  1.1  jmcneill 	/* Map AUDIOIN subregion from parent bus space. */
    261  1.1  jmcneill 	if (bus_space_subregion(sc->sc_iot, sc->sc_hdl,
    262  1.1  jmcneill 	    (HW_AUDIOIN_BASE - HW_DIGFILT_BASE), HW_AUDIOIN_SIZE,
    263  1.1  jmcneill 	    &sc->sc_aihdl)) {
    264  1.1  jmcneill 		aprint_error_dev(sc->sc_dev,
    265  1.1  jmcneill 			"Unable to submap AUDIOIN bus space\n");
    266  1.1  jmcneill 		return;
    267  1.1  jmcneill 	}
    268  1.1  jmcneill 
    269  1.1  jmcneill 	/* Enable clocks to the DIGFILT block. */
    270  1.1  jmcneill 	clkctrl_en_filtclk();
    271  1.1  jmcneill 	delay(10);
    272  1.1  jmcneill 
    273  1.1  jmcneill 	digfilt_ao_reset(sc);	/* Reset AUDIOOUT. */
    274  1.1  jmcneill 	/* Not yet: digfilt_ai_reset(sc); */
    275  1.1  jmcneill 
    276  1.1  jmcneill 	v = AO_RD(sc, HW_AUDIOOUT_VERSION);
    277  1.1  jmcneill 	aprint_normal(": DIGFILT Block v%" __PRIuBIT ".%" __PRIuBIT
    278  1.1  jmcneill 		".%" __PRIuBIT "\n",
    279  1.1  jmcneill 		__SHIFTOUT(v, HW_AUDIOOUT_VERSION_MAJOR),
    280  1.1  jmcneill 		__SHIFTOUT(v, HW_AUDIOOUT_VERSION_MINOR),
    281  1.1  jmcneill 		__SHIFTOUT(v, HW_AUDIOOUT_VERSION_STEP));
    282  1.1  jmcneill 
    283  1.1  jmcneill 	digfilt_ao_init(sc);
    284  1.1  jmcneill 	digfilt_ao_set_rate(sc, 44100);	/* Default sample rate 44.1 kHz. */
    285  1.1  jmcneill 
    286  1.1  jmcneill 	mutex_init(&sc->sc_lock, MUTEX_DEFAULT, IPL_NONE);
    287  1.1  jmcneill 	mutex_init(&sc->sc_intr_lock, MUTEX_DEFAULT, IPL_SCHED);
    288  1.1  jmcneill 
    289  1.1  jmcneill 	/* HW supported formats. */
    290  1.1  jmcneill 	sc->sc_format.mode = AUMODE_PLAY|AUMODE_RECORD;
    291  1.1  jmcneill 	sc->sc_format.encoding = AUDIO_ENCODING_SLINEAR_LE;
    292  1.1  jmcneill 	sc->sc_format.validbits = 16;
    293  1.1  jmcneill 	sc->sc_format.precision = 16;
    294  1.1  jmcneill 	sc->sc_format.channels = 2;
    295  1.1  jmcneill 	sc->sc_format.channel_mask = AUFMT_STEREO;
    296  1.1  jmcneill 	sc->sc_format.frequency_type = 8;
    297  1.1  jmcneill 	sc->sc_format.frequency[0] = 8000;
    298  1.1  jmcneill 	sc->sc_format.frequency[1] = 11025;
    299  1.1  jmcneill 	sc->sc_format.frequency[2] = 12000;
    300  1.1  jmcneill 	sc->sc_format.frequency[3] = 16000;
    301  1.1  jmcneill 	sc->sc_format.frequency[4] = 22050;
    302  1.1  jmcneill 	sc->sc_format.frequency[5] = 24000;
    303  1.1  jmcneill 	sc->sc_format.frequency[6] = 32000;
    304  1.1  jmcneill 	sc->sc_format.frequency[7] = 44100;
    305  1.1  jmcneill 
    306  1.1  jmcneill 	sc->sc_audiodev = audio_attach_mi(&digfilt_hw_if, sc, sc->sc_dev);
    307  1.1  jmcneill 
    308  1.1  jmcneill 	/* Default mutes. */
    309  1.1  jmcneill 	sc->sc_mute = DIGFILT_MUTE_LINE;
    310  1.1  jmcneill 	digfilt_ao_apply_mutes(sc);
    311  1.1  jmcneill 
    312  1.1  jmcneill 	/* Allocate DMA safe memory for the DMA chain. */
    313  1.1  jmcneill 	sc->sc_dmachain = digfilt_ao_alloc_dmachain(sc,
    314  1.1  jmcneill 		sizeof(struct apbdma_command) * DIGFILT_DMA_CHAIN_LENGTH);
    315  1.1  jmcneill 	if (sc->sc_dmachain == NULL) {
    316  1.1  jmcneill 		aprint_error_dev(self, "digfilt_ao_alloc_dmachain failed\n");
    317  1.1  jmcneill 		return;
    318  1.1  jmcneill 	}
    319  1.1  jmcneill 
    320  1.1  jmcneill 	intr = intr_establish(IRQ_DAC_DMA, IPL_SCHED, IST_LEVEL, dac_dma_intr,
    321  1.1  jmcneill 			sc);
    322  1.1  jmcneill 	if (intr == NULL) {
    323  1.1  jmcneill 		aprint_error_dev(sc->sc_dev,
    324  1.1  jmcneill 			"Unable to establish IRQ for DAC_DMA\n");
    325  1.1  jmcneill 		return;
    326  1.1  jmcneill 	}
    327  1.1  jmcneill 
    328  1.1  jmcneill 	intr = intr_establish(IRQ_DAC_ERROR, IPL_SCHED, IST_LEVEL,
    329  1.1  jmcneill 		dac_error_intr, sc);
    330  1.1  jmcneill 	if (intr == NULL) {
    331  1.1  jmcneill 		aprint_error_dev(sc->sc_dev,
    332  1.1  jmcneill 			"Unable to establish IRQ for DAC_ERROR\n");
    333  1.1  jmcneill 		return;
    334  1.1  jmcneill 	}
    335  1.1  jmcneill 
    336  1.1  jmcneill 	/* Initialize DMA channel. */
    337  1.1  jmcneill 	apbdma_chan_init(sc->sc_dmac, DIGFILT_DMA_CHANNEL);
    338  1.1  jmcneill 
    339  1.1  jmcneill 	digfilt_attached = 1;
    340  1.1  jmcneill 
    341  1.1  jmcneill 	return;
    342  1.1  jmcneill }
    343  1.1  jmcneill 
    344  1.1  jmcneill static int
    345  1.1  jmcneill digfilt_activate(device_t self, enum devact act)
    346  1.1  jmcneill {
    347  1.1  jmcneill 	return EOPNOTSUPP;
    348  1.1  jmcneill }
    349  1.1  jmcneill 
    350  1.1  jmcneill static int
    351  1.2     isaki digfilt_query_format(void *priv, audio_format_query_t *afp)
    352  1.1  jmcneill {
    353  1.1  jmcneill 	struct digfilt_softc *sc = priv;
    354  1.1  jmcneill 
    355  1.2     isaki 	return audio_query_format(&sc->sc_format, 1, afp);
    356  1.1  jmcneill }
    357  1.1  jmcneill 
    358  1.1  jmcneill static int
    359  1.2     isaki digfilt_set_format(void *priv, int setmode,
    360  1.2     isaki     const audio_params_t *play, const audio_params_t *rec,
    361  1.2     isaki     audio_filter_reg_t *pfil, audio_filter_reg_t *rfil)
    362  1.1  jmcneill {
    363  1.1  jmcneill 	struct digfilt_softc *sc = priv;
    364  1.1  jmcneill 
    365  1.2     isaki 	if ((setmode & AUMODE_PLAY)) {
    366  1.1  jmcneill 		/* At this point bitrate should be figured out. */
    367  1.1  jmcneill 		digfilt_ao_set_rate(sc, sc->sc_pparam.sample_rate);
    368  1.1  jmcneill 	}
    369  1.1  jmcneill 
    370  1.1  jmcneill 	return 0;
    371  1.1  jmcneill }
    372  1.1  jmcneill 
    373  1.1  jmcneill static int
    374  1.1  jmcneill digfilt_round_blocksize(void *priv, int bs, int mode,
    375  1.1  jmcneill const audio_params_t *param)
    376  1.1  jmcneill {
    377  1.1  jmcneill 	int blocksize;
    378  1.1  jmcneill 
    379  1.1  jmcneill 	if (bs > DIGFILT_BLOCKSIZE_MAX)
    380  1.1  jmcneill 		blocksize = DIGFILT_BLOCKSIZE_MAX;
    381  1.1  jmcneill 	else
    382  1.1  jmcneill 		blocksize = bs & ~(DIGFILT_BLOCKSIZE_ROUND-1);
    383  1.1  jmcneill 
    384  1.1  jmcneill 	return blocksize;
    385  1.1  jmcneill }
    386  1.1  jmcneill 
    387  1.1  jmcneill static int
    388  1.1  jmcneill digfilt_init_output(void *priv, void *buffer, int size)
    389  1.1  jmcneill {
    390  1.1  jmcneill 	struct digfilt_softc *sc = priv;
    391  1.1  jmcneill 	apbdma_command_t dma_cmd;
    392  1.1  jmcneill 	int i;
    393  1.1  jmcneill 	dma_cmd = sc->sc_dmachain;
    394  1.1  jmcneill 	sc->sc_cmd_index = 0;
    395  1.1  jmcneill 
    396  1.1  jmcneill 	/*
    397  1.1  jmcneill 	 * Build circular DMA command chain template for later use.
    398  1.1  jmcneill 	 */
    399  1.1  jmcneill 	for (i = 0; i < DIGFILT_DMA_CHAIN_LENGTH; i++) {
    400  1.1  jmcneill 		/* Last entry loops back to first. */
    401  1.1  jmcneill 		if (i == DIGFILT_DMA_CHAIN_LENGTH - 1)
    402  1.1  jmcneill 			dma_cmd[i].next = (void *)(sc->sc_c_dmamp->dm_segs[0].ds_addr);
    403  1.1  jmcneill 		else
    404  1.1  jmcneill 			dma_cmd[i].next = (void *)(sc->sc_c_dmamp->dm_segs[0].ds_addr + (sizeof(struct apbdma_command) * (1 + i)));
    405  1.1  jmcneill 
    406  1.1  jmcneill 		dma_cmd[i].control = __SHIFTIN(DIGFILT_BLOCKSIZE_MAX,  APBDMA_CMD_XFER_COUNT) |
    407  1.1  jmcneill 		    __SHIFTIN(1, APBDMA_CMD_CMDPIOWORDS) |
    408  1.1  jmcneill 		    APBDMA_CMD_SEMAPHORE |
    409  1.1  jmcneill 		    APBDMA_CMD_IRQONCMPLT |
    410  1.1  jmcneill 		    APBDMA_CMD_CHAIN |
    411  1.1  jmcneill 		    __SHIFTIN(APBDMA_CMD_DMA_READ, APBDMA_CMD_COMMAND);
    412  1.1  jmcneill 
    413  1.1  jmcneill 		dma_cmd[i].buffer = (void *)(sc->sc_c_dmamp->dm_segs[0].ds_addr);
    414  1.1  jmcneill 
    415  1.1  jmcneill 		dma_cmd[i].pio_words[0] = HW_AUDIOOUT_CTRL_WORD_LENGTH |
    416  1.1  jmcneill 		    HW_AUDIOOUT_CTRL_FIFO_ERROR_IRQ_EN |
    417  1.1  jmcneill 		    HW_AUDIOOUT_CTRL_RUN;
    418  1.1  jmcneill 
    419  1.1  jmcneill 	}
    420  1.1  jmcneill 
    421  1.1  jmcneill 	apbdma_chan_set_chain(sc->sc_dmac, DIGFILT_DMA_CHANNEL, sc->sc_c_dmamp);
    422  1.1  jmcneill 
    423  1.1  jmcneill 	return 0;
    424  1.1  jmcneill }
    425  1.1  jmcneill 
    426  1.1  jmcneill static int
    427  1.1  jmcneill digfilt_start_output(void *priv, void *start, int bs, void (*intr)(void*), void *intarg)
    428  1.1  jmcneill {
    429  1.1  jmcneill 	struct digfilt_softc *sc = priv;
    430  1.1  jmcneill 	apbdma_command_t dma_cmd;
    431  1.1  jmcneill 	bus_addr_t offset;
    432  1.1  jmcneill 
    433  1.1  jmcneill 	sc->sc_intr = intr;
    434  1.1  jmcneill 	sc->sc_intarg = intarg;
    435  1.1  jmcneill 	dma_cmd = sc->sc_dmachain;
    436  1.1  jmcneill 
    437  1.1  jmcneill 	offset = (bus_addr_t)start - (bus_addr_t)sc->sc_buffer;
    438  1.1  jmcneill 
    439  1.1  jmcneill 	dma_cmd[sc->sc_cmd_index].buffer =
    440  1.1  jmcneill 	    (void *)((bus_addr_t)sc->sc_dmamp->dm_segs[0].ds_addr + offset);
    441  1.1  jmcneill 
    442  1.1  jmcneill 	bus_dmamap_sync(sc->sc_dmat, sc->sc_dmamp, offset, bs, BUS_DMASYNC_PREWRITE);
    443  1.1  jmcneill 	bus_dmamap_sync(sc->sc_dmat, sc->sc_c_dmamp,
    444  1.1  jmcneill 	    sizeof(struct apbdma_command) * sc->sc_cmd_index, sizeof(struct apbdma_command), BUS_DMASYNC_PREWRITE);
    445  1.1  jmcneill 
    446  1.1  jmcneill 	sc->sc_cmd_index++;
    447  1.1  jmcneill 	if (sc->sc_cmd_index > DIGFILT_DMA_CHAIN_LENGTH - 1)
    448  1.1  jmcneill 		sc->sc_cmd_index = 0;
    449  1.1  jmcneill 
    450  1.1  jmcneill 	apbdma_run(sc->sc_dmac, DIGFILT_DMA_CHANNEL);
    451  1.1  jmcneill 
    452  1.1  jmcneill 	return 0;
    453  1.1  jmcneill }
    454  1.1  jmcneill 
    455  1.1  jmcneill static int
    456  1.1  jmcneill digfilt_halt_output(void *priv)
    457  1.1  jmcneill {
    458  1.2     isaki 	struct digfilt_softc *sc = priv;
    459  1.2     isaki 
    460  1.2     isaki 	sc->sc_cmd_index = 0;
    461  1.1  jmcneill 	return 0;
    462  1.1  jmcneill }
    463  1.1  jmcneill 
    464  1.1  jmcneill static int
    465  1.1  jmcneill digfilt_getdev(void *priv, struct audio_device *ad)
    466  1.1  jmcneill {
    467  1.1  jmcneill 	struct digfilt_softc *sc = priv;
    468  1.1  jmcneill 
    469  1.1  jmcneill 	strncpy(ad->name, device_xname(sc->sc_dev), MAX_AUDIO_DEV_LEN);
    470  1.1  jmcneill 	strncpy(ad->version, "", MAX_AUDIO_DEV_LEN);
    471  1.1  jmcneill 	strncpy(ad->config, "", MAX_AUDIO_DEV_LEN);
    472  1.1  jmcneill 
    473  1.1  jmcneill 	return 0;
    474  1.1  jmcneill }
    475  1.1  jmcneill 
    476  1.1  jmcneill static int
    477  1.1  jmcneill digfilt_set_port(void *priv, mixer_ctrl_t *mc)
    478  1.1  jmcneill {
    479  1.1  jmcneill 	struct digfilt_softc *sc = priv;
    480  1.1  jmcneill 	uint32_t val;
    481  1.1  jmcneill 	uint8_t nvol;
    482  1.1  jmcneill 
    483  1.1  jmcneill 	switch (mc->dev) {
    484  1.1  jmcneill 	case DIGFILT_OUTPUT_DAC_VOLUME:
    485  1.1  jmcneill 		val = AO_RD(sc, HW_AUDIOOUT_DACVOLUME);
    486  1.1  jmcneill 		val &= ~(HW_AUDIOOUT_DACVOLUME_VOLUME_LEFT |
    487  1.1  jmcneill 		    HW_AUDIOOUT_DACVOLUME_VOLUME_RIGHT);
    488  1.1  jmcneill 
    489  1.1  jmcneill 		/* DAC volume field is 8 bits. */
    490  1.1  jmcneill 		nvol = mc->un.value.level[AUDIO_MIXER_LEVEL_LEFT];
    491  1.1  jmcneill 		if (nvol > 0xff)
    492  1.1  jmcneill 			nvol = 0xff;
    493  1.1  jmcneill 
    494  1.1  jmcneill 		val |= __SHIFTIN(nvol, HW_AUDIOOUT_DACVOLUME_VOLUME_LEFT);
    495  1.1  jmcneill 
    496  1.1  jmcneill 		nvol = mc->un.value.level[AUDIO_MIXER_LEVEL_RIGHT];
    497  1.1  jmcneill 		if (nvol > 0xff)
    498  1.1  jmcneill 			nvol = 0xff;
    499  1.1  jmcneill 
    500  1.1  jmcneill 		val |= __SHIFTIN(nvol, HW_AUDIOOUT_DACVOLUME_VOLUME_RIGHT);
    501  1.1  jmcneill 
    502  1.1  jmcneill 		AO_WR(sc, HW_AUDIOOUT_DACVOLUME, val);
    503  1.1  jmcneill 
    504  1.1  jmcneill 		return 0;
    505  1.1  jmcneill 
    506  1.1  jmcneill 	case DIGFILT_OUTPUT_HP_VOLUME:
    507  1.1  jmcneill 		val = AO_RD(sc, HW_AUDIOOUT_HPVOL);
    508  1.1  jmcneill 		val &= ~(HW_AUDIOOUT_HPVOL_VOL_LEFT |
    509  1.1  jmcneill 		    HW_AUDIOOUT_HPVOL_VOL_RIGHT);
    510  1.1  jmcneill 
    511  1.1  jmcneill 		/* HP volume field is 7 bits. */
    512  1.1  jmcneill 		nvol = mc->un.value.level[AUDIO_MIXER_LEVEL_LEFT];
    513  1.1  jmcneill 		if (nvol > 0x7f)
    514  1.1  jmcneill 			nvol = 0x7f;
    515  1.1  jmcneill 
    516  1.1  jmcneill 		nvol = ~nvol;
    517  1.1  jmcneill 		val |= __SHIFTIN(nvol, HW_AUDIOOUT_HPVOL_VOL_LEFT);
    518  1.1  jmcneill 
    519  1.1  jmcneill 		nvol = mc->un.value.level[AUDIO_MIXER_LEVEL_RIGHT];
    520  1.1  jmcneill 		if (nvol > 0x7f)
    521  1.1  jmcneill 			nvol = 0x7f;
    522  1.1  jmcneill 
    523  1.1  jmcneill 		nvol = ~nvol;
    524  1.1  jmcneill 		val |= __SHIFTIN(nvol, HW_AUDIOOUT_HPVOL_VOL_RIGHT);
    525  1.1  jmcneill 
    526  1.1  jmcneill 		AO_WR(sc, HW_AUDIOOUT_HPVOL, val);
    527  1.1  jmcneill 
    528  1.1  jmcneill 		return 0;
    529  1.1  jmcneill 
    530  1.1  jmcneill 	case DIGFILT_OUTPUT_LINE_VOLUME:
    531  1.1  jmcneill 		return 1;
    532  1.1  jmcneill 
    533  1.1  jmcneill 	case DIGFILT_OUTPUT_DAC_MUTE:
    534  1.1  jmcneill 		if (mc->un.ord)
    535  1.1  jmcneill 			sc->sc_mute |= DIGFILT_MUTE_DAC;
    536  1.1  jmcneill 		else
    537  1.1  jmcneill 			sc->sc_mute &= ~DIGFILT_MUTE_DAC;
    538  1.1  jmcneill 
    539  1.1  jmcneill 		digfilt_ao_apply_mutes(sc);
    540  1.1  jmcneill 
    541  1.1  jmcneill 		return 0;
    542  1.1  jmcneill 
    543  1.1  jmcneill 	case DIGFILT_OUTPUT_HP_MUTE:
    544  1.1  jmcneill 		if (mc->un.ord)
    545  1.1  jmcneill 			sc->sc_mute |= DIGFILT_MUTE_HP;
    546  1.1  jmcneill 		else
    547  1.1  jmcneill 			sc->sc_mute &= ~DIGFILT_MUTE_HP;
    548  1.1  jmcneill 
    549  1.1  jmcneill 		digfilt_ao_apply_mutes(sc);
    550  1.1  jmcneill 
    551  1.1  jmcneill 		return 0;
    552  1.1  jmcneill 
    553  1.1  jmcneill 	case DIGFILT_OUTPUT_LINE_MUTE:
    554  1.1  jmcneill 		if (mc->un.ord)
    555  1.1  jmcneill 			sc->sc_mute |= DIGFILT_MUTE_LINE;
    556  1.1  jmcneill 		else
    557  1.1  jmcneill 			sc->sc_mute &= ~DIGFILT_MUTE_LINE;
    558  1.1  jmcneill 
    559  1.1  jmcneill 		digfilt_ao_apply_mutes(sc);
    560  1.1  jmcneill 
    561  1.1  jmcneill 		return 0;
    562  1.1  jmcneill 	}
    563  1.1  jmcneill 
    564  1.1  jmcneill 	return ENXIO;
    565  1.1  jmcneill }
    566  1.1  jmcneill 
    567  1.1  jmcneill static int
    568  1.1  jmcneill digfilt_get_port(void *priv, mixer_ctrl_t *mc)
    569  1.1  jmcneill {
    570  1.1  jmcneill 	struct digfilt_softc *sc = priv;
    571  1.1  jmcneill 	uint32_t val;
    572  1.1  jmcneill 	uint8_t nvol;
    573  1.1  jmcneill 
    574  1.1  jmcneill         switch (mc->dev) {
    575  1.1  jmcneill         case DIGFILT_OUTPUT_DAC_VOLUME:
    576  1.1  jmcneill 		val = AO_RD(sc, HW_AUDIOOUT_DACVOLUME);
    577  1.1  jmcneill 
    578  1.1  jmcneill 		nvol = __SHIFTOUT(val, HW_AUDIOOUT_DACVOLUME_VOLUME_LEFT);
    579  1.1  jmcneill                 mc->un.value.level[AUDIO_MIXER_LEVEL_LEFT] = nvol;
    580  1.1  jmcneill 
    581  1.1  jmcneill 		nvol = __SHIFTOUT(val, HW_AUDIOOUT_DACVOLUME_VOLUME_RIGHT);
    582  1.1  jmcneill                 mc->un.value.level[AUDIO_MIXER_LEVEL_RIGHT] = nvol;
    583  1.1  jmcneill 
    584  1.1  jmcneill                 return 0;
    585  1.1  jmcneill 
    586  1.1  jmcneill         case DIGFILT_OUTPUT_HP_VOLUME:
    587  1.1  jmcneill 		val = AO_RD(sc, HW_AUDIOOUT_HPVOL);
    588  1.1  jmcneill 
    589  1.1  jmcneill 		nvol = __SHIFTOUT(val, HW_AUDIOOUT_HPVOL_VOL_LEFT);
    590  1.1  jmcneill 		mc->un.value.level[AUDIO_MIXER_LEVEL_LEFT] = ~nvol & 0x7f;
    591  1.1  jmcneill 
    592  1.1  jmcneill 		nvol = __SHIFTOUT(val, HW_AUDIOOUT_HPVOL_VOL_RIGHT);
    593  1.1  jmcneill 		mc->un.value.level[AUDIO_MIXER_LEVEL_RIGHT] = ~nvol & 0x7f;
    594  1.1  jmcneill 
    595  1.1  jmcneill 		return 0;
    596  1.1  jmcneill 
    597  1.1  jmcneill 	case DIGFILT_OUTPUT_LINE_VOLUME:
    598  1.1  jmcneill 		mc->un.value.level[AUDIO_MIXER_LEVEL_LEFT] = 255;
    599  1.1  jmcneill 		mc->un.value.level[AUDIO_MIXER_LEVEL_RIGHT] = 255;
    600  1.1  jmcneill 
    601  1.1  jmcneill 		return 0;
    602  1.1  jmcneill 
    603  1.1  jmcneill 	case DIGFILT_OUTPUT_DAC_MUTE:
    604  1.1  jmcneill 		val = AO_RD(sc, HW_AUDIOOUT_DACVOLUME);
    605  1.1  jmcneill 
    606  1.1  jmcneill 		mc->un.ord = (val & (HW_AUDIOOUT_DACVOLUME_MUTE_LEFT |
    607  1.1  jmcneill 		    HW_AUDIOOUT_DACVOLUME_MUTE_RIGHT)) ? 1 : 0;
    608  1.1  jmcneill 
    609  1.1  jmcneill 		return 0;
    610  1.1  jmcneill 
    611  1.1  jmcneill 	case DIGFILT_OUTPUT_HP_MUTE:
    612  1.1  jmcneill 		val = AO_RD(sc, HW_AUDIOOUT_HPVOL);
    613  1.1  jmcneill 
    614  1.1  jmcneill 		mc->un.ord = (val & HW_AUDIOOUT_HPVOL_MUTE) ? 1 : 0;
    615  1.1  jmcneill 
    616  1.1  jmcneill 		return 0;
    617  1.1  jmcneill 
    618  1.1  jmcneill 	case DIGFILT_OUTPUT_LINE_MUTE:
    619  1.1  jmcneill 		val = AO_RD(sc, HW_AUDIOOUT_SPEAKERCTRL);
    620  1.1  jmcneill 
    621  1.1  jmcneill 		mc->un.ord = (val & HW_AUDIOOUT_SPEAKERCTRL_MUTE) ? 1 : 0;
    622  1.1  jmcneill 
    623  1.1  jmcneill 		return 0;
    624  1.1  jmcneill         }
    625  1.1  jmcneill 
    626  1.1  jmcneill         return ENXIO;
    627  1.1  jmcneill }
    628  1.1  jmcneill 
    629  1.1  jmcneill static int
    630  1.1  jmcneill digfilt_query_devinfo(void *priv, mixer_devinfo_t *di)
    631  1.1  jmcneill {
    632  1.1  jmcneill 
    633  1.1  jmcneill 	switch (di->index) {
    634  1.1  jmcneill 	case DIGFILT_OUTPUT_CLASS:
    635  1.1  jmcneill 		di->mixer_class = DIGFILT_OUTPUT_CLASS;
    636  1.1  jmcneill 		strcpy(di->label.name, AudioCoutputs);
    637  1.1  jmcneill 		di->type = AUDIO_MIXER_CLASS;
    638  1.1  jmcneill 		di->next = di->prev = AUDIO_MIXER_LAST;
    639  1.1  jmcneill 		return 0;
    640  1.1  jmcneill 
    641  1.1  jmcneill 	case DIGFILT_OUTPUT_DAC_VOLUME:
    642  1.1  jmcneill 		di->mixer_class = DIGFILT_OUTPUT_CLASS;
    643  1.1  jmcneill 		strcpy(di->label.name, AudioNdac);
    644  1.1  jmcneill 		di->type = AUDIO_MIXER_VALUE;
    645  1.1  jmcneill 		di->prev = AUDIO_MIXER_LAST;
    646  1.1  jmcneill 		di->next = DIGFILT_OUTPUT_DAC_MUTE;
    647  1.1  jmcneill 		di->un.v.num_channels = 2;
    648  1.1  jmcneill 		strcpy(di->un.v.units.name, AudioNvolume);
    649  1.1  jmcneill 		return 0;
    650  1.1  jmcneill 
    651  1.1  jmcneill 	case DIGFILT_OUTPUT_DAC_MUTE:
    652  1.1  jmcneill 		di->mixer_class = DIGFILT_OUTPUT_CLASS;
    653  1.1  jmcneill 		di->type = AUDIO_MIXER_ENUM;
    654  1.1  jmcneill 		di->prev = DIGFILT_OUTPUT_DAC_VOLUME;
    655  1.1  jmcneill 		di->next = AUDIO_MIXER_LAST;
    656  1.1  jmcneill mute:
    657  1.1  jmcneill 		strlcpy(di->label.name, AudioNmute, sizeof(di->label.name));
    658  1.1  jmcneill 		di->un.e.num_mem = 2;
    659  1.1  jmcneill 		strlcpy(di->un.e.member[0].label.name, AudioNon,
    660  1.1  jmcneill 		    sizeof(di->un.e.member[0].label.name));
    661  1.1  jmcneill 		di->un.e.member[0].ord = 1;
    662  1.1  jmcneill 		strlcpy(di->un.e.member[1].label.name, AudioNoff,
    663  1.1  jmcneill 		    sizeof(di->un.e.member[1].label.name));
    664  1.1  jmcneill 		di->un.e.member[1].ord = 0;
    665  1.1  jmcneill 		return 0;
    666  1.1  jmcneill 
    667  1.1  jmcneill 	case DIGFILT_OUTPUT_HP_VOLUME:
    668  1.1  jmcneill 		di->mixer_class = DIGFILT_OUTPUT_CLASS;
    669  1.1  jmcneill 		strcpy(di->label.name, AudioNheadphone);
    670  1.1  jmcneill 		di->type = AUDIO_MIXER_VALUE;
    671  1.1  jmcneill 		di->prev = AUDIO_MIXER_LAST;
    672  1.1  jmcneill 		di->next = DIGFILT_OUTPUT_HP_MUTE;
    673  1.1  jmcneill 		di->un.v.num_channels = 2;
    674  1.1  jmcneill 		strcpy(di->un.v.units.name, AudioNvolume);
    675  1.1  jmcneill 		return 0;
    676  1.1  jmcneill 
    677  1.1  jmcneill 	case DIGFILT_OUTPUT_HP_MUTE:
    678  1.1  jmcneill 		di->mixer_class = DIGFILT_OUTPUT_CLASS;
    679  1.1  jmcneill 		di->type = AUDIO_MIXER_ENUM;
    680  1.1  jmcneill 		di->prev = DIGFILT_OUTPUT_HP_VOLUME;
    681  1.1  jmcneill 		di->next = AUDIO_MIXER_LAST;
    682  1.1  jmcneill 		goto mute;
    683  1.1  jmcneill 
    684  1.1  jmcneill 	case DIGFILT_OUTPUT_LINE_VOLUME:
    685  1.1  jmcneill 		di->mixer_class = DIGFILT_OUTPUT_CLASS;
    686  1.1  jmcneill 		strcpy(di->label.name, AudioNline);
    687  1.1  jmcneill 		di->type = AUDIO_MIXER_VALUE;
    688  1.1  jmcneill 		di->prev = AUDIO_MIXER_LAST;
    689  1.1  jmcneill 		di->next = DIGFILT_OUTPUT_LINE_MUTE;
    690  1.1  jmcneill 		di->un.v.num_channels = 2;
    691  1.1  jmcneill 		strcpy(di->un.v.units.name, AudioNvolume);
    692  1.1  jmcneill 		return 0;
    693  1.1  jmcneill 
    694  1.1  jmcneill 	case DIGFILT_OUTPUT_LINE_MUTE:
    695  1.1  jmcneill 		di->mixer_class = DIGFILT_OUTPUT_CLASS;
    696  1.1  jmcneill 		di->type = AUDIO_MIXER_ENUM;
    697  1.1  jmcneill 		di->prev = DIGFILT_OUTPUT_LINE_VOLUME;
    698  1.1  jmcneill 		di->next = AUDIO_MIXER_LAST;
    699  1.1  jmcneill 		goto mute;
    700  1.1  jmcneill 	}
    701  1.1  jmcneill 
    702  1.1  jmcneill         return ENXIO;
    703  1.1  jmcneill }
    704  1.1  jmcneill 
    705  1.1  jmcneill static void *
    706  1.1  jmcneill digfilt_allocm(void *priv, int direction, size_t size)
    707  1.1  jmcneill {
    708  1.1  jmcneill 	struct digfilt_softc *sc = priv;
    709  1.1  jmcneill 	int rsegs;
    710  1.1  jmcneill 	int error;
    711  1.1  jmcneill 
    712  1.1  jmcneill 	sc->sc_buffer = NULL;
    713  1.1  jmcneill 
    714  1.1  jmcneill 	/*
    715  1.1  jmcneill 	 * AUMODE_PLAY is DMA from memory to device.
    716  1.1  jmcneill 	 */
    717  1.1  jmcneill 	if (direction != AUMODE_PLAY)
    718  1.1  jmcneill 		return NULL;
    719  1.1  jmcneill 
    720  1.1  jmcneill 	error = bus_dmamem_alloc(sc->sc_dmat, size, PAGE_SIZE, 0, &sc->sc_ds[0], DIGFILT_DMA_NSEGS, &rsegs, BUS_DMA_NOWAIT);
    721  1.1  jmcneill 	if (error) {
    722  1.1  jmcneill 		aprint_error_dev(sc->sc_dev,
    723  1.1  jmcneill 		    "bus_dmamem_alloc: %d\n", error);
    724  1.1  jmcneill 		goto out;
    725  1.1  jmcneill 	}
    726  1.1  jmcneill 
    727  1.1  jmcneill 	error = bus_dmamem_map(sc->sc_dmat, sc->sc_ds, DIGFILT_DMA_NSEGS, size, &sc->sc_buffer, BUS_DMA_NOWAIT);
    728  1.1  jmcneill 	if (error) {
    729  1.1  jmcneill 		aprint_error_dev(sc->sc_dev, "bus_dmamem_map: %d\n", error);
    730  1.1  jmcneill 		goto dmamem_free;
    731  1.1  jmcneill 	}
    732  1.1  jmcneill 
    733  1.1  jmcneill 	/* After load sc_dmamp is valid. */
    734  1.1  jmcneill 	error = bus_dmamap_load(sc->sc_dmat, sc->sc_dmamp, sc->sc_buffer, size, NULL, BUS_DMA_NOWAIT|BUS_DMA_WRITE);
    735  1.1  jmcneill 	if (error) {
    736  1.1  jmcneill 		aprint_error_dev(sc->sc_dev, "bus_dmamap_load: %d\n", error);
    737  1.1  jmcneill 		goto dmamem_unmap;
    738  1.1  jmcneill 	}
    739  1.1  jmcneill 
    740  1.1  jmcneill 	memset(sc->sc_buffer, 0x00, size);
    741  1.1  jmcneill 
    742  1.1  jmcneill 	return sc->sc_buffer;
    743  1.1  jmcneill 
    744  1.1  jmcneill dmamem_unmap:
    745  1.1  jmcneill 	bus_dmamem_unmap(sc->sc_dmat, sc->sc_buffer, size);
    746  1.1  jmcneill dmamem_free:
    747  1.1  jmcneill 	bus_dmamem_free(sc->sc_dmat, sc->sc_ds, DIGFILT_DMA_NSEGS);
    748  1.1  jmcneill out:
    749  1.1  jmcneill 	return NULL;
    750  1.1  jmcneill }
    751  1.1  jmcneill 
    752  1.1  jmcneill static void
    753  1.1  jmcneill digfilt_freem(void *priv, void *kvap, size_t size)
    754  1.1  jmcneill {
    755  1.1  jmcneill 	struct digfilt_softc *sc = priv;
    756  1.1  jmcneill 
    757  1.1  jmcneill 	bus_dmamem_unmap(sc->sc_dmat, kvap, size);
    758  1.1  jmcneill 	bus_dmamem_free(sc->sc_dmat, sc->sc_ds, DIGFILT_DMA_NSEGS);
    759  1.1  jmcneill 
    760  1.1  jmcneill 	return;
    761  1.1  jmcneill }
    762  1.1  jmcneill 
    763  1.1  jmcneill static size_t
    764  1.1  jmcneill digfilt_round_buffersize(void *hdl, int direction, size_t bs)
    765  1.1  jmcneill {
    766  1.1  jmcneill 	int bufsize;
    767  1.1  jmcneill 
    768  1.1  jmcneill 	bufsize = bs & ~(DIGFILT_BLOCKSIZE_MAX-1);
    769  1.1  jmcneill 
    770  1.1  jmcneill 	return bufsize;
    771  1.1  jmcneill }
    772  1.1  jmcneill 
    773  1.1  jmcneill static int
    774  1.1  jmcneill digfilt_get_props(void *sc)
    775  1.1  jmcneill {
    776  1.1  jmcneill 	return (AUDIO_PROP_PLAYBACK | AUDIO_PROP_INDEPENDENT);
    777  1.1  jmcneill }
    778  1.1  jmcneill 
    779  1.1  jmcneill static void
    780  1.1  jmcneill digfilt_get_locks(void *priv, kmutex_t **intr, kmutex_t **thread)
    781  1.1  jmcneill {
    782  1.1  jmcneill 	struct digfilt_softc *sc = priv;
    783  1.1  jmcneill 
    784  1.1  jmcneill 	*intr = &sc->sc_intr_lock;
    785  1.1  jmcneill 	*thread = &sc->sc_lock;
    786  1.1  jmcneill 
    787  1.1  jmcneill 	return;
    788  1.1  jmcneill }
    789  1.1  jmcneill 
    790  1.1  jmcneill /*
    791  1.1  jmcneill  * IRQ for DAC error.
    792  1.1  jmcneill  */
    793  1.1  jmcneill static int
    794  1.1  jmcneill dac_error_intr(void *arg)
    795  1.1  jmcneill {
    796  1.1  jmcneill 	struct digfilt_softc *sc = arg;
    797  1.1  jmcneill 	AO_WR(sc, HW_AUDIOOUT_CTRL_CLR, HW_AUDIOOUT_CTRL_FIFO_UNDERFLOW_IRQ);
    798  1.1  jmcneill 	return 1;
    799  1.1  jmcneill }
    800  1.1  jmcneill 
    801  1.1  jmcneill /*
    802  1.1  jmcneill  * IRQ from DMA.
    803  1.1  jmcneill  */
    804  1.1  jmcneill static int
    805  1.1  jmcneill dac_dma_intr(void *arg)
    806  1.1  jmcneill {
    807  1.1  jmcneill 	struct digfilt_softc *sc = arg;
    808  1.1  jmcneill 
    809  1.1  jmcneill 	unsigned int dma_err;
    810  1.1  jmcneill 
    811  1.1  jmcneill 	mutex_enter(&sc->sc_intr_lock);
    812  1.1  jmcneill 
    813  1.1  jmcneill 	dma_err = apbdma_intr_status(sc->sc_dmac, DIGFILT_DMA_CHANNEL);
    814  1.1  jmcneill 
    815  1.1  jmcneill 	if (dma_err) {
    816  1.1  jmcneill 		apbdma_ack_error_intr(sc->sc_dmac, DIGFILT_DMA_CHANNEL);
    817  1.1  jmcneill 	}
    818  1.1  jmcneill 
    819  1.1  jmcneill 	sc->sc_intr(sc->sc_intarg);
    820  1.1  jmcneill 	apbdma_ack_intr(sc->sc_dmac, DIGFILT_DMA_CHANNEL);
    821  1.1  jmcneill 
    822  1.1  jmcneill 	mutex_exit(&sc->sc_intr_lock);
    823  1.1  jmcneill 
    824  1.1  jmcneill 	/* Return 1 to acknowledge IRQ. */
    825  1.1  jmcneill 	return 1;
    826  1.1  jmcneill }
    827  1.1  jmcneill 
    828  1.1  jmcneill static void *
    829  1.1  jmcneill digfilt_ao_alloc_dmachain(void *priv, size_t size)
    830  1.1  jmcneill {
    831  1.1  jmcneill 	struct digfilt_softc *sc = priv;
    832  1.1  jmcneill 	int rsegs;
    833  1.1  jmcneill 	int error;
    834  1.1  jmcneill 	void *kvap;
    835  1.1  jmcneill 
    836  1.1  jmcneill 	kvap = NULL;
    837  1.1  jmcneill 
    838  1.1  jmcneill 	error = bus_dmamem_alloc(sc->sc_dmat, size, PAGE_SIZE, 0, &sc->sc_c_ds[0], DIGFILT_DMA_NSEGS, &rsegs, BUS_DMA_NOWAIT);
    839  1.1  jmcneill 	if (error) {
    840  1.1  jmcneill 		aprint_error_dev(sc->sc_dev,
    841  1.1  jmcneill 		    "bus_dmamem_alloc: %d\n", error);
    842  1.1  jmcneill 		goto out;
    843  1.1  jmcneill 	}
    844  1.1  jmcneill 
    845  1.1  jmcneill 	error = bus_dmamem_map(sc->sc_dmat, sc->sc_c_ds, DIGFILT_DMA_NSEGS, size, &kvap, BUS_DMA_NOWAIT);
    846  1.1  jmcneill 	if (error) {
    847  1.1  jmcneill 		aprint_error_dev(sc->sc_dev, "bus_dmamem_map: %d\n", error);
    848  1.1  jmcneill 		goto dmamem_free;
    849  1.1  jmcneill 	}
    850  1.1  jmcneill 
    851  1.1  jmcneill 	/* After load sc_c_dmamp is valid. */
    852  1.1  jmcneill 	error = bus_dmamap_load(sc->sc_dmat, sc->sc_c_dmamp, kvap, size, NULL, BUS_DMA_NOWAIT|BUS_DMA_WRITE);
    853  1.1  jmcneill 	if (error) {
    854  1.1  jmcneill 		aprint_error_dev(sc->sc_dev, "bus_dmamap_load: %d\n", error);
    855  1.1  jmcneill 		goto dmamem_unmap;
    856  1.1  jmcneill 	}
    857  1.1  jmcneill 
    858  1.1  jmcneill 	memset(kvap, 0x00, size);
    859  1.1  jmcneill 
    860  1.1  jmcneill 	return kvap;
    861  1.1  jmcneill 
    862  1.1  jmcneill dmamem_unmap:
    863  1.1  jmcneill 	bus_dmamem_unmap(sc->sc_dmat, kvap, size);
    864  1.1  jmcneill dmamem_free:
    865  1.1  jmcneill 	bus_dmamem_free(sc->sc_dmat, sc->sc_c_ds, DIGFILT_DMA_NSEGS);
    866  1.1  jmcneill out:
    867  1.1  jmcneill 
    868  1.1  jmcneill 	return kvap;
    869  1.1  jmcneill }
    870  1.1  jmcneill 
    871  1.1  jmcneill static void
    872  1.1  jmcneill digfilt_ao_apply_mutes(struct digfilt_softc *sc)
    873  1.1  jmcneill {
    874  1.1  jmcneill 
    875  1.1  jmcneill 	/* DAC. */
    876  1.1  jmcneill 	if (sc->sc_mute & DIGFILT_MUTE_DAC) {
    877  1.1  jmcneill 		AO_WR(sc, HW_AUDIOOUT_DACVOLUME_SET,
    878  1.1  jmcneill 		    HW_AUDIOOUT_DACVOLUME_MUTE_LEFT |
    879  1.1  jmcneill 		    HW_AUDIOOUT_DACVOLUME_MUTE_RIGHT
    880  1.1  jmcneill 		);
    881  1.1  jmcneill 
    882  1.1  jmcneill 	} else {
    883  1.1  jmcneill 		AO_WR(sc, HW_AUDIOOUT_DACVOLUME_CLR,
    884  1.1  jmcneill 		    HW_AUDIOOUT_DACVOLUME_MUTE_LEFT |
    885  1.1  jmcneill 		    HW_AUDIOOUT_DACVOLUME_MUTE_RIGHT
    886  1.1  jmcneill 		);
    887  1.1  jmcneill 	}
    888  1.1  jmcneill 
    889  1.1  jmcneill 	/* HP. */
    890  1.1  jmcneill 	if (sc->sc_mute & DIGFILT_MUTE_HP)
    891  1.1  jmcneill 		AO_WR(sc, HW_AUDIOOUT_HPVOL_SET, HW_AUDIOOUT_HPVOL_MUTE);
    892  1.1  jmcneill 	else
    893  1.1  jmcneill 		AO_WR(sc, HW_AUDIOOUT_HPVOL_CLR, HW_AUDIOOUT_HPVOL_MUTE);
    894  1.1  jmcneill 
    895  1.1  jmcneill 	/* Line. */
    896  1.1  jmcneill 	if (sc->sc_mute & DIGFILT_MUTE_LINE)
    897  1.1  jmcneill 		AO_WR(sc, HW_AUDIOOUT_SPEAKERCTRL_SET,
    898  1.1  jmcneill 		    HW_AUDIOOUT_SPEAKERCTRL_MUTE);
    899  1.1  jmcneill 	else
    900  1.1  jmcneill 		AO_WR(sc, HW_AUDIOOUT_SPEAKERCTRL_CLR,
    901  1.1  jmcneill 		    HW_AUDIOOUT_SPEAKERCTRL_MUTE);
    902  1.1  jmcneill 
    903  1.1  jmcneill 	return;
    904  1.1  jmcneill }
    905  1.1  jmcneill 
    906  1.1  jmcneill /*
    907  1.1  jmcneill  * Initialize audio system.
    908  1.1  jmcneill  */
    909  1.1  jmcneill static void
    910  1.1  jmcneill digfilt_ao_init(struct digfilt_softc *sc)
    911  1.1  jmcneill {
    912  1.1  jmcneill 
    913  1.1  jmcneill 	AO_WR(sc, HW_AUDIOOUT_ANACLKCTRL_CLR, HW_AUDIOOUT_ANACLKCTRL_CLKGATE);
    914  1.1  jmcneill 	while ((AO_RD(sc, HW_AUDIOOUT_ANACLKCTRL) &
    915  1.1  jmcneill 	    HW_AUDIOOUT_ANACLKCTRL_CLKGATE));
    916  1.1  jmcneill 
    917  1.1  jmcneill 	/* Hold headphones outputs at ground. */
    918  1.1  jmcneill 	AO_WR(sc, HW_AUDIOOUT_ANACTRL_SET, HW_AUDIOOUT_ANACTRL_HP_HOLD_GND);
    919  1.1  jmcneill 
    920  1.1  jmcneill 	/* Remove pulldown resistors on headphone outputs. */
    921  1.1  jmcneill 	rtc_release_gnd(1);
    922  1.1  jmcneill 
    923  1.1  jmcneill 	/* Release pull down */
    924  1.1  jmcneill 	AO_WR(sc, HW_AUDIOOUT_ANACTRL_CLR, HW_AUDIOOUT_ANACTRL_HP_HOLD_GND);
    925  1.1  jmcneill 
    926  1.1  jmcneill 	AO_WR(sc, HW_AUDIOOUT_ANACTRL_SET, HW_AUDIOOUT_ANACTRL_HP_CLASSAB);
    927  1.1  jmcneill 
    928  1.1  jmcneill 	/* Enable Modules. */
    929  1.1  jmcneill 	AO_WR(sc, HW_AUDIOOUT_PWRDN_CLR,
    930  1.1  jmcneill 	    HW_AUDIOOUT_PWRDN_RIGHT_ADC |
    931  1.1  jmcneill 	    HW_AUDIOOUT_PWRDN_DAC |
    932  1.1  jmcneill 	    HW_AUDIOOUT_PWRDN_CAPLESS |
    933  1.1  jmcneill 	    HW_AUDIOOUT_PWRDN_HEADPHONE
    934  1.1  jmcneill 	);
    935  1.1  jmcneill 
    936  1.1  jmcneill 	return;
    937  1.1  jmcneill }
    938  1.1  jmcneill 
    939  1.1  jmcneill /*
    940  1.1  jmcneill  * Reset the AUDIOOUT block.
    941  1.1  jmcneill  *
    942  1.1  jmcneill  * Inspired by i.MX23 RM "39.3.10 Correct Way to Soft Reset a Block"
    943  1.1  jmcneill  */
    944  1.1  jmcneill static void
    945  1.1  jmcneill digfilt_ao_reset(struct digfilt_softc *sc)
    946  1.1  jmcneill {
    947  1.1  jmcneill 	unsigned int loop;
    948  1.1  jmcneill 
    949  1.1  jmcneill 	/* Prepare for soft-reset by making sure that SFTRST is not currently
    950  1.1  jmcneill 	* asserted. Also clear CLKGATE so we can wait for its assertion below.
    951  1.1  jmcneill 	*/
    952  1.1  jmcneill 	AO_WR(sc, HW_AUDIOOUT_CTRL_CLR, HW_AUDIOOUT_CTRL_SFTRST);
    953  1.1  jmcneill 
    954  1.1  jmcneill 	/* Wait at least a microsecond for SFTRST to deassert. */
    955  1.1  jmcneill 	loop = 0;
    956  1.1  jmcneill 	while ((AO_RD(sc, HW_AUDIOOUT_CTRL) & HW_AUDIOOUT_CTRL_SFTRST) ||
    957  1.1  jmcneill 	    (loop < DIGFILT_SOFT_RST_LOOP))
    958  1.1  jmcneill 		loop++;
    959  1.1  jmcneill 
    960  1.1  jmcneill 	/* Clear CLKGATE so we can wait for its assertion below. */
    961  1.1  jmcneill 	AO_WR(sc, HW_AUDIOOUT_CTRL_CLR, HW_AUDIOOUT_CTRL_CLKGATE);
    962  1.1  jmcneill 
    963  1.1  jmcneill 	/* Soft-reset the block. */
    964  1.1  jmcneill 	AO_WR(sc, HW_AUDIOOUT_CTRL_SET, HW_AUDIOOUT_CTRL_SFTRST);
    965  1.1  jmcneill 
    966  1.1  jmcneill 	/* Wait until clock is in the gated state. */
    967  1.1  jmcneill 	while (!(AO_RD(sc, HW_AUDIOOUT_CTRL) & HW_AUDIOOUT_CTRL_CLKGATE));
    968  1.1  jmcneill 
    969  1.1  jmcneill 	/* Bring block out of reset. */
    970  1.1  jmcneill 	AO_WR(sc, HW_AUDIOOUT_CTRL_CLR, HW_AUDIOOUT_CTRL_SFTRST);
    971  1.1  jmcneill 
    972  1.1  jmcneill 	loop = 0;
    973  1.1  jmcneill 	while ((AO_RD(sc, HW_AUDIOOUT_CTRL) & HW_AUDIOOUT_CTRL_SFTRST) ||
    974  1.1  jmcneill 	    (loop < DIGFILT_SOFT_RST_LOOP))
    975  1.1  jmcneill 		loop++;
    976  1.1  jmcneill 
    977  1.1  jmcneill 	AO_WR(sc, HW_AUDIOOUT_CTRL_CLR, HW_AUDIOOUT_CTRL_CLKGATE);
    978  1.1  jmcneill 
    979  1.1  jmcneill 	/* Wait until clock is in the NON-gated state. */
    980  1.1  jmcneill 	while (AO_RD(sc, HW_AUDIOOUT_CTRL) & HW_AUDIOOUT_CTRL_CLKGATE);
    981  1.1  jmcneill 
    982  1.1  jmcneill 	return;
    983  1.1  jmcneill }
    984  1.1  jmcneill 
    985  1.1  jmcneill static void
    986  1.1  jmcneill digfilt_ao_set_rate(struct digfilt_softc *sc, int sr)
    987  1.1  jmcneill {
    988  1.1  jmcneill 	uint32_t val;
    989  1.1  jmcneill 
    990  1.1  jmcneill 
    991  1.1  jmcneill 	val = AO_RD(sc, HW_AUDIOOUT_DACSRR);
    992  1.1  jmcneill 
    993  1.1  jmcneill 
    994  1.1  jmcneill 	val &= ~(HW_AUDIOOUT_DACSRR_BASEMULT | HW_AUDIOOUT_DACSRR_SRC_HOLD |
    995  1.1  jmcneill 	    HW_AUDIOOUT_DACSRR_SRC_INT | HW_AUDIOOUT_DACSRR_SRC_FRAC);
    996  1.1  jmcneill 
    997  1.1  jmcneill 	switch(sr) {
    998  1.1  jmcneill 	case 8000:
    999  1.1  jmcneill 		val |= (__SHIFTIN(0x1 ,HW_AUDIOOUT_DACSRR_BASEMULT) |
   1000  1.1  jmcneill 		    __SHIFTIN(0x3, HW_AUDIOOUT_DACSRR_SRC_HOLD) |
   1001  1.1  jmcneill 		    __SHIFTIN(0x17, HW_AUDIOOUT_DACSRR_SRC_INT) |
   1002  1.1  jmcneill 		    __SHIFTIN(0x0E00, HW_AUDIOOUT_DACSRR_SRC_FRAC));
   1003  1.1  jmcneill 		break;
   1004  1.1  jmcneill 	case 11025:
   1005  1.1  jmcneill 		val |= (__SHIFTIN(0x1 ,HW_AUDIOOUT_DACSRR_BASEMULT) |
   1006  1.1  jmcneill 		    __SHIFTIN(0x3, HW_AUDIOOUT_DACSRR_SRC_HOLD) |
   1007  1.1  jmcneill 		    __SHIFTIN(0x11, HW_AUDIOOUT_DACSRR_SRC_INT) |
   1008  1.1  jmcneill 		    __SHIFTIN(0x0037, HW_AUDIOOUT_DACSRR_SRC_FRAC));
   1009  1.1  jmcneill 		break;
   1010  1.1  jmcneill 	case 12000:
   1011  1.1  jmcneill 		val |= (__SHIFTIN(0x1 ,HW_AUDIOOUT_DACSRR_BASEMULT) |
   1012  1.1  jmcneill 		    __SHIFTIN(0x3, HW_AUDIOOUT_DACSRR_SRC_HOLD) |
   1013  1.1  jmcneill 		    __SHIFTIN(0x0F, HW_AUDIOOUT_DACSRR_SRC_INT) |
   1014  1.1  jmcneill 		    __SHIFTIN(0x13FF, HW_AUDIOOUT_DACSRR_SRC_FRAC));
   1015  1.1  jmcneill 		break;
   1016  1.1  jmcneill 	case 16000:
   1017  1.1  jmcneill 		val |= (__SHIFTIN(0x1 ,HW_AUDIOOUT_DACSRR_BASEMULT) |
   1018  1.1  jmcneill 		    __SHIFTIN(0x1, HW_AUDIOOUT_DACSRR_SRC_HOLD) |
   1019  1.1  jmcneill 		    __SHIFTIN(0x17, HW_AUDIOOUT_DACSRR_SRC_INT) |
   1020  1.1  jmcneill 		    __SHIFTIN(0x0E00, HW_AUDIOOUT_DACSRR_SRC_FRAC));
   1021  1.1  jmcneill 		break;
   1022  1.1  jmcneill 	case 22050:
   1023  1.1  jmcneill 		val |= (__SHIFTIN(0x1 ,HW_AUDIOOUT_DACSRR_BASEMULT) |
   1024  1.1  jmcneill 		    __SHIFTIN(0x1, HW_AUDIOOUT_DACSRR_SRC_HOLD) |
   1025  1.1  jmcneill 		    __SHIFTIN(0x11, HW_AUDIOOUT_DACSRR_SRC_INT) |
   1026  1.1  jmcneill 		    __SHIFTIN(0x0037, HW_AUDIOOUT_DACSRR_SRC_FRAC));
   1027  1.1  jmcneill 		break;
   1028  1.1  jmcneill 	case 24000:
   1029  1.1  jmcneill 		val |= (__SHIFTIN(0x1 ,HW_AUDIOOUT_DACSRR_BASEMULT) |
   1030  1.1  jmcneill 		    __SHIFTIN(0x1, HW_AUDIOOUT_DACSRR_SRC_HOLD) |
   1031  1.1  jmcneill 		    __SHIFTIN(0x0F, HW_AUDIOOUT_DACSRR_SRC_INT) |
   1032  1.1  jmcneill 		    __SHIFTIN(0x13FF, HW_AUDIOOUT_DACSRR_SRC_FRAC));
   1033  1.1  jmcneill 		break;
   1034  1.1  jmcneill 	case 32000:
   1035  1.1  jmcneill 		val |= (__SHIFTIN(0x1 ,HW_AUDIOOUT_DACSRR_BASEMULT) |
   1036  1.1  jmcneill 		    __SHIFTIN(0x0, HW_AUDIOOUT_DACSRR_SRC_HOLD) |
   1037  1.1  jmcneill 		    __SHIFTIN(0x17, HW_AUDIOOUT_DACSRR_SRC_INT) |
   1038  1.1  jmcneill 		    __SHIFTIN(0x0E00, HW_AUDIOOUT_DACSRR_SRC_FRAC));
   1039  1.1  jmcneill 		break;
   1040  1.1  jmcneill 	default:
   1041  1.1  jmcneill 		aprint_error_dev(sc->sc_dev, "uknown sample rate: %d\n", sr);
   1042  1.1  jmcneill 	case 44100:
   1043  1.1  jmcneill 		val |= (__SHIFTIN(0x1 ,HW_AUDIOOUT_DACSRR_BASEMULT) |
   1044  1.1  jmcneill 		    __SHIFTIN(0x0, HW_AUDIOOUT_DACSRR_SRC_HOLD) |
   1045  1.1  jmcneill 		    __SHIFTIN(0x11, HW_AUDIOOUT_DACSRR_SRC_INT) |
   1046  1.1  jmcneill 		    __SHIFTIN(0x0037, HW_AUDIOOUT_DACSRR_SRC_FRAC));
   1047  1.1  jmcneill 		break;
   1048  1.1  jmcneill 	}
   1049  1.1  jmcneill 
   1050  1.1  jmcneill 	AO_WR(sc, HW_AUDIOOUT_DACSRR, val);
   1051  1.1  jmcneill 
   1052  1.1  jmcneill 	val = AO_RD(sc, HW_AUDIOOUT_DACSRR);
   1053  1.1  jmcneill 
   1054  1.1  jmcneill 	return;
   1055  1.1  jmcneill }
   1056  1.1  jmcneill #if 0
   1057  1.1  jmcneill /*
   1058  1.1  jmcneill  * Reset the AUDIOIN block.
   1059  1.1  jmcneill  *
   1060  1.1  jmcneill  * Inspired by i.MX23 RM "39.3.10 Correct Way to Soft Reset a Block"
   1061  1.1  jmcneill  */
   1062  1.1  jmcneill static void
   1063  1.1  jmcneill digfilt_ai_reset(struct digfilt_softc *sc)
   1064  1.1  jmcneill {
   1065  1.1  jmcneill 	unsigned int loop;
   1066  1.1  jmcneill 
   1067  1.1  jmcneill 	/* Prepare for soft-reset by making sure that SFTRST is not currently
   1068  1.1  jmcneill 	* asserted. Also clear CLKGATE so we can wait for its assertion below.
   1069  1.1  jmcneill 	*/
   1070  1.1  jmcneill 	AI_WR(sc, HW_AUDIOIN_CTRL_CLR, HW_AUDIOIN_CTRL_SFTRST);
   1071  1.1  jmcneill 
   1072  1.1  jmcneill 	/* Wait at least a microsecond for SFTRST to deassert. */
   1073  1.1  jmcneill 	loop = 0;
   1074  1.1  jmcneill 	while ((AI_RD(sc, HW_AUDIOIN_CTRL) & HW_AUDIOIN_CTRL_SFTRST) ||
   1075  1.1  jmcneill 	    (loop < DIGFILT_SOFT_RST_LOOP))
   1076  1.1  jmcneill 		loop++;
   1077  1.1  jmcneill 
   1078  1.1  jmcneill 	/* Clear CLKGATE so we can wait for its assertion below. */
   1079  1.1  jmcneill 	AI_WR(sc, HW_AUDIOIN_CTRL_CLR, HW_AUDIOIN_CTRL_CLKGATE);
   1080  1.1  jmcneill 
   1081  1.1  jmcneill 	/* Soft-reset the block. */
   1082  1.1  jmcneill 	AI_WR(sc, HW_AUDIOIN_CTRL_SET, HW_AUDIOIN_CTRL_SFTRST);
   1083  1.1  jmcneill 
   1084  1.1  jmcneill 	/* Wait until clock is in the gated state. */
   1085  1.1  jmcneill 	while (!(AI_RD(sc, HW_AUDIOIN_CTRL) & HW_AUDIOIN_CTRL_CLKGATE));
   1086  1.1  jmcneill 
   1087  1.1  jmcneill 	/* Bring block out of reset. */
   1088  1.1  jmcneill 	AI_WR(sc, HW_AUDIOIN_CTRL_CLR, HW_AUDIOIN_CTRL_SFTRST);
   1089  1.1  jmcneill 
   1090  1.1  jmcneill 	loop = 0;
   1091  1.1  jmcneill 	while ((AI_RD(sc, HW_AUDIOIN_CTRL) & HW_AUDIOIN_CTRL_SFTRST) ||
   1092  1.1  jmcneill 	    (loop < DIGFILT_SOFT_RST_LOOP))
   1093  1.1  jmcneill 		loop++;
   1094  1.1  jmcneill 
   1095  1.1  jmcneill 	AI_WR(sc, HW_AUDIOIN_CTRL_CLR, HW_AUDIOIN_CTRL_CLKGATE);
   1096  1.1  jmcneill 
   1097  1.1  jmcneill 	/* Wait until clock is in the NON-gated state. */
   1098  1.1  jmcneill 	while (AI_RD(sc, HW_AUDIOIN_CTRL) & HW_AUDIOIN_CTRL_CLKGATE);
   1099  1.1  jmcneill 
   1100  1.1  jmcneill 	return;
   1101  1.1  jmcneill }
   1102  1.1  jmcneill #endif
   1103