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 TI |
361 | |
362 | uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED; | |
363 | uinfo->count = 1; | |
364 | uinfo->value.enumerated.items = ARRAY_SIZE(texts); | |
365 | if (uinfo->value.enumerated.item >= uinfo->value.enumerated.items) | |
366 | uinfo->value.enumerated.item = | |
367 | uinfo->value.enumerated.items - 1; | |
368 | strcpy(uinfo->value.enumerated.name, | |
369 | texts[uinfo->value.enumerated.item]); | |
370 | return 0; | |
371 | } | |
372 | ||
373 | static int maya_rec_src_get(struct snd_kcontrol *kcontrol, | |
374 | struct snd_ctl_elem_value *ucontrol) | |
375 | { | |
376 | struct snd_maya44 *chip = snd_kcontrol_chip(kcontrol); | |
377 | int sel; | |
378 | ||
379 | if (snd_ice1712_gpio_read(chip->ice) & (1 << GPIO_MIC_RELAY)) | |
380 | sel = 1; | |
381 | else | |
382 | sel = 0; | |
383 | ucontrol->value.enumerated.item[0] = sel; | |
384 | return 0; | |
385 | } | |
386 | ||
387 | static int maya_rec_src_put(struct snd_kcontrol *kcontrol, | |
388 | struct snd_ctl_elem_value *ucontrol) | |
389 | { | |
390 | struct snd_maya44 *chip = snd_kcontrol_chip(kcontrol); | |
391 | int sel = ucontrol->value.enumerated.item[0]; | |
392 | int changed; | |
393 | ||
394 | mutex_lock(&chip->mutex); | |
82134665 TI |
395 | changed = maya_set_gpio_bits(chip->ice, 1 << GPIO_MIC_RELAY, |
396 | sel ? (1 << GPIO_MIC_RELAY) : 0); | |
72cbfd45 TI |
397 | wm8776_select_input(chip, 0, sel ? MAYA_MIC_IN : MAYA_LINE_IN); |
398 | mutex_unlock(&chip->mutex); | |
399 | return changed; | |
400 | } | |
401 | ||
402 | /* | |
403 | * Maya44 routing switch settings have different meanings than the standard | |
404 | * ice1724 switches as defined in snd_vt1724_pro_route_info (ice1724.c). | |
405 | */ | |
406 | static int maya_pb_route_info(struct snd_kcontrol *kcontrol, | |
407 | struct snd_ctl_elem_info *uinfo) | |
408 | { | |
a2af050f | 409 | static const char * const texts[] = { |
72cbfd45 TI |
410 | "PCM Out", /* 0 */ |
411 | "Input 1", "Input 2", "Input 3", "Input 4" | |
412 | }; | |
413 | ||
414 | uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED; | |
415 | uinfo->count = 1; | |
416 | uinfo->value.enumerated.items = ARRAY_SIZE(texts); | |
417 | if (uinfo->value.enumerated.item >= uinfo->value.enumerated.items) | |
418 | uinfo->value.enumerated.item = | |
419 | uinfo->value.enumerated.items - 1; | |
420 | strcpy(uinfo->value.enumerated.name, | |
421 | texts[uinfo->value.enumerated.item]); | |
422 | return 0; | |
423 | } | |
424 | ||
425 | static int maya_pb_route_shift(int idx) | |
426 | { | |
427 | static const unsigned char shift[10] = | |
428 | { 8, 20, 0, 3, 11, 23, 14, 26, 17, 29 }; | |
429 | return shift[idx % 10]; | |
430 | } | |
431 | ||
432 | static int maya_pb_route_get(struct snd_kcontrol *kcontrol, | |
433 | struct snd_ctl_elem_value *ucontrol) | |
434 | { | |
435 | struct snd_maya44 *chip = snd_kcontrol_chip(kcontrol); | |
436 | int idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id); | |
437 | ucontrol->value.enumerated.item[0] = | |
438 | snd_ice1724_get_route_val(chip->ice, maya_pb_route_shift(idx)); | |
439 | return 0; | |
440 | } | |
441 | ||
442 | static int maya_pb_route_put(struct snd_kcontrol *kcontrol, | |
443 | struct snd_ctl_elem_value *ucontrol) | |
444 | { | |
445 | struct snd_maya44 *chip = snd_kcontrol_chip(kcontrol); | |
446 | int idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id); | |
447 | return snd_ice1724_put_route_val(chip->ice, | |
448 | ucontrol->value.enumerated.item[0], | |
449 | maya_pb_route_shift(idx)); | |
450 | } | |
451 | ||
452 | ||
453 | /* | |
454 | * controls to be added | |
455 | */ | |
456 | ||
e23e7a14 | 457 | static struct snd_kcontrol_new maya_controls[] = { |
72cbfd45 TI |
458 | { |
459 | .name = "Crossmix Playback Volume", | |
460 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | |
461 | .access = SNDRV_CTL_ELEM_ACCESS_READWRITE | | |
462 | SNDRV_CTL_ELEM_ACCESS_TLV_READ, | |
463 | .info = maya_vol_info, | |
464 | .get = maya_vol_get, | |
465 | .put = maya_vol_put, | |
466 | .tlv = { .p = db_scale_hp }, | |
467 | .private_value = WM_VOL_HP, | |
468 | .count = 2, | |
469 | }, | |
470 | { | |
471 | .name = "PCM Playback Volume", | |
472 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | |
473 | .access = SNDRV_CTL_ELEM_ACCESS_READWRITE | | |
474 | SNDRV_CTL_ELEM_ACCESS_TLV_READ, | |
475 | .info = maya_vol_info, | |
476 | .get = maya_vol_get, | |
477 | .put = maya_vol_put, | |
478 | .tlv = { .p = db_scale_dac }, | |
479 | .private_value = WM_VOL_DAC, | |
480 | .count = 2, | |
481 | }, | |
482 | { | |
483 | .name = "Line Capture Volume", | |
484 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | |
485 | .access = SNDRV_CTL_ELEM_ACCESS_READWRITE | | |
486 | SNDRV_CTL_ELEM_ACCESS_TLV_READ, | |
487 | .info = maya_vol_info, | |
488 | .get = maya_vol_get, | |
489 | .put = maya_vol_put, | |
490 | .tlv = { .p = db_scale_adc }, | |
491 | .private_value = WM_VOL_ADC, | |
492 | .count = 2, | |
493 | }, | |
494 | { | |
495 | .name = "PCM Playback Switch", | |
496 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | |
497 | .info = maya_sw_info, | |
498 | .get = maya_sw_get, | |
499 | .put = maya_sw_put, | |
500 | .private_value = COMPOSE_SW_VAL(WM_SW_DAC, | |
501 | WM8776_REG_OUTPUT_MUX, 0x01), | |
502 | .count = 2, | |
503 | }, | |
504 | { | |
505 | .name = "Bypass Playback Switch", | |
506 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | |
507 | .info = maya_sw_info, | |
508 | .get = maya_sw_get, | |
509 | .put = maya_sw_put, | |
510 | .private_value = COMPOSE_SW_VAL(WM_SW_BYPASS, | |
511 | WM8776_REG_OUTPUT_MUX, 0x04), | |
512 | .count = 2, | |
513 | }, | |
514 | { | |
515 | .name = "Capture Source", | |
516 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | |
517 | .info = maya_rec_src_info, | |
518 | .get = maya_rec_src_get, | |
519 | .put = maya_rec_src_put, | |
520 | }, | |
521 | { | |
522 | .name = "Mic Phantom Power Switch", | |
523 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | |
524 | .info = maya_gpio_sw_info, | |
525 | .get = maya_gpio_sw_get, | |
526 | .put = maya_gpio_sw_put, | |
527 | .private_value = COMPOSE_GPIO_VAL(GPIO_PHANTOM_OFF, 1), | |
528 | }, | |
529 | { | |
530 | .name = "SPDIF Capture Switch", | |
531 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | |
532 | .info = maya_gpio_sw_info, | |
533 | .get = maya_gpio_sw_get, | |
534 | .put = maya_gpio_sw_put, | |
535 | .private_value = COMPOSE_GPIO_VAL(GPIO_SPDIF_IN_INV, 1), | |
536 | }, | |
537 | { | |
538 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | |
539 | .name = "H/W Playback Route", | |
540 | .info = maya_pb_route_info, | |
541 | .get = maya_pb_route_get, | |
542 | .put = maya_pb_route_put, | |
543 | .count = 4, /* FIXME: do controls 5-9 have any meaning? */ | |
544 | }, | |
545 | }; | |
546 | ||
e23e7a14 | 547 | static int maya44_add_controls(struct snd_ice1712 *ice) |
72cbfd45 TI |
548 | { |
549 | int err, i; | |
550 | ||
551 | for (i = 0; i < ARRAY_SIZE(maya_controls); i++) { | |
552 | err = snd_ctl_add(ice->card, snd_ctl_new1(&maya_controls[i], | |
553 | ice->spec)); | |
554 | if (err < 0) | |
555 | return err; | |
556 | } | |
557 | return 0; | |
558 | } | |
559 | ||
560 | ||
561 | /* | |
562 | * initialize a wm8776 chip | |
563 | */ | |
e23e7a14 BP |
564 | static void wm8776_init(struct snd_ice1712 *ice, |
565 | struct snd_wm8776 *wm, unsigned int addr) | |
72cbfd45 TI |
566 | { |
567 | static const unsigned short inits_wm8776[] = { | |
568 | 0x02, 0x100, /* R2: headphone L+R muted + update */ | |
569 | 0x05, 0x100, /* R5: DAC output L+R muted + update */ | |
570 | 0x06, 0x000, /* R6: DAC output phase normal */ | |
571 | 0x07, 0x091, /* R7: DAC enable zero cross detection, | |
572 | normal output */ | |
573 | 0x08, 0x000, /* R8: DAC soft mute off */ | |
574 | 0x09, 0x000, /* R9: no deemph, DAC zero detect disabled */ | |
575 | 0x0a, 0x022, /* R10: DAC I2C mode, std polarities, 24bit */ | |
576 | 0x0b, 0x022, /* R11: ADC I2C mode, std polarities, 24bit, | |
577 | highpass filter enabled */ | |
578 | 0x0c, 0x042, /* R12: ADC+DAC slave, ADC+DAC 44,1kHz */ | |
579 | 0x0d, 0x000, /* R13: all power up */ | |
580 | 0x0e, 0x100, /* R14: ADC left muted, | |
581 | enable zero cross detection */ | |
582 | 0x0f, 0x100, /* R15: ADC right muted, | |
583 | enable zero cross detection */ | |
584 | /* R16: ALC...*/ | |
585 | 0x11, 0x000, /* R17: disable ALC */ | |
586 | /* R18: ALC...*/ | |
587 | /* R19: noise gate...*/ | |
588 | 0x15, 0x000, /* R21: ADC input mux init, mute all inputs */ | |
589 | 0x16, 0x001, /* R22: output mux, select DAC */ | |
590 | 0xff, 0xff | |
591 | }; | |
592 | ||
593 | const unsigned short *ptr; | |
594 | unsigned char reg; | |
595 | unsigned short data; | |
596 | ||
597 | wm->addr = addr; | |
598 | /* enable DAC output; mute bypass, aux & all inputs */ | |
599 | wm->switch_bits = (1 << WM_SW_DAC); | |
600 | ||
601 | ptr = inits_wm8776; | |
602 | while (*ptr != 0xff) { | |
603 | reg = *ptr++; | |
604 | data = *ptr++; | |
605 | wm8776_write(ice, wm, reg, data); | |
606 | } | |
607 | } | |
608 | ||
609 | ||
610 | /* | |
611 | * change the rate on the WM8776 codecs. | |
612 | * this assumes that the VT17xx's rate is changed by the calling function. | |
613 | * NOTE: even though the WM8776's are running in slave mode and rate | |
614 | * selection is automatic, we need to call snd_wm8776_set_rate() here | |
615 | * to make sure some flags are set correctly. | |
616 | */ | |
617 | static void set_rate(struct snd_ice1712 *ice, unsigned int rate) | |
618 | { | |
619 | struct snd_maya44 *chip = ice->spec; | |
620 | unsigned int ratio, adc_ratio, val; | |
621 | int i; | |
622 | ||
623 | switch (rate) { | |
624 | case 192000: | |
625 | ratio = WM8776_CLOCK_RATIO_128FS; | |
626 | break; | |
627 | case 176400: | |
628 | ratio = WM8776_CLOCK_RATIO_128FS; | |
629 | break; | |
630 | case 96000: | |
631 | ratio = WM8776_CLOCK_RATIO_256FS; | |
632 | break; | |
633 | case 88200: | |
634 | ratio = WM8776_CLOCK_RATIO_384FS; | |
635 | break; | |
636 | case 48000: | |
637 | ratio = WM8776_CLOCK_RATIO_512FS; | |
638 | break; | |
639 | case 44100: | |
640 | ratio = WM8776_CLOCK_RATIO_512FS; | |
641 | break; | |
642 | case 32000: | |
643 | ratio = WM8776_CLOCK_RATIO_768FS; | |
644 | break; | |
645 | case 0: | |
646 | /* no hint - S/PDIF input is master, simply return */ | |
647 | return; | |
648 | default: | |
649 | snd_BUG(); | |
650 | return; | |
651 | } | |
652 | ||
653 | /* | |
654 | * this currently sets the same rate for ADC and DAC, but limits | |
655 | * ADC rate to 256X (96kHz). For 256X mode (96kHz), this sets ADC | |
656 | * oversampling to 64x, as recommended by WM8776 datasheet. | |
657 | * Setting the rate is not really necessary in slave mode. | |
658 | */ | |
659 | adc_ratio = ratio; | |
660 | if (adc_ratio < WM8776_CLOCK_RATIO_256FS) | |
661 | adc_ratio = WM8776_CLOCK_RATIO_256FS; | |
662 | ||
663 | val = adc_ratio; | |
664 | if (adc_ratio == WM8776_CLOCK_RATIO_256FS) | |
665 | val |= 8; | |
666 | val |= ratio << 4; | |
667 | ||
668 | mutex_lock(&chip->mutex); | |
669 | for (i = 0; i < 2; i++) | |
670 | wm8776_write_bits(ice, &chip->wm[i], | |
671 | WM8776_REG_MASTER_MODE_CONTROL, | |
672 | 0x180, val); | |
673 | mutex_unlock(&chip->mutex); | |
674 | } | |
675 | ||
676 | /* | |
677 | * supported sample rates (to override the default one) | |
678 | */ | |
679 | ||
680 | static unsigned int rates[] = { | |
681 | 32000, 44100, 48000, 64000, 88200, 96000, 176400, 192000 | |
682 | }; | |
683 | ||
684 | /* playback rates: 32..192 kHz */ | |
685 | static struct snd_pcm_hw_constraint_list dac_rates = { | |
686 | .count = ARRAY_SIZE(rates), | |
687 | .list = rates, | |
688 | .mask = 0 | |
689 | }; | |
690 | ||
691 | ||
692 | /* | |
693 | * chip addresses on I2C bus | |
694 | */ | |
e23e7a14 | 695 | static unsigned char wm8776_addr[2] = { |
72cbfd45 TI |
696 | 0x34, 0x36, /* codec 0 & 1 */ |
697 | }; | |
698 | ||
699 | /* | |
700 | * initialize the chip | |
701 | */ | |
e23e7a14 | 702 | static int maya44_init(struct snd_ice1712 *ice) |
72cbfd45 TI |
703 | { |
704 | int i; | |
705 | struct snd_maya44 *chip; | |
706 | ||
707 | chip = kzalloc(sizeof(*chip), GFP_KERNEL); | |
708 | if (!chip) | |
709 | return -ENOMEM; | |
710 | mutex_init(&chip->mutex); | |
711 | chip->ice = ice; | |
712 | ice->spec = chip; | |
713 | ||
714 | /* initialise codecs */ | |
715 | ice->num_total_dacs = 4; | |
716 | ice->num_total_adcs = 4; | |
717 | ice->akm_codecs = 0; | |
718 | ||
719 | for (i = 0; i < 2; i++) { | |
720 | wm8776_init(ice, &chip->wm[i], wm8776_addr[i]); | |
721 | wm8776_select_input(chip, i, MAYA_LINE_IN); | |
722 | } | |
723 | ||
724 | /* set card specific rates */ | |
725 | ice->hw_rates = &dac_rates; | |
726 | ||
727 | /* register change rate notifier */ | |
728 | ice->gpio.set_pro_rate = set_rate; | |
729 | ||
730 | /* RDMA1 (2nd input channel) is used for ADC by default */ | |
731 | ice->force_rdma1 = 1; | |
732 | ||
733 | /* have an own routing control */ | |
734 | ice->own_routing = 1; | |
735 | ||
736 | return 0; | |
737 | } | |
738 | ||
739 | ||
740 | /* | |
741 | * Maya44 boards don't provide the EEPROM data except for the vendor IDs. | |
742 | * hence the driver needs to sets up it properly. | |
743 | */ | |
744 | ||
e23e7a14 | 745 | static unsigned char maya44_eeprom[] = { |
72cbfd45 TI |
746 | [ICE_EEP2_SYSCONF] = 0x45, |
747 | /* clock xin1=49.152MHz, mpu401, 2 stereo ADCs+DACs */ | |
748 | [ICE_EEP2_ACLINK] = 0x80, | |
749 | /* I2S */ | |
750 | [ICE_EEP2_I2S] = 0xf8, | |
751 | /* vol, 96k, 24bit, 192k */ | |
752 | [ICE_EEP2_SPDIF] = 0xc3, | |
753 | /* enable spdif out, spdif out supp, spdif-in, ext spdif out */ | |
754 | [ICE_EEP2_GPIO_DIR] = 0xff, | |
755 | [ICE_EEP2_GPIO_DIR1] = 0xff, | |
756 | [ICE_EEP2_GPIO_DIR2] = 0xff, | |
757 | [ICE_EEP2_GPIO_MASK] = 0/*0x9f*/, | |
758 | [ICE_EEP2_GPIO_MASK1] = 0/*0xff*/, | |
759 | [ICE_EEP2_GPIO_MASK2] = 0/*0x7f*/, | |
760 | [ICE_EEP2_GPIO_STATE] = (1 << GPIO_PHANTOM_OFF) | | |
761 | (1 << GPIO_SPDIF_IN_INV), | |
762 | [ICE_EEP2_GPIO_STATE1] = 0x00, | |
763 | [ICE_EEP2_GPIO_STATE2] = 0x00, | |
764 | }; | |
765 | ||
766 | /* entry point */ | |
e23e7a14 | 767 | struct snd_ice1712_card_info snd_vt1724_maya44_cards[] = { |
72cbfd45 TI |
768 | { |
769 | .subvendor = VT1724_SUBDEVICE_MAYA44, | |
770 | .name = "ESI Maya44", | |
771 | .model = "maya44", | |
772 | .chip_init = maya44_init, | |
773 | .build_controls = maya44_add_controls, | |
774 | .eeprom_size = sizeof(maya44_eeprom), | |
775 | .eeprom_data = maya44_eeprom, | |
776 | }, | |
777 | { } /* terminator */ | |
778 | }; |