Home | History | Annotate | Line # | Download | only in imx
      1  1.4    andvar /* $Id: imx23_digfilt.c,v 1.4 2021/10/04 20:48:05 andvar 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.3     isaki 	if (blocksize < DIGFILT_BLOCKSIZE_ROUND)
    384  1.3     isaki 		blocksize = DIGFILT_BLOCKSIZE_ROUND;
    385  1.1  jmcneill 
    386  1.1  jmcneill 	return blocksize;
    387  1.1  jmcneill }
    388  1.1  jmcneill 
    389  1.1  jmcneill static int
    390  1.1  jmcneill digfilt_init_output(void *priv, void *buffer, int size)
    391  1.1  jmcneill {
    392  1.1  jmcneill 	struct digfilt_softc *sc = priv;
    393  1.1  jmcneill 	apbdma_command_t dma_cmd;
    394  1.1  jmcneill 	int i;
    395  1.1  jmcneill 	dma_cmd = sc->sc_dmachain;
    396  1.1  jmcneill 	sc->sc_cmd_index = 0;
    397  1.1  jmcneill 
    398  1.1  jmcneill 	/*
    399  1.1  jmcneill 	 * Build circular DMA command chain template for later use.
    400  1.1  jmcneill 	 */
    401  1.1  jmcneill 	for (i = 0; i < DIGFILT_DMA_CHAIN_LENGTH; i++) {
    402  1.1  jmcneill 		/* Last entry loops back to first. */
    403  1.1  jmcneill 		if (i == DIGFILT_DMA_CHAIN_LENGTH - 1)
    404  1.1  jmcneill 			dma_cmd[i].next = (void *)(sc->sc_c_dmamp->dm_segs[0].ds_addr);
    405  1.1  jmcneill 		else
    406  1.1  jmcneill 			dma_cmd[i].next = (void *)(sc->sc_c_dmamp->dm_segs[0].ds_addr + (sizeof(struct apbdma_command) * (1 + i)));
    407  1.1  jmcneill 
    408  1.1  jmcneill 		dma_cmd[i].control = __SHIFTIN(DIGFILT_BLOCKSIZE_MAX,  APBDMA_CMD_XFER_COUNT) |
    409  1.1  jmcneill 		    __SHIFTIN(1, APBDMA_CMD_CMDPIOWORDS) |
    410  1.1  jmcneill 		    APBDMA_CMD_SEMAPHORE |
    411  1.1  jmcneill 		    APBDMA_CMD_IRQONCMPLT |
    412  1.1  jmcneill 		    APBDMA_CMD_CHAIN |
    413  1.1  jmcneill 		    __SHIFTIN(APBDMA_CMD_DMA_READ, APBDMA_CMD_COMMAND);
    414  1.1  jmcneill 
    415  1.1  jmcneill 		dma_cmd[i].buffer = (void *)(sc->sc_c_dmamp->dm_segs[0].ds_addr);
    416  1.1  jmcneill 
    417  1.1  jmcneill 		dma_cmd[i].pio_words[0] = HW_AUDIOOUT_CTRL_WORD_LENGTH |
    418  1.1  jmcneill 		    HW_AUDIOOUT_CTRL_FIFO_ERROR_IRQ_EN |
    419  1.1  jmcneill 		    HW_AUDIOOUT_CTRL_RUN;
    420  1.1  jmcneill 
    421  1.1  jmcneill 	}
    422  1.1  jmcneill 
    423  1.1  jmcneill 	apbdma_chan_set_chain(sc->sc_dmac, DIGFILT_DMA_CHANNEL, sc->sc_c_dmamp);
    424  1.1  jmcneill 
    425  1.1  jmcneill 	return 0;
    426  1.1  jmcneill }
    427  1.1  jmcneill 
    428  1.1  jmcneill static int
    429  1.1  jmcneill digfilt_start_output(void *priv, void *start, int bs, void (*intr)(void*), void *intarg)
    430  1.1  jmcneill {
    431  1.1  jmcneill 	struct digfilt_softc *sc = priv;
    432  1.1  jmcneill 	apbdma_command_t dma_cmd;
    433  1.1  jmcneill 	bus_addr_t offset;
    434  1.1  jmcneill 
    435  1.1  jmcneill 	sc->sc_intr = intr;
    436  1.1  jmcneill 	sc->sc_intarg = intarg;
    437  1.1  jmcneill 	dma_cmd = sc->sc_dmachain;
    438  1.1  jmcneill 
    439  1.1  jmcneill 	offset = (bus_addr_t)start - (bus_addr_t)sc->sc_buffer;
    440  1.1  jmcneill 
    441  1.1  jmcneill 	dma_cmd[sc->sc_cmd_index].buffer =
    442  1.1  jmcneill 	    (void *)((bus_addr_t)sc->sc_dmamp->dm_segs[0].ds_addr + offset);
    443  1.1  jmcneill 
    444  1.1  jmcneill 	bus_dmamap_sync(sc->sc_dmat, sc->sc_dmamp, offset, bs, BUS_DMASYNC_PREWRITE);
    445  1.1  jmcneill 	bus_dmamap_sync(sc->sc_dmat, sc->sc_c_dmamp,
    446  1.1  jmcneill 	    sizeof(struct apbdma_command) * sc->sc_cmd_index, sizeof(struct apbdma_command), BUS_DMASYNC_PREWRITE);
    447  1.1  jmcneill 
    448  1.1  jmcneill 	sc->sc_cmd_index++;
    449  1.1  jmcneill 	if (sc->sc_cmd_index > DIGFILT_DMA_CHAIN_LENGTH - 1)
    450  1.1  jmcneill 		sc->sc_cmd_index = 0;
    451  1.1  jmcneill 
    452  1.1  jmcneill 	apbdma_run(sc->sc_dmac, DIGFILT_DMA_CHANNEL);
    453  1.1  jmcneill 
    454  1.1  jmcneill 	return 0;
    455  1.1  jmcneill }
    456  1.1  jmcneill 
    457  1.1  jmcneill static int
    458  1.1  jmcneill digfilt_halt_output(void *priv)
    459  1.1  jmcneill {
    460  1.2     isaki 	struct digfilt_softc *sc = priv;
    461  1.2     isaki 
    462  1.2     isaki 	sc->sc_cmd_index = 0;
    463  1.1  jmcneill 	return 0;
    464  1.1  jmcneill }
    465  1.1  jmcneill 
    466  1.1  jmcneill static int
    467  1.1  jmcneill digfilt_getdev(void *priv, struct audio_device *ad)
    468  1.1  jmcneill {
    469  1.1  jmcneill 	struct digfilt_softc *sc = priv;
    470  1.1  jmcneill 
    471  1.1  jmcneill 	strncpy(ad->name, device_xname(sc->sc_dev), MAX_AUDIO_DEV_LEN);
    472  1.1  jmcneill 	strncpy(ad->version, "", MAX_AUDIO_DEV_LEN);
    473  1.1  jmcneill 	strncpy(ad->config, "", MAX_AUDIO_DEV_LEN);
    474  1.1  jmcneill 
    475  1.1  jmcneill 	return 0;
    476  1.1  jmcneill }
    477  1.1  jmcneill 
    478  1.1  jmcneill static int
    479  1.1  jmcneill digfilt_set_port(void *priv, mixer_ctrl_t *mc)
    480  1.1  jmcneill {
    481  1.1  jmcneill 	struct digfilt_softc *sc = priv;
    482  1.1  jmcneill 	uint32_t val;
    483  1.1  jmcneill 	uint8_t nvol;
    484  1.1  jmcneill 
    485  1.1  jmcneill 	switch (mc->dev) {
    486  1.1  jmcneill 	case DIGFILT_OUTPUT_DAC_VOLUME:
    487  1.1  jmcneill 		val = AO_RD(sc, HW_AUDIOOUT_DACVOLUME);
    488  1.1  jmcneill 		val &= ~(HW_AUDIOOUT_DACVOLUME_VOLUME_LEFT |
    489  1.1  jmcneill 		    HW_AUDIOOUT_DACVOLUME_VOLUME_RIGHT);
    490  1.1  jmcneill 
    491  1.1  jmcneill 		/* DAC volume field is 8 bits. */
    492  1.1  jmcneill 		nvol = mc->un.value.level[AUDIO_MIXER_LEVEL_LEFT];
    493  1.1  jmcneill 		if (nvol > 0xff)
    494  1.1  jmcneill 			nvol = 0xff;
    495  1.1  jmcneill 
    496  1.1  jmcneill 		val |= __SHIFTIN(nvol, HW_AUDIOOUT_DACVOLUME_VOLUME_LEFT);
    497  1.1  jmcneill 
    498  1.1  jmcneill 		nvol = mc->un.value.level[AUDIO_MIXER_LEVEL_RIGHT];
    499  1.1  jmcneill 		if (nvol > 0xff)
    500  1.1  jmcneill 			nvol = 0xff;
    501  1.1  jmcneill 
    502  1.1  jmcneill 		val |= __SHIFTIN(nvol, HW_AUDIOOUT_DACVOLUME_VOLUME_RIGHT);
    503  1.1  jmcneill 
    504  1.1  jmcneill 		AO_WR(sc, HW_AUDIOOUT_DACVOLUME, val);
    505  1.1  jmcneill 
    506  1.1  jmcneill 		return 0;
    507  1.1  jmcneill 
    508  1.1  jmcneill 	case DIGFILT_OUTPUT_HP_VOLUME:
    509  1.1  jmcneill 		val = AO_RD(sc, HW_AUDIOOUT_HPVOL);
    510  1.1  jmcneill 		val &= ~(HW_AUDIOOUT_HPVOL_VOL_LEFT |
    511  1.1  jmcneill 		    HW_AUDIOOUT_HPVOL_VOL_RIGHT);
    512  1.1  jmcneill 
    513  1.1  jmcneill 		/* HP volume field is 7 bits. */
    514  1.1  jmcneill 		nvol = mc->un.value.level[AUDIO_MIXER_LEVEL_LEFT];
    515  1.1  jmcneill 		if (nvol > 0x7f)
    516  1.1  jmcneill 			nvol = 0x7f;
    517  1.1  jmcneill 
    518  1.1  jmcneill 		nvol = ~nvol;
    519  1.1  jmcneill 		val |= __SHIFTIN(nvol, HW_AUDIOOUT_HPVOL_VOL_LEFT);
    520  1.1  jmcneill 
    521  1.1  jmcneill 		nvol = mc->un.value.level[AUDIO_MIXER_LEVEL_RIGHT];
    522  1.1  jmcneill 		if (nvol > 0x7f)
    523  1.1  jmcneill 			nvol = 0x7f;
    524  1.1  jmcneill 
    525  1.1  jmcneill 		nvol = ~nvol;
    526  1.1  jmcneill 		val |= __SHIFTIN(nvol, HW_AUDIOOUT_HPVOL_VOL_RIGHT);
    527  1.1  jmcneill 
    528  1.1  jmcneill 		AO_WR(sc, HW_AUDIOOUT_HPVOL, val);
    529  1.1  jmcneill 
    530  1.1  jmcneill 		return 0;
    531  1.1  jmcneill 
    532  1.1  jmcneill 	case DIGFILT_OUTPUT_LINE_VOLUME:
    533  1.1  jmcneill 		return 1;
    534  1.1  jmcneill 
    535  1.1  jmcneill 	case DIGFILT_OUTPUT_DAC_MUTE:
    536  1.1  jmcneill 		if (mc->un.ord)
    537  1.1  jmcneill 			sc->sc_mute |= DIGFILT_MUTE_DAC;
    538  1.1  jmcneill 		else
    539  1.1  jmcneill 			sc->sc_mute &= ~DIGFILT_MUTE_DAC;
    540  1.1  jmcneill 
    541  1.1  jmcneill 		digfilt_ao_apply_mutes(sc);
    542  1.1  jmcneill 
    543  1.1  jmcneill 		return 0;
    544  1.1  jmcneill 
    545  1.1  jmcneill 	case DIGFILT_OUTPUT_HP_MUTE:
    546  1.1  jmcneill 		if (mc->un.ord)
    547  1.1  jmcneill 			sc->sc_mute |= DIGFILT_MUTE_HP;
    548  1.1  jmcneill 		else
    549  1.1  jmcneill 			sc->sc_mute &= ~DIGFILT_MUTE_HP;
    550  1.1  jmcneill 
    551  1.1  jmcneill 		digfilt_ao_apply_mutes(sc);
    552  1.1  jmcneill 
    553  1.1  jmcneill 		return 0;
    554  1.1  jmcneill 
    555  1.1  jmcneill 	case DIGFILT_OUTPUT_LINE_MUTE:
    556  1.1  jmcneill 		if (mc->un.ord)
    557  1.1  jmcneill 			sc->sc_mute |= DIGFILT_MUTE_LINE;
    558  1.1  jmcneill 		else
    559  1.1  jmcneill 			sc->sc_mute &= ~DIGFILT_MUTE_LINE;
    560  1.1  jmcneill 
    561  1.1  jmcneill 		digfilt_ao_apply_mutes(sc);
    562  1.1  jmcneill 
    563  1.1  jmcneill 		return 0;
    564  1.1  jmcneill 	}
    565  1.1  jmcneill 
    566  1.1  jmcneill 	return ENXIO;
    567  1.1  jmcneill }
    568  1.1  jmcneill 
    569  1.1  jmcneill static int
    570  1.1  jmcneill digfilt_get_port(void *priv, mixer_ctrl_t *mc)
    571  1.1  jmcneill {
    572  1.1  jmcneill 	struct digfilt_softc *sc = priv;
    573  1.1  jmcneill 	uint32_t val;
    574  1.1  jmcneill 	uint8_t nvol;
    575  1.1  jmcneill 
    576  1.1  jmcneill         switch (mc->dev) {
    577  1.1  jmcneill         case DIGFILT_OUTPUT_DAC_VOLUME:
    578  1.1  jmcneill 		val = AO_RD(sc, HW_AUDIOOUT_DACVOLUME);
    579  1.1  jmcneill 
    580  1.1  jmcneill 		nvol = __SHIFTOUT(val, HW_AUDIOOUT_DACVOLUME_VOLUME_LEFT);
    581  1.1  jmcneill                 mc->un.value.level[AUDIO_MIXER_LEVEL_LEFT] = nvol;
    582  1.1  jmcneill 
    583  1.1  jmcneill 		nvol = __SHIFTOUT(val, HW_AUDIOOUT_DACVOLUME_VOLUME_RIGHT);
    584  1.1  jmcneill                 mc->un.value.level[AUDIO_MIXER_LEVEL_RIGHT] = nvol;
    585  1.1  jmcneill 
    586  1.1  jmcneill                 return 0;
    587  1.1  jmcneill 
    588  1.1  jmcneill         case DIGFILT_OUTPUT_HP_VOLUME:
    589  1.1  jmcneill 		val = AO_RD(sc, HW_AUDIOOUT_HPVOL);
    590  1.1  jmcneill 
    591  1.1  jmcneill 		nvol = __SHIFTOUT(val, HW_AUDIOOUT_HPVOL_VOL_LEFT);
    592  1.1  jmcneill 		mc->un.value.level[AUDIO_MIXER_LEVEL_LEFT] = ~nvol & 0x7f;
    593  1.1  jmcneill 
    594  1.1  jmcneill 		nvol = __SHIFTOUT(val, HW_AUDIOOUT_HPVOL_VOL_RIGHT);
    595  1.1  jmcneill 		mc->un.value.level[AUDIO_MIXER_LEVEL_RIGHT] = ~nvol & 0x7f;
    596  1.1  jmcneill 
    597  1.1  jmcneill 		return 0;
    598  1.1  jmcneill 
    599  1.1  jmcneill 	case DIGFILT_OUTPUT_LINE_VOLUME:
    600  1.1  jmcneill 		mc->un.value.level[AUDIO_MIXER_LEVEL_LEFT] = 255;
    601  1.1  jmcneill 		mc->un.value.level[AUDIO_MIXER_LEVEL_RIGHT] = 255;
    602  1.1  jmcneill 
    603  1.1  jmcneill 		return 0;
    604  1.1  jmcneill 
    605  1.1  jmcneill 	case DIGFILT_OUTPUT_DAC_MUTE:
    606  1.1  jmcneill 		val = AO_RD(sc, HW_AUDIOOUT_DACVOLUME);
    607  1.1  jmcneill 
    608  1.1  jmcneill 		mc->un.ord = (val & (HW_AUDIOOUT_DACVOLUME_MUTE_LEFT |
    609  1.1  jmcneill 		    HW_AUDIOOUT_DACVOLUME_MUTE_RIGHT)) ? 1 : 0;
    610  1.1  jmcneill 
    611  1.1  jmcneill 		return 0;
    612  1.1  jmcneill 
    613  1.1  jmcneill 	case DIGFILT_OUTPUT_HP_MUTE:
    614  1.1  jmcneill 		val = AO_RD(sc, HW_AUDIOOUT_HPVOL);
    615  1.1  jmcneill 
    616  1.1  jmcneill 		mc->un.ord = (val & HW_AUDIOOUT_HPVOL_MUTE) ? 1 : 0;
    617  1.1  jmcneill 
    618  1.1  jmcneill 		return 0;
    619  1.1  jmcneill 
    620  1.1  jmcneill 	case DIGFILT_OUTPUT_LINE_MUTE:
    621  1.1  jmcneill 		val = AO_RD(sc, HW_AUDIOOUT_SPEAKERCTRL);
    622  1.1  jmcneill 
    623  1.1  jmcneill 		mc->un.ord = (val & HW_AUDIOOUT_SPEAKERCTRL_MUTE) ? 1 : 0;
    624  1.1  jmcneill 
    625  1.1  jmcneill 		return 0;
    626  1.1  jmcneill         }
    627  1.1  jmcneill 
    628  1.1  jmcneill         return ENXIO;
    629  1.1  jmcneill }
    630  1.1  jmcneill 
    631  1.1  jmcneill static int
    632  1.1  jmcneill digfilt_query_devinfo(void *priv, mixer_devinfo_t *di)
    633  1.1  jmcneill {
    634  1.1  jmcneill 
    635  1.1  jmcneill 	switch (di->index) {
    636  1.1  jmcneill 	case DIGFILT_OUTPUT_CLASS:
    637  1.1  jmcneill 		di->mixer_class = DIGFILT_OUTPUT_CLASS;
    638  1.1  jmcneill 		strcpy(di->label.name, AudioCoutputs);
    639  1.1  jmcneill 		di->type = AUDIO_MIXER_CLASS;
    640  1.1  jmcneill 		di->next = di->prev = AUDIO_MIXER_LAST;
    641  1.1  jmcneill 		return 0;
    642  1.1  jmcneill 
    643  1.1  jmcneill 	case DIGFILT_OUTPUT_DAC_VOLUME:
    644  1.1  jmcneill 		di->mixer_class = DIGFILT_OUTPUT_CLASS;
    645  1.1  jmcneill 		strcpy(di->label.name, AudioNdac);
    646  1.1  jmcneill 		di->type = AUDIO_MIXER_VALUE;
    647  1.1  jmcneill 		di->prev = AUDIO_MIXER_LAST;
    648  1.1  jmcneill 		di->next = DIGFILT_OUTPUT_DAC_MUTE;
    649  1.1  jmcneill 		di->un.v.num_channels = 2;
    650  1.1  jmcneill 		strcpy(di->un.v.units.name, AudioNvolume);
    651  1.1  jmcneill 		return 0;
    652  1.1  jmcneill 
    653  1.1  jmcneill 	case DIGFILT_OUTPUT_DAC_MUTE:
    654  1.1  jmcneill 		di->mixer_class = DIGFILT_OUTPUT_CLASS;
    655  1.1  jmcneill 		di->type = AUDIO_MIXER_ENUM;
    656  1.1  jmcneill 		di->prev = DIGFILT_OUTPUT_DAC_VOLUME;
    657  1.1  jmcneill 		di->next = AUDIO_MIXER_LAST;
    658  1.1  jmcneill mute:
    659  1.1  jmcneill 		strlcpy(di->label.name, AudioNmute, sizeof(di->label.name));
    660  1.1  jmcneill 		di->un.e.num_mem = 2;
    661  1.1  jmcneill 		strlcpy(di->un.e.member[0].label.name, AudioNon,
    662  1.1  jmcneill 		    sizeof(di->un.e.member[0].label.name));
    663  1.1  jmcneill 		di->un.e.member[0].ord = 1;
    664  1.1  jmcneill 		strlcpy(di->un.e.member[1].label.name, AudioNoff,
    665  1.1  jmcneill 		    sizeof(di->un.e.member[1].label.name));
    666  1.1  jmcneill 		di->un.e.member[1].ord = 0;
    667  1.1  jmcneill 		return 0;
    668  1.1  jmcneill 
    669  1.1  jmcneill 	case DIGFILT_OUTPUT_HP_VOLUME:
    670  1.1  jmcneill 		di->mixer_class = DIGFILT_OUTPUT_CLASS;
    671  1.1  jmcneill 		strcpy(di->label.name, AudioNheadphone);
    672  1.1  jmcneill 		di->type = AUDIO_MIXER_VALUE;
    673  1.1  jmcneill 		di->prev = AUDIO_MIXER_LAST;
    674  1.1  jmcneill 		di->next = DIGFILT_OUTPUT_HP_MUTE;
    675  1.1  jmcneill 		di->un.v.num_channels = 2;
    676  1.1  jmcneill 		strcpy(di->un.v.units.name, AudioNvolume);
    677  1.1  jmcneill 		return 0;
    678  1.1  jmcneill 
    679  1.1  jmcneill 	case DIGFILT_OUTPUT_HP_MUTE:
    680  1.1  jmcneill 		di->mixer_class = DIGFILT_OUTPUT_CLASS;
    681  1.1  jmcneill 		di->type = AUDIO_MIXER_ENUM;
    682  1.1  jmcneill 		di->prev = DIGFILT_OUTPUT_HP_VOLUME;
    683  1.1  jmcneill 		di->next = AUDIO_MIXER_LAST;
    684  1.1  jmcneill 		goto mute;
    685  1.1  jmcneill 
    686  1.1  jmcneill 	case DIGFILT_OUTPUT_LINE_VOLUME:
    687  1.1  jmcneill 		di->mixer_class = DIGFILT_OUTPUT_CLASS;
    688  1.1  jmcneill 		strcpy(di->label.name, AudioNline);
    689  1.1  jmcneill 		di->type = AUDIO_MIXER_VALUE;
    690  1.1  jmcneill 		di->prev = AUDIO_MIXER_LAST;
    691  1.1  jmcneill 		di->next = DIGFILT_OUTPUT_LINE_MUTE;
    692  1.1  jmcneill 		di->un.v.num_channels = 2;
    693  1.1  jmcneill 		strcpy(di->un.v.units.name, AudioNvolume);
    694  1.1  jmcneill 		return 0;
    695  1.1  jmcneill 
    696  1.1  jmcneill 	case DIGFILT_OUTPUT_LINE_MUTE:
    697  1.1  jmcneill 		di->mixer_class = DIGFILT_OUTPUT_CLASS;
    698  1.1  jmcneill 		di->type = AUDIO_MIXER_ENUM;
    699  1.1  jmcneill 		di->prev = DIGFILT_OUTPUT_LINE_VOLUME;
    700  1.1  jmcneill 		di->next = AUDIO_MIXER_LAST;
    701  1.1  jmcneill 		goto mute;
    702  1.1  jmcneill 	}
    703  1.1  jmcneill 
    704  1.1  jmcneill         return ENXIO;
    705  1.1  jmcneill }
    706  1.1  jmcneill 
    707  1.1  jmcneill static void *
    708  1.1  jmcneill digfilt_allocm(void *priv, int direction, size_t size)
    709  1.1  jmcneill {
    710  1.1  jmcneill 	struct digfilt_softc *sc = priv;
    711  1.1  jmcneill 	int rsegs;
    712  1.1  jmcneill 	int error;
    713  1.1  jmcneill 
    714  1.1  jmcneill 	sc->sc_buffer = NULL;
    715  1.1  jmcneill 
    716  1.1  jmcneill 	/*
    717  1.1  jmcneill 	 * AUMODE_PLAY is DMA from memory to device.
    718  1.1  jmcneill 	 */
    719  1.1  jmcneill 	if (direction != AUMODE_PLAY)
    720  1.1  jmcneill 		return NULL;
    721  1.1  jmcneill 
    722  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);
    723  1.1  jmcneill 	if (error) {
    724  1.1  jmcneill 		aprint_error_dev(sc->sc_dev,
    725  1.1  jmcneill 		    "bus_dmamem_alloc: %d\n", error);
    726  1.1  jmcneill 		goto out;
    727  1.1  jmcneill 	}
    728  1.1  jmcneill 
    729  1.1  jmcneill 	error = bus_dmamem_map(sc->sc_dmat, sc->sc_ds, DIGFILT_DMA_NSEGS, size, &sc->sc_buffer, BUS_DMA_NOWAIT);
    730  1.1  jmcneill 	if (error) {
    731  1.1  jmcneill 		aprint_error_dev(sc->sc_dev, "bus_dmamem_map: %d\n", error);
    732  1.1  jmcneill 		goto dmamem_free;
    733  1.1  jmcneill 	}
    734  1.1  jmcneill 
    735  1.1  jmcneill 	/* After load sc_dmamp is valid. */
    736  1.1  jmcneill 	error = bus_dmamap_load(sc->sc_dmat, sc->sc_dmamp, sc->sc_buffer, size, NULL, BUS_DMA_NOWAIT|BUS_DMA_WRITE);
    737  1.1  jmcneill 	if (error) {
    738  1.1  jmcneill 		aprint_error_dev(sc->sc_dev, "bus_dmamap_load: %d\n", error);
    739  1.1  jmcneill 		goto dmamem_unmap;
    740  1.1  jmcneill 	}
    741  1.1  jmcneill 
    742  1.1  jmcneill 	memset(sc->sc_buffer, 0x00, size);
    743  1.1  jmcneill 
    744  1.1  jmcneill 	return sc->sc_buffer;
    745  1.1  jmcneill 
    746  1.1  jmcneill dmamem_unmap:
    747  1.1  jmcneill 	bus_dmamem_unmap(sc->sc_dmat, sc->sc_buffer, size);
    748  1.1  jmcneill dmamem_free:
    749  1.1  jmcneill 	bus_dmamem_free(sc->sc_dmat, sc->sc_ds, DIGFILT_DMA_NSEGS);
    750  1.1  jmcneill out:
    751  1.1  jmcneill 	return NULL;
    752  1.1  jmcneill }
    753  1.1  jmcneill 
    754  1.1  jmcneill static void
    755  1.1  jmcneill digfilt_freem(void *priv, void *kvap, size_t size)
    756  1.1  jmcneill {
    757  1.1  jmcneill 	struct digfilt_softc *sc = priv;
    758  1.1  jmcneill 
    759  1.1  jmcneill 	bus_dmamem_unmap(sc->sc_dmat, kvap, size);
    760  1.1  jmcneill 	bus_dmamem_free(sc->sc_dmat, sc->sc_ds, DIGFILT_DMA_NSEGS);
    761  1.1  jmcneill 
    762  1.1  jmcneill 	return;
    763  1.1  jmcneill }
    764  1.1  jmcneill 
    765  1.1  jmcneill static size_t
    766  1.1  jmcneill digfilt_round_buffersize(void *hdl, int direction, size_t bs)
    767  1.1  jmcneill {
    768  1.1  jmcneill 	int bufsize;
    769  1.1  jmcneill 
    770  1.1  jmcneill 	bufsize = bs & ~(DIGFILT_BLOCKSIZE_MAX-1);
    771  1.1  jmcneill 
    772  1.1  jmcneill 	return bufsize;
    773  1.1  jmcneill }
    774  1.1  jmcneill 
    775  1.1  jmcneill static int
    776  1.1  jmcneill digfilt_get_props(void *sc)
    777  1.1  jmcneill {
    778  1.1  jmcneill 	return (AUDIO_PROP_PLAYBACK | AUDIO_PROP_INDEPENDENT);
    779  1.1  jmcneill }
    780  1.1  jmcneill 
    781  1.1  jmcneill static void
    782  1.1  jmcneill digfilt_get_locks(void *priv, kmutex_t **intr, kmutex_t **thread)
    783  1.1  jmcneill {
    784  1.1  jmcneill 	struct digfilt_softc *sc = priv;
    785  1.1  jmcneill 
    786  1.1  jmcneill 	*intr = &sc->sc_intr_lock;
    787  1.1  jmcneill 	*thread = &sc->sc_lock;
    788  1.1  jmcneill 
    789  1.1  jmcneill 	return;
    790  1.1  jmcneill }
    791  1.1  jmcneill 
    792  1.1  jmcneill /*
    793  1.1  jmcneill  * IRQ for DAC error.
    794  1.1  jmcneill  */
    795  1.1  jmcneill static int
    796  1.1  jmcneill dac_error_intr(void *arg)
    797  1.1  jmcneill {
    798  1.1  jmcneill 	struct digfilt_softc *sc = arg;
    799  1.1  jmcneill 	AO_WR(sc, HW_AUDIOOUT_CTRL_CLR, HW_AUDIOOUT_CTRL_FIFO_UNDERFLOW_IRQ);
    800  1.1  jmcneill 	return 1;
    801  1.1  jmcneill }
    802  1.1  jmcneill 
    803  1.1  jmcneill /*
    804  1.1  jmcneill  * IRQ from DMA.
    805  1.1  jmcneill  */
    806  1.1  jmcneill static int
    807  1.1  jmcneill dac_dma_intr(void *arg)
    808  1.1  jmcneill {
    809  1.1  jmcneill 	struct digfilt_softc *sc = arg;
    810  1.1  jmcneill 
    811  1.1  jmcneill 	unsigned int dma_err;
    812  1.1  jmcneill 
    813  1.1  jmcneill 	mutex_enter(&sc->sc_intr_lock);
    814  1.1  jmcneill 
    815  1.1  jmcneill 	dma_err = apbdma_intr_status(sc->sc_dmac, DIGFILT_DMA_CHANNEL);
    816  1.1  jmcneill 
    817  1.1  jmcneill 	if (dma_err) {
    818  1.1  jmcneill 		apbdma_ack_error_intr(sc->sc_dmac, DIGFILT_DMA_CHANNEL);
    819  1.1  jmcneill 	}
    820  1.1  jmcneill 
    821  1.1  jmcneill 	sc->sc_intr(sc->sc_intarg);
    822  1.1  jmcneill 	apbdma_ack_intr(sc->sc_dmac, DIGFILT_DMA_CHANNEL);
    823  1.1  jmcneill 
    824  1.1  jmcneill 	mutex_exit(&sc->sc_intr_lock);
    825  1.1  jmcneill 
    826  1.1  jmcneill 	/* Return 1 to acknowledge IRQ. */
    827  1.1  jmcneill 	return 1;
    828  1.1  jmcneill }
    829  1.1  jmcneill 
    830  1.1  jmcneill static void *
    831  1.1  jmcneill digfilt_ao_alloc_dmachain(void *priv, size_t size)
    832  1.1  jmcneill {
    833  1.1  jmcneill 	struct digfilt_softc *sc = priv;
    834  1.1  jmcneill 	int rsegs;
    835  1.1  jmcneill 	int error;
    836  1.1  jmcneill 	void *kvap;
    837  1.1  jmcneill 
    838  1.1  jmcneill 	kvap = NULL;
    839  1.1  jmcneill 
    840  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);
    841  1.1  jmcneill 	if (error) {
    842  1.1  jmcneill 		aprint_error_dev(sc->sc_dev,
    843  1.1  jmcneill 		    "bus_dmamem_alloc: %d\n", error);
    844  1.1  jmcneill 		goto out;
    845  1.1  jmcneill 	}
    846  1.1  jmcneill 
    847  1.1  jmcneill 	error = bus_dmamem_map(sc->sc_dmat, sc->sc_c_ds, DIGFILT_DMA_NSEGS, size, &kvap, BUS_DMA_NOWAIT);
    848  1.1  jmcneill 	if (error) {
    849  1.1  jmcneill 		aprint_error_dev(sc->sc_dev, "bus_dmamem_map: %d\n", error);
    850  1.1  jmcneill 		goto dmamem_free;
    851  1.1  jmcneill 	}
    852  1.1  jmcneill 
    853  1.1  jmcneill 	/* After load sc_c_dmamp is valid. */
    854  1.1  jmcneill 	error = bus_dmamap_load(sc->sc_dmat, sc->sc_c_dmamp, kvap, size, NULL, BUS_DMA_NOWAIT|BUS_DMA_WRITE);
    855  1.1  jmcneill 	if (error) {
    856  1.1  jmcneill 		aprint_error_dev(sc->sc_dev, "bus_dmamap_load: %d\n", error);
    857  1.1  jmcneill 		goto dmamem_unmap;
    858  1.1  jmcneill 	}
    859  1.1  jmcneill 
    860  1.1  jmcneill 	memset(kvap, 0x00, size);
    861  1.1  jmcneill 
    862  1.1  jmcneill 	return kvap;
    863  1.1  jmcneill 
    864  1.1  jmcneill dmamem_unmap:
    865  1.1  jmcneill 	bus_dmamem_unmap(sc->sc_dmat, kvap, size);
    866  1.1  jmcneill dmamem_free:
    867  1.1  jmcneill 	bus_dmamem_free(sc->sc_dmat, sc->sc_c_ds, DIGFILT_DMA_NSEGS);
    868  1.1  jmcneill out:
    869  1.1  jmcneill 
    870  1.1  jmcneill 	return kvap;
    871  1.1  jmcneill }
    872  1.1  jmcneill 
    873  1.1  jmcneill static void
    874  1.1  jmcneill digfilt_ao_apply_mutes(struct digfilt_softc *sc)
    875  1.1  jmcneill {
    876  1.1  jmcneill 
    877  1.1  jmcneill 	/* DAC. */
    878  1.1  jmcneill 	if (sc->sc_mute & DIGFILT_MUTE_DAC) {
    879  1.1  jmcneill 		AO_WR(sc, HW_AUDIOOUT_DACVOLUME_SET,
    880  1.1  jmcneill 		    HW_AUDIOOUT_DACVOLUME_MUTE_LEFT |
    881  1.1  jmcneill 		    HW_AUDIOOUT_DACVOLUME_MUTE_RIGHT
    882  1.1  jmcneill 		);
    883  1.1  jmcneill 
    884  1.1  jmcneill 	} else {
    885  1.1  jmcneill 		AO_WR(sc, HW_AUDIOOUT_DACVOLUME_CLR,
    886  1.1  jmcneill 		    HW_AUDIOOUT_DACVOLUME_MUTE_LEFT |
    887  1.1  jmcneill 		    HW_AUDIOOUT_DACVOLUME_MUTE_RIGHT
    888  1.1  jmcneill 		);
    889  1.1  jmcneill 	}
    890  1.1  jmcneill 
    891  1.1  jmcneill 	/* HP. */
    892  1.1  jmcneill 	if (sc->sc_mute & DIGFILT_MUTE_HP)
    893  1.1  jmcneill 		AO_WR(sc, HW_AUDIOOUT_HPVOL_SET, HW_AUDIOOUT_HPVOL_MUTE);
    894  1.1  jmcneill 	else
    895  1.1  jmcneill 		AO_WR(sc, HW_AUDIOOUT_HPVOL_CLR, HW_AUDIOOUT_HPVOL_MUTE);
    896  1.1  jmcneill 
    897  1.1  jmcneill 	/* Line. */
    898  1.1  jmcneill 	if (sc->sc_mute & DIGFILT_MUTE_LINE)
    899  1.1  jmcneill 		AO_WR(sc, HW_AUDIOOUT_SPEAKERCTRL_SET,
    900  1.1  jmcneill 		    HW_AUDIOOUT_SPEAKERCTRL_MUTE);
    901  1.1  jmcneill 	else
    902  1.1  jmcneill 		AO_WR(sc, HW_AUDIOOUT_SPEAKERCTRL_CLR,
    903  1.1  jmcneill 		    HW_AUDIOOUT_SPEAKERCTRL_MUTE);
    904  1.1  jmcneill 
    905  1.1  jmcneill 	return;
    906  1.1  jmcneill }
    907  1.1  jmcneill 
    908  1.1  jmcneill /*
    909  1.1  jmcneill  * Initialize audio system.
    910  1.1  jmcneill  */
    911  1.1  jmcneill static void
    912  1.1  jmcneill digfilt_ao_init(struct digfilt_softc *sc)
    913  1.1  jmcneill {
    914  1.1  jmcneill 
    915  1.1  jmcneill 	AO_WR(sc, HW_AUDIOOUT_ANACLKCTRL_CLR, HW_AUDIOOUT_ANACLKCTRL_CLKGATE);
    916  1.1  jmcneill 	while ((AO_RD(sc, HW_AUDIOOUT_ANACLKCTRL) &
    917  1.1  jmcneill 	    HW_AUDIOOUT_ANACLKCTRL_CLKGATE));
    918  1.1  jmcneill 
    919  1.1  jmcneill 	/* Hold headphones outputs at ground. */
    920  1.1  jmcneill 	AO_WR(sc, HW_AUDIOOUT_ANACTRL_SET, HW_AUDIOOUT_ANACTRL_HP_HOLD_GND);
    921  1.1  jmcneill 
    922  1.1  jmcneill 	/* Remove pulldown resistors on headphone outputs. */
    923  1.1  jmcneill 	rtc_release_gnd(1);
    924  1.1  jmcneill 
    925  1.1  jmcneill 	/* Release pull down */
    926  1.1  jmcneill 	AO_WR(sc, HW_AUDIOOUT_ANACTRL_CLR, HW_AUDIOOUT_ANACTRL_HP_HOLD_GND);
    927  1.1  jmcneill 
    928  1.1  jmcneill 	AO_WR(sc, HW_AUDIOOUT_ANACTRL_SET, HW_AUDIOOUT_ANACTRL_HP_CLASSAB);
    929  1.1  jmcneill 
    930  1.1  jmcneill 	/* Enable Modules. */
    931  1.1  jmcneill 	AO_WR(sc, HW_AUDIOOUT_PWRDN_CLR,
    932  1.1  jmcneill 	    HW_AUDIOOUT_PWRDN_RIGHT_ADC |
    933  1.1  jmcneill 	    HW_AUDIOOUT_PWRDN_DAC |
    934  1.1  jmcneill 	    HW_AUDIOOUT_PWRDN_CAPLESS |
    935  1.1  jmcneill 	    HW_AUDIOOUT_PWRDN_HEADPHONE
    936  1.1  jmcneill 	);
    937  1.1  jmcneill 
    938  1.1  jmcneill 	return;
    939  1.1  jmcneill }
    940  1.1  jmcneill 
    941  1.1  jmcneill /*
    942  1.1  jmcneill  * Reset the AUDIOOUT block.
    943  1.1  jmcneill  *
    944  1.1  jmcneill  * Inspired by i.MX23 RM "39.3.10 Correct Way to Soft Reset a Block"
    945  1.1  jmcneill  */
    946  1.1  jmcneill static void
    947  1.1  jmcneill digfilt_ao_reset(struct digfilt_softc *sc)
    948  1.1  jmcneill {
    949  1.1  jmcneill 	unsigned int loop;
    950  1.1  jmcneill 
    951  1.1  jmcneill 	/* Prepare for soft-reset by making sure that SFTRST is not currently
    952  1.1  jmcneill 	* asserted. Also clear CLKGATE so we can wait for its assertion below.
    953  1.1  jmcneill 	*/
    954  1.1  jmcneill 	AO_WR(sc, HW_AUDIOOUT_CTRL_CLR, HW_AUDIOOUT_CTRL_SFTRST);
    955  1.1  jmcneill 
    956  1.1  jmcneill 	/* Wait at least a microsecond for SFTRST to deassert. */
    957  1.1  jmcneill 	loop = 0;
    958  1.1  jmcneill 	while ((AO_RD(sc, HW_AUDIOOUT_CTRL) & HW_AUDIOOUT_CTRL_SFTRST) ||
    959  1.1  jmcneill 	    (loop < DIGFILT_SOFT_RST_LOOP))
    960  1.1  jmcneill 		loop++;
    961  1.1  jmcneill 
    962  1.1  jmcneill 	/* Clear CLKGATE so we can wait for its assertion below. */
    963  1.1  jmcneill 	AO_WR(sc, HW_AUDIOOUT_CTRL_CLR, HW_AUDIOOUT_CTRL_CLKGATE);
    964  1.1  jmcneill 
    965  1.1  jmcneill 	/* Soft-reset the block. */
    966  1.1  jmcneill 	AO_WR(sc, HW_AUDIOOUT_CTRL_SET, HW_AUDIOOUT_CTRL_SFTRST);
    967  1.1  jmcneill 
    968  1.1  jmcneill 	/* Wait until clock is in the gated state. */
    969  1.1  jmcneill 	while (!(AO_RD(sc, HW_AUDIOOUT_CTRL) & HW_AUDIOOUT_CTRL_CLKGATE));
    970  1.1  jmcneill 
    971  1.1  jmcneill 	/* Bring block out of reset. */
    972  1.1  jmcneill 	AO_WR(sc, HW_AUDIOOUT_CTRL_CLR, HW_AUDIOOUT_CTRL_SFTRST);
    973  1.1  jmcneill 
    974  1.1  jmcneill 	loop = 0;
    975  1.1  jmcneill 	while ((AO_RD(sc, HW_AUDIOOUT_CTRL) & HW_AUDIOOUT_CTRL_SFTRST) ||
    976  1.1  jmcneill 	    (loop < DIGFILT_SOFT_RST_LOOP))
    977  1.1  jmcneill 		loop++;
    978  1.1  jmcneill 
    979  1.1  jmcneill 	AO_WR(sc, HW_AUDIOOUT_CTRL_CLR, HW_AUDIOOUT_CTRL_CLKGATE);
    980  1.1  jmcneill 
    981  1.1  jmcneill 	/* Wait until clock is in the NON-gated state. */
    982  1.1  jmcneill 	while (AO_RD(sc, HW_AUDIOOUT_CTRL) & HW_AUDIOOUT_CTRL_CLKGATE);
    983  1.1  jmcneill 
    984  1.1  jmcneill 	return;
    985  1.1  jmcneill }
    986  1.1  jmcneill 
    987  1.1  jmcneill static void
    988  1.1  jmcneill digfilt_ao_set_rate(struct digfilt_softc *sc, int sr)
    989  1.1  jmcneill {
    990  1.1  jmcneill 	uint32_t val;
    991  1.1  jmcneill 
    992  1.1  jmcneill 
    993  1.1  jmcneill 	val = AO_RD(sc, HW_AUDIOOUT_DACSRR);
    994  1.1  jmcneill 
    995  1.1  jmcneill 
    996  1.1  jmcneill 	val &= ~(HW_AUDIOOUT_DACSRR_BASEMULT | HW_AUDIOOUT_DACSRR_SRC_HOLD |
    997  1.1  jmcneill 	    HW_AUDIOOUT_DACSRR_SRC_INT | HW_AUDIOOUT_DACSRR_SRC_FRAC);
    998  1.1  jmcneill 
    999  1.1  jmcneill 	switch(sr) {
   1000  1.1  jmcneill 	case 8000:
   1001  1.1  jmcneill 		val |= (__SHIFTIN(0x1 ,HW_AUDIOOUT_DACSRR_BASEMULT) |
   1002  1.1  jmcneill 		    __SHIFTIN(0x3, HW_AUDIOOUT_DACSRR_SRC_HOLD) |
   1003  1.1  jmcneill 		    __SHIFTIN(0x17, HW_AUDIOOUT_DACSRR_SRC_INT) |
   1004  1.1  jmcneill 		    __SHIFTIN(0x0E00, HW_AUDIOOUT_DACSRR_SRC_FRAC));
   1005  1.1  jmcneill 		break;
   1006  1.1  jmcneill 	case 11025:
   1007  1.1  jmcneill 		val |= (__SHIFTIN(0x1 ,HW_AUDIOOUT_DACSRR_BASEMULT) |
   1008  1.1  jmcneill 		    __SHIFTIN(0x3, HW_AUDIOOUT_DACSRR_SRC_HOLD) |
   1009  1.1  jmcneill 		    __SHIFTIN(0x11, HW_AUDIOOUT_DACSRR_SRC_INT) |
   1010  1.1  jmcneill 		    __SHIFTIN(0x0037, HW_AUDIOOUT_DACSRR_SRC_FRAC));
   1011  1.1  jmcneill 		break;
   1012  1.1  jmcneill 	case 12000:
   1013  1.1  jmcneill 		val |= (__SHIFTIN(0x1 ,HW_AUDIOOUT_DACSRR_BASEMULT) |
   1014  1.1  jmcneill 		    __SHIFTIN(0x3, HW_AUDIOOUT_DACSRR_SRC_HOLD) |
   1015  1.1  jmcneill 		    __SHIFTIN(0x0F, HW_AUDIOOUT_DACSRR_SRC_INT) |
   1016  1.1  jmcneill 		    __SHIFTIN(0x13FF, HW_AUDIOOUT_DACSRR_SRC_FRAC));
   1017  1.1  jmcneill 		break;
   1018  1.1  jmcneill 	case 16000:
   1019  1.1  jmcneill 		val |= (__SHIFTIN(0x1 ,HW_AUDIOOUT_DACSRR_BASEMULT) |
   1020  1.1  jmcneill 		    __SHIFTIN(0x1, HW_AUDIOOUT_DACSRR_SRC_HOLD) |
   1021  1.1  jmcneill 		    __SHIFTIN(0x17, HW_AUDIOOUT_DACSRR_SRC_INT) |
   1022  1.1  jmcneill 		    __SHIFTIN(0x0E00, HW_AUDIOOUT_DACSRR_SRC_FRAC));
   1023  1.1  jmcneill 		break;
   1024  1.1  jmcneill 	case 22050:
   1025  1.1  jmcneill 		val |= (__SHIFTIN(0x1 ,HW_AUDIOOUT_DACSRR_BASEMULT) |
   1026  1.1  jmcneill 		    __SHIFTIN(0x1, HW_AUDIOOUT_DACSRR_SRC_HOLD) |
   1027  1.1  jmcneill 		    __SHIFTIN(0x11, HW_AUDIOOUT_DACSRR_SRC_INT) |
   1028  1.1  jmcneill 		    __SHIFTIN(0x0037, HW_AUDIOOUT_DACSRR_SRC_FRAC));
   1029  1.1  jmcneill 		break;
   1030  1.1  jmcneill 	case 24000:
   1031  1.1  jmcneill 		val |= (__SHIFTIN(0x1 ,HW_AUDIOOUT_DACSRR_BASEMULT) |
   1032  1.1  jmcneill 		    __SHIFTIN(0x1, HW_AUDIOOUT_DACSRR_SRC_HOLD) |
   1033  1.1  jmcneill 		    __SHIFTIN(0x0F, HW_AUDIOOUT_DACSRR_SRC_INT) |
   1034  1.1  jmcneill 		    __SHIFTIN(0x13FF, HW_AUDIOOUT_DACSRR_SRC_FRAC));
   1035  1.1  jmcneill 		break;
   1036  1.1  jmcneill 	case 32000:
   1037  1.1  jmcneill 		val |= (__SHIFTIN(0x1 ,HW_AUDIOOUT_DACSRR_BASEMULT) |
   1038  1.1  jmcneill 		    __SHIFTIN(0x0, HW_AUDIOOUT_DACSRR_SRC_HOLD) |
   1039  1.1  jmcneill 		    __SHIFTIN(0x17, HW_AUDIOOUT_DACSRR_SRC_INT) |
   1040  1.1  jmcneill 		    __SHIFTIN(0x0E00, HW_AUDIOOUT_DACSRR_SRC_FRAC));
   1041  1.1  jmcneill 		break;
   1042  1.1  jmcneill 	default:
   1043  1.4    andvar 		aprint_error_dev(sc->sc_dev, "unknown sample rate: %d\n", sr);
   1044  1.1  jmcneill 	case 44100:
   1045  1.1  jmcneill 		val |= (__SHIFTIN(0x1 ,HW_AUDIOOUT_DACSRR_BASEMULT) |
   1046  1.1  jmcneill 		    __SHIFTIN(0x0, HW_AUDIOOUT_DACSRR_SRC_HOLD) |
   1047  1.1  jmcneill 		    __SHIFTIN(0x11, HW_AUDIOOUT_DACSRR_SRC_INT) |
   1048  1.1  jmcneill 		    __SHIFTIN(0x0037, HW_AUDIOOUT_DACSRR_SRC_FRAC));
   1049  1.1  jmcneill 		break;
   1050  1.1  jmcneill 	}
   1051  1.1  jmcneill 
   1052  1.1  jmcneill 	AO_WR(sc, HW_AUDIOOUT_DACSRR, val);
   1053  1.1  jmcneill 
   1054  1.1  jmcneill 	val = AO_RD(sc, HW_AUDIOOUT_DACSRR);
   1055  1.1  jmcneill 
   1056  1.1  jmcneill 	return;
   1057  1.1  jmcneill }
   1058  1.1  jmcneill #if 0
   1059  1.1  jmcneill /*
   1060  1.1  jmcneill  * Reset the AUDIOIN block.
   1061  1.1  jmcneill  *
   1062  1.1  jmcneill  * Inspired by i.MX23 RM "39.3.10 Correct Way to Soft Reset a Block"
   1063  1.1  jmcneill  */
   1064  1.1  jmcneill static void
   1065  1.1  jmcneill digfilt_ai_reset(struct digfilt_softc *sc)
   1066  1.1  jmcneill {
   1067  1.1  jmcneill 	unsigned int loop;
   1068  1.1  jmcneill 
   1069  1.1  jmcneill 	/* Prepare for soft-reset by making sure that SFTRST is not currently
   1070  1.1  jmcneill 	* asserted. Also clear CLKGATE so we can wait for its assertion below.
   1071  1.1  jmcneill 	*/
   1072  1.1  jmcneill 	AI_WR(sc, HW_AUDIOIN_CTRL_CLR, HW_AUDIOIN_CTRL_SFTRST);
   1073  1.1  jmcneill 
   1074  1.1  jmcneill 	/* Wait at least a microsecond for SFTRST to deassert. */
   1075  1.1  jmcneill 	loop = 0;
   1076  1.1  jmcneill 	while ((AI_RD(sc, HW_AUDIOIN_CTRL) & HW_AUDIOIN_CTRL_SFTRST) ||
   1077  1.1  jmcneill 	    (loop < DIGFILT_SOFT_RST_LOOP))
   1078  1.1  jmcneill 		loop++;
   1079  1.1  jmcneill 
   1080  1.1  jmcneill 	/* Clear CLKGATE so we can wait for its assertion below. */
   1081  1.1  jmcneill 	AI_WR(sc, HW_AUDIOIN_CTRL_CLR, HW_AUDIOIN_CTRL_CLKGATE);
   1082  1.1  jmcneill 
   1083  1.1  jmcneill 	/* Soft-reset the block. */
   1084  1.1  jmcneill 	AI_WR(sc, HW_AUDIOIN_CTRL_SET, HW_AUDIOIN_CTRL_SFTRST);
   1085  1.1  jmcneill 
   1086  1.1  jmcneill 	/* Wait until clock is in the gated state. */
   1087  1.1  jmcneill 	while (!(AI_RD(sc, HW_AUDIOIN_CTRL) & HW_AUDIOIN_CTRL_CLKGATE));
   1088  1.1  jmcneill 
   1089  1.1  jmcneill 	/* Bring block out of reset. */
   1090  1.1  jmcneill 	AI_WR(sc, HW_AUDIOIN_CTRL_CLR, HW_AUDIOIN_CTRL_SFTRST);
   1091  1.1  jmcneill 
   1092  1.1  jmcneill 	loop = 0;
   1093  1.1  jmcneill 	while ((AI_RD(sc, HW_AUDIOIN_CTRL) & HW_AUDIOIN_CTRL_SFTRST) ||
   1094  1.1  jmcneill 	    (loop < DIGFILT_SOFT_RST_LOOP))
   1095  1.1  jmcneill 		loop++;
   1096  1.1  jmcneill 
   1097  1.1  jmcneill 	AI_WR(sc, HW_AUDIOIN_CTRL_CLR, HW_AUDIOIN_CTRL_CLKGATE);
   1098  1.1  jmcneill 
   1099  1.1  jmcneill 	/* Wait until clock is in the NON-gated state. */
   1100  1.1  jmcneill 	while (AI_RD(sc, HW_AUDIOIN_CTRL) & HW_AUDIOIN_CTRL_CLKGATE);
   1101  1.1  jmcneill 
   1102  1.1  jmcneill 	return;
   1103  1.1  jmcneill }
   1104  1.1  jmcneill #endif
   1105