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