1/*
2 *  Copyright (c) by Jaroslav Kysela <perex@suse.cz>
3 *  Routines for control of CS4235/4236B/4237B/4238B/4239 chips
4 *
5 *  Note:
6 *     -----
7 *
8 *  Bugs:
9 *     -----
10 *
11 *   This program is free software; you can redistribute it and/or modify
12 *   it under the terms of the GNU General Public License as published by
13 *   the Free Software Foundation; either version 2 of the License, or
14 *   (at your option) any later version.
15 *
16 *   This program is distributed in the hope that it will be useful,
17 *   but WITHOUT ANY WARRANTY; without even the implied warranty of
18 *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
19 *   GNU General Public License for more details.
20 *
21 *   You should have received a copy of the GNU General Public License
22 *   along with this program; if not, write to the Free Software
23 *   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
24 *
25 */
26
27/*
28 *  Indirect control registers (CS4236B+)
29 *
30 *  C0
31 *     D8: WSS reset (all chips)
32 *
33 *  C1 (all chips except CS4236)
34 *     D7-D5: version
35 *     D4-D0: chip id
36 *             11101 - CS4235
37 *             01011 - CS4236B
38 *             01000 - CS4237B
39 *             01001 - CS4238B
40 *             11110 - CS4239
41 *
42 *  C2
43 *     D7-D4: 3D Space (CS4235,CS4237B,CS4238B,CS4239)
44 *     D3-D0: 3D Center (CS4237B); 3D Volume (CS4238B)
45 *
46 *  C3
47 *     D7: 3D Enable (CS4237B)
48 *     D6: 3D Mono Enable (CS4237B)
49 *     D5: 3D Serial Output (CS4237B,CS4238B)
50 *     D4: 3D Enable (CS4235,CS4238B,CS4239)
51 *
52 *  C4
53 *     D7: consumer serial port enable (CS4237B,CS4238B)
54 *     D6: channels status block reset (CS4237B,CS4238B)
55 *     D5: user bit in sub-frame of digital audio data (CS4237B,CS4238B)
56 *     D4: validity bit bit in sub-frame of digital audio data (CS4237B,CS4238B)
57 *
58 *  C5  lower channel status (digital serial data description) (CS4237B,CS4238B)
59 *     D7-D6: first two bits of category code
60 *     D5: lock
61 *     D4-D3: pre-emphasis (0 = none, 1 = 50/15us)
62 *     D2: copy/copyright (0 = copy inhibited)
63 *     D1: 0 = digital audio / 1 = non-digital audio
64 *
65 *  C6  upper channel status (digital serial data description) (CS4237B,CS4238B)
66 *     D7-D6: sample frequency (0 = 44.1kHz)
67 *     D5: generation status (0 = no indication, 1 = original/commercially precaptureed data)
68 *     D4-D0: category code (upper bits)
69 *
70 *  C7  reserved (must write 0)
71 *
72 *  C8  wavetable control
73 *     D7: volume control interrupt enable (CS4235,CS4239)
74 *     D6: hardware volume control format (CS4235,CS4239)
75 *     D3: wavetable serial port enable (all chips)
76 *     D2: DSP serial port switch (all chips)
77 *     D1: disable MCLK (all chips)
78 *     D0: force BRESET low (all chips)
79 *
80 */
81
82#include <sound/driver.h>
83#include <asm/io.h>
84#include <linux/delay.h>
85#include <linux/init.h>
86#include <linux/time.h>
87#include <linux/wait.h>
88#include <sound/core.h>
89#include <sound/cs4231.h>
90#include <sound/asoundef.h>
91
92MODULE_AUTHOR("Jaroslav Kysela <perex@suse.cz>");
93MODULE_DESCRIPTION("Routines for control of CS4235/4236B/4237B/4238B/4239 chips");
94MODULE_LICENSE("GPL");
95
96/*
97 *
98 */
99
100static unsigned char snd_cs4236_ext_map[18] = {
101	/* CS4236_LEFT_LINE */		0xff,
102	/* CS4236_RIGHT_LINE */		0xff,
103	/* CS4236_LEFT_MIC */		0xdf,
104	/* CS4236_RIGHT_MIC */		0xdf,
105	/* CS4236_LEFT_MIX_CTRL */	0xe0 | 0x18,
106	/* CS4236_RIGHT_MIX_CTRL */	0xe0,
107	/* CS4236_LEFT_FM */		0xbf,
108	/* CS4236_RIGHT_FM */		0xbf,
109	/* CS4236_LEFT_DSP */		0xbf,
110	/* CS4236_RIGHT_DSP */		0xbf,
111	/* CS4236_RIGHT_LOOPBACK */	0xbf,
112	/* CS4236_DAC_MUTE */		0xe0,
113	/* CS4236_ADC_RATE */		0x01,	/* 48kHz */
114	/* CS4236_DAC_RATE */		0x01,	/* 48kHz */
115	/* CS4236_LEFT_MASTER */	0xbf,
116	/* CS4236_RIGHT_MASTER */	0xbf,
117	/* CS4236_LEFT_WAVE */		0xbf,
118	/* CS4236_RIGHT_WAVE */		0xbf
119};
120
121/*
122 *
123 */
124
125static void snd_cs4236_ctrl_out(struct snd_cs4231 *chip, unsigned char reg, unsigned char val)
126{
127	outb(reg, chip->cport + 3);
128	outb(chip->cimage[reg] = val, chip->cport + 4);
129}
130
131static unsigned char snd_cs4236_ctrl_in(struct snd_cs4231 *chip, unsigned char reg)
132{
133	outb(reg, chip->cport + 3);
134	return inb(chip->cport + 4);
135}
136
137/*
138 *  PCM
139 */
140
141#define CLOCKS 8
142
143static struct snd_ratnum clocks[CLOCKS] = {
144	{ .num = 16934400, .den_min = 353, .den_max = 353, .den_step = 1 },
145	{ .num = 16934400, .den_min = 529, .den_max = 529, .den_step = 1 },
146	{ .num = 16934400, .den_min = 617, .den_max = 617, .den_step = 1 },
147	{ .num = 16934400, .den_min = 1058, .den_max = 1058, .den_step = 1 },
148	{ .num = 16934400, .den_min = 1764, .den_max = 1764, .den_step = 1 },
149	{ .num = 16934400, .den_min = 2117, .den_max = 2117, .den_step = 1 },
150	{ .num = 16934400, .den_min = 2558, .den_max = 2558, .den_step = 1 },
151	{ .num = 16934400/16, .den_min = 21, .den_max = 192, .den_step = 1 }
152};
153
154static struct snd_pcm_hw_constraint_ratnums hw_constraints_clocks = {
155	.nrats = CLOCKS,
156	.rats = clocks,
157};
158
159static int snd_cs4236_xrate(struct snd_pcm_runtime *runtime)
160{
161	return snd_pcm_hw_constraint_ratnums(runtime, 0, SNDRV_PCM_HW_PARAM_RATE,
162					     &hw_constraints_clocks);
163}
164
165static unsigned char divisor_to_rate_register(unsigned int divisor)
166{
167	switch (divisor) {
168	case 353:	return 1;
169	case 529:	return 2;
170	case 617:	return 3;
171	case 1058:	return 4;
172	case 1764:	return 5;
173	case 2117:	return 6;
174	case 2558:	return 7;
175	default:
176		if (divisor < 21 || divisor > 192) {
177			snd_BUG();
178			return 192;
179		}
180		return divisor;
181	}
182}
183
184static void snd_cs4236_playback_format(struct snd_cs4231 *chip, struct snd_pcm_hw_params *params, unsigned char pdfr)
185{
186	unsigned long flags;
187	unsigned char rate = divisor_to_rate_register(params->rate_den);
188
189	spin_lock_irqsave(&chip->reg_lock, flags);
190	/* set fast playback format change and clean playback FIFO */
191	snd_cs4231_out(chip, CS4231_ALT_FEATURE_1, chip->image[CS4231_ALT_FEATURE_1] | 0x10);
192	snd_cs4231_out(chip, CS4231_PLAYBK_FORMAT, pdfr & 0xf0);
193	snd_cs4231_out(chip, CS4231_ALT_FEATURE_1, chip->image[CS4231_ALT_FEATURE_1] & ~0x10);
194	snd_cs4236_ext_out(chip, CS4236_DAC_RATE, rate);
195	spin_unlock_irqrestore(&chip->reg_lock, flags);
196}
197
198static void snd_cs4236_capture_format(struct snd_cs4231 *chip, struct snd_pcm_hw_params *params, unsigned char cdfr)
199{
200	unsigned long flags;
201	unsigned char rate = divisor_to_rate_register(params->rate_den);
202
203	spin_lock_irqsave(&chip->reg_lock, flags);
204	/* set fast capture format change and clean capture FIFO */
205	snd_cs4231_out(chip, CS4231_ALT_FEATURE_1, chip->image[CS4231_ALT_FEATURE_1] | 0x20);
206	snd_cs4231_out(chip, CS4231_REC_FORMAT, cdfr & 0xf0);
207	snd_cs4231_out(chip, CS4231_ALT_FEATURE_1, chip->image[CS4231_ALT_FEATURE_1] & ~0x20);
208	snd_cs4236_ext_out(chip, CS4236_ADC_RATE, rate);
209	spin_unlock_irqrestore(&chip->reg_lock, flags);
210}
211
212#ifdef CONFIG_PM
213
214static void snd_cs4236_suspend(struct snd_cs4231 *chip)
215{
216	int reg;
217	unsigned long flags;
218
219	spin_lock_irqsave(&chip->reg_lock, flags);
220	for (reg = 0; reg < 32; reg++)
221		chip->image[reg] = snd_cs4231_in(chip, reg);
222	for (reg = 0; reg < 18; reg++)
223		chip->eimage[reg] = snd_cs4236_ext_in(chip, CS4236_I23VAL(reg));
224	for (reg = 2; reg < 9; reg++)
225		chip->cimage[reg] = snd_cs4236_ctrl_in(chip, reg);
226	spin_unlock_irqrestore(&chip->reg_lock, flags);
227}
228
229static void snd_cs4236_resume(struct snd_cs4231 *chip)
230{
231	int reg;
232	unsigned long flags;
233
234	snd_cs4231_mce_up(chip);
235	spin_lock_irqsave(&chip->reg_lock, flags);
236	for (reg = 0; reg < 32; reg++) {
237		switch (reg) {
238		case CS4236_EXT_REG:
239		case CS4231_VERSION:
240		case 27:	/* why? CS4235 - master left */
241		case 29:	/* why? CS4235 - master right */
242			break;
243		default:
244			snd_cs4231_out(chip, reg, chip->image[reg]);
245			break;
246		}
247	}
248	for (reg = 0; reg < 18; reg++)
249		snd_cs4236_ext_out(chip, CS4236_I23VAL(reg), chip->eimage[reg]);
250	for (reg = 2; reg < 9; reg++) {
251		switch (reg) {
252		case 7:
253			break;
254		default:
255			snd_cs4236_ctrl_out(chip, reg, chip->cimage[reg]);
256		}
257	}
258	spin_unlock_irqrestore(&chip->reg_lock, flags);
259	snd_cs4231_mce_down(chip);
260}
261
262#endif /* CONFIG_PM */
263
264int snd_cs4236_create(struct snd_card *card,
265		      unsigned long port,
266		      unsigned long cport,
267		      int irq, int dma1, int dma2,
268		      unsigned short hardware,
269		      unsigned short hwshare,
270		      struct snd_cs4231 ** rchip)
271{
272	struct snd_cs4231 *chip;
273	unsigned char ver1, ver2;
274	unsigned int reg;
275	int err;
276
277	*rchip = NULL;
278	if (hardware == CS4231_HW_DETECT)
279		hardware = CS4231_HW_DETECT3;
280	if (cport < 0x100) {
281		snd_printk("please, specify control port for CS4236+ chips\n");
282		return -ENODEV;
283	}
284	if ((err = snd_cs4231_create(card, port, cport, irq, dma1, dma2, hardware, hwshare, &chip)) < 0)
285		return err;
286
287	if (!(chip->hardware & CS4231_HW_CS4236B_MASK)) {
288	        snd_printk("CS4236+: MODE3 and extended registers not available, hardware=0x%x\n",chip->hardware);
289		snd_device_free(card, chip);
290		return -ENODEV;
291	}
292	ver1 = snd_cs4236_ctrl_in(chip, 1);
293	ver2 = snd_cs4236_ext_in(chip, CS4236_VERSION);
294	snd_printdd("CS4236: [0x%lx] C1 (version) = 0x%x, ext = 0x%x\n", cport, ver1, ver2);
295	if (ver1 != ver2) {
296		snd_printk("CS4236+ chip detected, but control port 0x%lx is not valid\n", cport);
297		snd_device_free(card, chip);
298		return -ENODEV;
299	}
300	snd_cs4236_ctrl_out(chip, 0, 0x00);
301	snd_cs4236_ctrl_out(chip, 2, 0xff);
302	snd_cs4236_ctrl_out(chip, 3, 0x00);
303	snd_cs4236_ctrl_out(chip, 4, 0x80);
304	snd_cs4236_ctrl_out(chip, 5, ((IEC958_AES1_CON_PCM_CODER & 3) << 6) | IEC958_AES0_CON_EMPHASIS_NONE);
305	snd_cs4236_ctrl_out(chip, 6, IEC958_AES1_CON_PCM_CODER >> 2);
306	snd_cs4236_ctrl_out(chip, 7, 0x00);
307	/* 0x8c for C8 is valid for Turtle Beach Malibu - the IEC-958 output */
308	/* is working with this setup, other hardware should have */
309	/* different signal paths and this value should be selectable */
310	/* in the future */
311	snd_cs4236_ctrl_out(chip, 8, 0x8c);
312	chip->rate_constraint = snd_cs4236_xrate;
313	chip->set_playback_format = snd_cs4236_playback_format;
314	chip->set_capture_format = snd_cs4236_capture_format;
315#ifdef CONFIG_PM
316	chip->suspend = snd_cs4236_suspend;
317	chip->resume = snd_cs4236_resume;
318#endif
319
320	/* initialize extended registers */
321	for (reg = 0; reg < sizeof(snd_cs4236_ext_map); reg++)
322		snd_cs4236_ext_out(chip, CS4236_I23VAL(reg), snd_cs4236_ext_map[reg]);
323
324        /* initialize compatible but more featured registers */
325	snd_cs4231_out(chip, CS4231_LEFT_INPUT, 0x40);
326	snd_cs4231_out(chip, CS4231_RIGHT_INPUT, 0x40);
327	snd_cs4231_out(chip, CS4231_AUX1_LEFT_INPUT, 0xff);
328	snd_cs4231_out(chip, CS4231_AUX1_RIGHT_INPUT, 0xff);
329	snd_cs4231_out(chip, CS4231_AUX2_LEFT_INPUT, 0xdf);
330	snd_cs4231_out(chip, CS4231_AUX2_RIGHT_INPUT, 0xdf);
331	snd_cs4231_out(chip, CS4231_RIGHT_LINE_IN, 0xff);
332	snd_cs4231_out(chip, CS4231_LEFT_LINE_IN, 0xff);
333	snd_cs4231_out(chip, CS4231_RIGHT_LINE_IN, 0xff);
334	switch (chip->hardware) {
335	case CS4231_HW_CS4235:
336	case CS4231_HW_CS4239:
337		snd_cs4231_out(chip, CS4235_LEFT_MASTER, 0xff);
338		snd_cs4231_out(chip, CS4235_RIGHT_MASTER, 0xff);
339		break;
340	}
341
342	*rchip = chip;
343	return 0;
344}
345
346int snd_cs4236_pcm(struct snd_cs4231 *chip, int device, struct snd_pcm **rpcm)
347{
348	struct snd_pcm *pcm;
349	int err;
350
351	if ((err = snd_cs4231_pcm(chip, device, &pcm)) < 0)
352		return err;
353	pcm->info_flags &= ~SNDRV_PCM_INFO_JOINT_DUPLEX;
354	if (rpcm)
355		*rpcm = pcm;
356	return 0;
357}
358
359/*
360 *  MIXER
361 */
362
363#define CS4236_SINGLE(xname, xindex, reg, shift, mask, invert) \
364{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, .index = xindex, \
365  .info = snd_cs4236_info_single, \
366  .get = snd_cs4236_get_single, .put = snd_cs4236_put_single, \
367  .private_value = reg | (shift << 8) | (mask << 16) | (invert << 24) }
368
369static int snd_cs4236_info_single(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo)
370{
371	int mask = (kcontrol->private_value >> 16) & 0xff;
372
373	uinfo->type = mask == 1 ? SNDRV_CTL_ELEM_TYPE_BOOLEAN : SNDRV_CTL_ELEM_TYPE_INTEGER;
374	uinfo->count = 1;
375	uinfo->value.integer.min = 0;
376	uinfo->value.integer.max = mask;
377	return 0;
378}
379
380static int snd_cs4236_get_single(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
381{
382	struct snd_cs4231 *chip = snd_kcontrol_chip(kcontrol);
383	unsigned long flags;
384	int reg = kcontrol->private_value & 0xff;
385	int shift = (kcontrol->private_value >> 8) & 0xff;
386	int mask = (kcontrol->private_value >> 16) & 0xff;
387	int invert = (kcontrol->private_value >> 24) & 0xff;
388
389	spin_lock_irqsave(&chip->reg_lock, flags);
390	ucontrol->value.integer.value[0] = (chip->eimage[CS4236_REG(reg)] >> shift) & mask;
391	spin_unlock_irqrestore(&chip->reg_lock, flags);
392	if (invert)
393		ucontrol->value.integer.value[0] = mask - ucontrol->value.integer.value[0];
394	return 0;
395}
396
397static int snd_cs4236_put_single(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
398{
399	struct snd_cs4231 *chip = snd_kcontrol_chip(kcontrol);
400	unsigned long flags;
401	int reg = kcontrol->private_value & 0xff;
402	int shift = (kcontrol->private_value >> 8) & 0xff;
403	int mask = (kcontrol->private_value >> 16) & 0xff;
404	int invert = (kcontrol->private_value >> 24) & 0xff;
405	int change;
406	unsigned short val;
407
408	val = (ucontrol->value.integer.value[0] & mask);
409	if (invert)
410		val = mask - val;
411	val <<= shift;
412	spin_lock_irqsave(&chip->reg_lock, flags);
413	val = (chip->eimage[CS4236_REG(reg)] & ~(mask << shift)) | val;
414	change = val != chip->eimage[CS4236_REG(reg)];
415	snd_cs4236_ext_out(chip, reg, val);
416	spin_unlock_irqrestore(&chip->reg_lock, flags);
417	return change;
418}
419
420#define CS4236_SINGLEC(xname, xindex, reg, shift, mask, invert) \
421{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, .index = xindex, \
422  .info = snd_cs4236_info_single, \
423  .get = snd_cs4236_get_singlec, .put = snd_cs4236_put_singlec, \
424  .private_value = reg | (shift << 8) | (mask << 16) | (invert << 24) }
425
426static int snd_cs4236_get_singlec(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
427{
428	struct snd_cs4231 *chip = snd_kcontrol_chip(kcontrol);
429	unsigned long flags;
430	int reg = kcontrol->private_value & 0xff;
431	int shift = (kcontrol->private_value >> 8) & 0xff;
432	int mask = (kcontrol->private_value >> 16) & 0xff;
433	int invert = (kcontrol->private_value >> 24) & 0xff;
434
435	spin_lock_irqsave(&chip->reg_lock, flags);
436	ucontrol->value.integer.value[0] = (chip->cimage[reg] >> shift) & mask;
437	spin_unlock_irqrestore(&chip->reg_lock, flags);
438	if (invert)
439		ucontrol->value.integer.value[0] = mask - ucontrol->value.integer.value[0];
440	return 0;
441}
442
443static int snd_cs4236_put_singlec(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
444{
445	struct snd_cs4231 *chip = snd_kcontrol_chip(kcontrol);
446	unsigned long flags;
447	int reg = kcontrol->private_value & 0xff;
448	int shift = (kcontrol->private_value >> 8) & 0xff;
449	int mask = (kcontrol->private_value >> 16) & 0xff;
450	int invert = (kcontrol->private_value >> 24) & 0xff;
451	int change;
452	unsigned short val;
453
454	val = (ucontrol->value.integer.value[0] & mask);
455	if (invert)
456		val = mask - val;
457	val <<= shift;
458	spin_lock_irqsave(&chip->reg_lock, flags);
459	val = (chip->cimage[reg] & ~(mask << shift)) | val;
460	change = val != chip->cimage[reg];
461	snd_cs4236_ctrl_out(chip, reg, val);
462	spin_unlock_irqrestore(&chip->reg_lock, flags);
463	return change;
464}
465
466#define CS4236_DOUBLE(xname, xindex, left_reg, right_reg, shift_left, shift_right, mask, invert) \
467{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, .index = xindex, \
468  .info = snd_cs4236_info_double, \
469  .get = snd_cs4236_get_double, .put = snd_cs4236_put_double, \
470  .private_value = left_reg | (right_reg << 8) | (shift_left << 16) | (shift_right << 19) | (mask << 24) | (invert << 22) }
471
472static int snd_cs4236_info_double(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo)
473{
474	int mask = (kcontrol->private_value >> 24) & 0xff;
475
476	uinfo->type = mask == 1 ? SNDRV_CTL_ELEM_TYPE_BOOLEAN : SNDRV_CTL_ELEM_TYPE_INTEGER;
477	uinfo->count = 2;
478	uinfo->value.integer.min = 0;
479	uinfo->value.integer.max = mask;
480	return 0;
481}
482
483static int snd_cs4236_get_double(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
484{
485	struct snd_cs4231 *chip = snd_kcontrol_chip(kcontrol);
486	unsigned long flags;
487	int left_reg = kcontrol->private_value & 0xff;
488	int right_reg = (kcontrol->private_value >> 8) & 0xff;
489	int shift_left = (kcontrol->private_value >> 16) & 0x07;
490	int shift_right = (kcontrol->private_value >> 19) & 0x07;
491	int mask = (kcontrol->private_value >> 24) & 0xff;
492	int invert = (kcontrol->private_value >> 22) & 1;
493
494	spin_lock_irqsave(&chip->reg_lock, flags);
495	ucontrol->value.integer.value[0] = (chip->eimage[CS4236_REG(left_reg)] >> shift_left) & mask;
496	ucontrol->value.integer.value[1] = (chip->eimage[CS4236_REG(right_reg)] >> shift_right) & mask;
497	spin_unlock_irqrestore(&chip->reg_lock, flags);
498	if (invert) {
499		ucontrol->value.integer.value[0] = mask - ucontrol->value.integer.value[0];
500		ucontrol->value.integer.value[1] = mask - ucontrol->value.integer.value[1];
501	}
502	return 0;
503}
504
505static int snd_cs4236_put_double(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
506{
507	struct snd_cs4231 *chip = snd_kcontrol_chip(kcontrol);
508	unsigned long flags;
509	int left_reg = kcontrol->private_value & 0xff;
510	int right_reg = (kcontrol->private_value >> 8) & 0xff;
511	int shift_left = (kcontrol->private_value >> 16) & 0x07;
512	int shift_right = (kcontrol->private_value >> 19) & 0x07;
513	int mask = (kcontrol->private_value >> 24) & 0xff;
514	int invert = (kcontrol->private_value >> 22) & 1;
515	int change;
516	unsigned short val1, val2;
517
518	val1 = ucontrol->value.integer.value[0] & mask;
519	val2 = ucontrol->value.integer.value[1] & mask;
520	if (invert) {
521		val1 = mask - val1;
522		val2 = mask - val2;
523	}
524	val1 <<= shift_left;
525	val2 <<= shift_right;
526	spin_lock_irqsave(&chip->reg_lock, flags);
527	if (left_reg != right_reg) {
528		val1 = (chip->eimage[CS4236_REG(left_reg)] & ~(mask << shift_left)) | val1;
529		val2 = (chip->eimage[CS4236_REG(right_reg)] & ~(mask << shift_right)) | val2;
530		change = val1 != chip->eimage[CS4236_REG(left_reg)] || val2 != chip->eimage[CS4236_REG(right_reg)];
531		snd_cs4236_ext_out(chip, left_reg, val1);
532		snd_cs4236_ext_out(chip, right_reg, val2);
533	} else {
534		val1 = (chip->eimage[CS4236_REG(left_reg)] & ~((mask << shift_left) | (mask << shift_right))) | val1 | val2;
535		change = val1 != chip->eimage[CS4236_REG(left_reg)];
536		snd_cs4236_ext_out(chip, left_reg, val1);
537	}
538	spin_unlock_irqrestore(&chip->reg_lock, flags);
539	return change;
540}
541
542#define CS4236_DOUBLE1(xname, xindex, left_reg, right_reg, shift_left, shift_right, mask, invert) \
543{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, .index = xindex, \
544  .info = snd_cs4236_info_double, \
545  .get = snd_cs4236_get_double1, .put = snd_cs4236_put_double1, \
546  .private_value = left_reg | (right_reg << 8) | (shift_left << 16) | (shift_right << 19) | (mask << 24) | (invert << 22) }
547
548static int snd_cs4236_get_double1(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
549{
550	struct snd_cs4231 *chip = snd_kcontrol_chip(kcontrol);
551	unsigned long flags;
552	int left_reg = kcontrol->private_value & 0xff;
553	int right_reg = (kcontrol->private_value >> 8) & 0xff;
554	int shift_left = (kcontrol->private_value >> 16) & 0x07;
555	int shift_right = (kcontrol->private_value >> 19) & 0x07;
556	int mask = (kcontrol->private_value >> 24) & 0xff;
557	int invert = (kcontrol->private_value >> 22) & 1;
558
559	spin_lock_irqsave(&chip->reg_lock, flags);
560	ucontrol->value.integer.value[0] = (chip->image[left_reg] >> shift_left) & mask;
561	ucontrol->value.integer.value[1] = (chip->eimage[CS4236_REG(right_reg)] >> shift_right) & mask;
562	spin_unlock_irqrestore(&chip->reg_lock, flags);
563	if (invert) {
564		ucontrol->value.integer.value[0] = mask - ucontrol->value.integer.value[0];
565		ucontrol->value.integer.value[1] = mask - ucontrol->value.integer.value[1];
566	}
567	return 0;
568}
569
570static int snd_cs4236_put_double1(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
571{
572	struct snd_cs4231 *chip = snd_kcontrol_chip(kcontrol);
573	unsigned long flags;
574	int left_reg = kcontrol->private_value & 0xff;
575	int right_reg = (kcontrol->private_value >> 8) & 0xff;
576	int shift_left = (kcontrol->private_value >> 16) & 0x07;
577	int shift_right = (kcontrol->private_value >> 19) & 0x07;
578	int mask = (kcontrol->private_value >> 24) & 0xff;
579	int invert = (kcontrol->private_value >> 22) & 1;
580	int change;
581	unsigned short val1, val2;
582
583	val1 = ucontrol->value.integer.value[0] & mask;
584	val2 = ucontrol->value.integer.value[1] & mask;
585	if (invert) {
586		val1 = mask - val1;
587		val2 = mask - val2;
588	}
589	val1 <<= shift_left;
590	val2 <<= shift_right;
591	spin_lock_irqsave(&chip->reg_lock, flags);
592	val1 = (chip->image[left_reg] & ~(mask << shift_left)) | val1;
593	val2 = (chip->eimage[CS4236_REG(right_reg)] & ~(mask << shift_right)) | val2;
594	change = val1 != chip->image[left_reg] || val2 != chip->eimage[CS4236_REG(right_reg)];
595	snd_cs4231_out(chip, left_reg, val1);
596	snd_cs4236_ext_out(chip, right_reg, val2);
597	spin_unlock_irqrestore(&chip->reg_lock, flags);
598	return change;
599}
600
601#define CS4236_MASTER_DIGITAL(xname, xindex) \
602{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, .index = xindex, \
603  .info = snd_cs4236_info_double, \
604  .get = snd_cs4236_get_master_digital, .put = snd_cs4236_put_master_digital, \
605  .private_value = 71 << 24 }
606
607static inline int snd_cs4236_mixer_master_digital_invert_volume(int vol)
608{
609	return (vol < 64) ? 63 - vol : 64 + (71 - vol);
610}
611
612static int snd_cs4236_get_master_digital(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
613{
614	struct snd_cs4231 *chip = snd_kcontrol_chip(kcontrol);
615	unsigned long flags;
616
617	spin_lock_irqsave(&chip->reg_lock, flags);
618	ucontrol->value.integer.value[0] = snd_cs4236_mixer_master_digital_invert_volume(chip->eimage[CS4236_REG(CS4236_LEFT_MASTER)] & 0x7f);
619	ucontrol->value.integer.value[1] = snd_cs4236_mixer_master_digital_invert_volume(chip->eimage[CS4236_REG(CS4236_RIGHT_MASTER)] & 0x7f);
620	spin_unlock_irqrestore(&chip->reg_lock, flags);
621	return 0;
622}
623
624static int snd_cs4236_put_master_digital(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
625{
626	struct snd_cs4231 *chip = snd_kcontrol_chip(kcontrol);
627	unsigned long flags;
628	int change;
629	unsigned short val1, val2;
630
631	val1 = snd_cs4236_mixer_master_digital_invert_volume(ucontrol->value.integer.value[0] & 0x7f);
632	val2 = snd_cs4236_mixer_master_digital_invert_volume(ucontrol->value.integer.value[1] & 0x7f);
633	spin_lock_irqsave(&chip->reg_lock, flags);
634	val1 = (chip->eimage[CS4236_REG(CS4236_LEFT_MASTER)] & ~0x7f) | val1;
635	val2 = (chip->eimage[CS4236_REG(CS4236_RIGHT_MASTER)] & ~0x7f) | val2;
636	change = val1 != chip->eimage[CS4236_REG(CS4236_LEFT_MASTER)] || val2 != chip->eimage[CS4236_REG(CS4236_RIGHT_MASTER)];
637	snd_cs4236_ext_out(chip, CS4236_LEFT_MASTER, val1);
638	snd_cs4236_ext_out(chip, CS4236_RIGHT_MASTER, val2);
639	spin_unlock_irqrestore(&chip->reg_lock, flags);
640	return change;
641}
642
643#define CS4235_OUTPUT_ACCU(xname, xindex) \
644{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, .index = xindex, \
645  .info = snd_cs4236_info_double, \
646  .get = snd_cs4235_get_output_accu, .put = snd_cs4235_put_output_accu, \
647  .private_value = 3 << 24 }
648
649static inline int snd_cs4235_mixer_output_accu_get_volume(int vol)
650{
651	switch ((vol >> 5) & 3) {
652	case 0: return 1;
653	case 1: return 3;
654	case 2: return 2;
655	case 3: return 0;
656 	}
657	return 3;
658}
659
660static inline int snd_cs4235_mixer_output_accu_set_volume(int vol)
661{
662	switch (vol & 3) {
663	case 0: return 3 << 5;
664	case 1: return 0 << 5;
665	case 2: return 2 << 5;
666	case 3: return 1 << 5;
667	}
668	return 1 << 5;
669}
670
671static int snd_cs4235_get_output_accu(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
672{
673	struct snd_cs4231 *chip = snd_kcontrol_chip(kcontrol);
674	unsigned long flags;
675
676	spin_lock_irqsave(&chip->reg_lock, flags);
677	ucontrol->value.integer.value[0] = snd_cs4235_mixer_output_accu_get_volume(chip->image[CS4235_LEFT_MASTER]);
678	ucontrol->value.integer.value[1] = snd_cs4235_mixer_output_accu_get_volume(chip->image[CS4235_RIGHT_MASTER]);
679	spin_unlock_irqrestore(&chip->reg_lock, flags);
680	return 0;
681}
682
683static int snd_cs4235_put_output_accu(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
684{
685	struct snd_cs4231 *chip = snd_kcontrol_chip(kcontrol);
686	unsigned long flags;
687	int change;
688	unsigned short val1, val2;
689
690	val1 = snd_cs4235_mixer_output_accu_set_volume(ucontrol->value.integer.value[0]);
691	val2 = snd_cs4235_mixer_output_accu_set_volume(ucontrol->value.integer.value[1]);
692	spin_lock_irqsave(&chip->reg_lock, flags);
693	val1 = (chip->image[CS4235_LEFT_MASTER] & ~(3 << 5)) | val1;
694	val2 = (chip->image[CS4235_RIGHT_MASTER] & ~(3 << 5)) | val2;
695	change = val1 != chip->image[CS4235_LEFT_MASTER] || val2 != chip->image[CS4235_RIGHT_MASTER];
696	snd_cs4231_out(chip, CS4235_LEFT_MASTER, val1);
697	snd_cs4231_out(chip, CS4235_RIGHT_MASTER, val2);
698	spin_unlock_irqrestore(&chip->reg_lock, flags);
699	return change;
700}
701
702static struct snd_kcontrol_new snd_cs4236_controls[] = {
703
704CS4236_DOUBLE("Master Digital Playback Switch", 0, CS4236_LEFT_MASTER, CS4236_RIGHT_MASTER, 7, 7, 1, 1),
705CS4236_DOUBLE("Master Digital Capture Switch", 0, CS4236_DAC_MUTE, CS4236_DAC_MUTE, 7, 6, 1, 1),
706CS4236_MASTER_DIGITAL("Master Digital Volume", 0),
707
708CS4236_DOUBLE("Capture Boost Volume", 0, CS4236_LEFT_MIX_CTRL, CS4236_RIGHT_MIX_CTRL, 5, 5, 3, 1),
709
710CS4231_DOUBLE("PCM Playback Switch", 0, CS4231_LEFT_OUTPUT, CS4231_RIGHT_OUTPUT, 7, 7, 1, 1),
711CS4231_DOUBLE("PCM Playback Volume", 0, CS4231_LEFT_OUTPUT, CS4231_RIGHT_OUTPUT, 0, 0, 63, 1),
712
713CS4236_DOUBLE("DSP Playback Switch", 0, CS4236_LEFT_DSP, CS4236_RIGHT_DSP, 7, 7, 1, 1),
714CS4236_DOUBLE("DSP Playback Volume", 0, CS4236_LEFT_DSP, CS4236_RIGHT_DSP, 0, 0, 63, 1),
715
716CS4236_DOUBLE("FM Playback Switch", 0, CS4236_LEFT_FM, CS4236_RIGHT_FM, 7, 7, 1, 1),
717CS4236_DOUBLE("FM Playback Volume", 0, CS4236_LEFT_FM, CS4236_RIGHT_FM, 0, 0, 63, 1),
718
719CS4236_DOUBLE("Wavetable Playback Switch", 0, CS4236_LEFT_WAVE, CS4236_RIGHT_WAVE, 7, 7, 1, 1),
720CS4236_DOUBLE("Wavetable Playback Volume", 0, CS4236_LEFT_WAVE, CS4236_RIGHT_WAVE, 0, 0, 63, 1),
721
722CS4231_DOUBLE("Synth Playback Switch", 0, CS4231_LEFT_LINE_IN, CS4231_RIGHT_LINE_IN, 7, 7, 1, 1),
723CS4231_DOUBLE("Synth Volume", 0, CS4231_LEFT_LINE_IN, CS4231_RIGHT_LINE_IN, 0, 0, 31, 1),
724CS4231_DOUBLE("Synth Capture Switch", 0, CS4231_LEFT_LINE_IN, CS4231_RIGHT_LINE_IN, 6, 6, 1, 1),
725CS4231_DOUBLE("Synth Capture Bypass", 0, CS4231_LEFT_LINE_IN, CS4231_RIGHT_LINE_IN, 5, 5, 1, 1),
726
727CS4236_DOUBLE("Mic Playback Switch", 0, CS4236_LEFT_MIC, CS4236_RIGHT_MIC, 6, 6, 1, 1),
728CS4236_DOUBLE("Mic Capture Switch", 0, CS4236_LEFT_MIC, CS4236_RIGHT_MIC, 7, 7, 1, 1),
729CS4236_DOUBLE("Mic Volume", 0, CS4236_LEFT_MIC, CS4236_RIGHT_MIC, 0, 0, 31, 1),
730CS4236_DOUBLE("Mic Playback Boost", 0, CS4236_LEFT_MIC, CS4236_RIGHT_MIC, 5, 5, 1, 0),
731
732CS4231_DOUBLE("Line Playback Switch", 0, CS4231_AUX1_LEFT_INPUT, CS4231_AUX1_RIGHT_INPUT, 7, 7, 1, 1),
733CS4231_DOUBLE("Line Volume", 0, CS4231_AUX1_LEFT_INPUT, CS4231_AUX1_RIGHT_INPUT, 0, 0, 31, 1),
734CS4231_DOUBLE("Line Capture Switch", 0, CS4231_AUX1_LEFT_INPUT, CS4231_AUX1_RIGHT_INPUT, 6, 6, 1, 1),
735CS4231_DOUBLE("Line Capture Bypass", 0, CS4231_AUX1_LEFT_INPUT, CS4231_AUX1_RIGHT_INPUT, 5, 5, 1, 1),
736
737CS4231_DOUBLE("CD Playback Switch", 0, CS4231_AUX2_LEFT_INPUT, CS4231_AUX2_RIGHT_INPUT, 7, 7, 1, 1),
738CS4231_DOUBLE("CD Volume", 0, CS4231_AUX2_LEFT_INPUT, CS4231_AUX2_RIGHT_INPUT, 0, 0, 31, 1),
739CS4231_DOUBLE("CD Capture Switch", 0, CS4231_AUX2_LEFT_INPUT, CS4231_AUX2_RIGHT_INPUT, 6, 6, 1, 1),
740
741CS4236_DOUBLE1("Mono Output Playback Switch", 0, CS4231_MONO_CTRL, CS4236_RIGHT_MIX_CTRL, 6, 7, 1, 1),
742CS4236_DOUBLE1("Mono Playback Switch", 0, CS4231_MONO_CTRL, CS4236_LEFT_MIX_CTRL, 7, 7, 1, 1),
743CS4231_SINGLE("Mono Playback Volume", 0, CS4231_MONO_CTRL, 0, 15, 1),
744CS4231_SINGLE("Mono Playback Bypass", 0, CS4231_MONO_CTRL, 5, 1, 0),
745
746CS4231_DOUBLE("Capture Volume", 0, CS4231_LEFT_INPUT, CS4231_RIGHT_INPUT, 0, 0, 15, 0),
747CS4231_DOUBLE("Analog Loopback Capture Switch", 0, CS4231_LEFT_INPUT, CS4231_RIGHT_INPUT, 7, 7, 1, 0),
748
749CS4231_SINGLE("Digital Loopback Playback Switch", 0, CS4231_LOOPBACK, 0, 1, 0),
750CS4236_DOUBLE1("Digital Loopback Playback Volume", 0, CS4231_LOOPBACK, CS4236_RIGHT_LOOPBACK, 2, 0, 63, 1)
751};
752
753static struct snd_kcontrol_new snd_cs4235_controls[] = {
754
755CS4231_DOUBLE("Master Switch", 0, CS4235_LEFT_MASTER, CS4235_RIGHT_MASTER, 7, 7, 1, 1),
756CS4231_DOUBLE("Master Volume", 0, CS4235_LEFT_MASTER, CS4235_RIGHT_MASTER, 0, 0, 31, 1),
757
758CS4235_OUTPUT_ACCU("Playback Volume", 0),
759
760CS4236_DOUBLE("Master Digital Playback Switch", 0, CS4236_LEFT_MASTER, CS4236_RIGHT_MASTER, 7, 7, 1, 1),
761CS4236_DOUBLE("Master Digital Capture Switch", 0, CS4236_DAC_MUTE, CS4236_DAC_MUTE, 7, 6, 1, 1),
762CS4236_MASTER_DIGITAL("Master Digital Volume", 0),
763
764CS4231_DOUBLE("Master Digital Playback Switch", 1, CS4231_LEFT_LINE_IN, CS4231_RIGHT_LINE_IN, 7, 7, 1, 1),
765CS4231_DOUBLE("Master Digital Capture Switch", 1, CS4231_LEFT_LINE_IN, CS4231_RIGHT_LINE_IN, 6, 6, 1, 1),
766CS4231_DOUBLE("Master Digital Volume", 1, CS4231_LEFT_LINE_IN, CS4231_RIGHT_LINE_IN, 0, 0, 31, 1),
767
768CS4236_DOUBLE("Capture Volume", 0, CS4236_LEFT_MIX_CTRL, CS4236_RIGHT_MIX_CTRL, 5, 5, 3, 1),
769
770CS4231_DOUBLE("PCM Switch", 0, CS4231_LEFT_OUTPUT, CS4231_RIGHT_OUTPUT, 7, 7, 1, 1),
771CS4231_DOUBLE("PCM Volume", 0, CS4231_LEFT_OUTPUT, CS4231_RIGHT_OUTPUT, 0, 0, 63, 1),
772
773CS4236_DOUBLE("DSP Switch", 0, CS4236_LEFT_DSP, CS4236_RIGHT_DSP, 7, 7, 1, 1),
774
775CS4236_DOUBLE("FM Switch", 0, CS4236_LEFT_FM, CS4236_RIGHT_FM, 7, 7, 1, 1),
776
777CS4236_DOUBLE("Wavetable Switch", 0, CS4236_LEFT_WAVE, CS4236_RIGHT_WAVE, 7, 7, 1, 1),
778
779CS4236_DOUBLE("Mic Capture Switch", 0, CS4236_LEFT_MIC, CS4236_RIGHT_MIC, 7, 7, 1, 1),
780CS4236_DOUBLE("Mic Playback Switch", 0, CS4236_LEFT_MIC, CS4236_RIGHT_MIC, 6, 6, 1, 1),
781CS4236_SINGLE("Mic Volume", 0, CS4236_LEFT_MIC, 0, 31, 1),
782CS4236_SINGLE("Mic Playback Boost", 0, CS4236_LEFT_MIC, 5, 1, 0),
783
784CS4231_DOUBLE("Aux Playback Switch", 0, CS4231_AUX1_LEFT_INPUT, CS4231_AUX1_RIGHT_INPUT, 7, 7, 1, 1),
785CS4231_DOUBLE("Aux Capture Switch", 0, CS4231_AUX1_LEFT_INPUT, CS4231_AUX1_RIGHT_INPUT, 6, 6, 1, 1),
786CS4231_DOUBLE("Aux Volume", 0, CS4231_AUX1_LEFT_INPUT, CS4231_AUX1_RIGHT_INPUT, 0, 0, 31, 1),
787
788CS4231_DOUBLE("Aux Playback Switch", 1, CS4231_AUX2_LEFT_INPUT, CS4231_AUX2_RIGHT_INPUT, 7, 7, 1, 1),
789CS4231_DOUBLE("Aux Capture Switch", 1, CS4231_AUX2_LEFT_INPUT, CS4231_AUX2_RIGHT_INPUT, 6, 6, 1, 1),
790CS4231_DOUBLE("Aux Volume", 1, CS4231_AUX2_LEFT_INPUT, CS4231_AUX2_RIGHT_INPUT, 0, 0, 31, 1),
791
792CS4236_DOUBLE1("Master Mono Switch", 0, CS4231_MONO_CTRL, CS4236_RIGHT_MIX_CTRL, 6, 7, 1, 1),
793
794CS4236_DOUBLE1("Mono Switch", 0, CS4231_MONO_CTRL, CS4236_LEFT_MIX_CTRL, 7, 7, 1, 1),
795CS4231_SINGLE("Mono Volume", 0, CS4231_MONO_CTRL, 0, 15, 1),
796
797CS4231_DOUBLE("Analog Loopback Switch", 0, CS4231_LEFT_INPUT, CS4231_RIGHT_INPUT, 7, 7, 1, 0),
798};
799
800#define CS4236_IEC958_ENABLE(xname, xindex) \
801{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, .index = xindex, \
802  .info = snd_cs4236_info_single, \
803  .get = snd_cs4236_get_iec958_switch, .put = snd_cs4236_put_iec958_switch, \
804  .private_value = 1 << 16 }
805
806static int snd_cs4236_get_iec958_switch(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
807{
808	struct snd_cs4231 *chip = snd_kcontrol_chip(kcontrol);
809	unsigned long flags;
810
811	spin_lock_irqsave(&chip->reg_lock, flags);
812	ucontrol->value.integer.value[0] = chip->image[CS4231_ALT_FEATURE_1] & 0x02 ? 1 : 0;
813	spin_unlock_irqrestore(&chip->reg_lock, flags);
814	return 0;
815}
816
817static int snd_cs4236_put_iec958_switch(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
818{
819	struct snd_cs4231 *chip = snd_kcontrol_chip(kcontrol);
820	unsigned long flags;
821	int change;
822	unsigned short enable, val;
823
824	enable = ucontrol->value.integer.value[0] & 1;
825
826	mutex_lock(&chip->mce_mutex);
827	snd_cs4231_mce_up(chip);
828	spin_lock_irqsave(&chip->reg_lock, flags);
829	val = (chip->image[CS4231_ALT_FEATURE_1] & ~0x0e) | (0<<2) | (enable << 1);
830	change = val != chip->image[CS4231_ALT_FEATURE_1];
831	snd_cs4231_out(chip, CS4231_ALT_FEATURE_1, val);
832	val = snd_cs4236_ctrl_in(chip, 4) | 0xc0;
833	snd_cs4236_ctrl_out(chip, 4, val);
834	udelay(100);
835	val &= ~0x40;
836	snd_cs4236_ctrl_out(chip, 4, val);
837	spin_unlock_irqrestore(&chip->reg_lock, flags);
838	snd_cs4231_mce_down(chip);
839	mutex_unlock(&chip->mce_mutex);
840
841	return change;
842}
843
844static struct snd_kcontrol_new snd_cs4236_iec958_controls[] = {
845CS4236_IEC958_ENABLE("IEC958 Output Enable", 0),
846CS4236_SINGLEC("IEC958 Output Validity", 0, 4, 4, 1, 0),
847CS4236_SINGLEC("IEC958 Output User", 0, 4, 5, 1, 0),
848CS4236_SINGLEC("IEC958 Output CSBR", 0, 4, 6, 1, 0),
849CS4236_SINGLEC("IEC958 Output Channel Status Low", 0, 5, 1, 127, 0),
850CS4236_SINGLEC("IEC958 Output Channel Status High", 0, 6, 0, 255, 0)
851};
852
853static struct snd_kcontrol_new snd_cs4236_3d_controls_cs4235[] = {
854CS4236_SINGLEC("3D Control - Switch", 0, 3, 4, 1, 0),
855CS4236_SINGLEC("3D Control - Space", 0, 2, 4, 15, 1)
856};
857
858static struct snd_kcontrol_new snd_cs4236_3d_controls_cs4237[] = {
859CS4236_SINGLEC("3D Control - Switch", 0, 3, 7, 1, 0),
860CS4236_SINGLEC("3D Control - Space", 0, 2, 4, 15, 1),
861CS4236_SINGLEC("3D Control - Center", 0, 2, 0, 15, 1),
862CS4236_SINGLEC("3D Control - Mono", 0, 3, 6, 1, 0),
863CS4236_SINGLEC("3D Control - IEC958", 0, 3, 5, 1, 0)
864};
865
866static struct snd_kcontrol_new snd_cs4236_3d_controls_cs4238[] = {
867CS4236_SINGLEC("3D Control - Switch", 0, 3, 4, 1, 0),
868CS4236_SINGLEC("3D Control - Space", 0, 2, 4, 15, 1),
869CS4236_SINGLEC("3D Control - Volume", 0, 2, 0, 15, 1),
870CS4236_SINGLEC("3D Control - IEC958", 0, 3, 5, 1, 0)
871};
872
873int snd_cs4236_mixer(struct snd_cs4231 *chip)
874{
875	struct snd_card *card;
876	unsigned int idx, count;
877	int err;
878	struct snd_kcontrol_new *kcontrol;
879
880	snd_assert(chip != NULL && chip->card != NULL, return -EINVAL);
881	card = chip->card;
882	strcpy(card->mixername, snd_cs4231_chip_id(chip));
883
884	if (chip->hardware == CS4231_HW_CS4235 ||
885	    chip->hardware == CS4231_HW_CS4239) {
886		for (idx = 0; idx < ARRAY_SIZE(snd_cs4235_controls); idx++) {
887			if ((err = snd_ctl_add(card, snd_ctl_new1(&snd_cs4235_controls[idx], chip))) < 0)
888				return err;
889		}
890	} else {
891		for (idx = 0; idx < ARRAY_SIZE(snd_cs4236_controls); idx++) {
892			if ((err = snd_ctl_add(card, snd_ctl_new1(&snd_cs4236_controls[idx], chip))) < 0)
893				return err;
894		}
895	}
896	switch (chip->hardware) {
897	case CS4231_HW_CS4235:
898	case CS4231_HW_CS4239:
899		count = ARRAY_SIZE(snd_cs4236_3d_controls_cs4235);
900		kcontrol = snd_cs4236_3d_controls_cs4235;
901		break;
902	case CS4231_HW_CS4237B:
903		count = ARRAY_SIZE(snd_cs4236_3d_controls_cs4237);
904		kcontrol = snd_cs4236_3d_controls_cs4237;
905		break;
906	case CS4231_HW_CS4238B:
907		count = ARRAY_SIZE(snd_cs4236_3d_controls_cs4238);
908		kcontrol = snd_cs4236_3d_controls_cs4238;
909		break;
910	default:
911		count = 0;
912		kcontrol = NULL;
913	}
914	for (idx = 0; idx < count; idx++, kcontrol++) {
915		if ((err = snd_ctl_add(card, snd_ctl_new1(kcontrol, chip))) < 0)
916			return err;
917	}
918	if (chip->hardware == CS4231_HW_CS4237B ||
919	    chip->hardware == CS4231_HW_CS4238B) {
920		for (idx = 0; idx < ARRAY_SIZE(snd_cs4236_iec958_controls); idx++) {
921			if ((err = snd_ctl_add(card, snd_ctl_new1(&snd_cs4236_iec958_controls[idx], chip))) < 0)
922				return err;
923		}
924	}
925	return 0;
926}
927
928EXPORT_SYMBOL(snd_cs4236_create);
929EXPORT_SYMBOL(snd_cs4236_pcm);
930EXPORT_SYMBOL(snd_cs4236_mixer);
931
932/*
933 *  INIT part
934 */
935
936static int __init alsa_cs4236_init(void)
937{
938	return 0;
939}
940
941static void __exit alsa_cs4236_exit(void)
942{
943}
944
945module_init(alsa_cs4236_init)
946module_exit(alsa_cs4236_exit)
947