ac97_cmi.c revision 9484:fbd5ddc28e96
1/*
2 * CDDL HEADER START
3 *
4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License (the "License").
6 * You may not use this file except in compliance with the License.
7 *
8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 * or http://www.opensolaris.org/os/licensing.
10 * See the License for the specific language governing permissions
11 * and limitations under the License.
12 *
13 * When distributing Covered Code, include this CDDL HEADER in each
14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 * If applicable, add the following below this CDDL HEADER, with the
16 * fields enclosed by brackets "[]" replaced with your own identifying
17 * information: Portions Copyright [yyyy] [name of copyright owner]
18 *
19 * CDDL HEADER END
20 */
21/*
22 * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
23 * Use is subject to license terms.
24 */
25
26/*
27 * CMI (C-Media) codec extensions.
28 */
29
30#include <sys/types.h>
31#include <sys/ddi.h>
32#include <sys/sunddi.h>
33#include <sys/audio/audio_driver.h>
34#include <sys/audio/ac97.h>
35#include <sys/note.h>
36#include "ac97_impl.h"
37
38/*
39 * C-Media 9739 part is weird.  Instead of having independent volume
40 * controls for each of the channels, it uses a single master volume
41 * and just provides mute support for the other bits.  It does this
42 * for PCM volume as well, so we can't use it either.  Ugh.  It also
43 * has an optional 30 dB mic boost.  Apparently the 9761 behaves in
44 * much the same fashion as the 9739.
45 *
46 * C-Media 9738 is a more or less typical 4CH device according to the
47 * datasheet.  It however supports jack retasking allowing the line in
48 * jack to function as a surround output.  Google suggests that the
49 * volume controls on this part are about as busted as on the other
50 * parts.  So, we just use synthetic volume for it.
51 *
52 * C-Media 9780 is largely a mystery (ENODATASHEET).
53 */
54
55
56#define	CMI_TASK_REGISTER	0x5A	/* 9738 jack retasking */
57#define	CTR_F2R			0x2000	/* front routed to rear */
58#define	CTR_S2LNI		0x0400	/* surround to line in */
59
60#define	CMI_MULTICH_REGISTER	0x64	/* 9739 and 9761a */
61#define	CMR_PCBSW		0x8000	/* PC Beep volume bypass */
62#define	CMR_P47			0x4000	/* configure P47 function */
63#define	CMR_REFCTL		0x2000	/* enable vref output */
64#define	CMR_CLCTL		0x1000	/* center/lfe output enable */
65#define	CMR_S2LNI		0x0400	/* surround to line in */
66#define	CMR_MIX2S		0x0200	/* analog input pass to surround */
67#define	CMR_BSTSEL		0x0001	/* micboost use 30dB */
68
69static void
70cmi_set_micboost(ac97_ctrl_t *actrl, uint64_t value)
71{
72	ac97_t	*ac = actrl->actrl_ac97;
73
74	ac97_wr(ac, AC97_INTERRUPT_PAGING_REGISTER, 0);	/* select page 0 */
75	switch (value) {
76	case 0x1:
77		/* 0db */
78		ac97_clr(ac, AC97_MIC_VOLUME_REGISTER, MICVR_20dB_BOOST);
79		ac97_clr(ac, CMI_MULTICH_REGISTER, CMR_BSTSEL);
80		break;
81	case 0x2:
82		/* 20dB */
83		ac97_set(ac, AC97_MIC_VOLUME_REGISTER, MICVR_20dB_BOOST);
84		ac97_clr(ac, CMI_MULTICH_REGISTER, CMR_BSTSEL);
85		break;
86	case 0x4:
87		/* 30dB */
88		ac97_set(ac, AC97_MIC_VOLUME_REGISTER, MICVR_20dB_BOOST);
89		ac97_set(ac, CMI_MULTICH_REGISTER, CMR_BSTSEL);
90		break;
91	}
92}
93
94static void
95cmi_set_linein_func(ac97_ctrl_t *actrl, uint64_t value)
96{
97	ac97_t		*ac = actrl->actrl_ac97;
98
99	ac97_wr(ac, AC97_INTERRUPT_PAGING_REGISTER, 0);	/* select page 0 */
100	if (value & 2) {
101		ac97_set(ac, CMI_MULTICH_REGISTER, CMR_S2LNI);
102	} else {
103		ac97_clr(ac, CMI_MULTICH_REGISTER, CMR_S2LNI);
104	}
105}
106
107static void
108cmi_set_mic_func(ac97_ctrl_t *actrl, uint64_t value)
109{
110	ac97_t		*ac = actrl->actrl_ac97;
111
112	ac97_wr(ac, AC97_INTERRUPT_PAGING_REGISTER, 0);	/* select page 0 */
113	if (value & 2) {
114		ac97_set(ac, CMI_MULTICH_REGISTER, CMR_CLCTL);
115	} else {
116		ac97_clr(ac, CMI_MULTICH_REGISTER, CMR_CLCTL);
117	}
118}
119
120static void
121cmi_setup_micboost(ac97_t *ac)
122{
123	ac97_ctrl_t		*ctrl;
124
125	static const char	*values[] = {
126		AUDIO_VALUE_OFF,	/* 0dB */
127		AUDIO_VALUE_MEDIUM,	/* 20dB */
128		AUDIO_VALUE_HIGH,	/* 30dB */
129		NULL
130	};
131	ac97_ctrl_probe_t cpt = {
132		AUDIO_CTRL_ID_MICBOOST, 1, 0xf, 0xf, AUDIO_CTRL_TYPE_ENUM,
133		AC97_FLAGS | AUDIO_CTRL_FLAG_REC, 0, cmi_set_micboost,
134		NULL, 0, values };
135
136	ctrl = ac97_control_find(ac, AUDIO_CTRL_ID_MICBOOST);
137	if (ctrl) {
138		if (ctrl->actrl_initval) {
139			/* 20dB by default */
140			cpt.cp_initval = 1;
141		}
142		ac97_free_control(ctrl);
143	}
144
145	ac97_alloc_control(ac, &cpt);
146}
147
148static const char *cmi_linein_funcs[] = {
149	AUDIO_PORT_LINEIN,
150	AUDIO_PORT_SURROUND,
151	NULL
152};
153
154static const char *cmi_mic_funcs[] = {
155	AUDIO_PORT_MIC,
156	AUDIO_PORT_CENLFE,
157	NULL
158};
159
160static void
161cmi_setup_jack_funcs(ac97_t *ac)
162{
163	ac97_ctrl_probe_t	cp;
164	int			ival;
165
166	ac97_ctrl_probe_t linein_cpt = {
167		AUDIO_CTRL_ID_JACK1, 1, 3, 3, AUDIO_CTRL_TYPE_ENUM, AC97_FLAGS,
168		0, cmi_set_linein_func, NULL, 0, cmi_linein_funcs
169	};
170	ac97_ctrl_probe_t mic_cpt = {
171		AUDIO_CTRL_ID_JACK2, 1, 3, 3, AUDIO_CTRL_TYPE_ENUM, AC97_FLAGS,
172		0, cmi_set_mic_func, NULL, 0, cmi_mic_funcs
173	};
174
175	bcopy(&linein_cpt, &cp, sizeof (cp));
176	ival = ac97_get_prop(ac, AC97_PROP_LINEIN_FUNC, 0);
177	if ((ival >= 1) && (ival <= 2)) {
178		cp.cp_initval = ival;
179	}
180	ac97_alloc_control(ac, &cp);
181
182	bcopy(&mic_cpt, &cp, sizeof (cp));
183	ival = ac97_get_prop(ac, AC97_PROP_MIC_FUNC, 0);
184	if ((ival >= 1) && (ival <= 2)) {
185		cp.cp_initval = ival;
186	}
187	ac97_alloc_control(ac, &cp);
188}
189
190static void
191cmi_set_linein_func_9738(ac97_ctrl_t *actrl, uint64_t value)
192{
193	ac97_t		*ac = actrl->actrl_ac97;
194
195	if (value & 2) {
196		ac97_set(ac, CMI_TASK_REGISTER, CTR_S2LNI);
197	} else {
198		ac97_clr(ac, CMI_TASK_REGISTER, CTR_S2LNI);
199	}
200}
201
202static void
203cmi_set_spread_9738(ac97_ctrl_t *actrl, uint64_t value)
204{
205	ac97_t		*ac = actrl->actrl_ac97;
206
207	if (value) {
208		ac97_set(ac, CMI_TASK_REGISTER, CTR_F2R);
209	} else {
210		ac97_clr(ac, CMI_TASK_REGISTER, CTR_F2R);
211	}
212}
213
214static void
215cmi_setup_jack_func_9738(ac97_t *ac)
216{
217	ac97_ctrl_probe_t	cp;
218	int			ival;
219
220	ac97_ctrl_probe_t linein_cpt = {
221		AUDIO_CTRL_ID_JACK1, 1, 3, 3, AUDIO_CTRL_TYPE_ENUM, AC97_FLAGS,
222		0, cmi_set_linein_func_9738, NULL, 0, cmi_linein_funcs
223	};
224	ac97_ctrl_probe_t spread_cpt = {
225		AUDIO_CTRL_ID_SPREAD, 0, 0, 1, AUDIO_CTRL_TYPE_BOOLEAN,
226		AC97_FLAGS, 0, cmi_set_spread_9738,
227	};
228
229	bcopy(&linein_cpt, &cp, sizeof (cp));
230	ival = ac97_get_prop(ac, AC97_PROP_LINEIN_FUNC, 0);
231	if ((ival >= 1) && (ival <= 2)) {
232		cp.cp_initval = ival;
233	}
234	ac97_alloc_control(ac, &cp);
235
236	bcopy(&spread_cpt, &cp, sizeof (cp));
237	ival = ac97_get_prop(ac, AC97_PROP_SPREAD, -1);
238	if ((ival >= 0) && (ival <= 1)) {
239		cp.cp_initval = ival;
240	}
241	ac97_alloc_control(ac, &cp);
242}
243
244
245static void
246cmi_setup_volume(ac97_t *ac)
247{
248	ac97_ctrl_t	*ctrl;
249
250	/*
251	 * These CMI parts seem to be really weird.  They don't have
252	 * *any* functioning volume controls on them (mute only) apart
253	 * from the record and monitor sources (excluding PCM).  I
254	 * don't understand why not.  We just eliminate all of the
255	 * volume controls and replace with a soft volume control.
256	 * Its not an ideal situation, but I don't know what else I
257	 * can do about it.
258	 */
259	ctrl = ac97_control_find(ac, AUDIO_CTRL_ID_VOLUME);
260	if (ctrl) {
261		ac97_free_control(ctrl);
262	}
263	ctrl = ac97_control_find(ac, AUDIO_CTRL_ID_FRONT);
264	if (ctrl) {
265		ac97_free_control(ctrl);
266	}
267	ctrl = ac97_control_find(ac, AUDIO_CTRL_ID_SURROUND);
268	if (ctrl) {
269		ac97_free_control(ctrl);
270	}
271	ctrl = ac97_control_find(ac, AUDIO_CTRL_ID_CENTER);
272	if (ctrl) {
273		ac97_free_control(ctrl);
274	}
275	ctrl = ac97_control_find(ac, AUDIO_CTRL_ID_LFE);
276	if (ctrl) {
277		ac97_free_control(ctrl);
278	}
279
280	/* make sure we have disabled mute and attenuation on physical ctrls */
281	ac97_wr(ac, AC97_INTERRUPT_PAGING_REGISTER, 0);	/* select page 0 */
282	ac97_wr(ac, AC97_PCM_OUT_VOLUME_REGISTER, 0);
283	ac97_wr(ac, AC97_MASTER_VOLUME_REGISTER, 0);
284	ac97_wr(ac, AC97_EXTENDED_C_LFE_VOLUME_REGISTER, 0);
285	ac97_wr(ac, AC97_EXTENDED_LRS_VOLUME_REGISTER, 0);
286
287	(void) audio_dev_add_soft_volume(ac97_get_dev(ac));
288}
289
290void
291cmi9739_init(ac97_t *ac)
292{
293	cmi_setup_volume(ac);
294	cmi_setup_micboost(ac);
295	cmi_setup_jack_funcs(ac);
296}
297
298void
299cmi9761_init(ac97_t *ac)
300{
301	cmi_setup_volume(ac);
302	cmi_setup_micboost(ac);
303	cmi_setup_jack_funcs(ac);
304}
305
306void
307cmi9738_init(ac97_t *ac)
308{
309	cmi_setup_volume(ac);
310	cmi_setup_jack_func_9738(ac);
311}
312