1/*	$NetBSD: wm8731_zaudio.c,v 1.3 2019/05/08 13:40:17 isaki Exp $	*/
2
3/*-
4 * Copyright (c) 2013 The NetBSD Foundation, Inc.
5 * All rights reserved.
6 *
7 * This code is derived from software contributed to The NetBSD Foundation
8 * by TOYOKURA Atsushi.
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/*
33 * TODO:
34 *	- powerhooks (currently only works until first suspend)
35 */
36
37#include "opt_cputypes.h"
38#include "opt_zaudio.h"
39
40#include <sys/cdefs.h>
41__KERNEL_RCSID(0, "$NetBSD: wm8731_zaudio.c,v 1.3 2019/05/08 13:40:17 isaki Exp $");
42
43#include <sys/param.h>
44#include <sys/systm.h>
45#include <sys/callout.h>
46#include <sys/device.h>
47#include <sys/kmem.h>
48#include <sys/kernel.h>
49#include <sys/audioio.h>
50#include <sys/mutex.h>
51#include <sys/intr.h>
52#include <sys/bus.h>
53
54#include <dev/audio/audio_if.h>
55
56#include <dev/i2c/i2cvar.h>
57
58#include <arm/xscale/pxa2x0reg.h>
59#include <arm/xscale/pxa2x0var.h>
60#include <arm/xscale/pxa2x0_i2c.h>
61#include <arm/xscale/pxa2x0_i2s.h>
62#include <arm/xscale/pxa2x0_dmac.h>
63#include <arm/xscale/pxa2x0_gpio.h>
64
65#include <zaurus/zaurus/zaurus_var.h>
66#include <zaurus/dev/zaudiovar.h>
67#include <zaurus/dev/wm8731reg.h>
68#include <zaurus/dev/wm8731var.h>
69#include <zaurus/dev/scoopvar.h>
70
71#define WM8731_ADDRESS  0x1B
72
73/* GPIO pins */
74#define GPIO_HP_IN_C860	4
75
76#define WM8731_OP_SPKR	0
77#define WM8731_OP_MIC	1
78#define WM8731_OP_NUM	2
79
80static int	wm8731_finalize(device_t);
81static bool	wm8731_suspend(device_t, const pmf_qual_t *);
82static bool	wm8731_resume(device_t, const pmf_qual_t *);
83static void	wm8731_volume_up(device_t);
84static void	wm8731_volume_down(device_t);
85static void	wm8731_volume_toggle(device_t);
86
87static struct audio_device wm8731_device = {
88	"WM8731",
89	"1.0",
90	"wm"
91};
92
93static void wm8731_init(struct zaudio_softc *);
94static int wm8731_jack_intr(void *);
95static void wm8731_jack(void *);
96static void wm8731_standby(struct zaudio_softc *);
97static void wm8731_update_volume(struct zaudio_softc *, int);
98static void wm8731_update_mutes(struct zaudio_softc *, int);
99static void wm8731_play_setup(struct zaudio_softc *);
100/*static*/ void wm8731_record_setup(struct zaudio_softc *);
101static int wm8731_start_output(void *, void *, int, void (*)(void *), void *);
102static int wm8731_start_input(void *, void *, int, void (*)(void *), void *);
103static int wm8731_halt_output(void *);
104static int wm8731_halt_input(void *);
105static int wm8731_getdev(void *, struct audio_device *);
106static int wm8731_set_port(void *, struct mixer_ctrl *);
107static int wm8731_get_port(void *, struct mixer_ctrl *);
108static int wm8731_query_devinfo(void *, struct mixer_devinfo *);
109
110static struct audio_hw_if wm8731_hw_if = {
111	.open			= zaudio_open,
112	.close			= zaudio_close,
113	.query_format		= zaudio_query_format,
114	.set_format		= zaudio_set_format,
115	.round_blocksize	= zaudio_round_blocksize,
116	.commit_settings	= NULL,
117	.init_output		= NULL,
118	.init_input		= NULL,
119	.start_output		= wm8731_start_output,
120	.start_input		= wm8731_start_input,
121	.halt_output		= wm8731_halt_output,
122	.halt_input		= wm8731_halt_input,
123	.speaker_ctl		= NULL,
124	.getdev			= wm8731_getdev,
125	.set_port		= wm8731_set_port,
126	.get_port		= wm8731_get_port,
127	.query_devinfo		= wm8731_query_devinfo,
128	.allocm			= zaudio_allocm,
129	.freem			= zaudio_freem,
130	.round_buffersize	= zaudio_round_buffersize,
131	.get_props		= zaudio_get_props,
132	.trigger_output		= NULL,
133	.trigger_input		= NULL,
134	.dev_ioctl		= NULL,
135	.get_locks		= zaudio_get_locks,
136};
137
138static const uint16_t playback_regs[][2] = {
139	/* Power Down Control */
140	{ WM8731_PD_REG, WM8731_CLKOUTPD | WM8731_OSCPD | WM8731_OUTPD
141	    | WM8731_ADCPD | WM8731_MICPD | WM8731_LINEINPD },
142
143	/* Digital Audio Path Control */
144	{ WM8731_DAP_REG, 0 },
145
146	/* Analogue Audio Path Control */
147	{ WM8731_AAP_REG, WM8731_DACSEL | WM8731_MUTEMIC },
148
149	/* Activating DSP and DAI */
150	{ WM8731_AC_REG, WM8731_ACTIVE },
151
152	/* End of list */
153	{ 0xffff, 0xffff }
154};
155
156static const uint16_t record_regs[][2] = {
157	/* Power Down Control */
158	{ WM8731_PD_REG, WM8731_CLKOUTPD | WM8731_OSCPD | WM8731_DACPD
159	    | WM8731_LINEINPD },
160
161	/* Digital Audio Path Control */
162	{ WM8731_DAP_REG, 0 },
163
164	/* Analogue Audio Path Control */
165	{ WM8731_AAP_REG, WM8731_INSEL | WM8731_MICBOOST },
166
167	/* Activating DSP and DAI */
168	{ WM8731_AC_REG, WM8731_ACTIVE },
169
170	/* End of list */
171	{ 0xffff, 0xffff }
172};
173
174static __inline int
175wm8731_write(struct zaudio_softc *sc, int reg, int val)
176{
177	uint16_t tmp;
178	uint8_t cmd;
179	uint8_t data;
180
181	tmp = (reg << 9) | (val & 0x1ff);
182	cmd = tmp >> 8;
183	data = tmp;
184	return iic_exec(sc->sc_i2c, I2C_OP_WRITE_WITH_STOP, WM8731_ADDRESS,
185	    &cmd, 1, &data, 1, 0);
186}
187
188int
189wm8731_match(device_t parent, cfdata_t cf, struct i2c_attach_args *ia)
190{
191	int match_result;
192
193	if (ZAURUS_ISC1000 || ZAURUS_ISC3000)
194		return 0;
195
196	if (iic_use_direct_match(ia, cf, NULL, &match_result))
197		return match_result;
198
199	/* indirect config - check typical address */
200	if (ia->ia_addr == WM8731_ADDRESS)
201		return I2C_MATCH_ADDRESS_ONLY;
202
203	return 0;
204}
205
206void
207wm8731_attach(device_t parent, device_t self, struct i2c_attach_args *ia)
208{
209	struct zaudio_softc *sc = device_private(self);
210	int error;
211
212	aprint_normal(": I2S, WM8731 Audio\n");
213	aprint_naive("\n");
214
215	/* Check for an I2C response from the wm8731 */
216	iic_acquire_bus(sc->sc_i2c, 0);
217	error = wm8731_write(sc, WM8731_RESET_REG, 0);
218	iic_release_bus(sc->sc_i2c, 0);
219	if (error) {
220		aprint_error_dev(self, "codec failed to respond\n");
221		goto fail_i2c;
222	}
223	delay(100);
224
225	/* Allocate memory for volume & mute operations */
226	sc->sc_volume = kmem_zalloc(sizeof(*sc->sc_volume) * WM8731_OP_NUM,
227	    KM_SLEEP);
228	sc->sc_unmute = kmem_zalloc(sizeof(*sc->sc_unmute) * WM8731_OP_NUM,
229	    KM_SLEEP);
230	sc->sc_unmute_toggle = kmem_zalloc(
231	    sizeof(*sc->sc_unmute_toggle) * WM8731_OP_NUM, KM_SLEEP);
232
233	/* Speaker On by default. */
234	sc->sc_volume[WM8731_OP_SPKR].left = 180;
235	sc->sc_volume[WM8731_OP_SPKR].right = 180;
236	sc->sc_jack = FALSE;
237	UNMUTE(sc, WM8731_OP_SPKR, 1);
238	sc->sc_volume[WM8731_OP_MIC].left = 180;
239	UNMUTE(sc, WM8731_OP_MIC, 0);
240
241	/* Configure headphone jack state change handling. */
242	callout_setfunc(&sc->sc_to, wm8731_jack, sc);
243	pxa2x0_gpio_set_function(GPIO_HP_IN_C860, GPIO_IN);
244	(void) pxa2x0_gpio_intr_establish(GPIO_HP_IN_C860, IST_EDGE_BOTH,
245	    IPL_BIO, wm8731_jack_intr, sc);
246
247	/* wm8731_init() implicitly depends on ioexp or scoop */
248	config_finalize_register(self, wm8731_finalize);
249
250	audio_attach_mi(&wm8731_hw_if, sc, self);
251
252	if (!pmf_device_register(self, wm8731_suspend, wm8731_resume))
253		aprint_error_dev(self, "couldn't establish power handler\n");
254	if (!pmf_event_register(self, PMFE_AUDIO_VOLUME_UP,
255	    wm8731_volume_up, true))
256		aprint_error_dev(self, "couldn't register event handler\n");
257	if (!pmf_event_register(self, PMFE_AUDIO_VOLUME_DOWN,
258	    wm8731_volume_down, true))
259		aprint_error_dev(self, "couldn't register event handler\n");
260	if (!pmf_event_register(self, PMFE_AUDIO_VOLUME_TOGGLE,
261	    wm8731_volume_toggle, true))
262		aprint_error_dev(self, "couldn't register event handler\n");
263
264	return;
265
266fail_i2c:
267	pxa2x0_i2s_detach_sub(&sc->sc_i2s);
268}
269
270static int
271wm8731_finalize(device_t dv)
272{
273	struct zaudio_softc *sc = device_private(dv);
274
275	wm8731_init(sc);
276	return 0;
277}
278
279static bool
280wm8731_suspend(device_t dv, const pmf_qual_t *qual)
281{
282	struct zaudio_softc *sc = device_private(dv);
283
284	callout_stop(&sc->sc_to);
285	wm8731_standby(sc);
286
287	return true;
288}
289
290static bool
291wm8731_resume(device_t dv, const pmf_qual_t *qual)
292{
293	struct zaudio_softc *sc = device_private(dv);
294
295	pxa2x0_i2s_init(&sc->sc_i2s);
296	wm8731_init(sc);
297
298	return true;
299}
300
301static __inline uint8_t
302vol_sadd(int vol, int stride)
303{
304
305	vol += stride;
306	if (vol > 255)
307		return 255;
308	return (uint8_t)vol;
309}
310
311#ifndef	ZAUDIO_VOLUME_STRIDE
312#define	ZAUDIO_VOLUME_STRIDE	8
313#endif
314
315static void
316wm8731_volume_up(device_t dv)
317{
318	struct zaudio_softc *sc = device_private(dv);
319	int s;
320
321	s = splbio();
322	iic_acquire_bus(sc->sc_i2c, 0);
323
324	sc->sc_volume[WM8731_OP_SPKR].left =
325	    vol_sadd(sc->sc_volume[WM8731_OP_SPKR].left, ZAUDIO_VOLUME_STRIDE);
326	sc->sc_volume[WM8731_OP_SPKR].right =
327	    vol_sadd(sc->sc_volume[WM8731_OP_SPKR].right, ZAUDIO_VOLUME_STRIDE);
328
329	wm8731_update_volume(sc, WM8731_OP_SPKR);
330
331	iic_release_bus(sc->sc_i2c, 0);
332	splx(s);
333}
334
335static __inline uint8_t
336vol_ssub(int vol, int stride)
337{
338
339	vol -= stride;
340	if (vol < 0)
341		return 0;
342	return (uint8_t)vol;
343}
344
345static void
346wm8731_volume_down(device_t dv)
347{
348	struct zaudio_softc *sc = device_private(dv);
349	int s;
350
351	s = splbio();
352	iic_acquire_bus(sc->sc_i2c, 0);
353
354	sc->sc_volume[WM8731_OP_SPKR].left =
355	    vol_ssub(sc->sc_volume[WM8731_OP_SPKR].left, ZAUDIO_VOLUME_STRIDE);
356	sc->sc_volume[WM8731_OP_SPKR].right =
357	    vol_ssub(sc->sc_volume[WM8731_OP_SPKR].right, ZAUDIO_VOLUME_STRIDE);
358
359	wm8731_update_volume(sc, WM8731_OP_SPKR);
360
361	iic_release_bus(sc->sc_i2c, 0);
362	splx(s);
363}
364
365static void
366wm8731_volume_toggle(device_t dv)
367{
368	struct zaudio_softc *sc = device_private(dv);
369	int s;
370
371	s = splbio();
372	iic_acquire_bus(sc->sc_i2c, 0);
373
374	if (!sc->sc_unmute[WM8731_OP_SPKR]) {
375		sc->sc_unmute[WM8731_OP_SPKR] =
376		    sc->sc_unmute_toggle[WM8731_OP_SPKR];
377	} else {
378		sc->sc_unmute[WM8731_OP_SPKR] = 0;
379	}
380	wm8731_update_mutes(sc, 1);
381
382	iic_release_bus(sc->sc_i2c, 0);
383	splx(s);
384}
385
386static void
387wm8731_init(struct zaudio_softc *sc)
388{
389
390	iic_acquire_bus(sc->sc_i2c, 0);
391
392	/* Reset the codec */
393	wm8731_write(sc, WM8731_RESET_REG, 0);
394	delay(100);
395
396	/* Switch to standby power only */
397	wm8731_write(sc, WM8731_PD_REG, WM8731_CLKOUTPD | WM8731_OSCPD |
398	      WM8731_OUTPD | WM8731_DACPD | WM8731_ADCPD | WM8731_MICPD |
399	      WM8731_LINEINPD);
400
401	/* Configure digital interface for I2S */
402	wm8731_write(sc, WM8731_DAI_REG, WM8731_SET_IWL(2) | WM8731_SET_FORMAT(2));
403
404	/* Initialise volume levels */
405	wm8731_update_volume(sc, WM8731_OP_SPKR);
406	wm8731_update_volume(sc, WM8731_OP_MIC);
407
408	scoop_set_headphone(0);
409	scoop_set_speaker(0);
410	scoop_set_mic_bias(0);
411
412	iic_release_bus(sc->sc_i2c, 0);
413
414	/* Assume that the jack state has changed. */
415	wm8731_jack(sc);
416}
417
418static int
419wm8731_jack_intr(void *v)
420{
421	struct zaudio_softc *sc = v;
422
423	if (!callout_active(&sc->sc_to))
424		wm8731_jack(sc);
425
426	return 1;
427}
428
429static void
430wm8731_jack(void *v)
431{
432	struct zaudio_softc *sc = v;
433
434	switch (sc->sc_state) {
435	case ZAUDIO_JACK_STATE_OUT:
436		if (pxa2x0_gpio_get_bit(GPIO_HP_IN_C860)) {
437			sc->sc_state = ZAUDIO_JACK_STATE_INS;
438			sc->sc_icount = 0;
439		}
440		break;
441
442	case ZAUDIO_JACK_STATE_INS:
443		if (sc->sc_icount++ > 2) {
444			if (pxa2x0_gpio_get_bit(GPIO_HP_IN_C860)) {
445				sc->sc_state = ZAUDIO_JACK_STATE_IN;
446				sc->sc_jack = TRUE;
447				UNMUTE(sc, WM8731_OP_MIC, 1);
448				goto update_mutes;
449			} else
450				sc->sc_state = ZAUDIO_JACK_STATE_OUT;
451		}
452		break;
453
454	case ZAUDIO_JACK_STATE_IN:
455		if (!pxa2x0_gpio_get_bit(GPIO_HP_IN_C860)) {
456			sc->sc_state = ZAUDIO_JACK_STATE_REM;
457			sc->sc_icount = 0;
458		}
459		break;
460
461	case ZAUDIO_JACK_STATE_REM:
462		if (sc->sc_icount++ > 2) {
463			if (!pxa2x0_gpio_get_bit(GPIO_HP_IN_C860)) {
464				sc->sc_state = ZAUDIO_JACK_STATE_OUT;
465				sc->sc_jack = FALSE;
466				UNMUTE(sc, WM8731_OP_MIC, 0);
467				goto update_mutes;
468			} else
469				sc->sc_state = ZAUDIO_JACK_STATE_IN;
470		}
471		break;
472	}
473
474	callout_schedule(&sc->sc_to, hz/4);
475
476	return;
477
478update_mutes:
479	callout_stop(&sc->sc_to);
480
481	if (sc->sc_playing || sc->sc_recording) {
482		iic_acquire_bus(sc->sc_i2c, 0);
483		if (sc->sc_playing)
484			wm8731_update_mutes(sc, 1);
485		if (sc->sc_recording)
486			wm8731_update_mutes(sc, 2);
487		iic_release_bus(sc->sc_i2c, 0);
488	}
489}
490
491static void
492wm8731_standby(struct zaudio_softc *sc)
493{
494
495	iic_acquire_bus(sc->sc_i2c, 0);
496
497	/* Switch to standby power only */
498	wm8731_write(sc, WM8731_PD_REG, WM8731_CLKOUTPD | WM8731_OSCPD |
499	      WM8731_OUTPD | WM8731_DACPD | WM8731_ADCPD | WM8731_MICPD |
500	      WM8731_LINEINPD);
501
502	scoop_set_headphone(0);
503	scoop_set_speaker(0);
504	scoop_set_mic_bias(0);
505
506	/* Activating DSP and DAI */
507	wm8731_write(sc, WM8731_AC_REG, 0);
508
509	iic_release_bus(sc->sc_i2c, 0);
510}
511
512static void
513wm8731_update_volume(struct zaudio_softc *sc, int output)
514{
515	struct zaudio_volume *volume;
516
517	switch (output) {
518	case WM8731_OP_SPKR:
519		volume = &sc->sc_volume[WM8731_OP_SPKR];
520		wm8731_write(sc, WM8731_LHP_REG,
521		       WM8731_SET_LHPVOL(volume->left >> 1));
522		wm8731_write(sc, WM8731_RHP_REG,
523		       WM8731_SET_RHPVOL(volume->right >> 1));
524		break;
525
526	case WM8731_OP_MIC:
527		volume = &sc->sc_volume[WM8731_OP_MIC];
528		wm8731_write(sc, WM8731_LIN_REG, WM8731_LRINBOTH |
529		    WM8731_SET_LINVOL(volume->left >> 3));
530		break;
531	}
532}
533
534static void
535wm8731_update_mutes(struct zaudio_softc *sc, int mask)
536{
537	uint16_t val = WM8731_CLKOUTPD | WM8731_OSCPD | WM8731_LINEINPD;
538
539	/* playback */
540	if (mask & 1) {
541		val |= WM8731_ADCPD | WM8731_MICPD;
542		if (!sc->sc_unmute[WM8731_OP_SPKR]) {
543			val |= WM8731_OUTPD | WM8731_DACPD;
544		}
545		wm8731_write(sc, WM8731_PD_REG, val);
546		scoop_set_headphone(sc->sc_unmute[WM8731_OP_SPKR] & sc->sc_jack);
547		scoop_set_speaker(sc->sc_unmute[WM8731_OP_SPKR] & !sc->sc_jack);
548	}
549
550	/* record */
551	if (mask & 2) {
552		val = WM8731_OUTPD | WM8731_DACPD;
553		if (!sc->sc_unmute[WM8731_OP_MIC]) {
554			val |= WM8731_ADCPD | WM8731_MICPD;
555		}
556		wm8731_write(sc, WM8731_PD_REG, val);
557		scoop_set_mic_bias(sc->sc_unmute[WM8731_OP_MIC]);
558	}
559}
560
561static void
562wm8731_play_setup(struct zaudio_softc *sc)
563{
564	int i;
565
566	iic_acquire_bus(sc->sc_i2c, 0);
567
568	/* Program the codec with playback settings */
569	for (i = 0; playback_regs[i][0] != 0xffff; i++) {
570		wm8731_write(sc, playback_regs[i][0], playback_regs[i][1]);
571	}
572	wm8731_update_mutes(sc, 1);
573
574	iic_release_bus(sc->sc_i2c, 0);
575}
576
577/*static*/ void
578wm8731_record_setup(struct zaudio_softc *sc)
579{
580	int i;
581
582	iic_acquire_bus(sc->sc_i2c, 0);
583
584	/* Program the codec with playback settings */
585	for (i = 0; record_regs[i][0] != 0xffff; i++) {
586		wm8731_write(sc, record_regs[i][0], record_regs[i][1]);
587	}
588	wm8731_update_mutes(sc, 2);
589
590	iic_release_bus(sc->sc_i2c, 0);
591}
592
593static int
594wm8731_halt_output(void *hdl)
595{
596	struct zaudio_softc *sc = hdl;
597	int rv;
598
599	rv = pxa2x0_i2s_halt_output(&sc->sc_i2s);
600	if (!sc->sc_recording)
601		wm8731_standby(sc);
602	sc->sc_playing = 0;
603
604	return rv;
605}
606
607static int
608wm8731_halt_input(void *hdl)
609{
610	struct zaudio_softc *sc = hdl;
611	int rv;
612
613	rv = pxa2x0_i2s_halt_input(&sc->sc_i2s);
614	if (!sc->sc_playing)
615		wm8731_standby(sc);
616	sc->sc_recording = 0;
617
618	return rv;
619}
620
621static int
622wm8731_getdev(void *hdl, struct audio_device *ret)
623{
624
625	*ret = wm8731_device;
626	return 0;
627}
628
629#define WM8731_SPKR_LVL		0
630#define WM8731_SPKR_MUTE	1
631#define WM8731_MIC_LVL		2
632#define WM8731_MIC_MUTE		3
633#define WM8731_RECORD_SOURCE	4
634#define WM8731_OUTPUT_CLASS	5
635#define WM8731_INPUT_CLASS	6
636#define WM8731_RECORD_CLASS	7
637
638static int
639wm8731_set_port(void *hdl, struct mixer_ctrl *mc)
640{
641	struct zaudio_softc *sc = hdl;
642	int error = EINVAL;
643	int s;
644
645	s = splbio();
646	iic_acquire_bus(sc->sc_i2c, 0);
647
648	switch (mc->dev) {
649	case WM8731_SPKR_LVL:
650		if (mc->type != AUDIO_MIXER_VALUE)
651			break;
652		if (mc->un.value.num_channels == 1) {
653			sc->sc_volume[WM8731_OP_SPKR].left =
654			    mc->un.value.level[AUDIO_MIXER_LEVEL_MONO];
655			sc->sc_volume[WM8731_OP_SPKR].right =
656			    mc->un.value.level[AUDIO_MIXER_LEVEL_MONO];
657		} else if (mc->un.value.num_channels == 2) {
658			sc->sc_volume[WM8731_OP_SPKR].left =
659			    mc->un.value.level[AUDIO_MIXER_LEVEL_LEFT];
660			sc->sc_volume[WM8731_OP_SPKR].right =
661			    mc->un.value.level[AUDIO_MIXER_LEVEL_RIGHT];
662		}
663		else
664			break;
665		wm8731_update_volume(sc, WM8731_OP_SPKR);
666		error = 0;
667		break;
668
669	case WM8731_SPKR_MUTE:
670		if (mc->type != AUDIO_MIXER_ENUM)
671			break;
672		UNMUTE(sc, WM8731_OP_SPKR, mc->un.ord ? 1 : 0);
673		wm8731_update_mutes(sc, 1);
674		error = 0;
675		break;
676
677	case WM8731_MIC_LVL:
678		if (mc->type != AUDIO_MIXER_VALUE)
679			break;
680		if (mc->un.value.num_channels == 1)
681			sc->sc_volume[WM8731_OP_MIC].left =
682			    mc->un.value.level[AUDIO_MIXER_LEVEL_MONO];
683		else
684			break;
685		wm8731_update_volume(sc, WM8731_OP_MIC);
686		error = 0;
687		break;
688
689	case WM8731_MIC_MUTE:
690		if (mc->type != AUDIO_MIXER_ENUM)
691			break;
692		UNMUTE(sc, WM8731_OP_MIC, mc->un.ord ? 1 : 0);
693		wm8731_update_mutes(sc, 2);
694		error = 0;
695		break;
696
697	case WM8731_RECORD_SOURCE:
698		if (mc->type != AUDIO_MIXER_ENUM)
699			break;
700		if (mc->un.ord != 0)
701			break;
702		/* MIC only */
703		error = 0;
704		break;
705	}
706
707	iic_release_bus(sc->sc_i2c, 0);
708	splx(s);
709
710	return error;
711}
712
713static int
714wm8731_get_port(void *hdl, struct mixer_ctrl *mc)
715{
716	struct zaudio_softc *sc = hdl;
717	int error = EINVAL;
718
719	switch (mc->dev) {
720	case WM8731_SPKR_LVL:
721		if (mc->type != AUDIO_MIXER_VALUE)
722			break;
723		if (mc->un.value.num_channels == 1)
724			mc->un.value.level[AUDIO_MIXER_LEVEL_MONO] =
725			    sc->sc_volume[WM8731_OP_SPKR].left;
726		else if (mc->un.value.num_channels == 2) {
727			mc->un.value.level[AUDIO_MIXER_LEVEL_LEFT] =
728			    sc->sc_volume[WM8731_OP_SPKR].left;
729			mc->un.value.level[AUDIO_MIXER_LEVEL_RIGHT] =
730			    sc->sc_volume[WM8731_OP_SPKR].right;
731		}
732		else
733			break;
734		error = 0;
735		break;
736
737	case WM8731_SPKR_MUTE:
738		if (mc->type != AUDIO_MIXER_ENUM)
739			break;
740		mc->un.ord = sc->sc_unmute[WM8731_OP_SPKR] ? 1 : 0;
741		error = 0;
742		break;
743
744	case WM8731_MIC_LVL:
745		if (mc->type != AUDIO_MIXER_VALUE)
746			break;
747		if (mc->un.value.num_channels == 1)
748			mc->un.value.level[AUDIO_MIXER_LEVEL_MONO] =
749			    sc->sc_volume[WM8731_OP_MIC].left;
750		else
751			break;
752		error = 0;
753		break;
754
755	case WM8731_MIC_MUTE:
756		if (mc->type != AUDIO_MIXER_ENUM)
757			break;
758		mc->un.ord = sc->sc_unmute[WM8731_OP_MIC] ? 1 : 0;
759		error = 0;
760		break;
761
762	case WM8731_RECORD_SOURCE:
763		if (mc->type != AUDIO_MIXER_ENUM)
764			break;
765		mc->un.ord = 0; /* MIC only */
766		error = 0;
767		break;
768	}
769
770	return error;
771}
772
773/*ARGSUSED*/
774static int
775wm8731_query_devinfo(void *hdl, struct mixer_devinfo *di)
776{
777
778	switch (di->index) {
779	case WM8731_SPKR_LVL:
780		di->type = AUDIO_MIXER_VALUE;
781		di->mixer_class = WM8731_OUTPUT_CLASS;
782		di->prev = AUDIO_MIXER_LAST;
783		di->next = WM8731_SPKR_MUTE;
784		strlcpy(di->label.name, AudioNspeaker,
785		    sizeof(di->label.name));
786		di->un.v.num_channels = 1;
787		strlcpy(di->un.v.units.name, AudioNvolume,
788		    sizeof(di->un.v.units.name));
789		break;
790
791	case WM8731_SPKR_MUTE:
792		di->type = AUDIO_MIXER_ENUM;
793		di->mixer_class = WM8731_OUTPUT_CLASS;
794		di->prev = WM8731_SPKR_LVL;
795		di->next = AUDIO_MIXER_LAST;
796mute:
797		strlcpy(di->label.name, AudioNmute, sizeof(di->label.name));
798		di->un.e.num_mem = 2;
799		strlcpy(di->un.e.member[0].label.name, AudioNon,
800		    sizeof(di->un.e.member[0].label.name));
801		di->un.e.member[0].ord = 0;
802		strlcpy(di->un.e.member[1].label.name, AudioNoff,
803		    sizeof(di->un.e.member[1].label.name));
804		di->un.e.member[1].ord = 1;
805		break;
806
807	case WM8731_MIC_LVL:
808		di->type = AUDIO_MIXER_VALUE;
809		di->mixer_class = WM8731_INPUT_CLASS;
810		di->prev = AUDIO_MIXER_LAST;
811		di->next = WM8731_MIC_MUTE;
812		strlcpy(di->label.name, AudioNmicrophone,
813		    sizeof(di->label.name));
814		strlcpy(di->un.v.units.name, AudioNvolume,
815		    sizeof(di->un.v.units.name));
816		di->un.v.num_channels = 1;
817		break;
818
819	case WM8731_MIC_MUTE:
820		di->type = AUDIO_MIXER_ENUM;
821		di->mixer_class = WM8731_INPUT_CLASS;
822		di->prev = WM8731_MIC_LVL;
823		di->next = AUDIO_MIXER_LAST;
824		goto mute;
825
826	case WM8731_RECORD_SOURCE:
827		di->type = AUDIO_MIXER_ENUM;
828		di->mixer_class = WM8731_RECORD_CLASS;
829		di->prev = AUDIO_MIXER_LAST;
830		di->next = AUDIO_MIXER_LAST;
831		strlcpy(di->label.name, AudioNsource, sizeof(di->label.name));
832		di->un.e.num_mem = 1;
833		strlcpy(di->un.e.member[0].label.name, AudioNmicrophone,
834		    sizeof(di->un.e.member[0].label.name));
835		di->un.e.member[0].ord = 0;
836		break;
837
838	case WM8731_OUTPUT_CLASS:
839		di->type = AUDIO_MIXER_CLASS;
840		di->mixer_class = WM8731_OUTPUT_CLASS;
841		di->prev = AUDIO_MIXER_LAST;
842		di->next = AUDIO_MIXER_LAST;
843		strlcpy(di->label.name, AudioCoutputs, sizeof(di->label.name));
844		break;
845
846	case WM8731_INPUT_CLASS:
847		di->type = AUDIO_MIXER_CLASS;
848		di->mixer_class = WM8731_INPUT_CLASS;
849		di->prev = AUDIO_MIXER_LAST;
850		di->next = AUDIO_MIXER_LAST;
851		strlcpy(di->label.name, AudioCinputs, sizeof(di->label.name));
852		break;
853
854	case WM8731_RECORD_CLASS:
855		di->type = AUDIO_MIXER_CLASS;
856		di->mixer_class = WM8731_RECORD_CLASS;
857		di->prev = AUDIO_MIXER_LAST;
858		di->next = AUDIO_MIXER_LAST;
859		strlcpy(di->label.name, AudioCinputs, sizeof(di->label.name));
860		break;
861
862	default:
863		return ENXIO;
864	}
865
866	return 0;
867}
868
869static int
870wm8731_start_output(void *hdl, void *block, int bsize, void (*intr)(void *),
871    void *intrarg)
872{
873	struct zaudio_softc *sc = hdl;
874	int rv;
875
876	/* Power up codec if we are not already playing. */
877	if (!sc->sc_playing) {
878		sc->sc_playing = 1;
879		wm8731_play_setup(sc);
880	}
881
882	/* Start DMA via I2S */
883	rv = pxa2x0_i2s_start_output(&sc->sc_i2s, block, bsize, intr, intrarg);
884	if (rv) {
885		if (!sc->sc_recording)
886			wm8731_standby(sc);
887		sc->sc_playing = 0;
888	}
889
890	return rv;
891}
892
893static int
894wm8731_start_input(void *hdl, void *block, int bsize, void (*intr)(void *),
895    void *intrarg)
896{
897	struct zaudio_softc *sc = hdl;
898	int rv;
899
900	/* Power up codec if we are not already recording. */
901	if (!sc->sc_recording) {
902		sc->sc_recording = 1;
903		wm8731_record_setup(sc);
904	}
905
906	/* Start DMA via I2S */
907	rv = pxa2x0_i2s_start_input(&sc->sc_i2s, block, bsize, intr, intrarg);
908	if (rv) {
909		if (!sc->sc_playing)
910			wm8731_standby(sc);
911		sc->sc_recording = 0;
912	}
913	return rv;
914}
915