xref: /openbmc/linux/sound/pci/ice1712/wtm.c (revision 25985edc)
1 /*
2  *	ALSA driver for ICEnsemble VT1724 (Envy24HT)
3  *
4  *	Lowlevel functions for Ego Sys Waveterminal 192M
5  *
6  *		Copyright (c) 2006 Guedez Clement <klem.dev@gmail.com>
7  *		Some functions are taken from the Prodigy192 driver
8  *		source
9  *
10  *	This program is free software; you can redistribute it and/or modify
11  *	it under the terms of the GNU General Public License as published by
12  *	the Free Software Foundation; either version 2 of the License, or
13  *	(at your option) any later version.
14  *
15  *	This program is distributed in the hope that it will be useful,
16  *	but WITHOUT ANY WARRANTY; without even the implied warranty of
17  *	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18  *	GNU General Public License for more details.
19  *
20  *	You should have received a copy of the GNU General Public License
21  *	along with this program; if not, write to the Free Software
22  *	Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
23  *
24  */
25 
26 
27 
28 #include <linux/io.h>
29 #include <linux/delay.h>
30 #include <linux/interrupt.h>
31 #include <linux/init.h>
32 #include <sound/core.h>
33 
34 #include "ice1712.h"
35 #include "envy24ht.h"
36 #include "wtm.h"
37 #include "stac946x.h"
38 
39 
40 /*
41  *	2*ADC 6*DAC no1 ringbuffer r/w on i2c bus
42  */
43 static inline void stac9460_put(struct snd_ice1712 *ice, int reg,
44 						unsigned char val)
45 {
46 	snd_vt1724_write_i2c(ice, STAC9460_I2C_ADDR, reg, val);
47 }
48 
49 static inline unsigned char stac9460_get(struct snd_ice1712 *ice, int reg)
50 {
51 	return snd_vt1724_read_i2c(ice, STAC9460_I2C_ADDR, reg);
52 }
53 
54 /*
55  *	2*ADC 2*DAC no2 ringbuffer r/w on i2c bus
56  */
57 static inline void stac9460_2_put(struct snd_ice1712 *ice, int reg,
58 						unsigned char val)
59 {
60 	snd_vt1724_write_i2c(ice, STAC9460_2_I2C_ADDR, reg, val);
61 }
62 
63 static inline unsigned char stac9460_2_get(struct snd_ice1712 *ice, int reg)
64 {
65 	return snd_vt1724_read_i2c(ice, STAC9460_2_I2C_ADDR, reg);
66 }
67 
68 
69 /*
70  *	DAC mute control
71  */
72 #define stac9460_dac_mute_info		snd_ctl_boolean_mono_info
73 
74 static int stac9460_dac_mute_get(struct snd_kcontrol *kcontrol,
75 				struct snd_ctl_elem_value *ucontrol)
76 {
77 	struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);
78 	unsigned char val;
79 	int idx, id;
80 
81 	if (kcontrol->private_value) {
82 		idx = STAC946X_MASTER_VOLUME;
83 		id = 0;
84 	} else {
85 		id = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id);
86 		idx = id + STAC946X_LF_VOLUME;
87 	}
88 	if (id < 6)
89 		val = stac9460_get(ice, idx);
90 	else
91 		val = stac9460_2_get(ice, idx - 6);
92 	ucontrol->value.integer.value[0] = (~val >> 7) & 0x1;
93 	return 0;
94 }
95 
96 static int stac9460_dac_mute_put(struct snd_kcontrol *kcontrol,
97 				struct snd_ctl_elem_value *ucontrol)
98 {
99 	struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);
100 	unsigned char new, old;
101 	int id, idx;
102 	int change;
103 
104 	if (kcontrol->private_value) {
105 		idx = STAC946X_MASTER_VOLUME;
106 		old = stac9460_get(ice, idx);
107 		new = (~ucontrol->value.integer.value[0] << 7 & 0x80) |
108 							(old & ~0x80);
109 		change = (new != old);
110 		if (change) {
111 			stac9460_put(ice, idx, new);
112 			stac9460_2_put(ice, idx, new);
113 		}
114 	} else {
115 		id = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id);
116 		idx = id + STAC946X_LF_VOLUME;
117 		if (id < 6)
118 			old = stac9460_get(ice, idx);
119 		else
120 			old = stac9460_2_get(ice, idx - 6);
121 		new = (~ucontrol->value.integer.value[0] << 7 & 0x80) |
122 							(old & ~0x80);
123 		change = (new != old);
124 		if (change) {
125 			if (id < 6)
126 				stac9460_put(ice, idx, new);
127 			else
128 				stac9460_2_put(ice, idx - 6, new);
129 		}
130 	}
131 	return change;
132 }
133 
134 /*
135  * 	DAC volume attenuation mixer control
136  */
137 static int stac9460_dac_vol_info(struct snd_kcontrol *kcontrol,
138 				struct snd_ctl_elem_info *uinfo)
139 {
140 	uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
141 	uinfo->count = 1;
142 	uinfo->value.integer.min = 0;			/* mute */
143 	uinfo->value.integer.max = 0x7f;		/* 0dB */
144 	return 0;
145 }
146 
147 static int stac9460_dac_vol_get(struct snd_kcontrol *kcontrol,
148 				struct snd_ctl_elem_value *ucontrol)
149 {
150 	struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);
151 	int idx, id;
152 	unsigned char vol;
153 
154 	if (kcontrol->private_value) {
155 		idx = STAC946X_MASTER_VOLUME;
156 		id = 0;
157 	} else {
158 		id = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id);
159 		idx = id + STAC946X_LF_VOLUME;
160 	}
161 	if (id < 6)
162 		vol = stac9460_get(ice, idx) & 0x7f;
163 	else
164 		vol = stac9460_2_get(ice, idx - 6) & 0x7f;
165 	ucontrol->value.integer.value[0] = 0x7f - vol;
166 	return 0;
167 }
168 
169 static int stac9460_dac_vol_put(struct snd_kcontrol *kcontrol,
170 				struct snd_ctl_elem_value *ucontrol)
171 {
172 	struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);
173 	int idx, id;
174 	unsigned char tmp, ovol, nvol;
175 	int change;
176 
177 	if (kcontrol->private_value) {
178 		idx = STAC946X_MASTER_VOLUME;
179 		nvol = ucontrol->value.integer.value[0] & 0x7f;
180 		tmp = stac9460_get(ice, idx);
181 		ovol = 0x7f - (tmp & 0x7f);
182 		change = (ovol != nvol);
183 		if (change) {
184 			stac9460_put(ice, idx, (0x7f - nvol) | (tmp & 0x80));
185 			stac9460_2_put(ice, idx, (0x7f - nvol) | (tmp & 0x80));
186 		}
187 	} else {
188 		id = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id);
189 		idx = id + STAC946X_LF_VOLUME;
190 		nvol = ucontrol->value.integer.value[0] & 0x7f;
191 		if (id < 6)
192 			tmp = stac9460_get(ice, idx);
193 		else
194 			tmp = stac9460_2_get(ice, idx - 6);
195 		ovol = 0x7f - (tmp & 0x7f);
196 		change = (ovol != nvol);
197 		if (change) {
198 			if (id < 6)
199 				stac9460_put(ice, idx, (0x7f - nvol) |
200 							(tmp & 0x80));
201 			else
202 				stac9460_2_put(ice, idx-6, (0x7f - nvol) |
203 							(tmp & 0x80));
204 		}
205 	}
206 	return change;
207 }
208 
209 /*
210  * ADC mute control
211  */
212 #define stac9460_adc_mute_info		snd_ctl_boolean_stereo_info
213 
214 static int stac9460_adc_mute_get(struct snd_kcontrol *kcontrol,
215 				struct snd_ctl_elem_value *ucontrol)
216 {
217 	struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);
218 	unsigned char val;
219 	int i, id;
220 
221 	id = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id);
222 	if (id == 0) {
223 		for (i = 0; i < 2; ++i) {
224 			val = stac9460_get(ice, STAC946X_MIC_L_VOLUME + i);
225 			ucontrol->value.integer.value[i] = ~val>>7 & 0x1;
226 		}
227 	} else {
228 		for (i = 0; i < 2; ++i) {
229 			val = stac9460_2_get(ice, STAC946X_MIC_L_VOLUME + i);
230 			ucontrol->value.integer.value[i] = ~val>>7 & 0x1;
231 		}
232 	}
233 	return 0;
234 }
235 
236 static int stac9460_adc_mute_put(struct snd_kcontrol *kcontrol,
237 				struct snd_ctl_elem_value *ucontrol)
238 {
239 	struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);
240 	unsigned char new, old;
241 	int i, reg, id;
242 	int change;
243 
244 	id = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id);
245 	if (id == 0) {
246 		for (i = 0; i < 2; ++i) {
247 			reg = STAC946X_MIC_L_VOLUME + i;
248 			old = stac9460_get(ice, reg);
249 			new = (~ucontrol->value.integer.value[i]<<7&0x80) |
250 								(old&~0x80);
251 			change = (new != old);
252 			if (change)
253 				stac9460_put(ice, reg, new);
254 		}
255 	} else {
256 		for (i = 0; i < 2; ++i) {
257 			reg = STAC946X_MIC_L_VOLUME + i;
258 			old = stac9460_2_get(ice, reg);
259 			new = (~ucontrol->value.integer.value[i]<<7&0x80) |
260 								(old&~0x80);
261 			change = (new != old);
262 			if (change)
263 				stac9460_2_put(ice, reg, new);
264 		}
265 	}
266 	return change;
267 }
268 
269 /*
270  *ADC gain mixer control
271  */
272 static int stac9460_adc_vol_info(struct snd_kcontrol *kcontrol,
273 				struct snd_ctl_elem_info *uinfo)
274 {
275 	uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
276 	uinfo->count = 2;
277 	uinfo->value.integer.min = 0;		/* 0dB */
278 	uinfo->value.integer.max = 0x0f;	/* 22.5dB */
279 	return 0;
280 }
281 
282 static int stac9460_adc_vol_get(struct snd_kcontrol *kcontrol,
283 				struct snd_ctl_elem_value *ucontrol)
284 {
285 	struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);
286 	int i, reg, id;
287 	unsigned char vol;
288 
289 	id = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id);
290 	if (id == 0) {
291 		for (i = 0; i < 2; ++i) {
292 			reg = STAC946X_MIC_L_VOLUME + i;
293 			vol = stac9460_get(ice, reg) & 0x0f;
294 			ucontrol->value.integer.value[i] = 0x0f - vol;
295 		}
296 	} else {
297 		for (i = 0; i < 2; ++i) {
298 			reg = STAC946X_MIC_L_VOLUME + i;
299 			vol = stac9460_2_get(ice, reg) & 0x0f;
300 			ucontrol->value.integer.value[i] = 0x0f - vol;
301 		}
302 	}
303 	return 0;
304 }
305 
306 static int stac9460_adc_vol_put(struct snd_kcontrol *kcontrol,
307 				struct snd_ctl_elem_value *ucontrol)
308 {
309 	struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);
310 	int i, reg, id;
311 	unsigned char ovol, nvol;
312 	int change;
313 
314 	id = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id);
315 	if (id == 0) {
316 		for (i = 0; i < 2; ++i) {
317 			reg = STAC946X_MIC_L_VOLUME + i;
318 			nvol = ucontrol->value.integer.value[i] & 0x0f;
319 			ovol = 0x0f - stac9460_get(ice, reg);
320 			change = ((ovol & 0x0f) != nvol);
321 			if (change)
322 				stac9460_put(ice, reg, (0x0f - nvol) |
323 							(ovol & ~0x0f));
324 		}
325 	} else {
326 		for (i = 0; i < 2; ++i) {
327 			reg = STAC946X_MIC_L_VOLUME + i;
328 			nvol = ucontrol->value.integer.value[i] & 0x0f;
329 			ovol = 0x0f - stac9460_2_get(ice, reg);
330 			change = ((ovol & 0x0f) != nvol);
331 			if (change)
332 				stac9460_2_put(ice, reg, (0x0f - nvol) |
333 							(ovol & ~0x0f));
334 		}
335 	}
336 	return change;
337 }
338 
339 /*
340  * MIC / LINE switch fonction
341  */
342 
343 #define stac9460_mic_sw_info		snd_ctl_boolean_mono_info
344 
345 static int stac9460_mic_sw_get(struct snd_kcontrol *kcontrol,
346 				struct snd_ctl_elem_value *ucontrol)
347 {
348 	struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);
349 	unsigned char val;
350 	int id;
351 
352 	id = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id);
353 	if (id == 0)
354 		val = stac9460_get(ice, STAC946X_GENERAL_PURPOSE);
355 	else
356 		val = stac9460_2_get(ice, STAC946X_GENERAL_PURPOSE);
357 	ucontrol->value.integer.value[0] = ~val>>7 & 0x1;
358 	return 0;
359 }
360 
361 static int stac9460_mic_sw_put(struct snd_kcontrol *kcontrol,
362 				struct snd_ctl_elem_value *ucontrol)
363 {
364 	struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);
365 	unsigned char new, old;
366 	int change, id;
367 
368 	id = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id);
369 	if (id == 0)
370 		old = stac9460_get(ice, STAC946X_GENERAL_PURPOSE);
371 	else
372 		old = stac9460_2_get(ice, STAC946X_GENERAL_PURPOSE);
373 	new = (~ucontrol->value.integer.value[0] << 7 & 0x80) | (old & ~0x80);
374 	change = (new != old);
375 	if (change) {
376 		if (id == 0)
377 			stac9460_put(ice, STAC946X_GENERAL_PURPOSE, new);
378 		else
379 			stac9460_2_put(ice, STAC946X_GENERAL_PURPOSE, new);
380 	}
381 	return change;
382 }
383 
384 /*
385  * Control tabs
386  */
387 static struct snd_kcontrol_new stac9640_controls[] __devinitdata = {
388 	{
389 		.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
390 		.name = "Master Playback Switch",
391 		.info = stac9460_dac_mute_info,
392 		.get = stac9460_dac_mute_get,
393 		.put = stac9460_dac_mute_put,
394 		.private_value = 1
395 	},
396 	{
397 		.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
398 		.name = "Master Playback Volume",
399 		.info = stac9460_dac_vol_info,
400 		.get = stac9460_dac_vol_get,
401 		.put = stac9460_dac_vol_put,
402 		.private_value = 1,
403 	},
404 	{
405 		.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
406 		.name = "MIC/Line switch",
407 		.count = 2,
408 		.info = stac9460_mic_sw_info,
409 		.get = stac9460_mic_sw_get,
410 		.put = stac9460_mic_sw_put,
411 
412 	},
413 	{
414 		.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
415 		.name = "DAC Switch",
416 		.count = 8,
417 		.info = stac9460_dac_mute_info,
418 		.get = stac9460_dac_mute_get,
419 		.put = stac9460_dac_mute_put,
420 	},
421 	{
422 		.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
423 		.name = "DAC Volume",
424 		.count = 8,
425 		.info = stac9460_dac_vol_info,
426 		.get = stac9460_dac_vol_get,
427 		.put = stac9460_dac_vol_put,
428 	},
429 	{
430 		.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
431 		.name = "ADC Switch",
432 		.count = 2,
433 		.info = stac9460_adc_mute_info,
434 		.get = stac9460_adc_mute_get,
435 		.put = stac9460_adc_mute_put,
436 	},
437 	{
438 		.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
439 		.name = "ADC Volume",
440 		.count = 2,
441 		.info = stac9460_adc_vol_info,
442 		.get = stac9460_adc_vol_get,
443 		.put = stac9460_adc_vol_put,
444 
445 	}
446 };
447 
448 
449 
450 /*INIT*/
451 static int __devinit wtm_add_controls(struct snd_ice1712 *ice)
452 {
453 	unsigned int i;
454 	int err;
455 
456 	for (i = 0; i < ARRAY_SIZE(stac9640_controls); i++) {
457 		err = snd_ctl_add(ice->card,
458 				snd_ctl_new1(&stac9640_controls[i], ice));
459 		if (err < 0)
460 			return err;
461 	}
462 	return 0;
463 }
464 
465 static int __devinit wtm_init(struct snd_ice1712 *ice)
466 {
467 	static unsigned short stac_inits_prodigy[] = {
468 		STAC946X_RESET, 0,
469 		(unsigned short)-1
470 	};
471 	unsigned short *p;
472 
473 	/*WTM 192M*/
474 	ice->num_total_dacs = 8;
475 	ice->num_total_adcs = 4;
476 	ice->force_rdma1 = 1;
477 
478 	/*initialize codec*/
479 	p = stac_inits_prodigy;
480 	for (; *p != (unsigned short)-1; p += 2) {
481 		stac9460_put(ice, p[0], p[1]);
482 		stac9460_2_put(ice, p[0], p[1]);
483 	}
484 	return 0;
485 }
486 
487 
488 static unsigned char wtm_eeprom[] __devinitdata = {
489 	0x47,	/*SYSCONF: clock 192KHz, 4ADC, 8DAC */
490 	0x80,	/* ACLINK : I2S */
491 	0xf8,	/* I2S: vol; 96k, 24bit, 192k */
492 	0xc1	/*SPDIF: out-en, spidf ext out*/,
493 	0x9f,	/* GPIO_DIR */
494 	0xff,	/* GPIO_DIR1 */
495 	0x7f,	/* GPIO_DIR2 */
496 	0x9f,	/* GPIO_MASK */
497 	0xff,	/* GPIO_MASK1 */
498 	0x7f,	/* GPIO_MASK2 */
499 	0x16,	/* GPIO_STATE */
500 	0x80,	/* GPIO_STATE1 */
501 	0x00,	/* GPIO_STATE2 */
502 };
503 
504 
505 /*entry point*/
506 struct snd_ice1712_card_info snd_vt1724_wtm_cards[] __devinitdata = {
507 	{
508 		.subvendor = VT1724_SUBDEVICE_WTM,
509 		.name = "ESI Waveterminal 192M",
510 		.model = "WT192M",
511 		.chip_init = wtm_init,
512 		.build_controls = wtm_add_controls,
513 		.eeprom_size = sizeof(wtm_eeprom),
514 		.eeprom_data = wtm_eeprom,
515 	},
516 	{} /*terminator*/
517 };
518