Blame view

sound/i2c/other/ak4xxx-adda.c 23.8 KB
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1
2
3
4
  /*
   *   ALSA driver for AK4524 / AK4528 / AK4529 / AK4355 / AK4358 / AK4381
   *   AD and DA converters
   *
c1017a4cd   Jaroslav Kysela   [ALSA] Changed Ja...
5
   *	Copyright (c) 2000-2004 Jaroslav Kysela <perex@perex.cz>,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
   *				Takashi Iwai <tiwai@suse.de>
   *
   *   This program is free software; you can redistribute it and/or modify
   *   it under the terms of the GNU General Public License as published by
   *   the Free Software Foundation; either version 2 of the License, or
   *   (at your option) any later version.
   *
   *   This program is distributed in the hope that it will be useful,
   *   but WITHOUT ANY WARRANTY; without even the implied warranty of
   *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   *   GNU General Public License for more details.
   *
   *   You should have received a copy of the GNU General Public License
   *   along with this program; if not, write to the Free Software
   *   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
   *
   */      
  
  #include <sound/driver.h>
  #include <asm/io.h>
  #include <linux/delay.h>
  #include <linux/interrupt.h>
  #include <linux/init.h>
  #include <sound/core.h>
  #include <sound/control.h>
723b2b0d3   Takashi Iwai   [ALSA] Clean up a...
31
  #include <sound/tlv.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
32
  #include <sound/ak4xxx-adda.h>
c1017a4cd   Jaroslav Kysela   [ALSA] Changed Ja...
33
  MODULE_AUTHOR("Jaroslav Kysela <perex@perex.cz>, Takashi Iwai <tiwai@suse.de>");
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
34
35
  MODULE_DESCRIPTION("Routines for control of AK452x / AK43xx  AD/DA converters");
  MODULE_LICENSE("GPL");
723b2b0d3   Takashi Iwai   [ALSA] Clean up a...
36
  /* write the given register and save the data to the cache */
cb9d24e43   Takashi Iwai   [ALSA] ak4xxx-add...
37
38
  void snd_akm4xxx_write(struct snd_akm4xxx *ak, int chip, unsigned char reg,
  		       unsigned char val)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
39
40
41
42
43
  {
  	ak->ops.lock(ak, chip);
  	ak->ops.write(ak, chip, reg, val);
  
  	/* save the data */
854b66e44   Takashi Iwai   [ALSA] ak4xxx - R...
44
  	snd_akm4xxx_set(ak, chip, reg, val);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
45
46
  	ak->ops.unlock(ak, chip);
  }
