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