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