Home | History | Annotate | Line # | Download | only in imx
      1 /* $NetBSD: imx23_digfilt.c,v 1.12 2026/07/07 04:54:34 skrll Exp $ */
      2 
      3 /*
      4  * Copyright (c) 2014 The NetBSD Foundation, Inc.
      5  * All rights reserved.
      6  *
      7  * This code is derived from software contributed to The NetBSD Foundation
      8  * by Petri Laakso.
      9  *
     10  * Redistribution and use in source and binary forms, with or without
     11  * modification, are permitted provided that the following conditions
     12  * are met:
     13  * 1. Redistributions of source code must retain the above copyright
     14  *    notice, this list of conditions and the following disclaimer.
     15  * 2. Redistributions in binary form must reproduce the above copyright
     16  *    notice, this list of conditions and the following disclaimer in the
     17  *    documentation and/or other materials provided with the distribution.
     18  *
     19  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
     20  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
     21  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
     22  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
     23  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
     24  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
     25  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
     26  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
     27  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
     28  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
     29  * POSSIBILITY OF SUCH DAMAGE.
     30  */
     31 
     32 #include <sys/param.h>
     33 #include <sys/cdefs.h>
     34 #include <sys/types.h>
     35 #include <sys/device.h>
     36 #include <sys/errno.h>
     37 #include <sys/systm.h>
     38 #include <sys/bus.h>
     39 #include <sys/mutex.h>
     40 #include <sys/audioio.h>
     41 #include <sys/mallocvar.h>
     42 
     43 #include <dev/audio/audio_if.h>
     44 #include <dev/fdt/fdtvar.h>
     45 
     46 #include <arm/imx/imx23_digfiltreg.h>
     47 #include <arm/imx/imx23var.h>
     48 
     49 #define DIGFILT_DMA_NSEGS 1
     50 
     51 struct imx23_digfilt_softc {
     52 	device_t sc_dev;
     53 	device_t sc_audiodev;
     54 	struct audio_format sc_format;
     55 	bus_space_handle_t sc_aohdl;
     56 	struct fdtbus_dma *dma_channel;
     57 	bus_dma_tag_t sc_dmat;
     58 	bus_dmamap_t sc_dmamp;
     59 	bus_dma_segment_t sc_ds[DIGFILT_DMA_NSEGS];
     60 	bus_space_handle_t sc_hdl;
     61 	bus_space_tag_t	sc_iot;
     62 	kmutex_t sc_intr_lock;
     63 	kmutex_t sc_lock;
     64 	audio_params_t sc_pparam;
     65 	void *sc_buffer;
     66 	void *sc_intarg;
     67 	void (*sc_intr)(void*);
     68 	uint8_t sc_mute;
     69 };
     70 
     71 /* Autoconf. */
     72 static int imx23_digfilt_match(device_t, cfdata_t, void *);
     73 static void imx23_digfilt_attach(device_t, device_t, void *);
     74 
     75 /* Audio driver interface. */
     76 static int imx23_digfilt_query_format(void *, audio_format_query_t *);
     77 static int imx23_digfilt_set_format(void *, int, const audio_params_t *,
     78 			 const audio_params_t *, audio_filter_reg_t *,
     79 			 audio_filter_reg_t *);
     80 static int imx23_digfilt_round_blocksize(void *, int, int,
     81 					 const audio_params_t *);
     82 static int imx23_digfilt_init_output(void *, void *, int );
     83 static int imx23_digfilt_start_output(void *, void *, int, void (*)(void *),
     84 				      void *);
     85 static int imx23_digfilt_halt_output(void *);
     86 static int imx23_digfilt_getdev(void *, struct audio_device *);
     87 static int imx23_digfilt_set_port(void *, mixer_ctrl_t *);
     88 static int imx23_digfilt_get_port(void *, mixer_ctrl_t *);
     89 static int imx23_digfilt_query_devinfo(void *, mixer_devinfo_t *);
     90 static void *imx23_digfilt_allocm(void *, int, size_t);
     91 static void imx23_digfilt_freem(void *, void *, size_t);
     92 static size_t imx23_digfilt_round_buffersize(void *, int, size_t);
     93 static int imx23_digfilt_get_props(void *);
     94 static void imx23_digfilt_get_locks(void *, kmutex_t **, kmutex_t **);
     95 
     96 /* IRQs */
     97 static int imx23_dac_error_intr(void *);
     98 static void imx23_dac_dma_intr(void *);
     99 
    100 /* Audio out. */
    101 static void imx23_digfilt_ao_apply_mutes(struct imx23_digfilt_softc *);
    102 static void imx23_digfilt_ao_init(struct imx23_digfilt_softc *);
    103 static void imx23_digfilt_ao_reset(struct imx23_digfilt_softc *);
    104 static void imx23_digfilt_ao_set_rate(struct imx23_digfilt_softc *, int);
    105 
    106 #define DIGFILT_BLOCKSIZE_MAX 8192
    107 #define DIGFILT_BLOCKSIZE_ROUND 2048
    108 #define DIGFILT_DMA_CHAIN_LENGTH 3
    109 #define DIGFILT_DMA_CHANNEL 1
    110 #define DIGFILT_MUTE_DAC 1
    111 #define DIGFILT_MUTE_HP 2
    112 #define DIGFILT_MUTE_LINE 4
    113 #define DIGFILT_SOFT_RST_LOOP 455	/* At least 1 us. */
    114 
    115 #define AO_RD(sc, reg)							\
    116 	bus_space_read_4(sc->sc_iot, sc->sc_aohdl, (reg))
    117 #define AO_WR(sc, reg, val)						\
    118 	bus_space_write_4(sc->sc_iot, sc->sc_aohdl, (reg), (val))
    119 
    120 CFATTACH_DECL_NEW(imx23digfilt, sizeof(struct imx23_digfilt_softc),
    121 		  imx23_digfilt_match, imx23_digfilt_attach, NULL, NULL);
    122 
    123 static const struct audio_hw_if imx23_digfilt_hw_if = {
    124 	.open = NULL,
    125 	.close = NULL,
    126 	.query_format = imx23_digfilt_query_format,
    127 	.set_format = imx23_digfilt_set_format,
    128 	.round_blocksize = imx23_digfilt_round_blocksize,
    129 	.commit_settings = NULL,
    130 	.init_output = imx23_digfilt_init_output,
    131 	.init_input = NULL,
    132 	.start_output = imx23_digfilt_start_output,
    133 	.start_input = NULL,
    134 	.halt_output = imx23_digfilt_halt_output,
    135 	.speaker_ctl = NULL,
    136 	.getdev = imx23_digfilt_getdev,
    137 	.set_port = imx23_digfilt_set_port,
    138 	.get_port = imx23_digfilt_get_port,
    139 	.query_devinfo = imx23_digfilt_query_devinfo,
    140 	.allocm = imx23_digfilt_allocm,
    141 	.freem = imx23_digfilt_freem,
    142 	.round_buffersize = imx23_digfilt_round_buffersize,
    143 	.get_props = imx23_digfilt_get_props,
    144 	.trigger_output = NULL,
    145 	.trigger_input = NULL,
    146 	.dev_ioctl = NULL,
    147 	.get_locks = imx23_digfilt_get_locks
    148 };
    149 
    150 enum {
    151 	DIGFILT_OUTPUT_CLASS,
    152 	DIGFILT_OUTPUT_DAC_VOLUME,
    153 	DIGFILT_OUTPUT_DAC_MUTE,
    154 	DIGFILT_OUTPUT_HP_VOLUME,
    155 	DIGFILT_OUTPUT_HP_MUTE,
    156 	DIGFILT_OUTPUT_LINE_VOLUME,
    157 	DIGFILT_OUTPUT_LINE_MUTE,
    158 	DIGFILT_ENUM_LAST
    159 };
    160 
    161 static const struct device_compatible_entry compat_data[] = {
    162 	{ .compat = "fsl,imx23-audioout" },
    163 	DEVICE_COMPAT_EOL
    164 };
    165 
    166 static int
    167 imx23_digfilt_match(device_t parent, cfdata_t match, void *aux)
    168 {
    169 	struct fdt_attach_args * const faa = aux;
    170 
    171 	return of_compatible_match(faa->faa_phandle, compat_data);
    172 }
    173 
    174 static void
    175 imx23_digfilt_attach(device_t parent, device_t self, void *aux)
    176 {
    177 	struct imx23_digfilt_softc * const sc = device_private(self);
    178 	struct fdt_attach_args * const faa = aux;
    179 	const int phandle = faa->faa_phandle;
    180 	int error;
    181 	char intrstr[128];
    182 
    183 	sc->sc_dev = self;
    184 	sc->sc_iot = faa->faa_bst;
    185 	sc->sc_dmat = faa->faa_dmat;
    186 
    187 	bus_addr_t addr;
    188 	bus_size_t size;
    189 	if (fdtbus_get_reg(phandle, 0, &addr, &size) != 0) {
    190 		aprint_error(": couldn't get register address\n");
    191 		return;
    192 	}
    193 	/* Map DIGFILT bus space. */
    194 	if (bus_space_map(faa->faa_bst, addr, size, 0, &sc->sc_hdl)) {
    195 		aprint_error(": couldn't map registers\n");
    196 		return;
    197 	}
    198 	/* Map AUDIOOUT subregion from parent bus space. */
    199 	if (bus_space_subregion(sc->sc_iot, sc->sc_hdl, 0, size,
    200 				&sc->sc_aohdl)) {
    201 		aprint_error_dev(sc->sc_dev,
    202 				 "Unable to submap AUDIOOUT bus space\n");
    203 		return;
    204 	}
    205 
    206 	/* acquire DMA channel */
    207 	sc->dma_channel = fdtbus_dma_get(phandle,"tx", imx23_dac_dma_intr, sc);
    208 	if (sc->dma_channel == NULL) {
    209 		aprint_error(": couldn't get dma access\n");
    210 		return;
    211 	}
    212 
    213 	/* Allocate DMA for audio buffer. */
    214 	error = bus_dmamap_create(sc->sc_dmat, MAXPHYS, DIGFILT_DMA_NSEGS,
    215 				  MAXPHYS, 0, BUS_DMA_NOWAIT | BUS_DMA_ALLOCNOW,
    216 				  &sc->sc_dmamp);
    217 	if (error) {
    218 		aprint_error_dev(sc->sc_dev, "Unable to allocate DMA handle\n");
    219 		return;
    220 	}
    221 
    222 	imx23_digfilt_ao_reset(sc);	/* Reset AUDIOOUT. */
    223 
    224 	uint32_t v = AO_RD(sc, HW_AUDIOOUT_VERSION);
    225 	aprint_normal(": DIGFILT Block v%" __PRIuBIT ".%" __PRIuBIT
    226 		".%" __PRIuBIT,
    227 		__SHIFTOUT(v, HW_AUDIOOUT_VERSION_MAJOR),
    228 		__SHIFTOUT(v, HW_AUDIOOUT_VERSION_MINOR),
    229 		__SHIFTOUT(v, HW_AUDIOOUT_VERSION_STEP));
    230 
    231 	imx23_digfilt_ao_init(sc);
    232 	/* Default sample rate 44.1 kHz. */
    233 	imx23_digfilt_ao_set_rate(sc, 44100);
    234 
    235 	mutex_init(&sc->sc_lock, MUTEX_DEFAULT, IPL_NONE);
    236 	mutex_init(&sc->sc_intr_lock, MUTEX_DEFAULT, IPL_SCHED);
    237 
    238 	/* HW supported formats. */
    239 	sc->sc_format.mode = AUMODE_PLAY;
    240 	sc->sc_format.encoding = AUDIO_ENCODING_SLINEAR_LE;
    241 	sc->sc_format.validbits = 16;
    242 	sc->sc_format.precision = 16;
    243 	sc->sc_format.channels = 2;
    244 	sc->sc_format.channel_mask = AUFMT_STEREO;
    245 	sc->sc_format.frequency_type = 8;
    246 	sc->sc_format.frequency[0] = 8000;
    247 	sc->sc_format.frequency[1] = 11025;
    248 	sc->sc_format.frequency[2] = 12000;
    249 	sc->sc_format.frequency[3] = 16000;
    250 	sc->sc_format.frequency[4] = 22050;
    251 	sc->sc_format.frequency[5] = 24000;
    252 	sc->sc_format.frequency[6] = 32000;
    253 	sc->sc_format.frequency[7] = 44100;
    254 
    255 	sc->sc_audiodev = audio_attach_mi(&imx23_digfilt_hw_if, sc, sc->sc_dev);
    256 
    257 	/* Default mutes. */
    258 	sc->sc_mute = DIGFILT_MUTE_LINE;
    259 	imx23_digfilt_ao_apply_mutes(sc);
    260 
    261 	/* establish error interrupt */
    262 	if (!fdtbus_intr_str(phandle, 0, intrstr, sizeof(intrstr))) {
    263 		aprint_error(": failed to decode interrupt\n");
    264 		return;
    265 	}
    266 	void *ih = fdtbus_intr_establish_xname(phandle, 0, IPL_SCHED, IST_LEVEL,
    267 					       imx23_dac_error_intr, sc,
    268 					       device_xname(self));
    269 	if (ih == NULL) {
    270 		aprint_error_dev(self, "couldn't establish error interrupt\n");
    271 		return;
    272 	}
    273 
    274 	aprint_normal("\n");
    275 }
    276 
    277 static int
    278 imx23_digfilt_query_format(void *priv, audio_format_query_t *afp)
    279 {
    280 	struct imx23_digfilt_softc *sc = priv;
    281 
    282 	return audio_query_format(&sc->sc_format, 1, afp);
    283 }
    284 
    285 static int
    286 imx23_digfilt_set_format(void *priv, int setmode, const audio_params_t *play,
    287 			 const audio_params_t *rec, audio_filter_reg_t *pfil,
    288 			 audio_filter_reg_t *rfil)
    289 {
    290 	struct imx23_digfilt_softc *sc = priv;
    291 
    292 	if ((setmode & AUMODE_PLAY)) {
    293 		sc->sc_pparam = *play;
    294 
    295 		/* At this point bitrate should be figured out. */
    296 		imx23_digfilt_ao_set_rate(sc, sc->sc_pparam.sample_rate);
    297 	}
    298 
    299 	return 0;
    300 }
    301 
    302 static int
    303 imx23_digfilt_round_blocksize(void *priv, int bs, int mode,
    304 			const audio_params_t *param)
    305 {
    306 	int blocksize;
    307 
    308 	if (bs > DIGFILT_BLOCKSIZE_MAX)
    309 		blocksize = DIGFILT_BLOCKSIZE_MAX;
    310 	else
    311 		blocksize = bs & ~(DIGFILT_BLOCKSIZE_ROUND-1);
    312 	if (blocksize < DIGFILT_BLOCKSIZE_ROUND)
    313 		blocksize = DIGFILT_BLOCKSIZE_ROUND;
    314 
    315 	return blocksize;
    316 }
    317 
    318 static int
    319 imx23_digfilt_init_output(void *priv, void *buffer, int size)
    320 {
    321 	return 0;
    322 }
    323 
    324 static int
    325 imx23_digfilt_start_output(void *priv, void *start, int bs,
    326 			   void (*intr)(void *), void *intarg)
    327 {
    328 	struct imx23_digfilt_softc *sc = priv;
    329 	struct fdtbus_dma_req req;
    330 
    331 	sc->sc_intr = intr;
    332 	sc->sc_intarg = intarg;
    333 
    334 	/* synthesize a dma segment with the correct offset+size */
    335 	bus_addr_t offset = (bus_addr_t)start - (bus_addr_t)sc->sc_buffer;
    336 	bus_dma_segment_t dma_seg;
    337 	dma_seg.ds_addr = sc->sc_dmamp->dm_segs[0].ds_addr + offset;
    338 	dma_seg.ds_len = bs;
    339 
    340 	/* configure DMA request */
    341 	req.dreq_dir = FDT_DMA_WRITE;
    342 	req.dreq_segs = &dma_seg;
    343 	req.dreq_nsegs = 1;
    344 	req.dreq_block_irq = 0;
    345 
    346 	/* configure DMA PIO words */
    347 	uint32_t pio_words[1];
    348 	pio_words[0] = HW_AUDIOOUT_CTRL_WORD_LENGTH |
    349 		       HW_AUDIOOUT_CTRL_RUN;
    350 	req.dreq_datalen = 1;
    351 	req.dreq_data = &pio_words;
    352 
    353 	/* send it off*/
    354 	bus_dmamap_sync(sc->sc_dmat, sc->sc_dmamp, offset, bs,
    355 			BUS_DMASYNC_PREWRITE);
    356 	fdtbus_dma_transfer(sc->dma_channel, &req);
    357 
    358 	return 0;
    359 }
    360 
    361 static int
    362 imx23_digfilt_halt_output(void *priv)
    363 {
    364 	struct imx23_digfilt_softc *sc = priv;
    365 
    366 	/* We have intr lock when this is called */
    367 	sc->sc_intr = NULL;
    368 
    369 	return 0;
    370 }
    371 
    372 static int
    373 imx23_digfilt_getdev(void *priv, struct audio_device *ad)
    374 {
    375 	struct imx23_digfilt_softc *sc = priv;
    376 
    377 	strncpy(ad->name, device_xname(sc->sc_dev), MAX_AUDIO_DEV_LEN);
    378 	strncpy(ad->version, "", MAX_AUDIO_DEV_LEN);
    379 	strncpy(ad->config, "", MAX_AUDIO_DEV_LEN);
    380 
    381 	return 0;
    382 }
    383 
    384 static int
    385 imx23_digfilt_set_port(void *priv, mixer_ctrl_t *mc)
    386 {
    387 	struct imx23_digfilt_softc *sc = priv;
    388 	uint32_t val;
    389 	uint8_t nvol;
    390 
    391 	switch (mc->dev) {
    392 	case DIGFILT_OUTPUT_DAC_VOLUME:
    393 		val = AO_RD(sc, HW_AUDIOOUT_DACVOLUME);
    394 		val &= ~(HW_AUDIOOUT_DACVOLUME_VOLUME_LEFT |
    395 		    HW_AUDIOOUT_DACVOLUME_VOLUME_RIGHT);
    396 
    397 		/* DAC volume field is 8 bits. */
    398 		nvol = mc->un.value.level[AUDIO_MIXER_LEVEL_LEFT];
    399 		if (nvol > 0xff)
    400 			nvol = 0xff;
    401 
    402 		val |= __SHIFTIN(nvol, HW_AUDIOOUT_DACVOLUME_VOLUME_LEFT);
    403 
    404 		nvol = mc->un.value.level[AUDIO_MIXER_LEVEL_RIGHT];
    405 		if (nvol > 0xff)
    406 			nvol = 0xff;
    407 
    408 		val |= __SHIFTIN(nvol, HW_AUDIOOUT_DACVOLUME_VOLUME_RIGHT);
    409 
    410 		AO_WR(sc, HW_AUDIOOUT_DACVOLUME, val);
    411 
    412 		return 0;
    413 
    414 	case DIGFILT_OUTPUT_HP_VOLUME:
    415 		val = AO_RD(sc, HW_AUDIOOUT_HPVOL);
    416 		val &= ~(HW_AUDIOOUT_HPVOL_VOL_LEFT |
    417 		    HW_AUDIOOUT_HPVOL_VOL_RIGHT);
    418 
    419 		/* HP volume field is 7 bits. */
    420 		nvol = mc->un.value.level[AUDIO_MIXER_LEVEL_LEFT];
    421 		if (nvol > 0x7f)
    422 			nvol = 0x7f;
    423 
    424 		nvol = ~nvol;
    425 		val |= __SHIFTIN(nvol, HW_AUDIOOUT_HPVOL_VOL_LEFT);
    426 
    427 		nvol = mc->un.value.level[AUDIO_MIXER_LEVEL_RIGHT];
    428 		if (nvol > 0x7f)
    429 			nvol = 0x7f;
    430 
    431 		nvol = ~nvol;
    432 		val |= __SHIFTIN(nvol, HW_AUDIOOUT_HPVOL_VOL_RIGHT);
    433 
    434 		AO_WR(sc, HW_AUDIOOUT_HPVOL, val);
    435 
    436 		return 0;
    437 
    438 	case DIGFILT_OUTPUT_LINE_VOLUME:
    439 		return 1;
    440 
    441 	case DIGFILT_OUTPUT_DAC_MUTE:
    442 		if (mc->un.ord)
    443 			sc->sc_mute |= DIGFILT_MUTE_DAC;
    444 		else
    445 			sc->sc_mute &= ~DIGFILT_MUTE_DAC;
    446 
    447 		imx23_digfilt_ao_apply_mutes(sc);
    448 
    449 		return 0;
    450 
    451 	case DIGFILT_OUTPUT_HP_MUTE:
    452 		if (mc->un.ord)
    453 			sc->sc_mute |= DIGFILT_MUTE_HP;
    454 		else
    455 			sc->sc_mute &= ~DIGFILT_MUTE_HP;
    456 
    457 		imx23_digfilt_ao_apply_mutes(sc);
    458 
    459 		return 0;
    460 
    461 	case DIGFILT_OUTPUT_LINE_MUTE:
    462 		if (mc->un.ord)
    463 			sc->sc_mute |= DIGFILT_MUTE_LINE;
    464 		else
    465 			sc->sc_mute &= ~DIGFILT_MUTE_LINE;
    466 
    467 		imx23_digfilt_ao_apply_mutes(sc);
    468 
    469 		return 0;
    470 	}
    471 
    472 	return ENXIO;
    473 }
    474 
    475 static int
    476 imx23_digfilt_get_port(void *priv, mixer_ctrl_t *mc)
    477 {
    478 	struct imx23_digfilt_softc *sc = priv;
    479 	uint32_t val;
    480 	uint8_t nvol;
    481 
    482 	switch (mc->dev) {
    483 	case DIGFILT_OUTPUT_DAC_VOLUME:
    484 		val = AO_RD(sc, HW_AUDIOOUT_DACVOLUME);
    485 
    486 		nvol = __SHIFTOUT(val, HW_AUDIOOUT_DACVOLUME_VOLUME_LEFT);
    487 		mc->un.value.level[AUDIO_MIXER_LEVEL_LEFT] = nvol;
    488 
    489 		nvol = __SHIFTOUT(val, HW_AUDIOOUT_DACVOLUME_VOLUME_RIGHT);
    490 		mc->un.value.level[AUDIO_MIXER_LEVEL_RIGHT] = nvol;
    491 
    492 		return 0;
    493 
    494 	case DIGFILT_OUTPUT_HP_VOLUME:
    495 		val = AO_RD(sc, HW_AUDIOOUT_HPVOL);
    496 
    497 		nvol = __SHIFTOUT(val, HW_AUDIOOUT_HPVOL_VOL_LEFT);
    498 		mc->un.value.level[AUDIO_MIXER_LEVEL_LEFT] = ~nvol & 0x7f;
    499 
    500 		nvol = __SHIFTOUT(val, HW_AUDIOOUT_HPVOL_VOL_RIGHT);
    501 		mc->un.value.level[AUDIO_MIXER_LEVEL_RIGHT] = ~nvol & 0x7f;
    502 
    503 		return 0;
    504 
    505 	case DIGFILT_OUTPUT_LINE_VOLUME:
    506 		mc->un.value.level[AUDIO_MIXER_LEVEL_LEFT] = 255;
    507 		mc->un.value.level[AUDIO_MIXER_LEVEL_RIGHT] = 255;
    508 
    509 		return 0;
    510 
    511 	case DIGFILT_OUTPUT_DAC_MUTE:
    512 		val = AO_RD(sc, HW_AUDIOOUT_DACVOLUME);
    513 
    514 		mc->un.ord = (val & (HW_AUDIOOUT_DACVOLUME_MUTE_LEFT |
    515 		    HW_AUDIOOUT_DACVOLUME_MUTE_RIGHT)) ? 1 : 0;
    516 
    517 		return 0;
    518 
    519 	case DIGFILT_OUTPUT_HP_MUTE:
    520 		val = AO_RD(sc, HW_AUDIOOUT_HPVOL);
    521 
    522 		mc->un.ord = (val & HW_AUDIOOUT_HPVOL_MUTE) ? 1 : 0;
    523 
    524 		return 0;
    525 
    526 	case DIGFILT_OUTPUT_LINE_MUTE:
    527 		val = AO_RD(sc, HW_AUDIOOUT_SPEAKERCTRL);
    528 
    529 		mc->un.ord = (val & HW_AUDIOOUT_SPEAKERCTRL_MUTE) ? 1 : 0;
    530 
    531 		return 0;
    532 	}
    533 
    534 	return ENXIO;
    535 }
    536 
    537 static int
    538 imx23_digfilt_query_devinfo(void *priv, mixer_devinfo_t *di)
    539 {
    540 
    541 	switch (di->index) {
    542 	case DIGFILT_OUTPUT_CLASS:
    543 		di->mixer_class = DIGFILT_OUTPUT_CLASS;
    544 		strcpy(di->label.name, AudioCoutputs);
    545 		di->type = AUDIO_MIXER_CLASS;
    546 		di->next = di->prev = AUDIO_MIXER_LAST;
    547 		return 0;
    548 
    549 	case DIGFILT_OUTPUT_DAC_VOLUME:
    550 		di->mixer_class = DIGFILT_OUTPUT_CLASS;
    551 		strcpy(di->label.name, AudioNdac);
    552 		di->type = AUDIO_MIXER_VALUE;
    553 		di->prev = AUDIO_MIXER_LAST;
    554 		di->next = DIGFILT_OUTPUT_DAC_MUTE;
    555 		di->un.v.num_channels = 2;
    556 		strcpy(di->un.v.units.name, AudioNvolume);
    557 		return 0;
    558 
    559 	case DIGFILT_OUTPUT_DAC_MUTE:
    560 		di->mixer_class = DIGFILT_OUTPUT_CLASS;
    561 		di->type = AUDIO_MIXER_ENUM;
    562 		di->prev = DIGFILT_OUTPUT_DAC_VOLUME;
    563 		di->next = AUDIO_MIXER_LAST;
    564 mute:
    565 		strlcpy(di->label.name, AudioNmute, sizeof(di->label.name));
    566 		di->un.e.num_mem = 2;
    567 		strlcpy(di->un.e.member[0].label.name, AudioNon,
    568 		    sizeof(di->un.e.member[0].label.name));
    569 		di->un.e.member[0].ord = 1;
    570 		strlcpy(di->un.e.member[1].label.name, AudioNoff,
    571 		    sizeof(di->un.e.member[1].label.name));
    572 		di->un.e.member[1].ord = 0;
    573 		return 0;
    574 
    575 	case DIGFILT_OUTPUT_HP_VOLUME:
    576 		di->mixer_class = DIGFILT_OUTPUT_CLASS;
    577 		strcpy(di->label.name, AudioNheadphone);
    578 		di->type = AUDIO_MIXER_VALUE;
    579 		di->prev = AUDIO_MIXER_LAST;
    580 		di->next = DIGFILT_OUTPUT_HP_MUTE;
    581 		di->un.v.num_channels = 2;
    582 		strcpy(di->un.v.units.name, AudioNvolume);
    583 		return 0;
    584 
    585 	case DIGFILT_OUTPUT_HP_MUTE:
    586 		di->mixer_class = DIGFILT_OUTPUT_CLASS;
    587 		di->type = AUDIO_MIXER_ENUM;
    588 		di->prev = DIGFILT_OUTPUT_HP_VOLUME;
    589 		di->next = AUDIO_MIXER_LAST;
    590 		goto mute;
    591 
    592 	case DIGFILT_OUTPUT_LINE_VOLUME:
    593 		di->mixer_class = DIGFILT_OUTPUT_CLASS;
    594 		strcpy(di->label.name, AudioNline);
    595 		di->type = AUDIO_MIXER_VALUE;
    596 		di->prev = AUDIO_MIXER_LAST;
    597 		di->next = DIGFILT_OUTPUT_LINE_MUTE;
    598 		di->un.v.num_channels = 2;
    599 		strcpy(di->un.v.units.name, AudioNvolume);
    600 		return 0;
    601 
    602 	case DIGFILT_OUTPUT_LINE_MUTE:
    603 		di->mixer_class = DIGFILT_OUTPUT_CLASS;
    604 		di->type = AUDIO_MIXER_ENUM;
    605 		di->prev = DIGFILT_OUTPUT_LINE_VOLUME;
    606 		di->next = AUDIO_MIXER_LAST;
    607 		goto mute;
    608 	}
    609 
    610 	return ENXIO;
    611 }
    612 
    613 static void *
    614 imx23_digfilt_allocm(void *priv, int direction, size_t size)
    615 {
    616 	struct imx23_digfilt_softc *sc = priv;
    617 	int rsegs;
    618 	int error;
    619 
    620 	sc->sc_buffer = NULL;
    621 
    622 	/*
    623 	 * AUMODE_PLAY is DMA from memory to device.
    624 	 */
    625 	if (direction != AUMODE_PLAY)
    626 		return NULL;
    627 
    628 	error = bus_dmamem_alloc(sc->sc_dmat, size, PAGE_SIZE, 0, &sc->sc_ds[0], DIGFILT_DMA_NSEGS, &rsegs, BUS_DMA_NOWAIT);
    629 	if (error) {
    630 		aprint_error_dev(sc->sc_dev,
    631 		    "bus_dmamem_alloc: %d\n", error);
    632 		goto out;
    633 	}
    634 
    635 	error = bus_dmamem_map(sc->sc_dmat, sc->sc_ds, DIGFILT_DMA_NSEGS, size, &sc->sc_buffer, BUS_DMA_NOWAIT);
    636 	if (error) {
    637 		aprint_error_dev(sc->sc_dev, "bus_dmamem_map: %d\n", error);
    638 		goto dmamem_free;
    639 	}
    640 
    641 	/* After load sc_dmamp is valid. */
    642 	error = bus_dmamap_load(sc->sc_dmat, sc->sc_dmamp, sc->sc_buffer, size, NULL, BUS_DMA_NOWAIT|BUS_DMA_WRITE);
    643 	if (error) {
    644 		aprint_error_dev(sc->sc_dev, "bus_dmamap_load: %d\n", error);
    645 		goto dmamem_unmap;
    646 	}
    647 
    648 	memset(sc->sc_buffer, 0x00, size);
    649 
    650 	return sc->sc_buffer;
    651 
    652 dmamem_unmap:
    653 	bus_dmamem_unmap(sc->sc_dmat, sc->sc_buffer, size);
    654 dmamem_free:
    655 	bus_dmamem_free(sc->sc_dmat, sc->sc_ds, DIGFILT_DMA_NSEGS);
    656 out:
    657 	return NULL;
    658 }
    659 
    660 static void
    661 imx23_digfilt_freem(void *priv, void *kvap, size_t size)
    662 {
    663 	struct imx23_digfilt_softc *sc = priv;
    664 
    665 	bus_dmamem_unmap(sc->sc_dmat, kvap, size);
    666 	bus_dmamem_free(sc->sc_dmat, sc->sc_ds, DIGFILT_DMA_NSEGS);
    667 }
    668 
    669 static size_t
    670 imx23_digfilt_round_buffersize(void *hdl, int direction, size_t bs)
    671 {
    672 	return bs;
    673 }
    674 
    675 static int
    676 imx23_digfilt_get_props(void *sc)
    677 {
    678 	return AUDIO_PROP_PLAYBACK;
    679 }
    680 
    681 static void
    682 imx23_digfilt_get_locks(void *priv, kmutex_t **intr, kmutex_t **thread)
    683 {
    684 	struct imx23_digfilt_softc *sc = priv;
    685 
    686 	*intr = &sc->sc_intr_lock;
    687 	*thread = &sc->sc_lock;
    688 }
    689 
    690 /*
    691  * IRQ for DAC error.
    692  */
    693 static int
    694 imx23_dac_error_intr(void *arg)
    695 {
    696 	struct imx23_digfilt_softc *sc = arg;
    697 	AO_WR(sc, HW_AUDIOOUT_CTRL_CLR, HW_AUDIOOUT_CTRL_FIFO_UNDERFLOW_IRQ);
    698 	return 1;
    699 }
    700 
    701 /*
    702  * IRQ from DMA.
    703  */
    704 static void
    705 imx23_dac_dma_intr(void *arg)
    706 {
    707 	struct imx23_digfilt_softc *sc = arg;
    708 
    709 	mutex_enter(&sc->sc_intr_lock);
    710 
    711 	/*
    712 	 * When halting, the driver finishes playing the current block, but
    713 	 * the audio subsystem no longer expects us to call back
    714 	 */
    715 	if (sc->sc_intr != NULL) {
    716 		sc->sc_intr(sc->sc_intarg);
    717 	}
    718 
    719 	mutex_exit(&sc->sc_intr_lock);
    720 }
    721 
    722 static void
    723 imx23_digfilt_ao_apply_mutes(struct imx23_digfilt_softc *sc)
    724 {
    725 
    726 	/* DAC. */
    727 	if (sc->sc_mute & DIGFILT_MUTE_DAC) {
    728 		AO_WR(sc, HW_AUDIOOUT_DACVOLUME_SET,
    729 		    HW_AUDIOOUT_DACVOLUME_MUTE_LEFT |
    730 		    HW_AUDIOOUT_DACVOLUME_MUTE_RIGHT
    731 		);
    732 
    733 	} else {
    734 		AO_WR(sc, HW_AUDIOOUT_DACVOLUME_CLR,
    735 		    HW_AUDIOOUT_DACVOLUME_MUTE_LEFT |
    736 		    HW_AUDIOOUT_DACVOLUME_MUTE_RIGHT
    737 		);
    738 	}
    739 
    740 	/* HP. */
    741 	if (sc->sc_mute & DIGFILT_MUTE_HP)
    742 		AO_WR(sc, HW_AUDIOOUT_HPVOL_SET, HW_AUDIOOUT_HPVOL_MUTE);
    743 	else
    744 		AO_WR(sc, HW_AUDIOOUT_HPVOL_CLR, HW_AUDIOOUT_HPVOL_MUTE);
    745 
    746 	/* Line. */
    747 	if (sc->sc_mute & DIGFILT_MUTE_LINE)
    748 		AO_WR(sc, HW_AUDIOOUT_SPEAKERCTRL_SET,
    749 		    HW_AUDIOOUT_SPEAKERCTRL_MUTE);
    750 	else
    751 		AO_WR(sc, HW_AUDIOOUT_SPEAKERCTRL_CLR,
    752 		    HW_AUDIOOUT_SPEAKERCTRL_MUTE);
    753 }
    754 
    755 /*
    756  * Initialize audio system.
    757  */
    758 static void
    759 imx23_digfilt_ao_init(struct imx23_digfilt_softc *sc)
    760 {
    761 
    762 	AO_WR(sc, HW_AUDIOOUT_ANACLKCTRL_CLR, HW_AUDIOOUT_ANACLKCTRL_CLKGATE);
    763 	while ((AO_RD(sc, HW_AUDIOOUT_ANACLKCTRL) & HW_AUDIOOUT_ANACLKCTRL_CLKGATE))
    764 		continue;
    765 
    766 	/* Hold headphones outputs at ground. */
    767 	AO_WR(sc, HW_AUDIOOUT_ANACTRL_SET, HW_AUDIOOUT_ANACTRL_HP_HOLD_GND);
    768 
    769 	/* Release pull down */
    770 	AO_WR(sc, HW_AUDIOOUT_ANACTRL_CLR, HW_AUDIOOUT_ANACTRL_HP_HOLD_GND);
    771 
    772 	AO_WR(sc, HW_AUDIOOUT_ANACTRL_SET, HW_AUDIOOUT_ANACTRL_HP_CLASSAB);
    773 
    774 	/* Enable Modules. */
    775 	AO_WR(sc, HW_AUDIOOUT_PWRDN_CLR,
    776 	    HW_AUDIOOUT_PWRDN_RIGHT_ADC |
    777 	    HW_AUDIOOUT_PWRDN_DAC |
    778 	    HW_AUDIOOUT_PWRDN_CAPLESS |
    779 	    HW_AUDIOOUT_PWRDN_HEADPHONE
    780 	);
    781 }
    782 
    783 /*
    784  * Reset the AUDIOOUT block.
    785  *
    786  * Inspired by i.MX23 RM "39.3.10 Correct Way to Soft Reset a Block"
    787  */
    788 static void
    789 imx23_digfilt_ao_reset(struct imx23_digfilt_softc *sc)
    790 {
    791 	unsigned int loop;
    792 
    793 	/*
    794 	 * Prepare for soft-reset by making sure that SFTRST is not currently
    795 	 * asserted. Also clear CLKGATE so we can wait for its assertion below.
    796 	 */
    797 	AO_WR(sc, HW_AUDIOOUT_CTRL_CLR, HW_AUDIOOUT_CTRL_SFTRST);
    798 
    799 	/* Wait at least a microsecond for SFTRST to deassert. */
    800 	loop = 0;
    801 	while ((AO_RD(sc, HW_AUDIOOUT_CTRL) & HW_AUDIOOUT_CTRL_SFTRST) ||
    802 	    (loop < DIGFILT_SOFT_RST_LOOP))
    803 		loop++;
    804 
    805 	/* Clear CLKGATE so we can wait for its assertion below. */
    806 	AO_WR(sc, HW_AUDIOOUT_CTRL_CLR, HW_AUDIOOUT_CTRL_CLKGATE);
    807 
    808 	/* Soft-reset the block. */
    809 	AO_WR(sc, HW_AUDIOOUT_CTRL_SET, HW_AUDIOOUT_CTRL_SFTRST);
    810 
    811 	/* Wait until clock is in the gated state. */
    812 	while (!(AO_RD(sc, HW_AUDIOOUT_CTRL) & HW_AUDIOOUT_CTRL_CLKGATE))
    813 		continue;
    814 
    815 	/* Bring block out of reset. */
    816 	AO_WR(sc, HW_AUDIOOUT_CTRL_CLR, HW_AUDIOOUT_CTRL_SFTRST);
    817 
    818 	loop = 0;
    819 	while ((AO_RD(sc, HW_AUDIOOUT_CTRL) & HW_AUDIOOUT_CTRL_SFTRST) ||
    820 	    (loop < DIGFILT_SOFT_RST_LOOP))
    821 		loop++;
    822 
    823 	AO_WR(sc, HW_AUDIOOUT_CTRL_CLR, HW_AUDIOOUT_CTRL_CLKGATE);
    824 
    825 	/* Wait until clock is in the NON-gated state. */
    826 	while (AO_RD(sc, HW_AUDIOOUT_CTRL) & HW_AUDIOOUT_CTRL_CLKGATE)
    827 		continue;
    828 }
    829 
    830 static void
    831 imx23_digfilt_ao_set_rate(struct imx23_digfilt_softc *sc, int sr)
    832 {
    833 	uint32_t val;
    834 
    835 
    836 	val = AO_RD(sc, HW_AUDIOOUT_DACSRR);
    837 
    838 
    839 	val &= ~(HW_AUDIOOUT_DACSRR_BASEMULT | HW_AUDIOOUT_DACSRR_SRC_HOLD |
    840 	    HW_AUDIOOUT_DACSRR_SRC_INT | HW_AUDIOOUT_DACSRR_SRC_FRAC);
    841 
    842 	switch(sr) {
    843 	case 8000:
    844 		val |= (__SHIFTIN(0x1 ,HW_AUDIOOUT_DACSRR_BASEMULT) |
    845 		    __SHIFTIN(0x3, HW_AUDIOOUT_DACSRR_SRC_HOLD) |
    846 		    __SHIFTIN(0x17, HW_AUDIOOUT_DACSRR_SRC_INT) |
    847 		    __SHIFTIN(0x0E00, HW_AUDIOOUT_DACSRR_SRC_FRAC));
    848 		break;
    849 	case 11025:
    850 		val |= (__SHIFTIN(0x1 ,HW_AUDIOOUT_DACSRR_BASEMULT) |
    851 		    __SHIFTIN(0x3, HW_AUDIOOUT_DACSRR_SRC_HOLD) |
    852 		    __SHIFTIN(0x11, HW_AUDIOOUT_DACSRR_SRC_INT) |
    853 		    __SHIFTIN(0x0037, HW_AUDIOOUT_DACSRR_SRC_FRAC));
    854 		break;
    855 	case 12000:
    856 		val |= (__SHIFTIN(0x1 ,HW_AUDIOOUT_DACSRR_BASEMULT) |
    857 		    __SHIFTIN(0x3, HW_AUDIOOUT_DACSRR_SRC_HOLD) |
    858 		    __SHIFTIN(0x0F, HW_AUDIOOUT_DACSRR_SRC_INT) |
    859 		    __SHIFTIN(0x13FF, HW_AUDIOOUT_DACSRR_SRC_FRAC));
    860 		break;
    861 	case 16000:
    862 		val |= (__SHIFTIN(0x1 ,HW_AUDIOOUT_DACSRR_BASEMULT) |
    863 		    __SHIFTIN(0x1, HW_AUDIOOUT_DACSRR_SRC_HOLD) |
    864 		    __SHIFTIN(0x17, HW_AUDIOOUT_DACSRR_SRC_INT) |
    865 		    __SHIFTIN(0x0E00, HW_AUDIOOUT_DACSRR_SRC_FRAC));
    866 		break;
    867 	case 22050:
    868 		val |= (__SHIFTIN(0x1 ,HW_AUDIOOUT_DACSRR_BASEMULT) |
    869 		    __SHIFTIN(0x1, HW_AUDIOOUT_DACSRR_SRC_HOLD) |
    870 		    __SHIFTIN(0x11, HW_AUDIOOUT_DACSRR_SRC_INT) |
    871 		    __SHIFTIN(0x0037, HW_AUDIOOUT_DACSRR_SRC_FRAC));
    872 		break;
    873 	case 24000:
    874 		val |= (__SHIFTIN(0x1 ,HW_AUDIOOUT_DACSRR_BASEMULT) |
    875 		    __SHIFTIN(0x1, HW_AUDIOOUT_DACSRR_SRC_HOLD) |
    876 		    __SHIFTIN(0x0F, HW_AUDIOOUT_DACSRR_SRC_INT) |
    877 		    __SHIFTIN(0x13FF, HW_AUDIOOUT_DACSRR_SRC_FRAC));
    878 		break;
    879 	case 32000:
    880 		val |= (__SHIFTIN(0x1 ,HW_AUDIOOUT_DACSRR_BASEMULT) |
    881 		    __SHIFTIN(0x0, HW_AUDIOOUT_DACSRR_SRC_HOLD) |
    882 		    __SHIFTIN(0x17, HW_AUDIOOUT_DACSRR_SRC_INT) |
    883 		    __SHIFTIN(0x0E00, HW_AUDIOOUT_DACSRR_SRC_FRAC));
    884 		break;
    885 	default:
    886 		aprint_error_dev(sc->sc_dev, "unknown sample rate: %d\n", sr);
    887 	case 44100:
    888 		val |= (__SHIFTIN(0x1 ,HW_AUDIOOUT_DACSRR_BASEMULT) |
    889 		    __SHIFTIN(0x0, HW_AUDIOOUT_DACSRR_SRC_HOLD) |
    890 		    __SHIFTIN(0x11, HW_AUDIOOUT_DACSRR_SRC_INT) |
    891 		    __SHIFTIN(0x0037, HW_AUDIOOUT_DACSRR_SRC_FRAC));
    892 		break;
    893 	}
    894 
    895 	AO_WR(sc, HW_AUDIOOUT_DACSRR, val);
    896 
    897 	val = AO_RD(sc, HW_AUDIOOUT_DACSRR);
    898 }
    899