cb9d24e43   Takashi Iwai   [ALSA] ak4xxx-add...
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
  EXPORT_SYMBOL(snd_akm4xxx_write);
  
  /* reset procedure for AK4524 and AK4528 */
  static void ak4524_reset(struct snd_akm4xxx *ak, int state)
  {
  	unsigned int chip;
  	unsigned char reg, maxreg;
  
  	if (ak->type == SND_AK4528)
  		maxreg = 0x06;
  	else
  		maxreg = 0x08;
  	for (chip = 0; chip < ak->num_dacs/2; chip++) {
  		snd_akm4xxx_write(ak, chip, 0x01, state ? 0x00 : 0x03);
  		if (state)
  			continue;
  		/* DAC volumes */
  		for (reg = 0x04; reg < maxreg; reg++)
  			snd_akm4xxx_write(ak, chip, reg,
  					  snd_akm4xxx_get(ak, chip, reg));
cb9d24e43   Takashi Iwai   [ALSA] ak4xxx-add...
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
  	}
  }
  
  /* reset procedure for AK4355 and AK4358 */
  static void ak4355_reset(struct snd_akm4xxx *ak, int state)
  {
  	unsigned char reg;
  
  	if (state) {
  		snd_akm4xxx_write(ak, 0, 0x01, 0x02); /* reset and soft-mute */
  		return;
  	}
  	for (reg = 0x00; reg < 0x0b; reg++)
  		if (reg != 0x01)
  			snd_akm4xxx_write(ak, 0, reg,
  					  snd_akm4xxx_get(ak, 0, reg));
  	snd_akm4xxx_write(ak, 0, 0x01, 0x01); /* un-reset, unmute */
  }
  
  /* reset procedure for AK4381 */
  static void ak4381_reset(struct snd_akm4xxx *ak, int state)
  {
  	unsigned int chip;
  	unsigned char reg;
  
  	for (chip = 0; chip < ak->num_dacs/2; chip++) {
  		snd_akm4xxx_write(ak, chip, 0x00, state ? 0x0c : 0x0f);
  		if (state)
  			continue;
  		for (reg = 0x01; reg < 0x05; reg++)
  			snd_akm4xxx_write(ak, chip, reg,
  					  snd_akm4xxx_get(ak, chip, reg));
  	}
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
101
102
103
104
105
106
  /*
   * reset the AKM codecs
   * @state: 1 = reset codec, 0 = restore the registers
   *
   * assert the reset operation and restores the register values to the chips.
   */
97f02e05f   Takashi Iwai   [ALSA] Remove xxx...
107
  void snd_akm4xxx_reset(struct snd_akm4xxx *ak, int state)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
108
  {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
109
110
111
  	switch (ak->type) {
  	case SND_AK4524:
  	case SND_AK4528:
cb9d24e43   Takashi Iwai   [ALSA] ak4xxx-add...
112
  		ak4524_reset(ak, state);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
113
114
115
116
117
118
  		break;
  	case SND_AK4529:
  		/* FIXME: needed for ak4529? */
  		break;
  	case SND_AK4355:
  	case SND_AK4358:
cb9d24e43   Takashi Iwai   [ALSA] ak4xxx-add...
119
  		ak4355_reset(ak, state);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
120
121
  		break;
  	case SND_AK4381:
cb9d24e43   Takashi Iwai   [ALSA] ak4xxx-add...
122
  		ak4381_reset(ak, state);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
123
  		break;
cf93907b9   Takashi Iwai   [ALSA] Fix compil...
124
125
  	default:
  		break;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
126
127
  	}
  }
cb9d24e43   Takashi Iwai   [ALSA] ak4xxx-add...
128
  EXPORT_SYMBOL(snd_akm4xxx_reset);
723b2b0d3   Takashi Iwai   [ALSA] Clean up a...
129
130
131
132
133
134
135
136
  
  /*
   * Volume conversion table for non-linear volumes
   * from -63.5dB (mute) to 0dB step 0.5dB
   *
   * Used for AK4524 input/ouput attenuation, AK4528, and
   * AK5365 input attenuation
   */
517400cbc   Takashi Iwai   [ALSA] Add some m...
137
  static const unsigned char vol_cvt_datt[128] = {
723b2b0d3   Takashi Iwai   [ALSA] Clean up a...
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
  	0x00, 0x01, 0x01, 0x02, 0x02, 0x03, 0x03, 0x04,
  	0x04, 0x04, 0x04, 0x05, 0x05, 0x05, 0x06, 0x06,
  	0x06, 0x07, 0x07, 0x08, 0x08, 0x08, 0x09, 0x0a,
  	0x0a, 0x0b, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x0f,
  	0x10, 0x10, 0x11, 0x12, 0x12, 0x13, 0x13, 0x14,
  	0x15, 0x16, 0x17, 0x17, 0x18, 0x19, 0x1a, 0x1c,
  	0x1d, 0x1e, 0x1f, 0x20, 0x21, 0x22, 0x23, 0x23,
  	0x24, 0x25, 0x26, 0x28, 0x29, 0x2a, 0x2b, 0x2d,
  	0x2e, 0x30, 0x30, 0x31, 0x32, 0x33, 0x34, 0x35,
  	0x37, 0x38, 0x39, 0x3b, 0x3c, 0x3e, 0x3f, 0x40,
  	0x41, 0x42, 0x43, 0x44, 0x46, 0x47, 0x48, 0x4a,
  	0x4b, 0x4d, 0x4e, 0x50, 0x51, 0x52, 0x53, 0x54,
  	0x55, 0x56, 0x58, 0x59, 0x5b, 0x5c, 0x5e, 0x5f,
  	0x60, 0x61, 0x62, 0x64, 0x65, 0x66, 0x67, 0x69,
  	0x6a, 0x6c, 0x6d, 0x6f, 0x70, 0x71, 0x72, 0x73,
  	0x75, 0x76, 0x77, 0x79, 0x7a, 0x7c, 0x7d, 0x7f,
  };
  
  /*
   * dB tables
   */
0cb29ea0d   Takashi Iwai   [ALSA] Add even m...
159
160
161
162
  static const DECLARE_TLV_DB_SCALE(db_scale_vol_datt, -6350, 50, 1);
  static const DECLARE_TLV_DB_SCALE(db_scale_8bit, -12750, 50, 1);
  static const DECLARE_TLV_DB_SCALE(db_scale_7bit, -6350, 50, 1);
  static const DECLARE_TLV_DB_LINEAR(db_scale_linear, TLV_DB_GAIN_MUTE, 0);
723b2b0d3   Takashi Iwai   [ALSA] Clean up a...
163

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
164
165
166
  /*
   * initialize all the ak4xxx chips
   */
97f02e05f   Takashi Iwai   [ALSA] Remove xxx...
167
  void snd_akm4xxx_init(struct snd_akm4xxx *ak)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
168
  {
0cb29ea0d   Takashi Iwai   [ALSA] Add even m...
169
  	static const unsigned char inits_ak4524[] = {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
170
171
172
173
174
175
176
  		0x00, 0x07, /* 0: all power up */
  		0x01, 0x00, /* 1: ADC/DAC reset */
  		0x02, 0x60, /* 2: 24bit I2S */
  		0x03, 0x19, /* 3: deemphasis off */
  		0x01, 0x03, /* 1: ADC/DAC enable */
  		0x04, 0x00, /* 4: ADC left muted */
  		0x05, 0x00, /* 5: ADC right muted */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
177
178
179
180
  		0x06, 0x00, /* 6: DAC left muted */
  		0x07, 0x00, /* 7: DAC right muted */
  		0xff, 0xff
  	};
517400cbc   Takashi Iwai   [ALSA] Add some m...
181
  	static const unsigned char inits_ak4528[] = {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
182
183
184
185
186
187
188
189
190
  		0x00, 0x07, /* 0: all power up */
  		0x01, 0x00, /* 1: ADC/DAC reset */
  		0x02, 0x60, /* 2: 24bit I2S */
  		0x03, 0x0d, /* 3: deemphasis off, turn LR highpass filters on */
  		0x01, 0x03, /* 1: ADC/DAC enable */
  		0x04, 0x00, /* 4: ADC left muted */
  		0x05, 0x00, /* 5: ADC right muted */
  		0xff, 0xff
  	};
517400cbc   Takashi Iwai   [ALSA] Add some m...
191
  	static const unsigned char inits_ak4529[] = {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
  		0x09, 0x01, /* 9: ATS=0, RSTN=1 */
  		0x0a, 0x3f, /* A: all power up, no zero/overflow detection */
  		0x00, 0x0c, /* 0: TDM=0, 24bit I2S, SMUTE=0 */
  		0x01, 0x00, /* 1: ACKS=0, ADC, loop off */
  		0x02, 0xff, /* 2: LOUT1 muted */
  		0x03, 0xff, /* 3: ROUT1 muted */
  		0x04, 0xff, /* 4: LOUT2 muted */
  		0x05, 0xff, /* 5: ROUT2 muted */
  		0x06, 0xff, /* 6: LOUT3 muted */
  		0x07, 0xff, /* 7: ROUT3 muted */
  		0x0b, 0xff, /* B: LOUT4 muted */
  		0x0c, 0xff, /* C: ROUT4 muted */
  		0x08, 0x55, /* 8: deemphasis all off */
  		0xff, 0xff
  	};
517400cbc   Takashi Iwai   [ALSA] Add some m...
207
  	static const unsigned char inits_ak4355[] = {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
208
  		0x01, 0x02, /* 1: reset and soft-mute */
cb9d24e43   Takashi Iwai   [ALSA] ak4xxx-add...
209
210
  		0x00, 0x06, /* 0: mode3(i2s), disable auto-clock detect,
  			     * disable DZF, sharp roll-off, RSTN#=0 */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
211
212
213
214
215
216
217
218
219
220
221
222
223
  		0x02, 0x0e, /* 2: DA's power up, normal speed, RSTN#=0 */
  		// 0x02, 0x2e, /* quad speed */
  		0x03, 0x01, /* 3: de-emphasis off */
  		0x04, 0x00, /* 4: LOUT1 volume muted */
  		0x05, 0x00, /* 5: ROUT1 volume muted */
  		0x06, 0x00, /* 6: LOUT2 volume muted */
  		0x07, 0x00, /* 7: ROUT2 volume muted */
  		0x08, 0x00, /* 8: LOUT3 volume muted */
  		0x09, 0x00, /* 9: ROUT3 volume muted */
  		0x0a, 0x00, /* a: DATT speed=0, ignore DZF */
  		0x01, 0x01, /* 1: un-reset, unmute */
  		0xff, 0xff
  	};
517400cbc   Takashi Iwai   [ALSA] Add some m...
224
  	static const unsigned char inits_ak4358[] = {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
225
  		0x01, 0x02, /* 1: reset and soft-mute */
cb9d24e43   Takashi Iwai   [ALSA] ak4xxx-add...
226
227
  		0x00, 0x06, /* 0: mode3(i2s), disable auto-clock detect,
  			     * disable DZF, sharp roll-off, RSTN#=0 */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
  		0x02, 0x0e, /* 2: DA's power up, normal speed, RSTN#=0 */
  		// 0x02, 0x2e, /* quad speed */
  		0x03, 0x01, /* 3: de-emphasis off */
  		0x04, 0x00, /* 4: LOUT1 volume muted */
  		0x05, 0x00, /* 5: ROUT1 volume muted */
  		0x06, 0x00, /* 6: LOUT2 volume muted */
  		0x07, 0x00, /* 7: ROUT2 volume muted */
  		0x08, 0x00, /* 8: LOUT3 volume muted */
  		0x09, 0x00, /* 9: ROUT3 volume muted */
  		0x0b, 0x00, /* b: LOUT4 volume muted */
  		0x0c, 0x00, /* c: ROUT4 volume muted */
  		0x0a, 0x00, /* a: DATT speed=0, ignore DZF */
  		0x01, 0x01, /* 1: un-reset, unmute */
  		0xff, 0xff
  	};
517400cbc   Takashi Iwai   [ALSA] Add some m...
243
  	static const unsigned char inits_ak4381[] = {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
244
  		0x00, 0x0c, /* 0: mode3(i2s), disable auto-clock detect */
cb9d24e43   Takashi Iwai   [ALSA] ak4xxx-add...
245
246
  		0x01, 0x02, /* 1: de-emphasis off, normal speed,
  			     * sharp roll-off, DZF off */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
247
248
249
250
251
252
253
254
255
  		// 0x01, 0x12, /* quad speed */
  		0x02, 0x00, /* 2: DZF disabled */
  		0x03, 0x00, /* 3: LATT 0 */
  		0x04, 0x00, /* 4: RATT 0 */
  		0x00, 0x0f, /* 0: power-up, un-reset */
  		0xff, 0xff
  	};
  
  	int chip, num_chips;
517400cbc   Takashi Iwai   [ALSA] Add some m...
256
257
  	const unsigned char *ptr, *inits;
  	unsigned char reg, data;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
258

723b2b0d3   Takashi Iwai   [ALSA] Clean up a...
259
260
  	memset(ak->images, 0, sizeof(ak->images));
  	memset(ak->volumes, 0, sizeof(ak->volumes));
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
  	switch (ak->type) {
  	case SND_AK4524:
  		inits = inits_ak4524;
  		num_chips = ak->num_dacs / 2;
  		break;
  	case SND_AK4528:
  		inits = inits_ak4528;
  		num_chips = ak->num_dacs / 2;
  		break;
  	case SND_AK4529:
  		inits = inits_ak4529;
  		num_chips = 1;
  		break;
  	case SND_AK4355:
  		inits = inits_ak4355;
  		num_chips = 1;
  		break;
  	case SND_AK4358:
  		inits = inits_ak4358;
  		num_chips = 1;
  		break;
  	case SND_AK4381:
  		inits = inits_ak4381;
  		num_chips = ak->num_dacs / 2;
  		break;
723b2b0d3   Takashi Iwai   [ALSA] Clean up a...
286
287
288
  	case SND_AK5365:
  		/* FIXME: any init sequence? */
  		return;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
289
290
291
292
293
294
295
296
297
298
299
300
301
302
  	default:
  		snd_BUG();
  		return;
  	}
  
  	for (chip = 0; chip < num_chips; chip++) {
  		ptr = inits;
  		while (*ptr != 0xff) {
  			reg = *ptr++;
  			data = *ptr++;
  			snd_akm4xxx_write(ak, chip, reg, data);
  		}
  	}
  }
cb9d24e43   Takashi Iwai   [ALSA] ak4xxx-add...
303
  EXPORT_SYMBOL(snd_akm4xxx_init);
723b2b0d3   Takashi Iwai   [ALSA] Clean up a...
304
305
306
  /*
   * Mixer callbacks
   */
854b66e44   Takashi Iwai   [ALSA] ak4xxx - R...
307
  #define AK_IPGA 			(1<<20)	/* including IPGA */
723b2b0d3   Takashi Iwai   [ALSA] Clean up a...
308
309
310
  #define AK_VOL_CVT 			(1<<21)	/* need dB conversion */
  #define AK_NEEDSMSB 			(1<<22)	/* need MSB update bit */
  #define AK_INVERT 			(1<<23)	/* data is inverted */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
311
312
  #define AK_GET_CHIP(val)		(((val) >> 8) & 0xff)
  #define AK_GET_ADDR(val)		((val) & 0xff)
854b66e44   Takashi Iwai   [ALSA] ak4xxx - R...
313
  #define AK_GET_SHIFT(val)		(((val) >> 16) & 0x0f)
723b2b0d3   Takashi Iwai   [ALSA] Clean up a...
314
  #define AK_GET_VOL_CVT(val)		(((val) >> 21) & 1)
854b66e44   Takashi Iwai   [ALSA] ak4xxx - R...
315
  #define AK_GET_IPGA(val)		(((val) >> 20) & 1)
3479307f8   Jochen Voss   [ALSA] Fix volume...
316
  #define AK_GET_NEEDSMSB(val)		(((val) >> 22) & 1)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
317
318
  #define AK_GET_INVERT(val)		(((val) >> 23) & 1)
  #define AK_GET_MASK(val)		(((val) >> 24) & 0xff)
cb9d24e43   Takashi Iwai   [ALSA] ak4xxx-add...
319
320
  #define AK_COMPOSE(chip,addr,shift,mask) \
  	(((chip) << 8) | (addr) | ((shift) << 16) | ((mask) << 24))
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
321

97f02e05f   Takashi Iwai   [ALSA] Remove xxx...
322
323
  static int snd_akm4xxx_volume_info(struct snd_kcontrol *kcontrol,
  				   struct snd_ctl_elem_info *uinfo)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
324
325
326
327
328
329
330
331
332
  {
  	unsigned int mask = AK_GET_MASK(kcontrol->private_value);
  
  	uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
  	uinfo->count = 1;
  	uinfo->value.integer.min = 0;
  	uinfo->value.integer.max = mask;
  	return 0;
  }
97f02e05f   Takashi Iwai   [ALSA] Remove xxx...
333
334
  static int snd_akm4xxx_volume_get(struct snd_kcontrol *kcontrol,
  				  struct snd_ctl_elem_value *ucontrol)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
335
  {
97f02e05f   Takashi Iwai   [ALSA] Remove xxx...
336
  	struct snd_akm4xxx *ak = snd_kcontrol_chip(kcontrol);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
337
338
  	int chip = AK_GET_CHIP(kcontrol->private_value);
  	int addr = AK_GET_ADDR(kcontrol->private_value);
3479307f8   Jochen Voss   [ALSA] Fix volume...
339

723b2b0d3   Takashi Iwai   [ALSA] Clean up a...
340
  	ucontrol->value.integer.value[0] = snd_akm4xxx_get_vol(ak, chip, addr);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
341
342
  	return 0;
  }
723b2b0d3   Takashi Iwai   [ALSA] Clean up a...
343
344
  static int put_ak_reg(struct snd_kcontrol *kcontrol, int addr,
  		      unsigned char nval)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
345
  {
97f02e05f   Takashi Iwai   [ALSA] Remove xxx...
346
  	struct snd_akm4xxx *ak = snd_kcontrol_chip(kcontrol);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
347
  	unsigned int mask = AK_GET_MASK(kcontrol->private_value);
723b2b0d3   Takashi Iwai   [ALSA] Clean up a...
348
  	int chip = AK_GET_CHIP(kcontrol->private_value);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
349

723b2b0d3   Takashi Iwai   [ALSA] Clean up a...
350
351
352
353
  	if (snd_akm4xxx_get_vol(ak, chip, addr) == nval)
  		return 0;
  
  	snd_akm4xxx_set_vol(ak, chip, addr, nval);
854b66e44   Takashi Iwai   [ALSA] ak4xxx - R...
354
  	if (AK_GET_VOL_CVT(kcontrol->private_value) && nval < 128)
723b2b0d3   Takashi Iwai   [ALSA] Clean up a...
355
  		nval = vol_cvt_datt[nval];
854b66e44   Takashi Iwai   [ALSA] ak4xxx - R...
356
357
  	if (AK_GET_IPGA(kcontrol->private_value) && nval >= 128)
  		nval++; /* need to correct + 1 since both 127 and 128 are 0dB */
723b2b0d3   Takashi Iwai   [ALSA] Clean up a...
358
  	if (AK_GET_INVERT(kcontrol->private_value))
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
359
  		nval = mask - nval;
723b2b0d3   Takashi Iwai   [ALSA] Clean up a...
360
  	if (AK_GET_NEEDSMSB(kcontrol->private_value))
3479307f8   Jochen Voss   [ALSA] Fix volume...
361
  		nval |= 0x80;
723b2b0d3   Takashi Iwai   [ALSA] Clean up a...
362
363
364
365
366
367
368
369
370
  	snd_akm4xxx_write(ak, chip, addr, nval);
  	return 1;
  }
  
  static int snd_akm4xxx_volume_put(struct snd_kcontrol *kcontrol,
  				  struct snd_ctl_elem_value *ucontrol)
  {
  	return put_ak_reg(kcontrol, AK_GET_ADDR(kcontrol->private_value),
  			  ucontrol->value.integer.value[0]);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
371
  }
c83c0c470   Jani Alinikula   [ALSA] Stereo con...
372
  static int snd_akm4xxx_stereo_volume_info(struct snd_kcontrol *kcontrol,
cb9d24e43   Takashi Iwai   [ALSA] ak4xxx-add...
373
  					  struct snd_ctl_elem_info *uinfo)
c83c0c470   Jani Alinikula   [ALSA] Stereo con...
374
375
376
377
378
379
380
381
382
383
384
  {
  	unsigned int mask = AK_GET_MASK(kcontrol->private_value);
  
  	uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
  	uinfo->count = 2;
  	uinfo->value.integer.min = 0;
  	uinfo->value.integer.max = mask;
  	return 0;
  }
  
  static int snd_akm4xxx_stereo_volume_get(struct snd_kcontrol *kcontrol,
cb9d24e43   Takashi Iwai   [ALSA] ak4xxx-add...
385
  					 struct snd_ctl_elem_value *ucontrol)
c83c0c470   Jani Alinikula   [ALSA] Stereo con...
386
387
388
389
  {
  	struct snd_akm4xxx *ak = snd_kcontrol_chip(kcontrol);
  	int chip = AK_GET_CHIP(kcontrol->private_value);
  	int addr = AK_GET_ADDR(kcontrol->private_value);
c83c0c470   Jani Alinikula   [ALSA] Stereo con...
390

723b2b0d3   Takashi Iwai   [ALSA] Clean up a...
391
392
  	ucontrol->value.integer.value[0] = snd_akm4xxx_get_vol(ak, chip, addr);
  	ucontrol->value.integer.value[1] = snd_akm4xxx_get_vol(ak, chip, addr+1);
c83c0c470   Jani Alinikula   [ALSA] Stereo con...
393
394
395
396
  	return 0;
  }
  
  static int snd_akm4xxx_stereo_volume_put(struct snd_kcontrol *kcontrol,
cb9d24e43   Takashi Iwai   [ALSA] ak4xxx-add...
397
  					 struct snd_ctl_elem_value *ucontrol)
c83c0c470   Jani Alinikula   [ALSA] Stereo con...
398
  {
c83c0c470   Jani Alinikula   [ALSA] Stereo con...
399
  	int addr = AK_GET_ADDR(kcontrol->private_value);
723b2b0d3   Takashi Iwai   [ALSA] Clean up a...
400
  	int change;
c83c0c470   Jani Alinikula   [ALSA] Stereo con...
401

723b2b0d3   Takashi Iwai   [ALSA] Clean up a...
402
403
404
405
  	change = put_ak_reg(kcontrol, addr, ucontrol->value.integer.value[0]);
  	change |= put_ak_reg(kcontrol, addr + 1,
  			     ucontrol->value.integer.value[1]);
  	return change;
c83c0c470   Jani Alinikula   [ALSA] Stereo con...
406
  }
97f02e05f   Takashi Iwai   [ALSA] Remove xxx...
407
408
  static int snd_akm4xxx_deemphasis_info(struct snd_kcontrol *kcontrol,
  				       struct snd_ctl_elem_info *uinfo)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
409
410
411
412
413
414
415
416
417
  {
  	static char *texts[4] = {
  		"44.1kHz", "Off", "48kHz", "32kHz",
  	};
  	uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
  	uinfo->count = 1;
  	uinfo->value.enumerated.items = 4;
  	if (uinfo->value.enumerated.item >= 4)
  		uinfo->value.enumerated.item = 3;
cb9d24e43   Takashi Iwai   [ALSA] ak4xxx-add...
418
419
  	strcpy(uinfo->value.enumerated.name,
  	       texts[uinfo->value.enumerated.item]);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
420
421
  	return 0;
  }
97f02e05f   Takashi Iwai   [ALSA] Remove xxx...
422
423
  static int snd_akm4xxx_deemphasis_get(struct snd_kcontrol *kcontrol,
  				      struct snd_ctl_elem_value *ucontrol)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
424
  {
97f02e05f   Takashi Iwai   [ALSA] Remove xxx...
425
  	struct snd_akm4xxx *ak = snd_kcontrol_chip(kcontrol);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
426
427
428
  	int chip = AK_GET_CHIP(kcontrol->private_value);
  	int addr = AK_GET_ADDR(kcontrol->private_value);
  	int shift = AK_GET_SHIFT(kcontrol->private_value);
cb9d24e43   Takashi Iwai   [ALSA] ak4xxx-add...
429
430
  	ucontrol->value.enumerated.item[0] =
  		(snd_akm4xxx_get(ak, chip, addr) >> shift) & 3;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
431
432
  	return 0;
  }
97f02e05f   Takashi Iwai   [ALSA] Remove xxx...
433
434
  static int snd_akm4xxx_deemphasis_put(struct snd_kcontrol *kcontrol,
  				      struct snd_ctl_elem_value *ucontrol)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
435
  {
97f02e05f   Takashi Iwai   [ALSA] Remove xxx...
436
  	struct snd_akm4xxx *ak = snd_kcontrol_chip(kcontrol);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
437
438
439
440
441
442
  	int chip = AK_GET_CHIP(kcontrol->private_value);
  	int addr = AK_GET_ADDR(kcontrol->private_value);
  	int shift = AK_GET_SHIFT(kcontrol->private_value);
  	unsigned char nval = ucontrol->value.enumerated.item[0] & 3;
  	int change;
  	
cb9d24e43   Takashi Iwai   [ALSA] ak4xxx-add...
443
444
  	nval = (nval << shift) |
  		(snd_akm4xxx_get(ak, chip, addr) & ~(3 << shift));
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
445
446
447
448
449
  	change = snd_akm4xxx_get(ak, chip, addr) != nval;
  	if (change)
  		snd_akm4xxx_write(ak, chip, addr, nval);
  	return change;
  }
a5ce88909   Takashi Iwai   [ALSA] Clean up w...
450
  #define ak4xxx_switch_info	snd_ctl_boolean_mono_info
30ba6e207   Jochen Voss   [ALSA] Revolution...
451
452
453
454
455
456
457
458
459
  
  static int ak4xxx_switch_get(struct snd_kcontrol *kcontrol,
  			     struct snd_ctl_elem_value *ucontrol)
  {
  	struct snd_akm4xxx *ak = snd_kcontrol_chip(kcontrol);
  	int chip = AK_GET_CHIP(kcontrol->private_value);
  	int addr = AK_GET_ADDR(kcontrol->private_value);
  	int shift = AK_GET_SHIFT(kcontrol->private_value);
  	int invert = AK_GET_INVERT(kcontrol->private_value);
ea7cfcdfe   Pavel Hofman   [ALSA] ice1724 - ...
460
461
  	/* we observe the (1<<shift) bit only */
  	unsigned char val = snd_akm4xxx_get(ak, chip, addr) & (1<<shift);
30ba6e207   Jochen Voss   [ALSA] Revolution...
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
  	if (invert)
  		val = ! val;
  	ucontrol->value.integer.value[0] = (val & (1<<shift)) != 0;
  	return 0;
  }
  
  static int ak4xxx_switch_put(struct snd_kcontrol *kcontrol,
  			     struct snd_ctl_elem_value *ucontrol)
  {
  	struct snd_akm4xxx *ak = snd_kcontrol_chip(kcontrol);
  	int chip = AK_GET_CHIP(kcontrol->private_value);
  	int addr = AK_GET_ADDR(kcontrol->private_value);
  	int shift = AK_GET_SHIFT(kcontrol->private_value);
  	int invert = AK_GET_INVERT(kcontrol->private_value);
  	long flag = ucontrol->value.integer.value[0];
  	unsigned char val, oval;
  	int change;
  
  	if (invert)
  		flag = ! flag;
  	oval = snd_akm4xxx_get(ak, chip, addr);
  	if (flag)
  		val = oval | (1<<shift);
  	else
  		val = oval & ~(1<<shift);
  	change = (oval != val);
  	if (change)
  		snd_akm4xxx_write(ak, chip, addr, val);
  	return change;
  }
a58e7cb16   Jochen Voss   [ALSA] Enable cap...
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
  #define AK5365_NUM_INPUTS 5
  
  static int ak4xxx_capture_source_info(struct snd_kcontrol *kcontrol,
  				      struct snd_ctl_elem_info *uinfo)
  {
  	struct snd_akm4xxx *ak = snd_kcontrol_chip(kcontrol);
  	int mixer_ch = AK_GET_SHIFT(kcontrol->private_value);
  	const char **input_names;
  	int  num_names, idx;
  
  	input_names = ak->adc_info[mixer_ch].input_names;
  
  	num_names = 0;
  	while (num_names < AK5365_NUM_INPUTS && input_names[num_names])
  		++num_names;
  	
  	uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
  	uinfo->count = 1;
  	uinfo->value.enumerated.items = num_names;
  	idx = uinfo->value.enumerated.item;
  	if (idx >= num_names)
  		return -EINVAL;
  	strncpy(uinfo->value.enumerated.name, input_names[idx],
  		sizeof(uinfo->value.enumerated.name));
  	return 0;
  }
  
  static int ak4xxx_capture_source_get(struct snd_kcontrol *kcontrol,
  				     struct snd_ctl_elem_value *ucontrol)
  {
  	struct snd_akm4xxx *ak = snd_kcontrol_chip(kcontrol);
  	int chip = AK_GET_CHIP(kcontrol->private_value);
  	int addr = AK_GET_ADDR(kcontrol->private_value);
  	int mask = AK_GET_MASK(kcontrol->private_value);
  	unsigned char val;
  
  	val = snd_akm4xxx_get(ak, chip, addr) & mask;
  	ucontrol->value.enumerated.item[0] = val;
  	return 0;
  }
  
  static int ak4xxx_capture_source_put(struct snd_kcontrol *kcontrol,
  				     struct snd_ctl_elem_value *ucontrol)
  {
  	struct snd_akm4xxx *ak = snd_kcontrol_chip(kcontrol);
  	int chip = AK_GET_CHIP(kcontrol->private_value);
  	int addr = AK_GET_ADDR(kcontrol->private_value);
  	int mask = AK_GET_MASK(kcontrol->private_value);
  	unsigned char oval, val;
  
  	oval = snd_akm4xxx_get(ak, chip, addr);
  	val = oval & ~mask;
  	val |= ucontrol->value.enumerated.item[0] & mask;
  	if (val != oval) {
  		snd_akm4xxx_write(ak, chip, addr, val);
  		return 1;
  	}
  	return 0;
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
551
552
553
  /*
   * build AK4xxx controls
   */
723b2b0d3   Takashi Iwai   [ALSA] Clean up a...
554
  static int build_dac_controls(struct snd_akm4xxx *ak)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
555
  {
723b2b0d3   Takashi Iwai   [ALSA] Clean up a...
556
557
  	int idx, err, mixer_ch, num_stereo;
  	struct snd_kcontrol_new knew;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
558

723b2b0d3   Takashi Iwai   [ALSA] Clean up a...
559
  	mixer_ch = 0;
c83c0c470   Jani Alinikula   [ALSA] Stereo con...
560
  	for (idx = 0; idx < ak->num_dacs; ) {
ea7cfcdfe   Pavel Hofman   [ALSA] ice1724 - ...
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
  		/* mute control for Revolution 7.1 - AK4381 */
  		if (ak->type == SND_AK4381 
  				&&  ak->dac_info[mixer_ch].switch_name) {
  			memset(&knew, 0, sizeof(knew));
  			knew.iface = SNDRV_CTL_ELEM_IFACE_MIXER;
  			knew.count = 1;
  			knew.access = SNDRV_CTL_ELEM_ACCESS_READWRITE;
  			knew.name = ak->dac_info[mixer_ch].switch_name;
  			knew.info = ak4xxx_switch_info;
  			knew.get = ak4xxx_switch_get;
  			knew.put = ak4xxx_switch_put;
  			knew.access = 0;
  			/* register 1, bit 0 (SMUTE): 0 = normal operation,
  			   1 = mute */
  			knew.private_value =
  				AK_COMPOSE(idx/2, 1, 0, 0) | AK_INVERT;
  			err = snd_ctl_add(ak->card, snd_ctl_new1(&knew, ak));
  			if (err < 0)
  				return err;
  		}
723b2b0d3   Takashi Iwai   [ALSA] Clean up a...
581
582
583
584
  		memset(&knew, 0, sizeof(knew));
  		if (! ak->dac_info || ! ak->dac_info[mixer_ch].name) {
  			knew.name = "DAC Volume";
  			knew.index = mixer_ch + ak->idx_offset * 2;
c83c0c470   Jani Alinikula   [ALSA] Stereo con...
585
  			num_stereo = 1;
c83c0c470   Jani Alinikula   [ALSA] Stereo con...
586
  		} else {
723b2b0d3   Takashi Iwai   [ALSA] Clean up a...
587
588
  			knew.name = ak->dac_info[mixer_ch].name;
  			num_stereo = ak->dac_info[mixer_ch].num_channels;
c83c0c470   Jani Alinikula   [ALSA] Stereo con...
589
  		}
723b2b0d3   Takashi Iwai   [ALSA] Clean up a...
590
591
592
593
  		knew.iface = SNDRV_CTL_ELEM_IFACE_MIXER;
  		knew.count = 1;
  		knew.access = SNDRV_CTL_ELEM_ACCESS_READWRITE |
  			SNDRV_CTL_ELEM_ACCESS_TLV_READ;
c83c0c470   Jani Alinikula   [ALSA] Stereo con...
594
  		if (num_stereo == 2) {
723b2b0d3   Takashi Iwai   [ALSA] Clean up a...
595
596
597
  			knew.info = snd_akm4xxx_stereo_volume_info;
  			knew.get = snd_akm4xxx_stereo_volume_get;
  			knew.put = snd_akm4xxx_stereo_volume_put;
c83c0c470   Jani Alinikula   [ALSA] Stereo con...
598
  		} else {
723b2b0d3   Takashi Iwai   [ALSA] Clean up a...
599
600
601
  			knew.info = snd_akm4xxx_volume_info;
  			knew.get = snd_akm4xxx_volume_get;
  			knew.put = snd_akm4xxx_volume_put;
c83c0c470   Jani Alinikula   [ALSA] Stereo con...
602
  		}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
603
604
  		switch (ak->type) {
  		case SND_AK4524:
cb9d24e43   Takashi Iwai   [ALSA] ak4xxx-add...
605
  			/* register 6 & 7 */
723b2b0d3   Takashi Iwai   [ALSA] Clean up a...
606
607
608
609
  			knew.private_value =
  				AK_COMPOSE(idx/2, (idx%2) + 6, 0, 127) |
  				AK_VOL_CVT;
  			knew.tlv.p = db_scale_vol_datt;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
610
611
  			break;
  		case SND_AK4528:
cb9d24e43   Takashi Iwai   [ALSA] ak4xxx-add...
612
  			/* register 4 & 5 */
723b2b0d3   Takashi Iwai   [ALSA] Clean up a...
613
614
615
616
  			knew.private_value =
  				AK_COMPOSE(idx/2, (idx%2) + 4, 0, 127) |
  				AK_VOL_CVT;
  			knew.tlv.p = db_scale_vol_datt;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
617
618
  			break;
  		case SND_AK4529: {
cb9d24e43   Takashi Iwai   [ALSA] ak4xxx-add...
619
620
  			/* registers 2-7 and b,c */
  			int val = idx < 6 ? idx + 2 : (idx - 6) + 0xb;
723b2b0d3   Takashi Iwai   [ALSA] Clean up a...
621
  			knew.private_value =
cb9d24e43   Takashi Iwai   [ALSA] ak4xxx-add...
622
  				AK_COMPOSE(0, val, 0, 255) | AK_INVERT;
723b2b0d3   Takashi Iwai   [ALSA] Clean up a...
623
  			knew.tlv.p = db_scale_8bit;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
624
625
626
  			break;
  		}
  		case SND_AK4355:
cb9d24e43   Takashi Iwai   [ALSA] ak4xxx-add...
627
  			/* register 4-9, chip #0 only */
723b2b0d3   Takashi Iwai   [ALSA] Clean up a...
628
629
  			knew.private_value = AK_COMPOSE(0, idx + 4, 0, 255);
  			knew.tlv.p = db_scale_8bit;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
630
  			break;
3479307f8   Jochen Voss   [ALSA] Fix volume...
631
632
633
  		case SND_AK4358: {
  			/* register 4-9 and 11-12, chip #0 only */
  			int  addr = idx < 6 ? idx + 4 : idx + 5;
723b2b0d3   Takashi Iwai   [ALSA] Clean up a...
634
  			knew.private_value =
3479307f8   Jochen Voss   [ALSA] Fix volume...
635
  				AK_COMPOSE(0, addr, 0, 127) | AK_NEEDSMSB;
723b2b0d3   Takashi Iwai   [ALSA] Clean up a...
636
  			knew.tlv.p = db_scale_7bit;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
637
  			break;
3479307f8   Jochen Voss   [ALSA] Fix volume...
638
  		}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
639
  		case SND_AK4381:
cb9d24e43   Takashi Iwai   [ALSA] ak4xxx-add...
640
  			/* register 3 & 4 */
723b2b0d3   Takashi Iwai   [ALSA] Clean up a...
641
  			knew.private_value =
cb9d24e43   Takashi Iwai   [ALSA] ak4xxx-add...
642
  				AK_COMPOSE(idx/2, (idx%2) + 3, 0, 255);
723b2b0d3   Takashi Iwai   [ALSA] Clean up a...
643
  			knew.tlv.p = db_scale_linear;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
644
645
  			break;
  		default:
723b2b0d3   Takashi Iwai   [ALSA] Clean up a...
646
  			return -EINVAL;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
647
  		}
c83c0c470   Jani Alinikula   [ALSA] Stereo con...
648

723b2b0d3   Takashi Iwai   [ALSA] Clean up a...
649
  		err = snd_ctl_add(ak->card, snd_ctl_new1(&knew, ak));
cb9d24e43   Takashi Iwai   [ALSA] ak4xxx-add...
650
  		if (err < 0)
723b2b0d3   Takashi Iwai   [ALSA] Clean up a...
651
  			return err;
c83c0c470   Jani Alinikula   [ALSA] Stereo con...
652
653
654
  
  		idx += num_stereo;
  		mixer_ch++;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
655
  	}
723b2b0d3   Takashi Iwai   [ALSA] Clean up a...
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
  	return 0;
  }
  
  static int build_adc_controls(struct snd_akm4xxx *ak)
  {
  	int idx, err, mixer_ch, num_stereo;
  	struct snd_kcontrol_new knew;
  
  	mixer_ch = 0;
  	for (idx = 0; idx < ak->num_adcs;) {
  		memset(&knew, 0, sizeof(knew));
  		if (! ak->adc_info || ! ak->adc_info[mixer_ch].name) {
  			knew.name = "ADC Volume";
  			knew.index = mixer_ch + ak->idx_offset * 2;
  			num_stereo = 1;
  		} else {
  			knew.name = ak->adc_info[mixer_ch].name;
  			num_stereo = ak->adc_info[mixer_ch].num_channels;
  		}
  		knew.iface = SNDRV_CTL_ELEM_IFACE_MIXER;
  		knew.count = 1;
  		knew.access = SNDRV_CTL_ELEM_ACCESS_READWRITE |
  			SNDRV_CTL_ELEM_ACCESS_TLV_READ;
  		if (num_stereo == 2) {
  			knew.info = snd_akm4xxx_stereo_volume_info;
  			knew.get = snd_akm4xxx_stereo_volume_get;
  			knew.put = snd_akm4xxx_stereo_volume_put;
  		} else {
  			knew.info = snd_akm4xxx_volume_info;
  			knew.get = snd_akm4xxx_volume_get;
  			knew.put = snd_akm4xxx_volume_put;
  		}
cb9d24e43   Takashi Iwai   [ALSA] ak4xxx-add...
688
  		/* register 4 & 5 */
854b66e44   Takashi Iwai   [ALSA] ak4xxx - R...
689
690
691
692
  		if (ak->type == SND_AK5365)
  			knew.private_value =
  				AK_COMPOSE(idx/2, (idx%2) + 4, 0, 151) |
  				AK_VOL_CVT | AK_IPGA;
683fe1537   Jochen Voss   [ALSA] Revolution...
693
  		else
854b66e44   Takashi Iwai   [ALSA] ak4xxx - R...
694
695
696
697
  			knew.private_value =
  				AK_COMPOSE(idx/2, (idx%2) + 4, 0, 163) |
  				AK_VOL_CVT | AK_IPGA;
  		knew.tlv.p = db_scale_vol_datt;
723b2b0d3   Takashi Iwai   [ALSA] Clean up a...
698
  		err = snd_ctl_add(ak->card, snd_ctl_new1(&knew, ak));
683fe1537   Jochen Voss   [ALSA] Revolution...
699
  		if (err < 0)
723b2b0d3   Takashi Iwai   [ALSA] Clean up a...
700
701
702
703
  			return err;
  
  		if (ak->type == SND_AK5365 && (idx % 2) == 0) {
  			if (! ak->adc_info || 
a58e7cb16   Jochen Voss   [ALSA] Enable cap...
704
  			    ! ak->adc_info[mixer_ch].switch_name) {
723b2b0d3   Takashi Iwai   [ALSA] Clean up a...
705
  				knew.name = "Capture Switch";
a58e7cb16   Jochen Voss   [ALSA] Enable cap...
706
707
  				knew.index = mixer_ch + ak->idx_offset * 2;
  			} else
723b2b0d3   Takashi Iwai   [ALSA] Clean up a...
708
709
710
711
712
713
714
715
716
717
718
719
  				knew.name = ak->adc_info[mixer_ch].switch_name;
  			knew.info = ak4xxx_switch_info;
  			knew.get = ak4xxx_switch_get;
  			knew.put = ak4xxx_switch_put;
  			knew.access = 0;
  			/* register 2, bit 0 (SMUTE): 0 = normal operation,
  			   1 = mute */
  			knew.private_value =
  				AK_COMPOSE(idx/2, 2, 0, 0) | AK_INVERT;
  			err = snd_ctl_add(ak->card, snd_ctl_new1(&knew, ak));
  			if (err < 0)
  				return err;
a58e7cb16   Jochen Voss   [ALSA] Enable cap...
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
  
  			memset(&knew, 0, sizeof(knew));
  			knew.name = ak->adc_info[mixer_ch].selector_name;
  			if (!knew.name) {
  				knew.name = "Capture Channel";
  				knew.index = mixer_ch + ak->idx_offset * 2;
  			}
  
  			knew.iface = SNDRV_CTL_ELEM_IFACE_MIXER;
  			knew.info = ak4xxx_capture_source_info;
  			knew.get = ak4xxx_capture_source_get;
  			knew.put = ak4xxx_capture_source_put;
  			knew.access = 0;
  			/* input selector control: reg. 1, bits 0-2.
  			 * mis-use 'shift' to pass mixer_ch */
  			knew.private_value
  				= AK_COMPOSE(idx/2, 1, mixer_ch, 0x07);
  			err = snd_ctl_add(ak->card, snd_ctl_new1(&knew, ak));
  			if (err < 0)
  				return err;
723b2b0d3   Takashi Iwai   [ALSA] Clean up a...
740
  		}
30ba6e207   Jochen Voss   [ALSA] Revolution...
741

723b2b0d3   Takashi Iwai   [ALSA] Clean up a...
742
743
  		idx += num_stereo;
  		mixer_ch++;
683fe1537   Jochen Voss   [ALSA] Revolution...
744
  	}
723b2b0d3   Takashi Iwai   [ALSA] Clean up a...
745
746
747
748
749
750
751
  	return 0;
  }
  
  static int build_deemphasis(struct snd_akm4xxx *ak, int num_emphs)
  {
  	int idx, err;
  	struct snd_kcontrol_new knew;
683fe1537   Jochen Voss   [ALSA] Revolution...
752

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
753
  	for (idx = 0; idx < num_emphs; idx++) {
723b2b0d3   Takashi Iwai   [ALSA] Clean up a...
754
755
756
757
758
759
760
761
  		memset(&knew, 0, sizeof(knew));
  		knew.name = "Deemphasis";
  		knew.index = idx + ak->idx_offset;
  		knew.iface = SNDRV_CTL_ELEM_IFACE_MIXER;
  		knew.count = 1;
  		knew.info = snd_akm4xxx_deemphasis_info;
  		knew.get = snd_akm4xxx_deemphasis_get;
  		knew.put = snd_akm4xxx_deemphasis_put;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
762
763
764
  		switch (ak->type) {
  		case SND_AK4524:
  		case SND_AK4528:
cb9d24e43   Takashi Iwai   [ALSA] ak4xxx-add...
765
  			/* register 3 */
723b2b0d3   Takashi Iwai   [ALSA] Clean up a...
766
  			knew.private_value = AK_COMPOSE(idx, 3, 0, 0);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
767
768
769
  			break;
  		case SND_AK4529: {
  			int shift = idx == 3 ? 6 : (2 - idx) * 2;
cb9d24e43   Takashi Iwai   [ALSA] ak4xxx-add...
770
  			/* register 8 with shift */
723b2b0d3   Takashi Iwai   [ALSA] Clean up a...
771
  			knew.private_value = AK_COMPOSE(0, 8, shift, 0);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
772
773
774
775
  			break;
  		}
  		case SND_AK4355:
  		case SND_AK4358:
723b2b0d3   Takashi Iwai   [ALSA] Clean up a...
776
  			knew.private_value = AK_COMPOSE(idx, 3, 0, 0);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
777
778
  			break;
  		case SND_AK4381:
723b2b0d3   Takashi Iwai   [ALSA] Clean up a...
779
  			knew.private_value = AK_COMPOSE(idx, 1, 1, 0);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
780
  			break;
cf93907b9   Takashi Iwai   [ALSA] Fix compil...
781
  		default:
723b2b0d3   Takashi Iwai   [ALSA] Clean up a...
782
  			return -EINVAL;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
783
  		}
723b2b0d3   Takashi Iwai   [ALSA] Clean up a...
784
  		err = snd_ctl_add(ak->card, snd_ctl_new1(&knew, ak));
cb9d24e43   Takashi Iwai   [ALSA] ak4xxx-add...
785
  		if (err < 0)
723b2b0d3   Takashi Iwai   [ALSA] Clean up a...
786
  			return err;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
787
  	}
723b2b0d3   Takashi Iwai   [ALSA] Clean up a...
788
  	return 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
789
  }
723b2b0d3   Takashi Iwai   [ALSA] Clean up a...
790
791
792
793
794
795
796
  int snd_akm4xxx_build_controls(struct snd_akm4xxx *ak)
  {
  	int err, num_emphs;
  
  	err = build_dac_controls(ak);
  	if (err < 0)
  		return err;
854b66e44   Takashi Iwai   [ALSA] ak4xxx - R...
797
798
799
  	err = build_adc_controls(ak);
  	if (err < 0)
  		return err;
723b2b0d3   Takashi Iwai   [ALSA] Clean up a...
800
801
802
803
804
805
806
807
808
809
810
811
  
  	if (ak->type == SND_AK4355 || ak->type == SND_AK4358)
  		num_emphs = 1;
  	else
  		num_emphs = ak->num_dacs / 2;
  	err = build_deemphasis(ak, num_emphs);
  	if (err < 0)
  		return err;
  
  	return 0;
  }
  	
cb9d24e43   Takashi Iwai   [ALSA] ak4xxx-add...
812
  EXPORT_SYMBOL(snd_akm4xxx_build_controls);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
813
814
815
816
817
818
819
820
821
822
823
  static int __init alsa_akm4xxx_module_init(void)
  {
  	return 0;
  }
          
  static void __exit alsa_akm4xxx_module_exit(void)
  {
  }
          
  module_init(alsa_akm4xxx_module_init)
  module_exit(alsa_akm4xxx_module_exit)