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