Annotation of sys/arch/zaurus/dev/zaurus_audio.c, Revision 1.1.1.1
1.1 nbrk 1: /* $OpenBSD: zaurus_audio.c,v 1.8 2005/08/18 13:23:02 robert Exp $ */
2:
3: /*
4: * Copyright (c) 2005 Christopher Pascoe <pascoe@openbsd.org>
5: *
6: * Permission to use, copy, modify, and distribute this software for any
7: * purpose with or without fee is hereby granted, provided that the above
8: * copyright notice and this permission notice appear in all copies.
9: *
10: * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
11: * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
12: * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
13: * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
14: * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
15: * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
16: * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17: */
18:
19: /*
20: * TODO:
21: * - powerhooks (currently only works until first suspend)
22: * - record support
23: */
24:
25: #include <sys/param.h>
26: #include <sys/systm.h>
27: #include <sys/timeout.h>
28: #include <sys/device.h>
29: #include <sys/malloc.h>
30: #include <sys/kernel.h>
31: #include <sys/audioio.h>
32:
33: #include <machine/intr.h>
34: #include <machine/bus.h>
35:
36: #include <arm/xscale/pxa2x0reg.h>
37: #include <arm/xscale/pxa2x0var.h>
38: #include <arm/xscale/pxa2x0_i2c.h>
39: #include <arm/xscale/pxa2x0_i2s.h>
40: #include <arm/xscale/pxa2x0_dmac.h>
41: #include <arm/xscale/pxa2x0_gpio.h>
42:
43: #include <zaurus/dev/zaurus_scoopvar.h>
44: #include <dev/i2c/wm8750reg.h>
45:
46: #include <dev/audio_if.h>
47: #include <dev/mulaw.h>
48: #include <dev/auconv.h>
49:
50: #define WM8750_ADDRESS 0x1B
51: #define SPKR_VOLUME 112
52:
53: #define wm8750_write(sc, reg, val) pxa2x0_i2c_write_2(&sc->sc_i2c, \
54: WM8750_ADDRESS, (((reg) << 9) | ((val) & 0x1ff)))
55:
56: int zaudio_match(struct device *, void *, void *);
57: void zaudio_attach(struct device *, struct device *, void *);
58: int zaudio_detach(struct device *, int);
59: void zaudio_power(int, void *);
60:
61: #define ZAUDIO_OP_SPKR 0
62: #define ZAUDIO_OP_HP 1
63:
64: #define ZAUDIO_JACK_STATE_OUT 0
65: #define ZAUDIO_JACK_STATE_IN 1
66: #define ZAUDIO_JACK_STATE_INS 2
67: #define ZAUDIO_JACK_STATE_REM 3
68:
69: /* GPIO pins */
70: #define GPIO_HP_IN_C3000 116
71:
72: struct zaudio_volume {
73: u_int8_t left;
74: u_int8_t right;
75: };
76:
77: struct zaudio_softc {
78: struct device sc_dev;
79:
80: /* i2s device softc */
81: /* NB: pxa2x0_i2s requires this to be the second struct member */
82: struct pxa2x0_i2s_softc sc_i2s;
83:
84: /* i2c device softc */
85: struct pxa2x0_i2c_softc sc_i2c;
86:
87: void *sc_powerhook;
88: int sc_playing;
89:
90: struct zaudio_volume sc_volume[2];
91: char sc_unmute[2];
92:
93: int sc_state;
94: int sc_icount;
95: struct timeout sc_to;
96: };
97:
98: struct cfattach zaudio_ca = {
99: sizeof(struct zaudio_softc), zaudio_match, zaudio_attach,
100: zaudio_detach
101: };
102:
103: struct cfdriver zaudio_cd = {
104: NULL, "zaudio", DV_DULL
105: };
106:
107: struct audio_device wm8750_device = {
108: "WM8750",
109: "1.0",
110: "wm"
111: };
112:
113: void zaudio_init(struct zaudio_softc *);
114: int zaudio_jack_intr(void *);
115: void zaudio_jack(void *);
116: void zaudio_standby(struct zaudio_softc *);
117: void zaudio_update_volume(struct zaudio_softc *, int);
118: void zaudio_update_mutes(struct zaudio_softc *);
119: void zaudio_play_setup(struct zaudio_softc *);
120: int zaudio_open(void *, int);
121: void zaudio_close(void *);
122: int zaudio_query_encoding(void *, struct audio_encoding *);
123: int zaudio_set_params(void *, int, int, struct audio_params *,
124: struct audio_params *);
125: int zaudio_halt_output(void *);
126: int zaudio_halt_input(void *);
127: int zaudio_getdev(void *, struct audio_device *);
128: int zaudio_set_port(void *, struct mixer_ctrl *);
129: int zaudio_get_port(void *, struct mixer_ctrl *);
130: int zaudio_query_devinfo(void *, struct mixer_devinfo *);
131: int zaudio_get_props(void *);
132: int zaudio_start_output(void *, void *, int, void (*)(void *), void *);
133: int zaudio_start_input(void *, void *, int, void (*)(void *), void *);
134:
135: struct audio_hw_if wm8750_hw_if = {
136: zaudio_open,
137: zaudio_close,
138: NULL /* zaudio_drain */,
139: zaudio_query_encoding,
140: zaudio_set_params,
141: pxa2x0_i2s_round_blocksize,
142: NULL /* zaudio_commit_settings */,
143: NULL /* zaudio_init_output */,
144: NULL /* zaudio_init_input */,
145: zaudio_start_output,
146: zaudio_start_input,
147: zaudio_halt_output,
148: zaudio_halt_input,
149: NULL /* zaudio_speaker_ctl */,
150: zaudio_getdev,
151: NULL /* zaudio_setfd */,
152: zaudio_set_port,
153: zaudio_get_port,
154: zaudio_query_devinfo,
155: pxa2x0_i2s_allocm,
156: pxa2x0_i2s_freem,
157: pxa2x0_i2s_round_buffersize,
158: pxa2x0_i2s_mappage,
159: zaudio_get_props,
160: NULL /* zaudio_trigger_output */,
161: NULL /* zaudio_trigger_input */
162: };
163:
164: static const unsigned short playback_registers[][2] = {
165: /* Unmute DAC */
166: { ADCDACCTL_REG, 0x000 },
167:
168: /* 16 bit audio words */
169: { AUDINT_REG, AUDINT_SET_FORMAT(2) },
170:
171: /* Enable thermal protection, power */
172: { ADCTL1_REG, ADCTL1_TSDEN | ADCTL1_SET_VSEL(3) },
173:
174: /* Enable speaker driver, DAC oversampling */
175: { ADCTL2_REG, ADCTL2_ROUT2INV | ADCTL2_DACOSR },
176:
177: /* Set DAC voltage references */
178: { PWRMGMT1_REG, PWRMGMT1_SET_VMIDSEL(1) | PWRMGMT1_VREF },
179:
180: /* Direct DACs to output mixers */
181: { LOUTMIX1_REG, LOUTMIX1_LD2LO },
182: { ROUTMIX2_REG, ROUTMIX2_RD2RO },
183:
184: /* End of list */
185: { 0xffff, 0xffff }
186: };
187:
188: int
189: zaudio_match(struct device *parent, void *match, void *aux)
190: {
191: return (1);
192: }
193:
194: void
195: zaudio_attach(struct device *parent, struct device *self, void *aux)
196: {
197: struct zaudio_softc *sc = (struct zaudio_softc *)self;
198: struct pxaip_attach_args *pxa = aux;
199: int err;
200:
201: sc->sc_powerhook = powerhook_establish(zaudio_power, sc);
202: if (sc->sc_powerhook == NULL) {
203: printf(": unable to establish powerhook\n");
204: return;
205: }
206:
207: sc->sc_i2s.sc_iot = pxa->pxa_iot;
208: sc->sc_i2s.sc_dmat = pxa->pxa_dmat;
209: sc->sc_i2s.sc_size = PXA2X0_I2S_SIZE;
210: if (pxa2x0_i2s_attach_sub(&sc->sc_i2s)) {
211: printf(": unable to attach I2S\n");
212: goto fail_i2s;
213: }
214:
215: sc->sc_i2c.sc_iot = pxa->pxa_iot;
216: sc->sc_i2c.sc_size = PXA2X0_I2C_SIZE;
217: if (pxa2x0_i2c_attach_sub(&sc->sc_i2c)) {
218: printf(": unable to attach I2C\n");
219: goto fail_i2c;
220: }
221:
222: /* Check for an I2C response from the wm8750 */
223: pxa2x0_i2c_open(&sc->sc_i2c);
224: err = wm8750_write(sc, RESET_REG, 0);
225: pxa2x0_i2c_close(&sc->sc_i2c);
226:
227: if (err) {
228: printf(": codec failed to respond\n");
229: goto fail_probe;
230: }
231: delay(100);
232:
233: /* Speaker on, headphones off by default. */
234: sc->sc_volume[ZAUDIO_OP_SPKR].left = 240;
235: sc->sc_unmute[ZAUDIO_OP_SPKR] = 1;
236: sc->sc_volume[ZAUDIO_OP_HP].left = 180;
237: sc->sc_volume[ZAUDIO_OP_HP].right = 180;
238: sc->sc_unmute[ZAUDIO_OP_HP] = 0;
239:
240: /* Configure headphone jack state change handling. */
241: timeout_set(&sc->sc_to, zaudio_jack, sc);
242: pxa2x0_gpio_set_function(GPIO_HP_IN_C3000, GPIO_IN);
243: (void)pxa2x0_gpio_intr_establish(GPIO_HP_IN_C3000,
244: IST_EDGE_BOTH, IPL_BIO, zaudio_jack_intr, sc, "hpjk");
245:
246: zaudio_init(sc);
247:
248: printf(": I2C, I2S, WM8750 Audio\n");
249:
250: audio_attach_mi(&wm8750_hw_if, sc, &sc->sc_dev);
251:
252: return;
253:
254: fail_probe:
255: pxa2x0_i2c_detach_sub(&sc->sc_i2c);
256: fail_i2c:
257: pxa2x0_i2s_detach_sub(&sc->sc_i2s);
258: fail_i2s:
259: powerhook_disestablish(sc->sc_powerhook);
260: }
261:
262: int
263: zaudio_detach(struct device *self, int flags)
264: {
265: struct zaudio_softc *sc = (struct zaudio_softc *)self;
266:
267: if (sc->sc_powerhook != NULL) {
268: powerhook_disestablish(sc->sc_powerhook);
269: sc->sc_powerhook = NULL;
270: }
271:
272: pxa2x0_i2c_detach_sub(&sc->sc_i2c);
273: pxa2x0_i2s_detach_sub(&sc->sc_i2s);
274:
275: return (0);
276: }
277:
278: void
279: zaudio_power(int why, void *arg)
280: {
281: struct zaudio_softc *sc = arg;
282:
283: switch (why) {
284: case PWR_STANDBY:
285: case PWR_SUSPEND:
286: timeout_del(&sc->sc_to);
287: zaudio_standby(sc);
288: break;
289:
290: case PWR_RESUME:
291: pxa2x0_i2s_init(&sc->sc_i2s);
292: pxa2x0_i2c_init(&sc->sc_i2c);
293: zaudio_init(sc);
294: break;
295: }
296: }
297:
298: void
299: zaudio_init(struct zaudio_softc *sc)
300: {
301: pxa2x0_i2c_open(&sc->sc_i2c);
302:
303: /* Reset the codec */
304: wm8750_write(sc, RESET_REG, 0);
305: delay(100);
306:
307: /* Switch to standby power only */
308: wm8750_write(sc, PWRMGMT1_REG, PWRMGMT1_SET_VMIDSEL(2));
309: wm8750_write(sc, PWRMGMT2_REG, 0);
310:
311: /* Configure digital interface for I2S */
312: wm8750_write(sc, AUDINT_REG, AUDINT_SET_FORMAT(2));
313:
314: /* Initialise volume levels */
315: zaudio_update_volume(sc, ZAUDIO_OP_SPKR);
316: zaudio_update_volume(sc, ZAUDIO_OP_HP);
317: scoop_set_headphone(0);
318:
319: pxa2x0_i2c_close(&sc->sc_i2c);
320:
321: /* Assume that the jack state has changed. */
322: zaudio_jack(sc);
323:
324: }
325:
326: int
327: zaudio_jack_intr(void *v)
328: {
329: struct zaudio_softc *sc = v;
330:
331: if (!timeout_triggered(&sc->sc_to))
332: zaudio_jack(sc);
333:
334: return (1);
335: }
336:
337: void
338: zaudio_jack(void *v)
339: {
340: struct zaudio_softc *sc = v;
341:
342: switch (sc->sc_state) {
343: case ZAUDIO_JACK_STATE_OUT:
344: if (pxa2x0_gpio_get_bit(GPIO_HP_IN_C3000)) {
345: sc->sc_state = ZAUDIO_JACK_STATE_INS;
346: sc->sc_icount = 0;
347: }
348: break;
349: case ZAUDIO_JACK_STATE_INS:
350: if (sc->sc_icount++ > 2) {
351: if (pxa2x0_gpio_get_bit(GPIO_HP_IN_C3000)) {
352: sc->sc_state = ZAUDIO_JACK_STATE_IN;
353: sc->sc_unmute[ZAUDIO_OP_SPKR] = 0;
354: sc->sc_unmute[ZAUDIO_OP_HP] = 1;
355: goto update_mutes;
356: } else
357: sc->sc_state = ZAUDIO_JACK_STATE_OUT;
358: }
359: break;
360: case ZAUDIO_JACK_STATE_IN:
361: if (!pxa2x0_gpio_get_bit(GPIO_HP_IN_C3000)) {
362: sc->sc_state = ZAUDIO_JACK_STATE_REM;
363: sc->sc_icount = 0;
364: }
365: break;
366: case ZAUDIO_JACK_STATE_REM:
367: if (sc->sc_icount++ > 2) {
368: if (!pxa2x0_gpio_get_bit(GPIO_HP_IN_C3000)) {
369: sc->sc_state = ZAUDIO_JACK_STATE_OUT;
370: sc->sc_unmute[ZAUDIO_OP_SPKR] = 1;
371: sc->sc_unmute[ZAUDIO_OP_HP] = 0;
372: goto update_mutes;
373: } else
374: sc->sc_state = ZAUDIO_JACK_STATE_IN;
375: }
376: break;
377: }
378:
379: timeout_add(&sc->sc_to, hz/4);
380: return;
381:
382: update_mutes:
383: timeout_del(&sc->sc_to);
384:
385: if (sc->sc_playing) {
386: pxa2x0_i2c_open(&sc->sc_i2c);
387: zaudio_update_mutes(sc);
388: pxa2x0_i2c_close(&sc->sc_i2c);
389: }
390: }
391:
392: void
393: zaudio_standby(struct zaudio_softc *sc)
394: {
395: pxa2x0_i2c_open(&sc->sc_i2c);
396:
397: /* Switch codec to standby power only */
398: wm8750_write(sc, PWRMGMT1_REG, PWRMGMT1_SET_VMIDSEL(2));
399: wm8750_write(sc, PWRMGMT2_REG, 0);
400:
401: scoop_set_headphone(0);
402:
403: pxa2x0_i2c_close(&sc->sc_i2c);
404: }
405:
406: void
407: zaudio_update_volume(struct zaudio_softc *sc, int output)
408: {
409: switch(output) {
410: case ZAUDIO_OP_SPKR:
411: wm8750_write(sc, LOUT2VOL_REG, LOUT2VOL_LO2VU | LOUT2VOL_LO2ZC |
412: LOUT2VOL_SET_LOUT2VOL(sc->sc_volume[ZAUDIO_OP_SPKR
413: ].left >> 1));
414: wm8750_write(sc, ROUT2VOL_REG, ROUT2VOL_RO2VU | ROUT2VOL_RO2ZC |
415: ROUT2VOL_SET_ROUT2VOL(sc->sc_volume[ZAUDIO_OP_SPKR
416: ].left >> 1));
417: break;
418: case ZAUDIO_OP_HP:
419: wm8750_write(sc, LOUT1VOL_REG, LOUT1VOL_LO1VU | LOUT1VOL_LO1ZC |
420: LOUT1VOL_SET_LOUT1VOL(sc->sc_volume[ZAUDIO_OP_HP
421: ].left >> 1));
422: wm8750_write(sc, ROUT1VOL_REG, ROUT1VOL_RO1VU | ROUT1VOL_RO1ZC |
423: ROUT1VOL_SET_ROUT1VOL(sc->sc_volume[ZAUDIO_OP_HP
424: ].right >> 1));
425: break;
426: }
427: }
428:
429: void
430: zaudio_update_mutes(struct zaudio_softc *sc)
431: {
432: unsigned short val;
433:
434: val = PWRMGMT2_DACL | PWRMGMT2_DACR;
435:
436: if (sc->sc_unmute[ZAUDIO_OP_SPKR])
437: val |= PWRMGMT2_LOUT2 | PWRMGMT2_ROUT2;
438:
439: if (sc->sc_unmute[ZAUDIO_OP_HP])
440: val |= PWRMGMT2_LOUT1 | PWRMGMT2_ROUT1;
441:
442: wm8750_write(sc, PWRMGMT2_REG, val);
443:
444: scoop_set_headphone(sc->sc_unmute[ZAUDIO_OP_HP]);
445: }
446:
447: void
448: zaudio_play_setup(struct zaudio_softc *sc)
449: {
450: int i = 0;
451:
452: pxa2x0_i2c_open(&sc->sc_i2c);
453:
454: /* Program the codec with playback settings */
455: while (playback_registers[i][0] != 0xffff) {
456: wm8750_write(sc, playback_registers[i][0],
457: playback_registers[i][1]);
458: i++;
459: }
460: zaudio_update_mutes(sc);
461:
462: pxa2x0_i2c_close(&sc->sc_i2c);
463: }
464:
465: int
466: zaudio_open(void *hdl, int flags)
467: {
468: struct zaudio_softc *sc = hdl;
469:
470: /* Power on the I2S bus and codec */
471: pxa2x0_i2s_open(&sc->sc_i2s);
472:
473: return 0;
474: }
475:
476: void
477: zaudio_close(void *hdl)
478: {
479: struct zaudio_softc *sc = hdl;
480:
481: /* Power off the I2S bus and codec */
482: pxa2x0_i2s_close(&sc->sc_i2s);
483: }
484:
485: int
486: zaudio_query_encoding(void *hdl, struct audio_encoding *aep)
487: {
488: switch (aep->index) {
489: case 0:
490: strlcpy(aep->name, AudioEulinear, sizeof(aep->name));
491: aep->encoding = AUDIO_ENCODING_ULINEAR;
492: aep->precision = 8;
493: aep->flags = 0;
494: return (0);
495: case 1:
496: strlcpy(aep->name, AudioEmulaw, sizeof(aep->name));
497: aep->encoding = AUDIO_ENCODING_ULAW;
498: aep->precision = 8;
499: aep->flags = AUDIO_ENCODINGFLAG_EMULATED;
500: return (0);
501: case 2:
502: strlcpy(aep->name, AudioEalaw, sizeof(aep->name));
503: aep->encoding = AUDIO_ENCODING_ALAW;
504: aep->precision = 8;
505: aep->flags = AUDIO_ENCODINGFLAG_EMULATED;
506: return (0);
507: case 3:
508: strlcpy(aep->name, AudioEslinear, sizeof(aep->name));
509: aep->encoding = AUDIO_ENCODING_SLINEAR;
510: aep->precision = 8;
511: aep->flags = AUDIO_ENCODINGFLAG_EMULATED;
512: return (0);
513: case 4:
514: strlcpy(aep->name, AudioEslinear_le, sizeof(aep->name));
515: aep->encoding = AUDIO_ENCODING_SLINEAR_LE;
516: aep->precision = 16;
517: aep->flags = 0;
518: return (0);
519: case 5:
520: strlcpy(aep->name, AudioEulinear_le, sizeof(aep->name));
521: aep->encoding = AUDIO_ENCODING_ULINEAR_LE;
522: aep->precision = 16;
523: aep->flags = AUDIO_ENCODINGFLAG_EMULATED;
524: return (0);
525: case 6:
526: strlcpy(aep->name, AudioEslinear_be, sizeof(aep->name));
527: aep->encoding = AUDIO_ENCODING_SLINEAR_BE;
528: aep->precision = 16;
529: aep->flags = AUDIO_ENCODINGFLAG_EMULATED;
530: return (0);
531: case 7:
532: strlcpy(aep->name, AudioEulinear_be, sizeof(aep->name));
533: aep->encoding = AUDIO_ENCODING_ULINEAR_BE;
534: aep->precision = 16;
535: aep->flags = AUDIO_ENCODINGFLAG_EMULATED;
536: return (0);
537: default:
538: return (EINVAL);
539: }
540: }
541:
542: int
543: zaudio_set_params(void *hdl, int setmode, int usemode,
544: struct audio_params *play, struct audio_params *rec)
545: {
546: struct zaudio_softc *sc = hdl;
547:
548: if (setmode & AUMODE_PLAY) {
549: play->factor = 1;
550: play->sw_code = NULL;
551: switch(play->encoding) {
552: case AUDIO_ENCODING_ULAW:
553: switch (play->channels) {
554: case 1:
555: play->factor = 4;
556: play->sw_code = mulaw_to_slinear16_mts;
557: break;
558: case 2:
559: play->factor = 2;
560: play->sw_code = mulaw_to_slinear16;
561: break;
562: default:
563: return (EINVAL);
564: }
565: break;
566: case AUDIO_ENCODING_SLINEAR_LE:
567: switch (play->precision) {
568: case 8:
569: switch (play->channels) {
570: case 1:
571: play->factor = 4;
572: play->sw_code = linear8_to_linear16_mts;
573: break;
574: case 2:
575: play->factor = 2;
576: play->sw_code = linear8_to_linear16;
577: break;
578: default:
579: return (EINVAL);
580: }
581: break;
582: case 16:
583: switch (play->channels) {
584: case 1:
585: play->factor = 2;
586: play->sw_code = noswap_bytes_mts;
587: break;
588: case 2:
589: break;
590: default:
591: return (EINVAL);
592: }
593: break;
594: default:
595: return (EINVAL);
596: }
597: break;
598: case AUDIO_ENCODING_ULINEAR_LE:
599: switch (play->precision) {
600: case 8:
601: switch (play->channels) {
602: case 1:
603: play->factor = 4;
604: play->sw_code =
605: ulinear8_to_linear16_mts;
606: break;
607: case 2:
608: play->factor = 2;
609: play->sw_code = ulinear8_to_linear16;
610: break;
611: default:
612: return (EINVAL);
613: }
614: break;
615: case 16:
616: switch (play->channels) {
617: case 1:
618: play->factor = 2;
619: play->sw_code = change_sign16_mts;
620: break;
621: case 2:
622: play->sw_code = change_sign16;
623: break;
624: default:
625: return (EINVAL);
626: }
627: break;
628: default:
629: return (EINVAL);
630: }
631: break;
632: case AUDIO_ENCODING_ALAW:
633: switch (play->channels) {
634: case 1:
635: play->factor = 4;
636: play->sw_code = alaw_to_slinear16_mts;
637: case 2:
638: play->factor = 2;
639: play->sw_code = alaw_to_slinear16;
640: default:
641: return (EINVAL);
642: }
643: break;
644: case AUDIO_ENCODING_SLINEAR_BE:
645: switch (play->precision) {
646: case 8:
647: switch (play->channels) {
648: case 1:
649: play->factor = 4;
650: play->sw_code =
651: linear8_to_linear16_mts;
652: break;
653: case 2:
654: play->factor = 2;
655: play->sw_code = linear8_to_linear16;
656: break;
657: default:
658: return (EINVAL);
659: }
660: break;
661: case 16:
662: switch (play->channels) {
663: case 1:
664: play->factor = 2;
665: play->sw_code = swap_bytes_mts;
666: break;
667: case 2:
668: play->sw_code = swap_bytes;
669: break;
670: default:
671: return (EINVAL);
672: }
673: break;
674: default:
675: return (EINVAL);
676: }
677: break;
678: case AUDIO_ENCODING_ULINEAR_BE:
679: switch (play->precision) {
680: case 8:
681: switch (play->channels) {
682: case 1:
683: play->factor = 4;
684: play->sw_code =
685: ulinear8_to_linear16_mts;
686: break;
687: case 2:
688: play->factor = 2;
689: play->sw_code = ulinear8_to_linear16;
690: break;
691: default:
692: return (EINVAL);
693: }
694: break;
695: case 16:
696: switch (play->channels) {
697: case 1:
698: play->factor = 2;
699: play->sw_code =
700: change_sign16_swap_bytes_mts;
701: break;
702: case 2:
703: play->sw_code =
704: change_sign16_swap_bytes;
705: break;
706: default:
707: return (EINVAL);
708: }
709: break;
710: default:
711: return (EINVAL);
712: }
713: break;
714: default:
715: return (EINVAL);
716: }
717:
718: pxa2x0_i2s_setspeed(&sc->sc_i2s, &play->sample_rate);
719: }
720:
721: #if RECORD_XXX_NOT_YET
722: if (setmode & AUMODE_RECORD) {
723: rec->factor = 1;
724: rec->sw_code = NULL;
725: switch(rec->encoding) {
726: case AUDIO_ENCODING_ULAW:
727: rec->sw_code = ulinear8_to_mulaw;
728: break;
729: case AUDIO_ENCODING_SLINEAR_LE:
730: if (rec->precision == 8)
731: rec->sw_code = change_sign8;
732: break;
733: case AUDIO_ENCODING_ULINEAR_LE:
734: if (rec->precision == 16)
735: rec->sw_code = change_sign16;
736: break;
737: case AUDIO_ENCODING_ALAW:
738: rec->sw_code = ulinear8_to_alaw;
739: break;
740: case AUDIO_ENCODING_SLINEAR_BE:
741: if (rec->precision == 16)
742: rec->sw_code = swap_bytes;
743: else
744: rec->sw_code = change_sign8;
745: break;
746: case AUDIO_ENCODING_ULINEAR_BE:
747: if (rec->precision == 16)
748: rec->sw_code = swap_bytes_change_sign16;
749: break;
750: default:
751: return (EINVAL);
752: }
753:
754: pxa2x0_i2s_setspeed(sc, &rec->sample_rate);
755: }
756: #endif
757:
758: return (0);
759: }
760:
761: int
762: zaudio_halt_output(void *hdl)
763: {
764: struct zaudio_softc *sc = hdl;
765:
766: /* XXX forcibly stop output DMA? */
767:
768: zaudio_standby(sc);
769: sc->sc_playing = 0;
770:
771: return 0;
772: }
773:
774: int
775: zaudio_halt_input(void *hdl)
776: {
777: /* struct zaudio_softc *sc = hdl; */
778:
779: return 0;
780: }
781:
782: int
783: zaudio_getdev(void *hdl, struct audio_device *ret)
784: {
785: /* struct zaudio_softc *sc = hdl; */
786:
787: *ret = wm8750_device;
788: return 0;
789: }
790:
791: #define ZAUDIO_SPKR_LVL 0
792: #define ZAUDIO_SPKR_MUTE 1
793: #define ZAUDIO_HP_LVL 2
794: #define ZAUDIO_HP_MUTE 3
795: #define ZAUDIO_OUTPUT_CLASS 4
796:
797: int
798: zaudio_set_port(void *hdl, struct mixer_ctrl *mc)
799: {
800: struct zaudio_softc *sc = hdl;
801: int error = EINVAL, s;
802:
803: s = splbio();
804: pxa2x0_i2c_open(&sc->sc_i2c);
805:
806: switch (mc->dev) {
807: case ZAUDIO_SPKR_LVL:
808: if (mc->type != AUDIO_MIXER_VALUE)
809: break;
810: if (mc->un.value.num_channels == 1)
811: sc->sc_volume[ZAUDIO_OP_SPKR].left =
812: mc->un.value.level[AUDIO_MIXER_LEVEL_MONO];
813: else
814: break;
815: zaudio_update_volume(sc, ZAUDIO_OP_SPKR);
816: error = 0;
817: break;
818: case ZAUDIO_SPKR_MUTE:
819: if (mc->type != AUDIO_MIXER_ENUM)
820: break;
821: sc->sc_unmute[ZAUDIO_OP_SPKR] = mc->un.ord ? 1 : 0;
822: zaudio_update_mutes(sc);
823: error = 0;
824: break;
825: case ZAUDIO_HP_LVL:
826: if (mc->type != AUDIO_MIXER_VALUE)
827: break;
828: if (mc->un.value.num_channels == 1) {
829: sc->sc_volume[ZAUDIO_OP_HP].left =
830: mc->un.value.level[AUDIO_MIXER_LEVEL_MONO];
831: sc->sc_volume[ZAUDIO_OP_HP].right =
832: mc->un.value.level[AUDIO_MIXER_LEVEL_MONO];
833: } else if (mc->un.value.num_channels == 2) {
834: sc->sc_volume[ZAUDIO_OP_HP].left =
835: mc->un.value.level[AUDIO_MIXER_LEVEL_LEFT];
836: sc->sc_volume[ZAUDIO_OP_HP].right =
837: mc->un.value.level[AUDIO_MIXER_LEVEL_RIGHT];
838: }
839: else
840: break;
841: zaudio_update_volume(sc, ZAUDIO_OP_HP);
842: error = 0;
843: break;
844: case ZAUDIO_HP_MUTE:
845: if (mc->type != AUDIO_MIXER_ENUM)
846: break;
847: sc->sc_unmute[ZAUDIO_OP_HP] = mc->un.ord ? 1 : 0;
848: zaudio_update_mutes(sc);
849: error = 0;
850: break;
851: }
852:
853: pxa2x0_i2c_close(&sc->sc_i2c);
854: splx(s);
855:
856: return error;
857: }
858:
859: int
860: zaudio_get_port(void *hdl, struct mixer_ctrl *mc)
861: {
862: struct zaudio_softc *sc = hdl;
863: int error = EINVAL;
864:
865: switch (mc->dev) {
866: case ZAUDIO_SPKR_LVL:
867: if (mc->type != AUDIO_MIXER_VALUE)
868: break;
869: if (mc->un.value.num_channels == 1)
870: mc->un.value.level[AUDIO_MIXER_LEVEL_MONO] =
871: sc->sc_volume[ZAUDIO_OP_SPKR].left;
872: else
873: break;
874: error = 0;
875: break;
876: case ZAUDIO_SPKR_MUTE:
877: if (mc->type != AUDIO_MIXER_ENUM)
878: break;
879: mc->un.ord = sc->sc_unmute[ZAUDIO_OP_SPKR] ? 1 : 0;
880: error = 0;
881: break;
882: case ZAUDIO_HP_LVL:
883: if (mc->type != AUDIO_MIXER_VALUE)
884: break;
885: if (mc->un.value.num_channels == 1)
886: mc->un.value.level[AUDIO_MIXER_LEVEL_MONO] =
887: sc->sc_volume[ZAUDIO_OP_HP].left;
888: else if (mc->un.value.num_channels == 2) {
889: mc->un.value.level[AUDIO_MIXER_LEVEL_LEFT] =
890: sc->sc_volume[ZAUDIO_OP_HP].left;
891: mc->un.value.level[AUDIO_MIXER_LEVEL_RIGHT] =
892: sc->sc_volume[ZAUDIO_OP_HP].right;
893: }
894: else
895: break;
896: error = 0;
897: break;
898: case ZAUDIO_HP_MUTE:
899: if (mc->type != AUDIO_MIXER_ENUM)
900: break;
901: mc->un.ord = sc->sc_unmute[ZAUDIO_OP_HP] ? 1 : 0;
902: error = 0;
903: break;
904: }
905:
906: return error;
907: }
908:
909: int
910: zaudio_query_devinfo(void *hdl, struct mixer_devinfo *di)
911: {
912: /* struct zaudio_softc *sc = hdl; */
913:
914: switch (di->index) {
915: case ZAUDIO_SPKR_LVL:
916: di->type = AUDIO_MIXER_VALUE;
917: di->mixer_class = ZAUDIO_OUTPUT_CLASS;
918: di->prev = AUDIO_MIXER_LAST;
919: di->next = ZAUDIO_SPKR_MUTE;
920: strlcpy(di->label.name, AudioNspeaker,
921: sizeof(di->label.name));
922: strlcpy(di->un.v.units.name, AudioNvolume,
923: sizeof(di->un.v.units.name));
924: di->un.v.num_channels = 1;
925: break;
926: case ZAUDIO_SPKR_MUTE:
927: di->type = AUDIO_MIXER_ENUM;
928: di->mixer_class = ZAUDIO_OUTPUT_CLASS;
929: di->prev = ZAUDIO_SPKR_LVL;
930: di->next = AUDIO_MIXER_LAST;
931: goto mute;
932: case ZAUDIO_HP_LVL:
933: di->type = AUDIO_MIXER_VALUE;
934: di->mixer_class = ZAUDIO_OUTPUT_CLASS;
935: di->prev = AUDIO_MIXER_LAST;
936: di->next = ZAUDIO_HP_MUTE;
937: strlcpy(di->label.name, AudioNheadphone,
938: sizeof(di->label.name));
939: di->un.v.num_channels = 1;
940: strlcpy(di->un.v.units.name, AudioNvolume,
941: sizeof(di->un.v.units.name));
942: break;
943: case ZAUDIO_HP_MUTE:
944: di->type = AUDIO_MIXER_ENUM;
945: di->mixer_class = ZAUDIO_OUTPUT_CLASS;
946: di->prev = ZAUDIO_HP_LVL;
947: di->next = AUDIO_MIXER_LAST;
948: mute:
949: strlcpy(di->label.name, AudioNmute, sizeof(di->label.name));
950: di->un.e.num_mem = 2;
951: strlcpy(di->un.e.member[0].label.name, AudioNon,
952: sizeof(di->un.e.member[0].label.name));
953: di->un.e.member[0].ord = 0;
954: strlcpy(di->un.e.member[1].label.name, AudioNoff,
955: sizeof(di->un.e.member[1].label.name));
956: di->un.e.member[1].ord = 1;
957: break;
958: case ZAUDIO_OUTPUT_CLASS:
959: di->type = AUDIO_MIXER_CLASS;
960: di->mixer_class = ZAUDIO_OUTPUT_CLASS;
961: di->prev = AUDIO_MIXER_LAST;
962: di->next = AUDIO_MIXER_LAST;
963: strlcpy(di->label.name, AudioCoutputs,
964: sizeof(di->label.name));
965: break;
966: default:
967: return ENXIO;
968: }
969:
970: return 0;
971: }
972:
973: int
974: zaudio_get_props(void *hdl)
975: {
976: return AUDIO_PROP_MMAP | AUDIO_PROP_INDEPENDENT | AUDIO_PROP_FULLDUPLEX;
977: }
978:
979: int
980: zaudio_start_output(void *hdl, void *block, int bsize, void (*intr)(void *),
981: void *intrarg)
982: {
983: struct zaudio_softc *sc = hdl;
984: int err;
985:
986: /* Power up codec if we are not already playing. */
987: if (!sc->sc_playing) {
988: sc->sc_playing = 1;
989: zaudio_play_setup(sc);
990: }
991:
992: /* Start DMA via I2S */
993: err = pxa2x0_i2s_start_output(&sc->sc_i2s, block, bsize, intr, intrarg);
994: if (err) {
995: zaudio_standby(sc);
996: sc->sc_playing = 0;
997: }
998: return err;
999: }
1000:
1001: int
1002: zaudio_start_input(void *hdl, void *block, int bsize, void (*intr)(void *),
1003: void *intrarg)
1004: {
1005: return ENXIO;
1006: }
CVSweb