Commit | Line | Data |
---|---|---|
72cbfd45 TI |
1 | /* |
2 | * ALSA driver for ICEnsemble VT1724 (Envy24HT) | |
3 | * | |
4 | * Lowlevel functions for ESI Maya44 cards | |
5 | * | |
6 | * Copyright (c) 2009 Takashi Iwai <tiwai@suse.de> | |
7 | * Based on the patches by Rainer Zimmermann <mail@lightshed.de> | |
8 | * | |
9 | * This program is free software; you can redistribute it and/or modify | |
10 | * it under the terms of the GNU General Public License as published by | |
11 | * the Free Software Foundation; either version 2 of the License, or | |
12 | * (at your option) any later version. | |
13 | * | |
14 | * This program is distributed in the hope that it will be useful, | |
15 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
16 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
17 | * GNU General Public License for more details. | |
18 | * | |
19 | * You should have received a copy of the GNU General Public License | |
20 | * along with this program; if not, write to the Free Software | |
21 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | |
22 | * | |
23 | */ | |
24 | ||
25 | #include <linux/init.h> | |
26 | #include <linux/slab.h> | |
72cbfd45 TI |
27 | #include <sound/core.h> |
28 | #include <sound/control.h> | |
29 | #include <sound/pcm.h> | |
30 | #include <sound/tlv.h> | |
31 | ||
32 | #include "ice1712.h" | |
33 | #include "envy24ht.h" | |
34 | #include "maya44.h" | |
35 | ||
36 | /* WM8776 register indexes */ | |
37 | #define WM8776_REG_HEADPHONE_L 0x00 | |
38 | #define WM8776_REG_HEADPHONE_R 0x01 | |
39 | #define WM8776_REG_HEADPHONE_MASTER 0x02 | |
40 | #define WM8776_REG_DAC_ATTEN_L 0x03 | |
41 | #define WM8776_REG_DAC_ATTEN_R 0x04 | |
42 | #define WM8776_REG_DAC_ATTEN_MASTER 0x05 | |
43 | #define WM8776_REG_DAC_PHASE 0x06 | |
44 | #define WM8776_REG_DAC_CONTROL 0x07 | |
45 | #define WM8776_REG_DAC_MUTE 0x08 | |
46 | #define WM8776_REG_DAC_DEEMPH 0x09 | |
47 | #define WM8776_REG_DAC_IF_CONTROL 0x0a | |
48 | #define WM8776_REG_ADC_IF_CONTROL 0x0b | |
49 | #define WM8776_REG_MASTER_MODE_CONTROL 0x0c | |
50 | #define WM8776_REG_POWERDOWN 0x0d | |
51 | #define WM8776_REG_ADC_ATTEN_L 0x0e | |
52 | #define WM8776_REG_ADC_ATTEN_R 0x0f | |
53 | #define WM8776_REG_ADC_ALC1 0x10 | |
54 | #define WM8776_REG_ADC_ALC2 0x11 | |
55 | #define WM8776_REG_ADC_ALC3 0x12 | |
56 | #define WM8776_REG_ADC_NOISE_GATE 0x13 | |
57 | #define WM8776_REG_ADC_LIMITER 0x14 | |
58 | #define WM8776_REG_ADC_MUX 0x15 | |
59 | #define WM8776_REG_OUTPUT_MUX 0x16 | |
60 | #define WM8776_REG_RESET 0x17 | |
61 | ||
62 | #define WM8776_NUM_REGS 0x18 | |
63 | ||
64 | /* clock ratio identifiers for snd_wm8776_set_rate() */ | |
65 | #define WM8776_CLOCK_RATIO_128FS 0 | |
66 | #define WM8776_CLOCK_RATIO_192FS 1 | |
67 | #define WM8776_CLOCK_RATIO_256FS 2 | |
68 | #define WM8776_CLOCK_RATIO_384FS 3 | |
69 | #define WM8776_CLOCK_RATIO_512FS 4 | |
70 | #define WM8776_CLOCK_RATIO_768FS 5 | |
71 | ||
72 | enum { WM_VOL_HP, WM_VOL_DAC, WM_VOL_ADC, WM_NUM_VOLS }; | |
73 | enum { WM_SW_DAC, WM_SW_BYPASS, WM_NUM_SWITCHES }; | |
74 | ||
75 | struct snd_wm8776 { | |
76 | unsigned char addr; | |
77 | unsigned short regs[WM8776_NUM_REGS]; | |
78 | unsigned char volumes[WM_NUM_VOLS][2]; | |
79 | unsigned int switch_bits; | |
80 | }; | |
81 | ||
82 | struct snd_maya44 { | |
83 | struct snd_ice1712 *ice; | |
84 | struct snd_wm8776 wm[2]; | |
85 | struct mutex mutex; | |
86 | }; | |
87 | ||
88 | ||
89 | /* write the given register and save the data to the cache */ | |
90 | static void wm8776_write(struct snd_ice1712 *ice, struct snd_wm8776 *wm, | |
91 | unsigned char reg, unsigned short val) | |
92 | { | |
93 | /* | |
94 | * WM8776 registers are up to 9 bits wide, bit 8 is placed in the LSB | |
95 | * of the address field | |
96 | */ | |
97 | snd_vt1724_write_i2c(ice, wm->addr, | |
98 | (reg << 1) | ((val >> 8) & 1), | |
99 | val & 0xff); | |
100 | wm->regs[reg] = val; | |
101 | } | |
102 | ||
103 | /* | |
104 | * update the given register with and/or mask and save the data to the cache | |
105 | */ | |
106 | static int wm8776_write_bits(struct snd_ice1712 *ice, struct snd_wm8776 *wm, | |
107 | unsigned char reg, | |
108 | unsigned short mask, unsigned short val) | |
109 | { | |
110 | val |= wm->regs[reg] & ~mask; | |
111 | if (val != wm->regs[reg]) { | |
112 | wm8776_write(ice, wm, reg, val); | |
113 | return 1; | |
114 | } | |
115 | return 0; | |
116 | } | |
117 | ||
118 | ||
119 | /* | |
120 | * WM8776 volume controls | |
121 | */ | |
122 | ||
123 | struct maya_vol_info { | |
124 | unsigned int maxval; /* volume range: 0..maxval */ | |
125 | unsigned char regs[2]; /* left and right registers */ | |
126 | unsigned short mask; /* value mask */ | |
127 | unsigned short offset; /* zero-value offset */ | |
128 | unsigned short mute; /* mute bit */ | |
129 | unsigned short update; /* update bits */ | |
130 | unsigned char mux_bits[2]; /* extra bits for ADC mute */ | |
131 | }; | |
132 | ||
133 | static struct maya_vol_info vol_info[WM_NUM_VOLS] = { | |
134 | [WM_VOL_HP] = { | |
135 | .maxval = 80, | |
136 | .regs = { WM8776_REG_HEADPHONE_L, WM8776_REG_HEADPHONE_R }, | |
137 | .mask = 0x7f, | |
138 | .offset = 0x30, | |
139 | .mute = 0x00, | |
140 | .update = 0x180, /* update and zero-cross enable */ | |
141 | }, | |
142 | [WM_VOL_DAC] = { | |
143 | .maxval = 255, | |
144 | .regs = { WM8776_REG_DAC_ATTEN_L, WM8776_REG_DAC_ATTEN_R }, | |
145 | .mask = 0xff, | |
146 | .offset = 0x01, | |
147 | .mute = 0x00, | |
148 | .update = 0x100, /* zero-cross enable */ | |
149 | }, | |
150 | [WM_VOL_ADC] = { | |
151 | .maxval = 91, | |
152 | .regs = { WM8776_REG_ADC_ATTEN_L, WM8776_REG_ADC_ATTEN_R }, | |
153 | .mask = 0xff, | |
154 | .offset = 0xa5, | |
155 | .mute = 0xa5, | |
156 | .update = 0x100, /* update */ | |
157 | .mux_bits = { 0x80, 0x40 }, /* ADCMUX bits */ | |
158 | }, | |
159 | }; | |
160 | ||
161 | /* | |
162 | * dB tables | |
163 | */ | |
164 | /* headphone output: mute, -73..+6db (1db step) */ | |
165 | static const DECLARE_TLV_DB_SCALE(db_scale_hp, -7400, 100, 1); | |
166 | /* DAC output: mute, -127..0db (0.5db step) */ | |
167 | static const DECLARE_TLV_DB_SCALE(db_scale_dac, -12750, 50, 1); | |
168 | /* ADC gain: mute, -21..+24db (0.5db step) */ | |
169 | static const DECLARE_TLV_DB_SCALE(db_scale_adc, -2100, 50, 1); | |
170 | ||
171 | static int maya_vol_info(struct snd_kcontrol *kcontrol, | |
172 | struct snd_ctl_elem_info *uinfo) | |
173 | { | |
174 | unsigned int idx = kcontrol->private_value; | |
175 | struct maya_vol_info *vol = &vol_info[idx]; | |
176 | ||
177 | uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER; | |
178 | uinfo->count = 2; | |
179 | uinfo->value.integer.min = 0; | |
180 | uinfo->value.integer.max = vol->maxval; | |
181 | return 0; | |
182 | } | |
183 | ||
184 | static int maya_vol_get(struct snd_kcontrol *kcontrol, | |
185 | struct snd_ctl_elem_value *ucontrol) | |
186 | { | |
187 | struct snd_maya44 *chip = snd_kcontrol_chip(kcontrol); | |
188 | struct snd_wm8776 *wm = | |
189 | &chip->wm[snd_ctl_get_ioff(kcontrol, &ucontrol->id)]; | |
190 | unsigned int idx = kcontrol->private_value; | |
191 | ||
192 | mutex_lock(&chip->mutex); | |
193 | ucontrol->value.integer.value[0] = wm->volumes[idx][0]; | |
194 | ucontrol->value.integer.value[1] = wm->volumes[idx][1]; | |
195 | mutex_unlock(&chip->mutex); | |
196 | return 0; | |
197 | } | |
198 | ||
199 | static int maya_vol_put(struct snd_kcontrol *kcontrol, | |
200 | struct snd_ctl_elem_value *ucontrol) | |
201 | { | |
202 | struct snd_maya44 *chip = snd_kcontrol_chip(kcontrol); | |
203 | struct snd_wm8776 *wm = | |
204 | &chip->wm[snd_ctl_get_ioff(kcontrol, &ucontrol->id)]; | |
205 | unsigned int idx = kcontrol->private_value; | |
206 | struct maya_vol_info *vol = &vol_info[idx]; | |
207 | unsigned int val, data; | |
208 | int ch, changed = 0; | |
209 | ||
210 | mutex_lock(&chip->mutex); | |
211 | for (ch = 0; ch < 2; ch++) { | |
212 | val = ucontrol->value.integer.value[ch]; | |
213 | if (val > vol->maxval) | |
214 | val = vol->maxval; | |
215 | if (val == wm->volumes[idx][ch]) | |
216 | continue; | |
217 | if (!val) | |
218 | data = vol->mute; | |
219 | else | |
220 | data = (val - 1) + vol->offset; | |
221 | data |= vol->update; | |
222 | changed |= wm8776_write_bits(chip->ice, wm, vol->regs[ch], | |
223 | vol->mask | vol->update, data); | |
224 | if (vol->mux_bits[ch]) | |
225 | wm8776_write_bits(chip->ice, wm, WM8776_REG_ADC_MUX, | |
226 | vol->mux_bits[ch], | |
227 | val ? 0 : vol->mux_bits[ch]); | |
228 | wm->volumes[idx][ch] = val; | |
229 | } | |
230 | mutex_unlock(&chip->mutex); | |
231 | return changed; | |
232 | } | |
233 | ||
234 | /* | |
235 | * WM8776 switch controls | |
236 | */ | |
237 | ||
238 | #define COMPOSE_SW_VAL(idx, reg, mask) ((idx) | ((reg) << 8) | ((mask) << 16)) | |
239 | #define GET_SW_VAL_IDX(val) ((val) & 0xff) | |
240 | #define GET_SW_VAL_REG(val) (((val) >> 8) & 0xff) | |
241 | #define GET_SW_VAL_MASK(val) (((val) >> 16) & 0xff) | |
242 | ||
243 | #define maya_sw_info snd_ctl_boolean_mono_info | |
244 | ||
245 | static int maya_sw_get(struct snd_kcontrol *kcontrol, | |
246 | struct snd_ctl_elem_value *ucontrol) | |
247 | { | |
248 | struct snd_maya44 *chip = snd_kcontrol_chip(kcontrol); | |
249 | struct snd_wm8776 *wm = | |
250 | &chip->wm[snd_ctl_get_ioff(kcontrol, &ucontrol->id)]; | |
251 | unsigned int idx = GET_SW_VAL_IDX(kcontrol->private_value); | |
252 | ||
253 | ucontrol->value.integer.value[0] = (wm->switch_bits >> idx) & 1; | |
254 | return 0; | |
255 | } | |
256 | ||
257 | static int maya_sw_put(struct snd_kcontrol *kcontrol, | |
258 | struct snd_ctl_elem_value *ucontrol) | |
259 | { | |
260 | struct snd_maya44 *chip = snd_kcontrol_chip(kcontrol); | |
261 | struct snd_wm8776 *wm = | |
262 | &chip->wm[snd_ctl_get_ioff(kcontrol, &ucontrol->id)]; | |
263 | unsigned int idx = GET_SW_VAL_IDX(kcontrol->private_value); | |
264 | unsigned int mask, val; | |
265 | int changed; | |
266 | ||
267 | mutex_lock(&chip->mutex); | |
268 | mask = 1 << idx; | |
269 | wm->switch_bits &= ~mask; | |
270 | val = ucontrol->value.integer.value[0]; | |
271 | if (val) | |
272 | wm->switch_bits |= mask; | |
273 | mask = GET_SW_VAL_MASK(kcontrol->private_value); | |
274 | changed = wm8776_write_bits(chip->ice, wm, | |
275 | GET_SW_VAL_REG(kcontrol->private_value), | |
276 | mask, val ? mask : 0); | |
277 | mutex_unlock(&chip->mutex); | |
278 | return changed; | |
279 | } | |
280 | ||
281 | /* | |
282 | * GPIO pins (known ones for maya44) | |
283 | */ | |
284 | #define GPIO_PHANTOM_OFF 2 | |
285 | #define GPIO_MIC_RELAY 4 | |
286 | #define GPIO_SPDIF_IN_INV 5 | |
287 | #define GPIO_MUST_BE_0 7 | |
288 | ||
289 | /* | |
290 | * GPIO switch controls | |
291 | */ | |
292 | ||
293 | #define COMPOSE_GPIO_VAL(shift, inv) ((shift) | ((inv) << 8)) | |
294 | #define GET_GPIO_VAL_SHIFT(val) ((val) & 0xff) | |
295 | #define GET_GPIO_VAL_INV(val) (((val) >> 8) & 1) | |
296 | ||
297 | static int maya_set_gpio_bits(struct snd_ice1712 *ice, unsigned int mask, | |
298 | unsigned int bits) | |
299 | { | |
300 | unsigned int data; | |
301 | data = snd_ice1712_gpio_read(ice); | |
302 | if ((data & mask) == bits) | |
303 | return 0; | |
304 | snd_ice1712_gpio_write(ice, (data & ~mask) | bits); | |
305 | return 1; | |
306 | } | |
307 | ||
308 | #define maya_gpio_sw_info snd_ctl_boolean_mono_info | |
309 | ||
310 | static int maya_gpio_sw_get(struct snd_kcontrol *kcontrol, | |
311 | struct snd_ctl_elem_value *ucontrol) | |
312 | { | |
313 | struct snd_maya44 *chip = snd_kcontrol_chip(kcontrol); | |
314 | unsigned int shift = GET_GPIO_VAL_SHIFT(kcontrol->private_value); | |
315 | unsigned int val; | |
316 | ||
317 | val = (snd_ice1712_gpio_read(chip->ice) >> shift) & 1; | |
318 | if (GET_GPIO_VAL_INV(kcontrol->private_value)) | |
319 | val = !val; | |
320 | ucontrol->value.integer.value[0] = val; | |
321 | return 0; | |
322 | } | |
323 | ||
324 | static int maya_gpio_sw_put(struct snd_kcontrol *kcontrol, | |
325 | struct snd_ctl_elem_value *ucontrol) | |
326 | { | |
327 | struct snd_maya44 *chip = snd_kcontrol_chip(kcontrol); | |
328 | unsigned int shift = GET_GPIO_VAL_SHIFT(kcontrol->private_value); | |
329 | unsigned int val, mask; | |
330 | int changed; | |
331 | ||
332 | mutex_lock(&chip->mutex); | |
333 | mask = 1 << shift; | |
334 | val = ucontrol->value.integer.value[0]; | |
335 | if (GET_GPIO_VAL_INV(kcontrol->private_value)) | |
336 | val = !val; | |
337 | val = val ? mask : 0; | |
338 | changed = maya_set_gpio_bits(chip->ice, mask, val); | |
339 | mutex_unlock(&chip->mutex); | |
340 | return changed; | |
341 | } | |
342 | ||
343 | /* | |
344 | * capture source selection | |
345 | */ | |
346 | ||
347 | /* known working input slots (0-4) */ | |
348 | #define MAYA_LINE_IN 1 /* in-2 */ | |
82134665 | 349 | #define MAYA_MIC_IN 3 /* in-4 */ |
72cbfd45 TI |
350 | |
351 | static void wm8776_select_input(struct snd_maya44 *chip, int idx, int line) | |
352 | { | |
353 | wm8776_write_bits(chip->ice, &chip->wm[idx], WM8776_REG_ADC_MUX, | |
354 | 0x1f, 1 << line); | |
355 | } | |
356 | ||
357 | static int maya_rec_src_info(struct snd_kcontrol *kcontrol, | |
358 | struct snd_ctl_elem_info *uinfo) | |
359 | { | |
a2af050f | 360 | static const char * const texts[] = { "Line", "Mic" }; |
72cbfd45 | 361 | |
597da2e4 | 362 | return snd_ctl_enum_info(uinfo, 1, ARRAY_SIZE(texts), texts); |
72cbfd45 TI |
363 | } |
364 | ||
365 | static int maya_rec_src_get(struct snd_kcontrol *kcontrol, | |
366 | struct snd_ctl_elem_value *ucontrol) | |
367 | { | |
368 | struct snd_maya44 *chip = snd_kcontrol_chip(kcontrol); | |
369 | int sel; | |
370 | ||
371 | if (snd_ice1712_gpio_read(chip->ice) & (1 << GPIO_MIC_RELAY)) | |
372 | sel = 1; | |
373 | else | |
374 | sel = 0; | |
375 | ucontrol->value.enumerated.item[0] = sel; | |
376 | return 0; | |
377 | } | |
378 | ||
379 | static int maya_rec_src_put(struct snd_kcontrol *kcontrol, | |
380 | struct snd_ctl_elem_value *ucontrol) | |
381 | { | |
382 | struct snd_maya44 *chip = snd_kcontrol_chip(kcontrol); | |
383 | int sel = ucontrol->value.enumerated.item[0]; | |
384 | int changed; | |
385 | ||
386 | mutex_lock(&chip->mutex); | |
82134665 TI |
387 | changed = maya_set_gpio_bits(chip->ice, 1 << GPIO_MIC_RELAY, |
388 | sel ? (1 << GPIO_MIC_RELAY) : 0); | |
72cbfd45 TI |
389 | wm8776_select_input(chip, 0, sel ? MAYA_MIC_IN : MAYA_LINE_IN); |
390 | mutex_unlock(&chip->mutex); | |
391 | return changed; | |
392 | } | |
393 | ||
394 | /* | |
395 | * Maya44 routing switch settings have different meanings than the standard | |
396 | * ice1724 switches as defined in snd_vt1724_pro_route_info (ice1724.c). | |
397 | */ | |
398 | static int maya_pb_route_info(struct snd_kcontrol *kcontrol, | |
399 | struct snd_ctl_elem_info *uinfo) | |
400 | { | |
a2af050f | 401 | static const char * const texts[] = { |
72cbfd45 TI |
402 | "PCM Out", /* 0 */ |
403 | "Input 1", "Input 2", "Input 3", "Input 4" | |
404 | }; | |
405 | ||
597da2e4 | 406 | return snd_ctl_enum_info(uinfo, 1, ARRAY_SIZE(texts), texts); |
72cbfd45 TI |
407 | } |
408 | ||
409 | static int maya_pb_route_shift(int idx) | |
410 | { | |
411 | static const unsigned char shift[10] = | |
412 | { 8, 20, 0, 3, 11, 23, 14, 26, 17, 29 }; | |
413 | return shift[idx % 10]; | |
414 | } | |
415 | ||
416 | static int maya_pb_route_get(struct snd_kcontrol *kcontrol, | |
417 | struct snd_ctl_elem_value *ucontrol) | |
418 | { | |
419 | struct snd_maya44 *chip = snd_kcontrol_chip(kcontrol); | |
420 | int idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id); | |
421 | ucontrol->value.enumerated.item[0] = | |
422 | snd_ice1724_get_route_val(chip->ice, maya_pb_route_shift(idx)); | |
423 | return 0; | |
424 | } | |
425 | ||
426 | static int maya_pb_route_put(struct snd_kcontrol *kcontrol, | |
427 | struct snd_ctl_elem_value *ucontrol) | |
428 | { | |
429 | struct snd_maya44 *chip = snd_kcontrol_chip(kcontrol); | |
430 | int idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id); | |
431 | return snd_ice1724_put_route_val(chip->ice, | |
432 | ucontrol->value.enumerated.item[0], | |
433 | maya_pb_route_shift(idx)); | |
434 | } | |
435 | ||
436 | ||
437 | /* | |
438 | * controls to be added | |
439 | */ | |
440 | ||
e23e7a14 | 441 | static struct snd_kcontrol_new maya_controls[] = { |
72cbfd45 TI |
442 | { |
443 | .name = "Crossmix Playback Volume", | |
444 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | |
445 | .access = SNDRV_CTL_ELEM_ACCESS_READWRITE | | |
446 | SNDRV_CTL_ELEM_ACCESS_TLV_READ, | |
447 | .info = maya_vol_info, | |
448 | .get = maya_vol_get, | |
449 | .put = maya_vol_put, | |
450 | .tlv = { .p = db_scale_hp }, | |
451 | .private_value = WM_VOL_HP, | |
452 | .count = 2, | |
453 | }, | |
454 | { | |
455 | .name = "PCM Playback Volume", | |
456 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | |
457 | .access = SNDRV_CTL_ELEM_ACCESS_READWRITE | | |
458 | SNDRV_CTL_ELEM_ACCESS_TLV_READ, | |
459 | .info = maya_vol_info, | |
460 | .get = maya_vol_get, | |
461 | .put = maya_vol_put, | |
462 | .tlv = { .p = db_scale_dac }, | |
463 | .private_value = WM_VOL_DAC, | |
464 | .count = 2, | |
465 | }, | |
466 | { | |
467 | .name = "Line Capture Volume", | |
468 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | |
469 | .access = SNDRV_CTL_ELEM_ACCESS_READWRITE | | |
470 | SNDRV_CTL_ELEM_ACCESS_TLV_READ, | |
471 | .info = maya_vol_info, | |
472 | .get = maya_vol_get, | |
473 | .put = maya_vol_put, | |
474 | .tlv = { .p = db_scale_adc }, | |
475 | .private_value = WM_VOL_ADC, | |
476 | .count = 2, | |
477 | }, | |
478 | { | |
479 | .name = "PCM Playback Switch", | |
480 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | |
481 | .info = maya_sw_info, | |
482 | .get = maya_sw_get, | |
483 | .put = maya_sw_put, | |
484 | .private_value = COMPOSE_SW_VAL(WM_SW_DAC, | |
485 | WM8776_REG_OUTPUT_MUX, 0x01), | |
486 | .count = 2, | |
487 | }, | |
488 | { | |
489 | .name = "Bypass Playback Switch", | |
490 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | |
491 | .info = maya_sw_info, | |
492 | .get = maya_sw_get, | |
493 | .put = maya_sw_put, | |
494 | .private_value = COMPOSE_SW_VAL(WM_SW_BYPASS, | |
495 | WM8776_REG_OUTPUT_MUX, 0x04), | |
496 | .count = 2, | |
497 | }, | |
498 | { | |
499 | .name = "Capture Source", | |
500 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | |
501 | .info = maya_rec_src_info, | |
502 | .get = maya_rec_src_get, | |
503 | .put = maya_rec_src_put, | |
504 | }, | |
505 | { | |
506 | .name = "Mic Phantom Power Switch", | |
507 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | |
508 | .info = maya_gpio_sw_info, | |
509 | .get = maya_gpio_sw_get, | |
510 | .put = maya_gpio_sw_put, | |
511 | .private_value = COMPOSE_GPIO_VAL(GPIO_PHANTOM_OFF, 1), | |
512 | }, | |
513 | { | |
514 | .name = "SPDIF Capture Switch", | |
515 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | |
516 | .info = maya_gpio_sw_info, | |
517 | .get = maya_gpio_sw_get, | |
518 | .put = maya_gpio_sw_put, | |
519 | .private_value = COMPOSE_GPIO_VAL(GPIO_SPDIF_IN_INV, 1), | |
520 | }, | |
521 | { | |
522 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | |
523 | .name = "H/W Playback Route", | |
524 | .info = maya_pb_route_info, | |
525 | .get = maya_pb_route_get, | |
526 | .put = maya_pb_route_put, | |
527 | .count = 4, /* FIXME: do controls 5-9 have any meaning? */ | |
528 | }, | |
529 | }; | |
530 | ||
e23e7a14 | 531 | static int maya44_add_controls(struct snd_ice1712 *ice) |
72cbfd45 TI |
532 | { |
533 | int err, i; | |
534 | ||
535 | for (i = 0; i < ARRAY_SIZE(maya_controls); i++) { | |
536 | err = snd_ctl_add(ice->card, snd_ctl_new1(&maya_controls[i], | |
537 | ice->spec)); | |
538 | if (err < 0) | |
539 | return err; | |
540 | } | |
541 | return 0; | |
542 | } | |
543 | ||
544 | ||
545 | /* | |
546 | * initialize a wm8776 chip | |
547 | */ | |
e23e7a14 BP |
548 | static void wm8776_init(struct snd_ice1712 *ice, |
549 | struct snd_wm8776 *wm, unsigned int addr) | |
72cbfd45 TI |
550 | { |
551 | static const unsigned short inits_wm8776[] = { | |
552 | 0x02, 0x100, /* R2: headphone L+R muted + update */ | |
553 | 0x05, 0x100, /* R5: DAC output L+R muted + update */ | |
554 | 0x06, 0x000, /* R6: DAC output phase normal */ | |
555 | 0x07, 0x091, /* R7: DAC enable zero cross detection, | |
556 | normal output */ | |
557 | 0x08, 0x000, /* R8: DAC soft mute off */ | |
558 | 0x09, 0x000, /* R9: no deemph, DAC zero detect disabled */ | |
559 | 0x0a, 0x022, /* R10: DAC I2C mode, std polarities, 24bit */ | |
560 | 0x0b, 0x022, /* R11: ADC I2C mode, std polarities, 24bit, | |
561 | highpass filter enabled */ | |
562 | 0x0c, 0x042, /* R12: ADC+DAC slave, ADC+DAC 44,1kHz */ | |
563 | 0x0d, 0x000, /* R13: all power up */ | |
564 | 0x0e, 0x100, /* R14: ADC left muted, | |
565 | enable zero cross detection */ | |
566 | 0x0f, 0x100, /* R15: ADC right muted, | |
567 | enable zero cross detection */ | |
568 | /* R16: ALC...*/ | |
569 | 0x11, 0x000, /* R17: disable ALC */ | |
570 | /* R18: ALC...*/ | |
571 | /* R19: noise gate...*/ | |
572 | 0x15, 0x000, /* R21: ADC input mux init, mute all inputs */ | |
573 | 0x16, 0x001, /* R22: output mux, select DAC */ | |
574 | 0xff, 0xff | |
575 | }; | |
576 | ||
577 | const unsigned short *ptr; | |
578 | unsigned char reg; | |
579 | unsigned short data; | |
580 | ||
581 | wm->addr = addr; | |
582 | /* enable DAC output; mute bypass, aux & all inputs */ | |
583 | wm->switch_bits = (1 << WM_SW_DAC); | |
584 | ||
585 | ptr = inits_wm8776; | |
586 | while (*ptr != 0xff) { | |
587 | reg = *ptr++; | |
588 | data = *ptr++; | |
589 | wm8776_write(ice, wm, reg, data); | |
590 | } | |
591 | } | |
592 | ||
593 | ||
594 | /* | |
595 | * change the rate on the WM8776 codecs. | |
596 | * this assumes that the VT17xx's rate is changed by the calling function. | |
597 | * NOTE: even though the WM8776's are running in slave mode and rate | |
598 | * selection is automatic, we need to call snd_wm8776_set_rate() here | |
599 | * to make sure some flags are set correctly. | |
600 | */ | |
601 | static void set_rate(struct snd_ice1712 *ice, unsigned int rate) | |
602 | { | |
603 | struct snd_maya44 *chip = ice->spec; | |
604 | unsigned int ratio, adc_ratio, val; | |
605 | int i; | |
606 | ||
607 | switch (rate) { | |
608 | case 192000: | |
609 | ratio = WM8776_CLOCK_RATIO_128FS; | |
610 | break; | |
611 | case 176400: | |
612 | ratio = WM8776_CLOCK_RATIO_128FS; | |
613 | break; | |
614 | case 96000: | |
615 | ratio = WM8776_CLOCK_RATIO_256FS; | |
616 | break; | |
617 | case 88200: | |
618 | ratio = WM8776_CLOCK_RATIO_384FS; | |
619 | break; | |
620 | case 48000: | |
621 | ratio = WM8776_CLOCK_RATIO_512FS; | |
622 | break; | |
623 | case 44100: | |
624 | ratio = WM8776_CLOCK_RATIO_512FS; | |
625 | break; | |
626 | case 32000: | |
627 | ratio = WM8776_CLOCK_RATIO_768FS; | |
628 | break; | |
629 | case 0: | |
630 | /* no hint - S/PDIF input is master, simply return */ | |
631 | return; | |
632 | default: | |
633 | snd_BUG(); | |
634 | return; | |
635 | } | |
636 | ||
637 | /* | |
638 | * this currently sets the same rate for ADC and DAC, but limits | |
639 | * ADC rate to 256X (96kHz). For 256X mode (96kHz), this sets ADC | |
640 | * oversampling to 64x, as recommended by WM8776 datasheet. | |
641 | * Setting the rate is not really necessary in slave mode. | |
642 | */ | |
643 | adc_ratio = ratio; | |
644 | if (adc_ratio < WM8776_CLOCK_RATIO_256FS) | |
645 | adc_ratio = WM8776_CLOCK_RATIO_256FS; | |
646 | ||
647 | val = adc_ratio; | |
648 | if (adc_ratio == WM8776_CLOCK_RATIO_256FS) | |
649 | val |= 8; | |
650 | val |= ratio << 4; | |
651 | ||
652 | mutex_lock(&chip->mutex); | |
653 | for (i = 0; i < 2; i++) | |
654 | wm8776_write_bits(ice, &chip->wm[i], | |
655 | WM8776_REG_MASTER_MODE_CONTROL, | |
656 | 0x180, val); | |
657 | mutex_unlock(&chip->mutex); | |
658 | } | |
659 | ||
660 | /* | |
661 | * supported sample rates (to override the default one) | |
662 | */ | |
663 | ||
664 | static unsigned int rates[] = { | |
665 | 32000, 44100, 48000, 64000, 88200, 96000, 176400, 192000 | |
666 | }; | |
667 | ||
668 | /* playback rates: 32..192 kHz */ | |
669 | static struct snd_pcm_hw_constraint_list dac_rates = { | |
670 | .count = ARRAY_SIZE(rates), | |
671 | .list = rates, | |
672 | .mask = 0 | |
673 | }; | |
674 | ||
675 | ||
676 | /* | |
677 | * chip addresses on I2C bus | |
678 | */ | |
e23e7a14 | 679 | static unsigned char wm8776_addr[2] = { |
72cbfd45 TI |
680 | 0x34, 0x36, /* codec 0 & 1 */ |
681 | }; | |
682 | ||
683 | /* | |
684 | * initialize the chip | |
685 | */ | |
e23e7a14 | 686 | static int maya44_init(struct snd_ice1712 *ice) |
72cbfd45 TI |
687 | { |
688 | int i; | |
689 | struct snd_maya44 *chip; | |
690 | ||
691 | chip = kzalloc(sizeof(*chip), GFP_KERNEL); | |
692 | if (!chip) | |
693 | return -ENOMEM; | |
694 | mutex_init(&chip->mutex); | |
695 | chip->ice = ice; | |
696 | ice->spec = chip; | |
697 | ||
698 | /* initialise codecs */ | |
699 | ice->num_total_dacs = 4; | |
700 | ice->num_total_adcs = 4; | |
701 | ice->akm_codecs = 0; | |
702 | ||
703 | for (i = 0; i < 2; i++) { | |
704 | wm8776_init(ice, &chip->wm[i], wm8776_addr[i]); | |
705 | wm8776_select_input(chip, i, MAYA_LINE_IN); | |
706 | } | |
707 | ||
708 | /* set card specific rates */ | |
709 | ice->hw_rates = &dac_rates; | |
710 | ||
711 | /* register change rate notifier */ | |
712 | ice->gpio.set_pro_rate = set_rate; | |
713 | ||
714 | /* RDMA1 (2nd input channel) is used for ADC by default */ | |
715 | ice->force_rdma1 = 1; | |
716 | ||
717 | /* have an own routing control */ | |
718 | ice->own_routing = 1; | |
719 | ||
720 | return 0; | |
721 | } | |
722 | ||
723 | ||
724 | /* | |
725 | * Maya44 boards don't provide the EEPROM data except for the vendor IDs. | |
726 | * hence the driver needs to sets up it properly. | |
727 | */ | |
728 | ||
e23e7a14 | 729 | static unsigned char maya44_eeprom[] = { |
72cbfd45 TI |
730 | [ICE_EEP2_SYSCONF] = 0x45, |
731 | /* clock xin1=49.152MHz, mpu401, 2 stereo ADCs+DACs */ | |
732 | [ICE_EEP2_ACLINK] = 0x80, | |
733 | /* I2S */ | |
734 | [ICE_EEP2_I2S] = 0xf8, | |
735 | /* vol, 96k, 24bit, 192k */ | |
736 | [ICE_EEP2_SPDIF] = 0xc3, | |
737 | /* enable spdif out, spdif out supp, spdif-in, ext spdif out */ | |
738 | [ICE_EEP2_GPIO_DIR] = 0xff, | |
739 | [ICE_EEP2_GPIO_DIR1] = 0xff, | |
740 | [ICE_EEP2_GPIO_DIR2] = 0xff, | |
741 | [ICE_EEP2_GPIO_MASK] = 0/*0x9f*/, | |
742 | [ICE_EEP2_GPIO_MASK1] = 0/*0xff*/, | |
743 | [ICE_EEP2_GPIO_MASK2] = 0/*0x7f*/, | |
744 | [ICE_EEP2_GPIO_STATE] = (1 << GPIO_PHANTOM_OFF) | | |
745 | (1 << GPIO_SPDIF_IN_INV), | |
746 | [ICE_EEP2_GPIO_STATE1] = 0x00, | |
747 | [ICE_EEP2_GPIO_STATE2] = 0x00, | |
748 | }; | |
749 | ||
750 | /* entry point */ | |
e23e7a14 | 751 | struct snd_ice1712_card_info snd_vt1724_maya44_cards[] = { |
72cbfd45 TI |
752 | { |
753 | .subvendor = VT1724_SUBDEVICE_MAYA44, | |
754 | .name = "ESI Maya44", | |
755 | .model = "maya44", | |
756 | .chip_init = maya44_init, | |
757 | .build_controls = maya44_add_controls, | |
758 | .eeprom_size = sizeof(maya44_eeprom), | |
759 | .eeprom_data = maya44_eeprom, | |
760 | }, | |
761 | { } /* terminator */ | |
762 | }; |