1 | /* $NetBSD: cs4281.c,v 1.52 2016/07/07 06:55:41 msaitoh Exp $ */ |
2 | |
3 | /* |
4 | * Copyright (c) 2000 Tatoku Ogaito. All rights reserved. |
5 | * |
6 | * Redistribution and use in source and binary forms, with or without |
7 | * modification, are permitted provided that the following conditions |
8 | * are met: |
9 | * 1. Redistributions of source code must retain the above copyright |
10 | * notice, this list of conditions and the following disclaimer. |
11 | * 2. Redistributions in binary form must reproduce the above copyright |
12 | * notice, this list of conditions and the following disclaimer in the |
13 | * documentation and/or other materials provided with the distribution. |
14 | * 3. All advertising materials mentioning features or use of this software |
15 | * must display the following acknowledgement: |
16 | * This product includes software developed by Tatoku Ogaito |
17 | * for the NetBSD Project. |
18 | * 4. The name of the author may not be used to endorse or promote products |
19 | * derived from this software without specific prior written permission |
20 | * |
21 | * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR |
22 | * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES |
23 | * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. |
24 | * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, |
25 | * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT |
26 | * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, |
27 | * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY |
28 | * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
29 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF |
30 | * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
31 | */ |
32 | |
33 | /* |
34 | * Cirrus Logic CS4281 driver. |
35 | * Data sheets can be found |
36 | * http://www.cirrus.com/ftp/pub/4281.pdf |
37 | * ftp://ftp.alsa-project.org/pub/manuals/cirrus/cs4281tm.pdf |
38 | * |
39 | * TODO: |
40 | * 1: midi and FM support |
41 | * 2: ... |
42 | * |
43 | */ |
44 | |
45 | #include <sys/cdefs.h> |
46 | __KERNEL_RCSID(0, "$NetBSD: cs4281.c,v 1.52 2016/07/07 06:55:41 msaitoh Exp $" ); |
47 | |
48 | #include <sys/param.h> |
49 | #include <sys/systm.h> |
50 | #include <sys/kernel.h> |
51 | #include <sys/malloc.h> |
52 | #include <sys/fcntl.h> |
53 | #include <sys/device.h> |
54 | #include <sys/systm.h> |
55 | |
56 | #include <dev/pci/pcidevs.h> |
57 | #include <dev/pci/pcivar.h> |
58 | #include <dev/pci/cs4281reg.h> |
59 | #include <dev/pci/cs428xreg.h> |
60 | |
61 | #include <sys/audioio.h> |
62 | #include <dev/audio_if.h> |
63 | #include <dev/midi_if.h> |
64 | #include <dev/mulaw.h> |
65 | #include <dev/auconv.h> |
66 | |
67 | #include <dev/ic/ac97reg.h> |
68 | #include <dev/ic/ac97var.h> |
69 | |
70 | #include <dev/pci/cs428x.h> |
71 | |
72 | #include <sys/bus.h> |
73 | |
74 | #if defined(ENABLE_SECONDARY_CODEC) |
75 | #define MAX_CHANNELS (4) |
76 | #define MAX_FIFO_SIZE 32 /* 128/4channels */ |
77 | #else |
78 | #define MAX_CHANNELS (2) |
79 | #define MAX_FIFO_SIZE 64 /* 128/2channels */ |
80 | #endif |
81 | |
82 | /* IF functions for audio driver */ |
83 | static int cs4281_match(device_t, cfdata_t, void *); |
84 | static void cs4281_attach(device_t, device_t, void *); |
85 | static int cs4281_intr(void *); |
86 | static int cs4281_query_encoding(void *, struct audio_encoding *); |
87 | static int cs4281_set_params(void *, int, int, audio_params_t *, |
88 | audio_params_t *, stream_filter_list_t *, |
89 | stream_filter_list_t *); |
90 | static int cs4281_halt_output(void *); |
91 | static int cs4281_halt_input(void *); |
92 | static int cs4281_getdev(void *, struct audio_device *); |
93 | static int cs4281_trigger_output(void *, void *, void *, int, |
94 | void (*)(void *), void *, |
95 | const audio_params_t *); |
96 | static int cs4281_trigger_input(void *, void *, void *, int, |
97 | void (*)(void *), void *, |
98 | const audio_params_t *); |
99 | |
100 | static int cs4281_reset_codec(void *); |
101 | |
102 | /* Internal functions */ |
103 | static uint8_t cs4281_sr2regval(int); |
104 | static void cs4281_set_dac_rate(struct cs428x_softc *, int); |
105 | static void cs4281_set_adc_rate(struct cs428x_softc *, int); |
106 | static int cs4281_init(struct cs428x_softc *, int); |
107 | |
108 | /* Power Management */ |
109 | static bool cs4281_suspend(device_t, const pmf_qual_t *); |
110 | static bool cs4281_resume(device_t, const pmf_qual_t *); |
111 | |
112 | static const struct audio_hw_if cs4281_hw_if = { |
113 | NULL, /* open */ |
114 | NULL, /* close */ |
115 | NULL, |
116 | cs4281_query_encoding, |
117 | cs4281_set_params, |
118 | cs428x_round_blocksize, |
119 | NULL, |
120 | NULL, |
121 | NULL, |
122 | NULL, |
123 | NULL, |
124 | cs4281_halt_output, |
125 | cs4281_halt_input, |
126 | NULL, |
127 | cs4281_getdev, |
128 | NULL, |
129 | cs428x_mixer_set_port, |
130 | cs428x_mixer_get_port, |
131 | cs428x_query_devinfo, |
132 | cs428x_malloc, |
133 | cs428x_free, |
134 | cs428x_round_buffersize, |
135 | cs428x_mappage, |
136 | cs428x_get_props, |
137 | cs4281_trigger_output, |
138 | cs4281_trigger_input, |
139 | NULL, |
140 | cs428x_get_locks, |
141 | }; |
142 | |
143 | #if NMIDI > 0 && 0 |
144 | /* Midi Interface */ |
145 | static void cs4281_midi_close(void*); |
146 | static void cs4281_midi_getinfo(void *, struct midi_info *); |
147 | static int cs4281_midi_open(void *, int, void (*)(void *, int), |
148 | void (*)(void *), void *); |
149 | static int cs4281_midi_output(void *, int); |
150 | |
151 | static const struct midi_hw_if cs4281_midi_hw_if = { |
152 | cs4281_midi_open, |
153 | cs4281_midi_close, |
154 | cs4281_midi_output, |
155 | cs4281_midi_getinfo, |
156 | 0, |
157 | cs428x_get_locks, |
158 | }; |
159 | #endif |
160 | |
161 | CFATTACH_DECL_NEW(clct, sizeof(struct cs428x_softc), |
162 | cs4281_match, cs4281_attach, NULL, NULL); |
163 | |
164 | static struct audio_device cs4281_device = { |
165 | "CS4281" , |
166 | "" , |
167 | "cs4281" |
168 | }; |
169 | |
170 | |
171 | static int |
172 | cs4281_match(device_t parent, cfdata_t match, void *aux) |
173 | { |
174 | struct pci_attach_args *pa; |
175 | |
176 | pa = (struct pci_attach_args *)aux; |
177 | if (PCI_VENDOR(pa->pa_id) != PCI_VENDOR_CIRRUS) |
178 | return 0; |
179 | if (PCI_PRODUCT(pa->pa_id) == PCI_PRODUCT_CIRRUS_CS4281) |
180 | return 1; |
181 | return 0; |
182 | } |
183 | |
184 | static void |
185 | cs4281_attach(device_t parent, device_t self, void *aux) |
186 | { |
187 | struct cs428x_softc *sc; |
188 | struct pci_attach_args *pa; |
189 | pci_chipset_tag_t pc; |
190 | char const *intrstr; |
191 | pcireg_t reg; |
192 | int error; |
193 | char intrbuf[PCI_INTRSTR_LEN]; |
194 | |
195 | sc = device_private(self); |
196 | sc->sc_dev = self; |
197 | pa = (struct pci_attach_args *)aux; |
198 | pc = pa->pa_pc; |
199 | |
200 | pci_aprint_devinfo(pa, "Audio controller" ); |
201 | |
202 | sc->sc_pc = pa->pa_pc; |
203 | sc->sc_pt = pa->pa_tag; |
204 | |
205 | /* Map I/O register */ |
206 | if (pci_mapreg_map(pa, PCI_BA0, |
207 | PCI_MAPREG_TYPE_MEM|PCI_MAPREG_MEM_TYPE_32BIT, 0, |
208 | &sc->ba0t, &sc->ba0h, NULL, NULL)) { |
209 | aprint_error_dev(sc->sc_dev, "can't map BA0 space\n" ); |
210 | return; |
211 | } |
212 | if (pci_mapreg_map(pa, PCI_BA1, |
213 | PCI_MAPREG_TYPE_MEM|PCI_MAPREG_MEM_TYPE_32BIT, 0, |
214 | &sc->ba1t, &sc->ba1h, NULL, NULL)) { |
215 | aprint_error_dev(sc->sc_dev, "can't map BA1 space\n" ); |
216 | return; |
217 | } |
218 | |
219 | sc->sc_dmatag = pa->pa_dmat; |
220 | |
221 | /* power up chip */ |
222 | if ((error = pci_activate(pa->pa_pc, pa->pa_tag, self, |
223 | pci_activate_null)) && error != EOPNOTSUPP) { |
224 | aprint_error_dev(sc->sc_dev, "cannot activate %d\n" , error); |
225 | return; |
226 | } |
227 | |
228 | /* Enable the device (set bus master flag) */ |
229 | reg = pci_conf_read(pa->pa_pc, pa->pa_tag, PCI_COMMAND_STATUS_REG); |
230 | pci_conf_write(pa->pa_pc, pa->pa_tag, PCI_COMMAND_STATUS_REG, |
231 | reg | PCI_COMMAND_MASTER_ENABLE); |
232 | |
233 | #if 0 |
234 | /* LATENCY_TIMER setting */ |
235 | temp1 = pci_conf_read(pa->pa_pc, pa->pa_tag, PCI_BHLC_REG); |
236 | if (PCI_LATTIMER(temp1) < 32) { |
237 | temp1 &= 0xffff00ff; |
238 | temp1 |= 0x00002000; |
239 | pci_conf_write(pa->pa_pc, pa->pa_tag, PCI_BHLC_REG, temp1); |
240 | } |
241 | #endif |
242 | |
243 | /* Map and establish the interrupt. */ |
244 | if (pci_intr_map(pa, &sc->intrh)) { |
245 | aprint_error_dev(sc->sc_dev, "couldn't map interrupt\n" ); |
246 | return; |
247 | } |
248 | intrstr = pci_intr_string(pc, sc->intrh, intrbuf, sizeof(intrbuf)); |
249 | |
250 | mutex_init(&sc->sc_lock, MUTEX_DEFAULT, IPL_NONE); |
251 | mutex_init(&sc->sc_intr_lock, MUTEX_DEFAULT, IPL_AUDIO); |
252 | |
253 | sc->sc_ih = pci_intr_establish(sc->sc_pc, sc->intrh, IPL_AUDIO, |
254 | cs4281_intr, sc); |
255 | if (sc->sc_ih == NULL) { |
256 | aprint_error_dev(sc->sc_dev, "couldn't establish interrupt" ); |
257 | if (intrstr != NULL) |
258 | aprint_error(" at %s" , intrstr); |
259 | aprint_error("\n" ); |
260 | mutex_destroy(&sc->sc_lock); |
261 | mutex_destroy(&sc->sc_intr_lock); |
262 | return; |
263 | } |
264 | aprint_normal_dev(sc->sc_dev, "interrupting at %s\n" , intrstr); |
265 | |
266 | /* |
267 | * Sound System start-up |
268 | */ |
269 | if (cs4281_init(sc, 1) != 0) { |
270 | mutex_destroy(&sc->sc_lock); |
271 | mutex_destroy(&sc->sc_intr_lock); |
272 | return; |
273 | } |
274 | |
275 | sc->type = TYPE_CS4281; |
276 | sc->halt_input = cs4281_halt_input; |
277 | sc->halt_output = cs4281_halt_output; |
278 | |
279 | sc->dma_size = CS4281_BUFFER_SIZE / MAX_CHANNELS; |
280 | sc->dma_align = 0x10; |
281 | sc->hw_blocksize = sc->dma_size / 2; |
282 | |
283 | /* AC 97 attachment */ |
284 | sc->host_if.arg = sc; |
285 | sc->host_if.attach = cs428x_attach_codec; |
286 | sc->host_if.read = cs428x_read_codec; |
287 | sc->host_if.write = cs428x_write_codec; |
288 | sc->host_if.reset = cs4281_reset_codec; |
289 | if (ac97_attach(&sc->host_if, self, &sc->sc_lock) != 0) { |
290 | aprint_error_dev(sc->sc_dev, "ac97_attach failed\n" ); |
291 | mutex_destroy(&sc->sc_lock); |
292 | mutex_destroy(&sc->sc_intr_lock); |
293 | return; |
294 | } |
295 | audio_attach_mi(&cs4281_hw_if, sc, sc->sc_dev); |
296 | |
297 | #if NMIDI > 0 && 0 |
298 | midi_attach_mi(&cs4281_midi_hw_if, sc, sc->sc_dev); |
299 | #endif |
300 | |
301 | if (!pmf_device_register(self, cs4281_suspend, cs4281_resume)) |
302 | aprint_error_dev(self, "couldn't establish power handler\n" ); |
303 | } |
304 | |
305 | static int |
306 | cs4281_intr(void *p) |
307 | { |
308 | struct cs428x_softc *sc; |
309 | uint32_t intr, hdsr0, hdsr1; |
310 | char *empty_dma; |
311 | int handled; |
312 | |
313 | sc = p; |
314 | handled = 0; |
315 | hdsr0 = 0; |
316 | hdsr1 = 0; |
317 | |
318 | mutex_spin_enter(&sc->sc_intr_lock); |
319 | |
320 | /* grab interrupt register */ |
321 | intr = BA0READ4(sc, CS4281_HISR); |
322 | |
323 | DPRINTF(("cs4281_intr:" )); |
324 | /* not for me */ |
325 | if ((intr & HISR_INTENA) == 0) { |
326 | /* clear the interrupt register */ |
327 | BA0WRITE4(sc, CS4281_HICR, HICR_CHGM | HICR_IEV); |
328 | mutex_spin_exit(&sc->sc_intr_lock); |
329 | return 0; |
330 | } |
331 | |
332 | if (intr & HISR_DMA0) |
333 | hdsr0 = BA0READ4(sc, CS4281_HDSR0); /* clear intr condition */ |
334 | if (intr & HISR_DMA1) |
335 | hdsr1 = BA0READ4(sc, CS4281_HDSR1); /* clear intr condition */ |
336 | /* clear the interrupt register */ |
337 | BA0WRITE4(sc, CS4281_HICR, HICR_CHGM | HICR_IEV); |
338 | |
339 | #ifdef CS4280_DEBUG |
340 | DPRINTF(("intr = 0x%08x, hdsr0 = 0x%08x hdsr1 = 0x%08x\n" , |
341 | intr, hdsr0, hdsr1)); |
342 | #else |
343 | __USE(hdsr0); |
344 | __USE(hdsr1); |
345 | #endif |
346 | |
347 | /* Playback Interrupt */ |
348 | if (intr & HISR_DMA0) { |
349 | handled = 1; |
350 | if (sc->sc_prun) { |
351 | DPRINTF((" PB DMA 0x%x(%d)" , |
352 | (int)BA0READ4(sc, CS4281_DCA0), |
353 | (int)BA0READ4(sc, CS4281_DCC0))); |
354 | if ((sc->sc_pi%sc->sc_pcount) == 0) |
355 | sc->sc_pintr(sc->sc_parg); |
356 | /* copy buffer */ |
357 | ++sc->sc_pi; |
358 | empty_dma = sc->sc_pdma->addr; |
359 | if (sc->sc_pi&1) |
360 | empty_dma += sc->hw_blocksize; |
361 | memcpy(empty_dma, sc->sc_pn, sc->hw_blocksize); |
362 | sc->sc_pn += sc->hw_blocksize; |
363 | if (sc->sc_pn >= sc->sc_pe) |
364 | sc->sc_pn = sc->sc_ps; |
365 | } else { |
366 | aprint_error_dev(sc->sc_dev, "unexpected play intr\n" ); |
367 | } |
368 | } |
369 | if (intr & HISR_DMA1) { |
370 | handled = 1; |
371 | if (sc->sc_rrun) { |
372 | /* copy from DMA */ |
373 | DPRINTF((" CP DMA 0x%x(%d)" , (int)BA0READ4(sc, CS4281_DCA1), |
374 | (int)BA0READ4(sc, CS4281_DCC1))); |
375 | ++sc->sc_ri; |
376 | empty_dma = sc->sc_rdma->addr; |
377 | if ((sc->sc_ri & 1) == 0) |
378 | empty_dma += sc->hw_blocksize; |
379 | memcpy(sc->sc_rn, empty_dma, sc->hw_blocksize); |
380 | sc->sc_rn += sc->hw_blocksize; |
381 | if (sc->sc_rn >= sc->sc_re) |
382 | sc->sc_rn = sc->sc_rs; |
383 | if ((sc->sc_ri % sc->sc_rcount) == 0) |
384 | sc->sc_rintr(sc->sc_rarg); |
385 | } else { |
386 | aprint_error_dev(sc->sc_dev, |
387 | "unexpected record intr\n" ); |
388 | } |
389 | } |
390 | DPRINTF(("\n" )); |
391 | |
392 | mutex_spin_exit(&sc->sc_intr_lock); |
393 | |
394 | return handled; |
395 | } |
396 | |
397 | static int |
398 | cs4281_query_encoding(void *addr, struct audio_encoding *fp) |
399 | { |
400 | |
401 | switch (fp->index) { |
402 | case 0: |
403 | strcpy(fp->name, AudioEulinear); |
404 | fp->encoding = AUDIO_ENCODING_ULINEAR; |
405 | fp->precision = 8; |
406 | fp->flags = 0; |
407 | break; |
408 | case 1: |
409 | strcpy(fp->name, AudioEmulaw); |
410 | fp->encoding = AUDIO_ENCODING_ULAW; |
411 | fp->precision = 8; |
412 | fp->flags = AUDIO_ENCODINGFLAG_EMULATED; |
413 | break; |
414 | case 2: |
415 | strcpy(fp->name, AudioEalaw); |
416 | fp->encoding = AUDIO_ENCODING_ALAW; |
417 | fp->precision = 8; |
418 | fp->flags = AUDIO_ENCODINGFLAG_EMULATED; |
419 | break; |
420 | case 3: |
421 | strcpy(fp->name, AudioEslinear); |
422 | fp->encoding = AUDIO_ENCODING_SLINEAR; |
423 | fp->precision = 8; |
424 | fp->flags = 0; |
425 | break; |
426 | case 4: |
427 | strcpy(fp->name, AudioEslinear_le); |
428 | fp->encoding = AUDIO_ENCODING_SLINEAR_LE; |
429 | fp->precision = 16; |
430 | fp->flags = 0; |
431 | break; |
432 | case 5: |
433 | strcpy(fp->name, AudioEulinear_le); |
434 | fp->encoding = AUDIO_ENCODING_ULINEAR_LE; |
435 | fp->precision = 16; |
436 | fp->flags = 0; |
437 | break; |
438 | case 6: |
439 | strcpy(fp->name, AudioEslinear_be); |
440 | fp->encoding = AUDIO_ENCODING_SLINEAR_BE; |
441 | fp->precision = 16; |
442 | fp->flags = 0; |
443 | break; |
444 | case 7: |
445 | strcpy(fp->name, AudioEulinear_be); |
446 | fp->encoding = AUDIO_ENCODING_ULINEAR_BE; |
447 | fp->precision = 16; |
448 | fp->flags = 0; |
449 | break; |
450 | default: |
451 | return EINVAL; |
452 | } |
453 | return 0; |
454 | } |
455 | |
456 | static int |
457 | cs4281_set_params(void *addr, int setmode, int usemode, |
458 | audio_params_t *play, audio_params_t *rec, stream_filter_list_t *pfil, |
459 | stream_filter_list_t *rfil) |
460 | { |
461 | audio_params_t hw; |
462 | struct cs428x_softc *sc; |
463 | audio_params_t *p; |
464 | stream_filter_list_t *fil; |
465 | int mode; |
466 | |
467 | sc = addr; |
468 | for (mode = AUMODE_RECORD; mode != -1; |
469 | mode = mode == AUMODE_RECORD ? AUMODE_PLAY : -1) { |
470 | if ((setmode & mode) == 0) |
471 | continue; |
472 | |
473 | p = mode == AUMODE_PLAY ? play : rec; |
474 | |
475 | if (p == play) { |
476 | DPRINTFN(5, |
477 | ("play: sample=%u precision=%u channels=%u\n" , |
478 | p->sample_rate, p->precision, p->channels)); |
479 | if (p->sample_rate < 6023 || p->sample_rate > 48000 || |
480 | (p->precision != 8 && p->precision != 16) || |
481 | (p->channels != 1 && p->channels != 2)) { |
482 | return EINVAL; |
483 | } |
484 | } else { |
485 | DPRINTFN(5, |
486 | ("rec: sample=%u precision=%u channels=%u\n" , |
487 | p->sample_rate, p->precision, p->channels)); |
488 | if (p->sample_rate < 6023 || p->sample_rate > 48000 || |
489 | (p->precision != 8 && p->precision != 16) || |
490 | (p->channels != 1 && p->channels != 2)) { |
491 | return EINVAL; |
492 | } |
493 | } |
494 | hw = *p; |
495 | fil = mode == AUMODE_PLAY ? pfil : rfil; |
496 | |
497 | switch (p->encoding) { |
498 | case AUDIO_ENCODING_SLINEAR_BE: |
499 | break; |
500 | case AUDIO_ENCODING_SLINEAR_LE: |
501 | break; |
502 | case AUDIO_ENCODING_ULINEAR_BE: |
503 | break; |
504 | case AUDIO_ENCODING_ULINEAR_LE: |
505 | break; |
506 | case AUDIO_ENCODING_ULAW: |
507 | hw.encoding = AUDIO_ENCODING_SLINEAR_LE; |
508 | fil->append(fil, mode == AUMODE_PLAY ? mulaw_to_linear8 |
509 | : linear8_to_mulaw, &hw); |
510 | break; |
511 | case AUDIO_ENCODING_ALAW: |
512 | hw.encoding = AUDIO_ENCODING_SLINEAR_LE; |
513 | fil->append(fil, mode == AUMODE_PLAY ? alaw_to_linear8 |
514 | : linear8_to_alaw, &hw); |
515 | break; |
516 | default: |
517 | return EINVAL; |
518 | } |
519 | } |
520 | |
521 | /* set sample rate */ |
522 | cs4281_set_dac_rate(sc, play->sample_rate); |
523 | cs4281_set_adc_rate(sc, rec->sample_rate); |
524 | return 0; |
525 | } |
526 | |
527 | static int |
528 | cs4281_halt_output(void *addr) |
529 | { |
530 | struct cs428x_softc *sc; |
531 | |
532 | sc = addr; |
533 | BA0WRITE4(sc, CS4281_DCR0, BA0READ4(sc, CS4281_DCR0) | DCRn_MSK); |
534 | sc->sc_prun = 0; |
535 | return 0; |
536 | } |
537 | |
538 | static int |
539 | cs4281_halt_input(void *addr) |
540 | { |
541 | struct cs428x_softc *sc; |
542 | |
543 | sc = addr; |
544 | BA0WRITE4(sc, CS4281_DCR1, BA0READ4(sc, CS4281_DCR1) | DCRn_MSK); |
545 | sc->sc_rrun = 0; |
546 | return 0; |
547 | } |
548 | |
549 | static int |
550 | cs4281_getdev(void *addr, struct audio_device *retp) |
551 | { |
552 | |
553 | *retp = cs4281_device; |
554 | return 0; |
555 | } |
556 | |
557 | static int |
558 | cs4281_trigger_output(void *addr, void *start, void *end, int blksize, |
559 | void (*intr)(void *), void *arg, |
560 | const audio_params_t *param) |
561 | { |
562 | struct cs428x_softc *sc; |
563 | uint32_t fmt; |
564 | struct cs428x_dma *p; |
565 | int dma_count; |
566 | |
567 | sc = addr; |
568 | fmt = 0; |
569 | #ifdef DIAGNOSTIC |
570 | if (sc->sc_prun) |
571 | printf("cs4281_trigger_output: already running\n" ); |
572 | #endif |
573 | sc->sc_prun = 1; |
574 | |
575 | DPRINTF(("cs4281_trigger_output: sc=%p start=%p end=%p " |
576 | "blksize=%d intr=%p(%p)\n" , addr, start, end, blksize, intr, arg)); |
577 | sc->sc_pintr = intr; |
578 | sc->sc_parg = arg; |
579 | |
580 | /* stop playback DMA */ |
581 | BA0WRITE4(sc, CS4281_DCR0, BA0READ4(sc, CS4281_DCR0) | DCRn_MSK); |
582 | |
583 | DPRINTF(("param: precision=%d channels=%d encoding=%d\n" , |
584 | param->precision, param->channels, param->encoding)); |
585 | for (p = sc->sc_dmas; p != NULL && BUFADDR(p) != start; p = p->next) |
586 | continue; |
587 | if (p == NULL) { |
588 | printf("cs4281_trigger_output: bad addr %p\n" , start); |
589 | return EINVAL; |
590 | } |
591 | |
592 | sc->sc_pcount = blksize / sc->hw_blocksize; |
593 | sc->sc_ps = (char *)start; |
594 | sc->sc_pe = (char *)end; |
595 | sc->sc_pdma = p; |
596 | sc->sc_pbuf = KERNADDR(p); |
597 | sc->sc_pi = 0; |
598 | sc->sc_pn = sc->sc_ps; |
599 | if (blksize >= sc->dma_size) { |
600 | sc->sc_pn = sc->sc_ps + sc->dma_size; |
601 | memcpy(sc->sc_pbuf, start, sc->dma_size); |
602 | ++sc->sc_pi; |
603 | } else { |
604 | sc->sc_pn = sc->sc_ps + sc->hw_blocksize; |
605 | memcpy(sc->sc_pbuf, start, sc->hw_blocksize); |
606 | } |
607 | |
608 | dma_count = sc->dma_size; |
609 | if (param->precision != 8) |
610 | dma_count /= 2; /* 16 bit */ |
611 | if (param->channels > 1) |
612 | dma_count /= 2; /* Stereo */ |
613 | |
614 | DPRINTF(("cs4281_trigger_output: DMAADDR(p)=0x%x count=%d\n" , |
615 | (int)DMAADDR(p), dma_count)); |
616 | BA0WRITE4(sc, CS4281_DBA0, DMAADDR(p)); |
617 | BA0WRITE4(sc, CS4281_DBC0, dma_count-1); |
618 | |
619 | /* set playback format */ |
620 | fmt = BA0READ4(sc, CS4281_DMR0) & ~DMRn_FMTMSK; |
621 | if (param->precision == 8) |
622 | fmt |= DMRn_SIZE8; |
623 | if (param->channels == 1) |
624 | fmt |= DMRn_MONO; |
625 | if (param->encoding == AUDIO_ENCODING_ULINEAR_BE || |
626 | param->encoding == AUDIO_ENCODING_SLINEAR_BE) |
627 | fmt |= DMRn_BEND; |
628 | if (param->encoding == AUDIO_ENCODING_ULINEAR_BE || |
629 | param->encoding == AUDIO_ENCODING_ULINEAR_LE) |
630 | fmt |= DMRn_USIGN; |
631 | BA0WRITE4(sc, CS4281_DMR0, fmt); |
632 | |
633 | /* set sample rate */ |
634 | sc->sc_prate = param->sample_rate; |
635 | cs4281_set_dac_rate(sc, param->sample_rate); |
636 | |
637 | /* start DMA */ |
638 | BA0WRITE4(sc, CS4281_DCR0, BA0READ4(sc, CS4281_DCR0) & ~DCRn_MSK); |
639 | /* Enable interrupts */ |
640 | BA0WRITE4(sc, CS4281_HICR, HICR_IEV | HICR_CHGM); |
641 | |
642 | DPRINTF(("HICR =0x%08x(expected 0x00000001)\n" , BA0READ4(sc, CS4281_HICR))); |
643 | DPRINTF(("HIMR =0x%08x(expected 0x00f0fc3f)\n" , BA0READ4(sc, CS4281_HIMR))); |
644 | DPRINTF(("DMR0 =0x%08x(expected 0x2???0018)\n" , BA0READ4(sc, CS4281_DMR0))); |
645 | DPRINTF(("DCR0 =0x%08x(expected 0x00030000)\n" , BA0READ4(sc, CS4281_DCR0))); |
646 | DPRINTF(("FCR0 =0x%08x(expected 0x81000f00)\n" , BA0READ4(sc, CS4281_FCR0))); |
647 | DPRINTF(("DACSR=0x%08x(expected 1 for 44kHz 5 for 8kHz)\n" , |
648 | BA0READ4(sc, CS4281_DACSR))); |
649 | DPRINTF(("SRCSA=0x%08x(expected 0x0b0a0100)\n" , BA0READ4(sc, CS4281_SRCSA))); |
650 | DPRINTF(("SSPM&SSPM_PSRCEN =0x%08x(expected 0x00000010)\n" , |
651 | BA0READ4(sc, CS4281_SSPM) & SSPM_PSRCEN)); |
652 | |
653 | return 0; |
654 | } |
655 | |
656 | static int |
657 | cs4281_trigger_input(void *addr, void *start, void *end, int blksize, |
658 | void (*intr)(void *), void *arg, |
659 | const audio_params_t *param) |
660 | { |
661 | struct cs428x_softc *sc; |
662 | struct cs428x_dma *p; |
663 | uint32_t fmt; |
664 | int dma_count; |
665 | |
666 | sc = addr; |
667 | fmt = 0; |
668 | #ifdef DIAGNOSTIC |
669 | if (sc->sc_rrun) |
670 | printf("cs4281_trigger_input: already running\n" ); |
671 | #endif |
672 | sc->sc_rrun = 1; |
673 | DPRINTF(("cs4281_trigger_input: sc=%p start=%p end=%p " |
674 | "blksize=%d intr=%p(%p)\n" , addr, start, end, blksize, intr, arg)); |
675 | sc->sc_rintr = intr; |
676 | sc->sc_rarg = arg; |
677 | |
678 | /* stop recording DMA */ |
679 | BA0WRITE4(sc, CS4281_DCR1, BA0READ4(sc, CS4281_DCR1) | DCRn_MSK); |
680 | |
681 | for (p = sc->sc_dmas; p && BUFADDR(p) != start; p = p->next) |
682 | continue; |
683 | if (!p) { |
684 | printf("cs4281_trigger_input: bad addr %p\n" , start); |
685 | return EINVAL; |
686 | } |
687 | |
688 | sc->sc_rcount = blksize / sc->hw_blocksize; |
689 | sc->sc_rs = (char *)start; |
690 | sc->sc_re = (char *)end; |
691 | sc->sc_rdma = p; |
692 | sc->sc_rbuf = KERNADDR(p); |
693 | sc->sc_ri = 0; |
694 | sc->sc_rn = sc->sc_rs; |
695 | |
696 | dma_count = sc->dma_size; |
697 | if (param->precision != 8) |
698 | dma_count /= 2; |
699 | if (param->channels > 1) |
700 | dma_count /= 2; |
701 | |
702 | DPRINTF(("cs4281_trigger_input: DMAADDR(p)=0x%x count=%d\n" , |
703 | (int)DMAADDR(p), dma_count)); |
704 | BA0WRITE4(sc, CS4281_DBA1, DMAADDR(p)); |
705 | BA0WRITE4(sc, CS4281_DBC1, dma_count-1); |
706 | |
707 | /* set recording format */ |
708 | fmt = BA0READ4(sc, CS4281_DMR1) & ~DMRn_FMTMSK; |
709 | if (param->precision == 8) |
710 | fmt |= DMRn_SIZE8; |
711 | if (param->channels == 1) |
712 | fmt |= DMRn_MONO; |
713 | if (param->encoding == AUDIO_ENCODING_ULINEAR_BE || |
714 | param->encoding == AUDIO_ENCODING_SLINEAR_BE) |
715 | fmt |= DMRn_BEND; |
716 | if (param->encoding == AUDIO_ENCODING_ULINEAR_BE || |
717 | param->encoding == AUDIO_ENCODING_ULINEAR_LE) |
718 | fmt |= DMRn_USIGN; |
719 | BA0WRITE4(sc, CS4281_DMR1, fmt); |
720 | |
721 | /* set sample rate */ |
722 | sc->sc_rrate = param->sample_rate; |
723 | cs4281_set_adc_rate(sc, param->sample_rate); |
724 | |
725 | /* Start DMA */ |
726 | BA0WRITE4(sc, CS4281_DCR1, BA0READ4(sc, CS4281_DCR1) & ~DCRn_MSK); |
727 | /* Enable interrupts */ |
728 | BA0WRITE4(sc, CS4281_HICR, HICR_IEV | HICR_CHGM); |
729 | |
730 | DPRINTF(("HICR=0x%08x\n" , BA0READ4(sc, CS4281_HICR))); |
731 | DPRINTF(("HIMR=0x%08x\n" , BA0READ4(sc, CS4281_HIMR))); |
732 | DPRINTF(("DMR1=0x%08x\n" , BA0READ4(sc, CS4281_DMR1))); |
733 | DPRINTF(("DCR1=0x%08x\n" , BA0READ4(sc, CS4281_DCR1))); |
734 | |
735 | return 0; |
736 | } |
737 | |
738 | static bool |
739 | cs4281_suspend(device_t dv, const pmf_qual_t *qual) |
740 | { |
741 | struct cs428x_softc *sc = device_private(dv); |
742 | |
743 | mutex_enter(&sc->sc_lock); |
744 | mutex_spin_exit(&sc->sc_intr_lock); |
745 | |
746 | /* save current playback status */ |
747 | if (sc->sc_prun) { |
748 | sc->sc_suspend_state.cs4281.dcr0 = BA0READ4(sc, CS4281_DCR0); |
749 | sc->sc_suspend_state.cs4281.dmr0 = BA0READ4(sc, CS4281_DMR0); |
750 | sc->sc_suspend_state.cs4281.dbc0 = BA0READ4(sc, CS4281_DBC0); |
751 | sc->sc_suspend_state.cs4281.dba0 = BA0READ4(sc, CS4281_DBA0); |
752 | } |
753 | |
754 | /* save current capture status */ |
755 | if (sc->sc_rrun) { |
756 | sc->sc_suspend_state.cs4281.dcr1 = BA0READ4(sc, CS4281_DCR1); |
757 | sc->sc_suspend_state.cs4281.dmr1 = BA0READ4(sc, CS4281_DMR1); |
758 | sc->sc_suspend_state.cs4281.dbc1 = BA0READ4(sc, CS4281_DBC1); |
759 | sc->sc_suspend_state.cs4281.dba1 = BA0READ4(sc, CS4281_DBA1); |
760 | } |
761 | /* Stop DMA */ |
762 | BA0WRITE4(sc, CS4281_DCR0, BA0READ4(sc, CS4281_DCR0) | DCRn_MSK); |
763 | BA0WRITE4(sc, CS4281_DCR1, BA0READ4(sc, CS4281_DCR1) | DCRn_MSK); |
764 | |
765 | mutex_spin_exit(&sc->sc_intr_lock); |
766 | mutex_exit(&sc->sc_lock); |
767 | |
768 | return true; |
769 | } |
770 | |
771 | static bool |
772 | cs4281_resume(device_t dv, const pmf_qual_t *qual) |
773 | { |
774 | struct cs428x_softc *sc = device_private(dv); |
775 | |
776 | mutex_enter(&sc->sc_lock); |
777 | mutex_spin_enter(&sc->sc_intr_lock); |
778 | |
779 | cs4281_init(sc, 0); |
780 | cs4281_reset_codec(sc); |
781 | |
782 | /* restore ac97 registers */ |
783 | mutex_spin_exit(&sc->sc_intr_lock); |
784 | (*sc->codec_if->vtbl->restore_ports)(sc->codec_if); |
785 | mutex_spin_enter(&sc->sc_intr_lock); |
786 | |
787 | /* restore DMA related status */ |
788 | if (sc->sc_prun) { |
789 | cs4281_set_dac_rate(sc, sc->sc_prate); |
790 | BA0WRITE4(sc, CS4281_DBA0, sc->sc_suspend_state.cs4281.dba0); |
791 | BA0WRITE4(sc, CS4281_DBC0, sc->sc_suspend_state.cs4281.dbc0); |
792 | BA0WRITE4(sc, CS4281_DMR0, sc->sc_suspend_state.cs4281.dmr0); |
793 | BA0WRITE4(sc, CS4281_DCR0, sc->sc_suspend_state.cs4281.dcr0); |
794 | } |
795 | if (sc->sc_rrun) { |
796 | cs4281_set_adc_rate(sc, sc->sc_rrate); |
797 | BA0WRITE4(sc, CS4281_DBA1, sc->sc_suspend_state.cs4281.dba1); |
798 | BA0WRITE4(sc, CS4281_DBC1, sc->sc_suspend_state.cs4281.dbc1); |
799 | BA0WRITE4(sc, CS4281_DMR1, sc->sc_suspend_state.cs4281.dmr1); |
800 | BA0WRITE4(sc, CS4281_DCR1, sc->sc_suspend_state.cs4281.dcr1); |
801 | } |
802 | /* enable intterupts */ |
803 | if (sc->sc_prun || sc->sc_rrun) |
804 | BA0WRITE4(sc, CS4281_HICR, HICR_IEV | HICR_CHGM); |
805 | |
806 | mutex_spin_exit(&sc->sc_intr_lock); |
807 | mutex_exit(&sc->sc_lock); |
808 | |
809 | return true; |
810 | } |
811 | |
812 | /* control AC97 codec */ |
813 | static int |
814 | cs4281_reset_codec(void *addr) |
815 | { |
816 | struct cs428x_softc *sc; |
817 | uint16_t data; |
818 | uint32_t dat32; |
819 | int n; |
820 | |
821 | sc = addr; |
822 | |
823 | DPRINTFN(3, ("cs4281_reset_codec\n" )); |
824 | |
825 | /* Reset codec */ |
826 | BA0WRITE4(sc, CS428X_ACCTL, 0); |
827 | delay(50); /* delay 50us */ |
828 | |
829 | BA0WRITE4(sc, CS4281_SPMC, 0); |
830 | delay(100); /* delay 100us */ |
831 | BA0WRITE4(sc, CS4281_SPMC, SPMC_RSTN); |
832 | #if defined(ENABLE_SECONDARY_CODEC) |
833 | BA0WRITE4(sc, CS4281_SPMC, SPMC_RSTN | SPCM_ASDIN2E); |
834 | BA0WRITE4(sc, CS4281_SERMC, SERMC_TCID); |
835 | #endif |
836 | delay(50000); /* XXX: delay 50ms */ |
837 | |
838 | /* Enable ASYNC generation */ |
839 | BA0WRITE4(sc, CS428X_ACCTL, ACCTL_ESYN); |
840 | |
841 | /* Wait for codec ready. Linux driver waits 50ms here */ |
842 | n = 0; |
843 | while ((BA0READ4(sc, CS428X_ACSTS) & ACSTS_CRDY) == 0) { |
844 | delay(100); |
845 | if (++n > 1000) { |
846 | printf("reset_codec: AC97 codec ready timeout\n" ); |
847 | return ETIMEDOUT; |
848 | } |
849 | } |
850 | #if defined(ENABLE_SECONDARY_CODEC) |
851 | /* secondary codec ready*/ |
852 | n = 0; |
853 | while ((BA0READ4(sc, CS4281_ACSTS2) & ACSTS2_CRDY2) == 0) { |
854 | delay(100); |
855 | if (++n > 1000) |
856 | return 0; |
857 | } |
858 | #endif |
859 | /* Set the serial timing configuration */ |
860 | /* XXX: undocumented but the Linux driver do this */ |
861 | BA0WRITE4(sc, CS4281_SERMC, SERMC_PTCAC97); |
862 | |
863 | /* Wait for codec ready signal */ |
864 | n = 0; |
865 | do { |
866 | delay(1000); |
867 | if (++n > 1000) { |
868 | aprint_error_dev(sc->sc_dev, |
869 | "timeout waiting for codec ready\n" ); |
870 | return ETIMEDOUT; |
871 | } |
872 | dat32 = BA0READ4(sc, CS428X_ACSTS) & ACSTS_CRDY; |
873 | } while (dat32 == 0); |
874 | |
875 | /* Enable Valid Frame output on ASDOUT */ |
876 | BA0WRITE4(sc, CS428X_ACCTL, ACCTL_ESYN | ACCTL_VFRM); |
877 | |
878 | /* Wait until codec calibration is finished. Codec register 26h */ |
879 | n = 0; |
880 | do { |
881 | delay(1); |
882 | if (++n > 1000) { |
883 | aprint_error_dev(sc->sc_dev, |
884 | "timeout waiting for codec calibration\n" ); |
885 | return ETIMEDOUT; |
886 | } |
887 | cs428x_read_codec(sc, AC97_REG_POWER, &data); |
888 | } while ((data & 0x0f) != 0x0f); |
889 | |
890 | /* Set the serial timing configuration again */ |
891 | /* XXX: undocumented but the Linux driver do this */ |
892 | BA0WRITE4(sc, CS4281_SERMC, SERMC_PTCAC97); |
893 | |
894 | /* Wait until we've sampled input slots 3 & 4 as valid */ |
895 | n = 0; |
896 | do { |
897 | delay(1000); |
898 | if (++n > 1000) { |
899 | aprint_error_dev(sc->sc_dev, "timeout waiting for " |
900 | "sampled input slots as valid\n" ); |
901 | return ETIMEDOUT; |
902 | } |
903 | dat32 = BA0READ4(sc, CS428X_ACISV) & (ACISV_ISV3 | ACISV_ISV4) ; |
904 | } while (dat32 != (ACISV_ISV3 | ACISV_ISV4)); |
905 | |
906 | /* Start digital data transfer of audio data to the codec */ |
907 | BA0WRITE4(sc, CS428X_ACOSV, (ACOSV_SLV3 | ACOSV_SLV4)); |
908 | return 0; |
909 | } |
910 | |
911 | |
912 | /* Internal functions */ |
913 | |
914 | /* convert sample rate to register value */ |
915 | static uint8_t |
916 | cs4281_sr2regval(int rate) |
917 | { |
918 | uint8_t retval; |
919 | |
920 | /* We don't have to change here. but anyway ... */ |
921 | if (rate > 48000) |
922 | rate = 48000; |
923 | if (rate < 6023) |
924 | rate = 6023; |
925 | |
926 | switch (rate) { |
927 | case 8000: |
928 | retval = 5; |
929 | break; |
930 | case 11025: |
931 | retval = 4; |
932 | break; |
933 | case 16000: |
934 | retval = 3; |
935 | break; |
936 | case 22050: |
937 | retval = 2; |
938 | break; |
939 | case 44100: |
940 | retval = 1; |
941 | break; |
942 | case 48000: |
943 | retval = 0; |
944 | break; |
945 | default: |
946 | retval = 1536000/rate; /* == 24576000/(rate*16) */ |
947 | } |
948 | return retval; |
949 | } |
950 | |
951 | static void |
952 | cs4281_set_adc_rate(struct cs428x_softc *sc, int rate) |
953 | { |
954 | |
955 | BA0WRITE4(sc, CS4281_ADCSR, cs4281_sr2regval(rate)); |
956 | } |
957 | |
958 | static void |
959 | cs4281_set_dac_rate(struct cs428x_softc *sc, int rate) |
960 | { |
961 | |
962 | BA0WRITE4(sc, CS4281_DACSR, cs4281_sr2regval(rate)); |
963 | } |
964 | |
965 | static int |
966 | cs4281_init(struct cs428x_softc *sc, int init) |
967 | { |
968 | int n; |
969 | uint16_t data; |
970 | uint32_t dat32; |
971 | |
972 | /* set "Configuration Write Protect" register to |
973 | * 0x4281 to allow to write */ |
974 | BA0WRITE4(sc, CS4281_CWPR, 0x4281); |
975 | |
976 | /* |
977 | * Unset "Full Power-Down bit of Extended PCI Power Management |
978 | * Control" register to release the reset state. |
979 | */ |
980 | dat32 = BA0READ4(sc, CS4281_EPPMC); |
981 | if (dat32 & EPPMC_FPDN) { |
982 | BA0WRITE4(sc, CS4281_EPPMC, dat32 & ~EPPMC_FPDN); |
983 | } |
984 | |
985 | /* Start PLL out in known state */ |
986 | BA0WRITE4(sc, CS4281_CLKCR1, 0); |
987 | /* Start serial ports out in known state */ |
988 | BA0WRITE4(sc, CS4281_SERMC, 0); |
989 | |
990 | /* Reset codec */ |
991 | BA0WRITE4(sc, CS428X_ACCTL, 0); |
992 | delay(50); /* delay 50us */ |
993 | |
994 | BA0WRITE4(sc, CS4281_SPMC, 0); |
995 | delay(100); /* delay 100us */ |
996 | BA0WRITE4(sc, CS4281_SPMC, SPMC_RSTN); |
997 | #if defined(ENABLE_SECONDARY_CODEC) |
998 | BA0WRITE4(sc, CS4281_SPMC, SPMC_RSTN | SPCM_ASDIN2E); |
999 | BA0WRITE4(sc, CS4281_SERMC, SERMC_TCID); |
1000 | #endif |
1001 | delay(50000); /* XXX: delay 50ms */ |
1002 | |
1003 | /* Turn on Sound System clocks based on ABITCLK */ |
1004 | BA0WRITE4(sc, CS4281_CLKCR1, CLKCR1_DLLP); |
1005 | delay(50000); /* XXX: delay 50ms */ |
1006 | BA0WRITE4(sc, CS4281_CLKCR1, CLKCR1_SWCE | CLKCR1_DLLP); |
1007 | |
1008 | /* Set enables for sections that are needed in the SSPM registers */ |
1009 | BA0WRITE4(sc, CS4281_SSPM, |
1010 | SSPM_MIXEN | /* Mixer */ |
1011 | SSPM_CSRCEN | /* Capture SRC */ |
1012 | SSPM_PSRCEN | /* Playback SRC */ |
1013 | SSPM_JSEN | /* Joystick */ |
1014 | SSPM_ACLEN | /* AC LINK */ |
1015 | SSPM_FMEN /* FM */ |
1016 | ); |
1017 | |
1018 | /* Wait for clock stabilization */ |
1019 | n = 0; |
1020 | #if 1 |
1021 | /* what document says */ |
1022 | while ((BA0READ4(sc, CS4281_CLKCR1)& (CLKCR1_DLLRDY | CLKCR1_CLKON)) |
1023 | != (CLKCR1_DLLRDY | CLKCR1_CLKON)) { |
1024 | delay(100); |
1025 | if (++n > 1000) { |
1026 | aprint_error_dev(sc->sc_dev, |
1027 | "timeout waiting for clock stabilization\n" ); |
1028 | return -1; |
1029 | } |
1030 | } |
1031 | #else |
1032 | /* Cirrus driver for Linux does */ |
1033 | while (!(BA0READ4(sc, CS4281_CLKCR1) & CLKCR1_DLLRDY)) { |
1034 | delay(1000); |
1035 | if (++n > 1000) { |
1036 | aprint_error_dev(sc->sc_dev, |
1037 | "timeout waiting for clock stabilization\n" ); |
1038 | return -1; |
1039 | } |
1040 | } |
1041 | #endif |
1042 | |
1043 | /* Enable ASYNC generation */ |
1044 | BA0WRITE4(sc, CS428X_ACCTL, ACCTL_ESYN); |
1045 | |
1046 | /* Wait for codec ready. Linux driver waits 50ms here */ |
1047 | n = 0; |
1048 | while ((BA0READ4(sc, CS428X_ACSTS) & ACSTS_CRDY) == 0) { |
1049 | delay(100); |
1050 | if (++n > 1000) { |
1051 | aprint_error_dev(sc->sc_dev, |
1052 | "timeout waiting for codec ready\n" ); |
1053 | return -1; |
1054 | } |
1055 | } |
1056 | |
1057 | #if defined(ENABLE_SECONDARY_CODEC) |
1058 | /* secondary codec ready*/ |
1059 | n = 0; |
1060 | while ((BA0READ4(sc, CS4281_ACSTS2) & ACSTS2_CRDY2) == 0) { |
1061 | delay(100); |
1062 | if (++n > 1000) { |
1063 | aprint_error_dev(sc->sc_dev, |
1064 | "timeout waiting for secondary codec ready\n" ); |
1065 | return -1; |
1066 | } |
1067 | } |
1068 | #endif |
1069 | |
1070 | /* Set the serial timing configuration */ |
1071 | /* XXX: undocumented but the Linux driver do this */ |
1072 | BA0WRITE4(sc, CS4281_SERMC, SERMC_PTCAC97); |
1073 | |
1074 | /* Wait for codec ready signal */ |
1075 | n = 0; |
1076 | do { |
1077 | delay(1000); |
1078 | if (++n > 1000) { |
1079 | aprint_error_dev(sc->sc_dev, |
1080 | "timeout waiting for codec ready\n" ); |
1081 | return -1; |
1082 | } |
1083 | dat32 = BA0READ4(sc, CS428X_ACSTS) & ACSTS_CRDY; |
1084 | } while (dat32 == 0); |
1085 | |
1086 | /* Enable Valid Frame output on ASDOUT */ |
1087 | BA0WRITE4(sc, CS428X_ACCTL, ACCTL_ESYN | ACCTL_VFRM); |
1088 | |
1089 | /* Wait until codec calibration is finished. codec register 26h */ |
1090 | n = 0; |
1091 | do { |
1092 | delay(1); |
1093 | if (++n > 1000) { |
1094 | aprint_error_dev(sc->sc_dev, |
1095 | "timeout waiting for codec calibration\n" ); |
1096 | return -1; |
1097 | } |
1098 | cs428x_read_codec(sc, AC97_REG_POWER, &data); |
1099 | } while ((data & 0x0f) != 0x0f); |
1100 | |
1101 | /* Set the serial timing configuration again */ |
1102 | /* XXX: undocumented but the Linux driver do this */ |
1103 | BA0WRITE4(sc, CS4281_SERMC, SERMC_PTCAC97); |
1104 | |
1105 | /* Wait until we've sampled input slots 3 & 4 as valid */ |
1106 | n = 0; |
1107 | do { |
1108 | delay(1000); |
1109 | if (++n > 1000) { |
1110 | aprint_error_dev(sc->sc_dev, "timeout waiting for " |
1111 | "sampled input slots as valid\n" ); |
1112 | return -1; |
1113 | } |
1114 | dat32 = BA0READ4(sc, CS428X_ACISV) & (ACISV_ISV3 | ACISV_ISV4); |
1115 | } while (dat32 != (ACISV_ISV3 | ACISV_ISV4)); |
1116 | |
1117 | /* Start digital data transfer of audio data to the codec */ |
1118 | BA0WRITE4(sc, CS428X_ACOSV, (ACOSV_SLV3 | ACOSV_SLV4)); |
1119 | |
1120 | cs428x_write_codec(sc, AC97_REG_HEADPHONE_VOLUME, 0); |
1121 | cs428x_write_codec(sc, AC97_REG_MASTER_VOLUME, 0); |
1122 | |
1123 | /* Power on the DAC */ |
1124 | cs428x_read_codec(sc, AC97_REG_POWER, &data); |
1125 | cs428x_write_codec(sc, AC97_REG_POWER, data & 0xfdff); |
1126 | |
1127 | /* Wait until we sample a DAC ready state. |
1128 | * Not documented, but Linux driver does. |
1129 | */ |
1130 | for (n = 0; n < 32; ++n) { |
1131 | delay(1000); |
1132 | cs428x_read_codec(sc, AC97_REG_POWER, &data); |
1133 | if (data & 0x02) |
1134 | break; |
1135 | } |
1136 | |
1137 | /* Power on the ADC */ |
1138 | cs428x_read_codec(sc, AC97_REG_POWER, &data); |
1139 | cs428x_write_codec(sc, AC97_REG_POWER, data & 0xfeff); |
1140 | |
1141 | /* Wait until we sample ADC ready state. |
1142 | * Not documented, but Linux driver does. |
1143 | */ |
1144 | for (n = 0; n < 32; ++n) { |
1145 | delay(1000); |
1146 | cs428x_read_codec(sc, AC97_REG_POWER, &data); |
1147 | if (data & 0x01) |
1148 | break; |
1149 | } |
1150 | |
1151 | #if 0 |
1152 | /* Initialize AC-Link features */ |
1153 | /* variable sample-rate support */ |
1154 | mem = BA0READ4(sc, CS4281_SERMC); |
1155 | mem |= (SERMC_ODSEN1 | SERMC_ODSEN2); |
1156 | BA0WRITE4(sc, CS4281_SERMC, mem); |
1157 | /* XXX: more... */ |
1158 | |
1159 | /* Initialize SSCR register features */ |
1160 | /* XXX: hardware volume setting */ |
1161 | BA0WRITE4(sc, CS4281_SSCR, ~SSCR_HVC); /* disable HW volume setting */ |
1162 | #endif |
1163 | |
1164 | /* disable Sound Blaster Pro emulation */ |
1165 | /* XXX: |
1166 | * Cannot set since the documents does not describe which bit is |
1167 | * correspond to SSCR_SB. Since the reset value of SSCR is 0, |
1168 | * we can ignore it.*/ |
1169 | #if 0 |
1170 | BA0WRITE4(sc, CS4281_SSCR, SSCR_SB); |
1171 | #endif |
1172 | |
1173 | /* map AC97 PCM playback to DMA Channel 0 */ |
1174 | /* Reset FEN bit to setup first */ |
1175 | BA0WRITE4(sc, CS4281_FCR0, (BA0READ4(sc, CS4281_FCR0) & ~FCRn_FEN)); |
1176 | /* |
1177 | *| RS[4:0]/| | |
1178 | *| LS[4:0] | AC97 | Slot Function |
1179 | *|---------+--------+-------------------- |
1180 | *| 0 | 3 | Left PCM Playback |
1181 | *| 1 | 4 | Right PCM Playback |
1182 | *| 2 | 5 | Phone Line 1 DAC |
1183 | *| 3 | 6 | Center PCM Playback |
1184 | *.... |
1185 | * quoted from Table 29(p109) |
1186 | */ |
1187 | dat32 = 0x01 << 24 | /* RS[4:0] = 1 see above */ |
1188 | 0x00 << 16 | /* LS[4:0] = 0 see above */ |
1189 | 0x0f << 8 | /* SZ[6:0] = 15 size of buffer */ |
1190 | 0x00 << 0 ; /* OF[6:0] = 0 offset */ |
1191 | BA0WRITE4(sc, CS4281_FCR0, dat32); |
1192 | BA0WRITE4(sc, CS4281_FCR0, dat32 | FCRn_FEN); |
1193 | |
1194 | /* map AC97 PCM record to DMA Channel 1 */ |
1195 | /* Reset FEN bit to setup first */ |
1196 | BA0WRITE4(sc, CS4281_FCR1, (BA0READ4(sc, CS4281_FCR1) & ~FCRn_FEN)); |
1197 | /* |
1198 | *| RS[4:0]/| |
1199 | *| LS[4:0] | AC97 | Slot Function |
1200 | *|---------+------+------------------- |
1201 | *| 10 | 3 | Left PCM Record |
1202 | *| 11 | 4 | Right PCM Record |
1203 | *| 12 | 5 | Phone Line 1 ADC |
1204 | *| 13 | 6 | Mic ADC |
1205 | *.... |
1206 | * quoted from Table 30(p109) |
1207 | */ |
1208 | dat32 = 0x0b << 24 | /* RS[4:0] = 11 See above */ |
1209 | 0x0a << 16 | /* LS[4:0] = 10 See above */ |
1210 | 0x0f << 8 | /* SZ[6:0] = 15 Size of buffer */ |
1211 | 0x10 << 0 ; /* OF[6:0] = 16 offset */ |
1212 | |
1213 | /* XXX: I cannot understand why FCRn_PSH is needed here. */ |
1214 | BA0WRITE4(sc, CS4281_FCR1, dat32 | FCRn_PSH); |
1215 | BA0WRITE4(sc, CS4281_FCR1, dat32 | FCRn_FEN); |
1216 | |
1217 | #if 0 |
1218 | /* Disable DMA Channel 2, 3 */ |
1219 | BA0WRITE4(sc, CS4281_FCR2, (BA0READ4(sc, CS4281_FCR2) & ~FCRn_FEN)); |
1220 | BA0WRITE4(sc, CS4281_FCR3, (BA0READ4(sc, CS4281_FCR3) & ~FCRn_FEN)); |
1221 | #endif |
1222 | |
1223 | /* Set the SRC Slot Assignment accordingly */ |
1224 | /*| PLSS[4:0]/ |
1225 | *| PRSS[4:0] | AC97 | Slot Function |
1226 | *|-----------+------+---------------- |
1227 | *| 0 | 3 | Left PCM Playback |
1228 | *| 1 | 4 | Right PCM Playback |
1229 | *| 2 | 5 | phone line 1 DAC |
1230 | *| 3 | 6 | Center PCM Playback |
1231 | *| 4 | 7 | Left Surround PCM Playback |
1232 | *| 5 | 8 | Right Surround PCM Playback |
1233 | *...... |
1234 | * |
1235 | *| CLSS[4:0]/ |
1236 | *| CRSS[4:0] | AC97 | Codec |Slot Function |
1237 | *|-----------+------+-------+----------------- |
1238 | *| 10 | 3 |Primary| Left PCM Record |
1239 | *| 11 | 4 |Primary| Right PCM Record |
1240 | *| 12 | 5 |Primary| Phone Line 1 ADC |
1241 | *| 13 | 6 |Primary| Mic ADC |
1242 | *|..... |
1243 | *| 20 | 3 | Sec. | Left PCM Record |
1244 | *| 21 | 4 | Sec. | Right PCM Record |
1245 | *| 22 | 5 | Sec. | Phone Line 1 ADC |
1246 | *| 23 | 6 | Sec. | Mic ADC |
1247 | */ |
1248 | dat32 = 0x0b << 24 | /* CRSS[4:0] Right PCM Record(primary) */ |
1249 | 0x0a << 16 | /* CLSS[4:0] Left PCM Record(primary) */ |
1250 | 0x01 << 8 | /* PRSS[4:0] Right PCM Playback */ |
1251 | 0x00 << 0; /* PLSS[4:0] Left PCM Playback */ |
1252 | BA0WRITE4(sc, CS4281_SRCSA, dat32); |
1253 | |
1254 | /* Set interrupt to occurred at Half and Full terminal |
1255 | * count interrupt enable for DMA channel 0 and 1. |
1256 | * To keep DMA stop, set MSK. |
1257 | */ |
1258 | dat32 = DCRn_HTCIE | DCRn_TCIE | DCRn_MSK; |
1259 | BA0WRITE4(sc, CS4281_DCR0, dat32); |
1260 | BA0WRITE4(sc, CS4281_DCR1, dat32); |
1261 | |
1262 | /* Set Auto-Initialize Contorl enable */ |
1263 | BA0WRITE4(sc, CS4281_DMR0, |
1264 | DMRn_DMA | DMRn_AUTO | DMRn_TR_READ); |
1265 | BA0WRITE4(sc, CS4281_DMR1, |
1266 | DMRn_DMA | DMRn_AUTO | DMRn_TR_WRITE); |
1267 | |
1268 | /* Clear DMA Mask in HIMR */ |
1269 | dat32 = ~HIMR_DMAIM & ~HIMR_D1IM & ~HIMR_D0IM; |
1270 | BA0WRITE4(sc, CS4281_HIMR, |
1271 | BA0READ4(sc, CS4281_HIMR) & dat32); |
1272 | |
1273 | /* set current status */ |
1274 | if (init != 0) { |
1275 | sc->sc_prun = 0; |
1276 | sc->sc_rrun = 0; |
1277 | } |
1278 | |
1279 | /* setup playback volume */ |
1280 | BA0WRITE4(sc, CS4281_PPRVC, 7); |
1281 | BA0WRITE4(sc, CS4281_PPLVC, 7); |
1282 | |
1283 | return 0; |
1284 | } |
1285 | |