• Home
  • History
  • Annotate
  • Line#
  • Navigate
  • Raw
  • Download
  • only in /asuswrt-rt-n18u-9.0.0.4.380.2695/release/src-rt-6.x.4708/linux/linux-2.6/sound/pci/ice1712/
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 */
43static 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
49static 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 */
57static 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
63static 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
74static 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
96static 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 */
137static 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
147static 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
169static 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
214static 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
236static 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 */
272static 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
282static 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
306static 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
345static 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
361static 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 */
387static 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*/
451static 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
465static 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
488static 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*/
506struct 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