Commit | Line | Data |
---|---|---|
1da177e4 LT |
1 | /* |
2 | * ALSA driver for ICEnsemble VT1724 (Envy24HT) | |
3 | * | |
4 | * Lowlevel functions for AudioTrak Prodigy 192 cards | |
7d4b4380 PH |
5 | * Supported IEC958 input from optional MI/ODI/O add-on card. |
6 | * | |
7 | * Specifics (SW, HW): | |
8 | * ------------------- | |
9 | * * 49.5MHz crystal | |
10 | * * SPDIF-OUT on the card: | |
11 | * - coax (through isolation transformer)/toslink supplied by | |
12 | * 74HC04 gates - 3 in parallel | |
13 | * - output switched between on-board CD drive dig-out connector | |
14 | * and ice1724 SPDTX pin, using 74HC02 NOR gates, controlled | |
15 | * by GPIO20 (0 = CD dig-out, 1 = SPDTX) | |
16 | * * SPDTX goes straight to MI/ODI/O card's SPDIF-OUT coax | |
17 | * | |
18 | * * MI/ODI/O card: AK4114 based, used for iec958 input only | |
19 | * - toslink input -> RX0 | |
20 | * - coax input -> RX1 | |
21 | * - 4wire protocol: | |
22 | * AK4114 ICE1724 | |
23 | * ------------------------------ | |
24 | * CDTO (pin 32) -- GPIO11 pin 86 | |
25 | * CDTI (pin 33) -- GPIO10 pin 77 | |
26 | * CCLK (pin 34) -- GPIO9 pin 76 | |
27 | * CSN (pin 35) -- GPIO8 pin 75 | |
28 | * - output data Mode 7 (24bit, I2S, slave) | |
c5a30f85 PH |
29 | * - both MCKO1 and MCKO2 of ak4114 are fed to FPGA, which |
30 | * outputs master clock to SPMCLKIN of ice1724. | |
31 | * Experimentally I found out that only a combination of | |
32 | * OCKS0=1, OCKS1=1 (128fs, 64fs output) and ice1724 - | |
33 | * VT1724_MT_I2S_MCLK_128X=0 (256fs input) yields correct | |
34 | * sampling rate. That means the the FPGA doubles the | |
35 | * MCK01 rate. | |
1da177e4 LT |
36 | * |
37 | * Copyright (c) 2003 Takashi Iwai <tiwai@suse.de> | |
38 | * Copyright (c) 2003 Dimitromanolakis Apostolos <apostol@cs.utoronto.ca> | |
39 | * Copyright (c) 2004 Kouichi ONO <co2b@ceres.dti.ne.jp> | |
40 | * | |
41 | * This program is free software; you can redistribute it and/or modify | |
42 | * it under the terms of the GNU General Public License as published by | |
43 | * the Free Software Foundation; either version 2 of the License, or | |
44 | * (at your option) any later version. | |
45 | * | |
46 | * This program is distributed in the hope that it will be useful, | |
47 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
48 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
49 | * GNU General Public License for more details. | |
50 | * | |
51 | * You should have received a copy of the GNU General Public License | |
52 | * along with this program; if not, write to the Free Software | |
53 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | |
54 | * | |
55 | */ | |
56 | ||
1da177e4 LT |
57 | #include <linux/delay.h> |
58 | #include <linux/interrupt.h> | |
59 | #include <linux/init.h> | |
60 | #include <linux/slab.h> | |
61 | #include <sound/core.h> | |
62 | ||
63 | #include "ice1712.h" | |
64 | #include "envy24ht.h" | |
65 | #include "prodigy192.h" | |
66 | #include "stac946x.h" | |
f640c320 | 67 | #include <sound/tlv.h> |
1da177e4 | 68 | |
7cda8ba9 TI |
69 | struct prodigy192_spec { |
70 | struct ak4114 *ak4114; | |
71 | /* rate change needs atomic mute/unmute of all dacs*/ | |
72 | struct mutex mute_mutex; | |
73 | }; | |
74 | ||
ab0c7d72 | 75 | static inline void stac9460_put(struct snd_ice1712 *ice, int reg, unsigned char val) |
1da177e4 LT |
76 | { |
77 | snd_vt1724_write_i2c(ice, PRODIGY192_STAC9460_ADDR, reg, val); | |
78 | } | |
79 | ||
ab0c7d72 | 80 | static inline unsigned char stac9460_get(struct snd_ice1712 *ice, int reg) |
1da177e4 LT |
81 | { |
82 | return snd_vt1724_read_i2c(ice, PRODIGY192_STAC9460_ADDR, reg); | |
83 | } | |
84 | ||
85 | /* | |
86 | * DAC mute control | |
87 | */ | |
6632d64b PH |
88 | |
89 | /* | |
90 | * idx = STAC9460 volume register number, mute: 0 = mute, 1 = unmute | |
91 | */ | |
92 | static int stac9460_dac_mute(struct snd_ice1712 *ice, int idx, | |
93 | unsigned char mute) | |
94 | { | |
95 | unsigned char new, old; | |
96 | int change; | |
97 | old = stac9460_get(ice, idx); | |
98 | new = (~mute << 7 & 0x80) | (old & ~0x80); | |
99 | change = (new != old); | |
100 | if (change) | |
6dfb5aff | 101 | /* dev_dbg(ice->card->dev, "Volume register 0x%02x: 0x%02x\n", idx, new);*/ |
6632d64b PH |
102 | stac9460_put(ice, idx, new); |
103 | return change; | |
104 | } | |
105 | ||
a5ce8890 | 106 | #define stac9460_dac_mute_info snd_ctl_boolean_mono_info |
1da177e4 | 107 | |
ab0c7d72 | 108 | static int stac9460_dac_mute_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) |
1da177e4 | 109 | { |
ab0c7d72 | 110 | struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol); |
1da177e4 LT |
111 | unsigned char val; |
112 | int idx; | |
113 | ||
114 | if (kcontrol->private_value) | |
115 | idx = STAC946X_MASTER_VOLUME; | |
116 | else | |
117 | idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id) + STAC946X_LF_VOLUME; | |
118 | val = stac9460_get(ice, idx); | |
119 | ucontrol->value.integer.value[0] = (~val >> 7) & 0x1; | |
120 | return 0; | |
121 | } | |
122 | ||
ab0c7d72 | 123 | static int stac9460_dac_mute_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) |
1da177e4 | 124 | { |
ab0c7d72 | 125 | struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol); |
7cda8ba9 | 126 | struct prodigy192_spec *spec = ice->spec; |
6632d64b | 127 | int idx, change; |
1da177e4 LT |
128 | |
129 | if (kcontrol->private_value) | |
130 | idx = STAC946X_MASTER_VOLUME; | |
131 | else | |
132 | idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id) + STAC946X_LF_VOLUME; | |
6632d64b | 133 | /* due to possible conflicts with stac9460_set_rate_val, mutexing */ |
7cda8ba9 | 134 | mutex_lock(&spec->mute_mutex); |
e2ea7cfc | 135 | /* |
6dfb5aff | 136 | dev_dbg(ice->card->dev, "Mute put: reg 0x%02x, ctrl value: 0x%02x\n", idx, |
e2ea7cfc TI |
137 | ucontrol->value.integer.value[0]); |
138 | */ | |
6632d64b | 139 | change = stac9460_dac_mute(ice, idx, ucontrol->value.integer.value[0]); |
7cda8ba9 | 140 | mutex_unlock(&spec->mute_mutex); |
1da177e4 LT |
141 | return change; |
142 | } | |
143 | ||
144 | /* | |
145 | * DAC volume attenuation mixer control | |
146 | */ | |
ab0c7d72 | 147 | static int stac9460_dac_vol_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo) |
1da177e4 LT |
148 | { |
149 | uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER; | |
150 | uinfo->count = 1; | |
151 | uinfo->value.integer.min = 0; /* mute */ | |
152 | uinfo->value.integer.max = 0x7f; /* 0dB */ | |
153 | return 0; | |
154 | } | |
155 | ||
ab0c7d72 | 156 | static int stac9460_dac_vol_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) |
1da177e4 | 157 | { |
ab0c7d72 | 158 | struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol); |
1da177e4 LT |
159 | int idx; |
160 | unsigned char vol; | |
161 | ||
162 | if (kcontrol->private_value) | |
163 | idx = STAC946X_MASTER_VOLUME; | |
164 | else | |
165 | idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id) + STAC946X_LF_VOLUME; | |
166 | vol = stac9460_get(ice, idx) & 0x7f; | |
167 | ucontrol->value.integer.value[0] = 0x7f - vol; | |
168 | ||
169 | return 0; | |
170 | } | |
171 | ||
ab0c7d72 | 172 | static int stac9460_dac_vol_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) |
1da177e4 | 173 | { |
ab0c7d72 | 174 | struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol); |
1da177e4 LT |
175 | int idx; |
176 | unsigned char tmp, ovol, nvol; | |
177 | int change; | |
178 | ||
179 | if (kcontrol->private_value) | |
180 | idx = STAC946X_MASTER_VOLUME; | |
181 | else | |
182 | idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id) + STAC946X_LF_VOLUME; | |
183 | nvol = ucontrol->value.integer.value[0]; | |
184 | tmp = stac9460_get(ice, idx); | |
185 | ovol = 0x7f - (tmp & 0x7f); | |
186 | change = (ovol != nvol); | |
187 | if (change) { | |
6632d64b | 188 | ovol = (0x7f - nvol) | (tmp & 0x80); |
e2ea7cfc | 189 | /* |
6dfb5aff | 190 | dev_dbg(ice->card->dev, "DAC Volume: reg 0x%02x: 0x%02x\n", |
e2ea7cfc TI |
191 | idx, ovol); |
192 | */ | |
1da177e4 LT |
193 | stac9460_put(ice, idx, (0x7f - nvol) | (tmp & 0x80)); |
194 | } | |
195 | return change; | |
196 | } | |
197 | ||
198 | /* | |
199 | * ADC mute control | |
200 | */ | |
a5ce8890 | 201 | #define stac9460_adc_mute_info snd_ctl_boolean_stereo_info |
1da177e4 | 202 | |
ab0c7d72 | 203 | static int stac9460_adc_mute_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) |
1da177e4 | 204 | { |
ab0c7d72 | 205 | struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol); |
1da177e4 LT |
206 | unsigned char val; |
207 | int i; | |
208 | ||
209 | for (i = 0; i < 2; ++i) { | |
210 | val = stac9460_get(ice, STAC946X_MIC_L_VOLUME + i); | |
211 | ucontrol->value.integer.value[i] = ~val>>7 & 0x1; | |
212 | } | |
213 | ||
214 | return 0; | |
215 | } | |
216 | ||
ab0c7d72 | 217 | static int stac9460_adc_mute_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) |
1da177e4 | 218 | { |
ab0c7d72 | 219 | struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol); |
1da177e4 LT |
220 | unsigned char new, old; |
221 | int i, reg; | |
222 | int change; | |
223 | ||
224 | for (i = 0; i < 2; ++i) { | |
225 | reg = STAC946X_MIC_L_VOLUME + i; | |
226 | old = stac9460_get(ice, reg); | |
227 | new = (~ucontrol->value.integer.value[i]<<7&0x80) | (old&~0x80); | |
228 | change = (new != old); | |
229 | if (change) | |
230 | stac9460_put(ice, reg, new); | |
231 | } | |
232 | ||
233 | return change; | |
234 | } | |
235 | ||
236 | /* | |
237 | * ADC gain mixer control | |
238 | */ | |
ab0c7d72 | 239 | static int stac9460_adc_vol_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo) |
1da177e4 LT |
240 | { |
241 | uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER; | |
242 | uinfo->count = 2; | |
243 | uinfo->value.integer.min = 0; /* 0dB */ | |
244 | uinfo->value.integer.max = 0x0f; /* 22.5dB */ | |
245 | return 0; | |
246 | } | |
247 | ||
ab0c7d72 | 248 | static int stac9460_adc_vol_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) |
1da177e4 | 249 | { |
ab0c7d72 | 250 | struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol); |
1da177e4 LT |
251 | int i, reg; |
252 | unsigned char vol; | |
253 | ||
254 | for (i = 0; i < 2; ++i) { | |
255 | reg = STAC946X_MIC_L_VOLUME + i; | |
256 | vol = stac9460_get(ice, reg) & 0x0f; | |
257 | ucontrol->value.integer.value[i] = 0x0f - vol; | |
258 | } | |
259 | ||
260 | return 0; | |
261 | } | |
262 | ||
ab0c7d72 | 263 | static int stac9460_adc_vol_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) |
1da177e4 | 264 | { |
ab0c7d72 | 265 | struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol); |
1da177e4 LT |
266 | int i, reg; |
267 | unsigned char ovol, nvol; | |
268 | int change; | |
269 | ||
270 | for (i = 0; i < 2; ++i) { | |
271 | reg = STAC946X_MIC_L_VOLUME + i; | |
9cd17cd2 | 272 | nvol = ucontrol->value.integer.value[i] & 0x0f; |
1da177e4 LT |
273 | ovol = 0x0f - stac9460_get(ice, reg); |
274 | change = ((ovol & 0x0f) != nvol); | |
275 | if (change) | |
276 | stac9460_put(ice, reg, (0x0f - nvol) | (ovol & ~0x0f)); | |
277 | } | |
278 | ||
279 | return change; | |
280 | } | |
281 | ||
7d4b4380 PH |
282 | static int stac9460_mic_sw_info(struct snd_kcontrol *kcontrol, |
283 | struct snd_ctl_elem_info *uinfo) | |
284 | { | |
a2af050f | 285 | static const char * const texts[2] = { "Line In", "Mic" }; |
7d4b4380 | 286 | |
597da2e4 | 287 | return snd_ctl_enum_info(uinfo, 1, 2, texts); |
7d4b4380 PH |
288 | } |
289 | ||
290 | ||
291 | static int stac9460_mic_sw_get(struct snd_kcontrol *kcontrol, | |
292 | struct snd_ctl_elem_value *ucontrol) | |
293 | { | |
294 | struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol); | |
295 | unsigned char val; | |
296 | ||
297 | val = stac9460_get(ice, STAC946X_GENERAL_PURPOSE); | |
298 | ucontrol->value.enumerated.item[0] = (val >> 7) & 0x1; | |
299 | return 0; | |
300 | } | |
301 | ||
302 | static int stac9460_mic_sw_put(struct snd_kcontrol *kcontrol, | |
303 | struct snd_ctl_elem_value *ucontrol) | |
304 | { | |
305 | struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol); | |
306 | unsigned char new, old; | |
307 | int change; | |
308 | old = stac9460_get(ice, STAC946X_GENERAL_PURPOSE); | |
309 | new = (ucontrol->value.enumerated.item[0] << 7 & 0x80) | (old & ~0x80); | |
310 | change = (new != old); | |
311 | if (change) | |
312 | stac9460_put(ice, STAC946X_GENERAL_PURPOSE, new); | |
313 | return change; | |
314 | } | |
6632d64b PH |
315 | /* |
316 | * Handler for setting correct codec rate - called when rate change is detected | |
317 | */ | |
841b23d4 | 318 | static void stac9460_set_rate_val(struct snd_ice1712 *ice, unsigned int rate) |
6632d64b PH |
319 | { |
320 | unsigned char old, new; | |
321 | int idx; | |
322 | unsigned char changed[7]; | |
7cda8ba9 | 323 | struct prodigy192_spec *spec = ice->spec; |
6632d64b PH |
324 | |
325 | if (rate == 0) /* no hint - S/PDIF input is master, simply return */ | |
326 | return; | |
327 | else if (rate <= 48000) | |
328 | new = 0x08; /* 256x, base rate mode */ | |
329 | else if (rate <= 96000) | |
330 | new = 0x11; /* 256x, mid rate mode */ | |
331 | else | |
332 | new = 0x12; /* 128x, high rate mode */ | |
333 | old = stac9460_get(ice, STAC946X_MASTER_CLOCKING); | |
334 | if (old == new) | |
335 | return; | |
336 | /* change detected, setting master clock, muting first */ | |
337 | /* due to possible conflicts with mute controls - mutexing */ | |
7cda8ba9 | 338 | mutex_lock(&spec->mute_mutex); |
6632d64b PH |
339 | /* we have to remember current mute status for each DAC */ |
340 | for (idx = 0; idx < 7 ; ++idx) | |
341 | changed[idx] = stac9460_dac_mute(ice, | |
342 | STAC946X_MASTER_VOLUME + idx, 0); | |
6dfb5aff | 343 | /*dev_dbg(ice->card->dev, "Rate change: %d, new MC: 0x%02x\n", rate, new);*/ |
6632d64b PH |
344 | stac9460_put(ice, STAC946X_MASTER_CLOCKING, new); |
345 | udelay(10); | |
346 | /* unmuting - only originally unmuted dacs - | |
347 | * i.e. those changed when muting */ | |
348 | for (idx = 0; idx < 7 ; ++idx) { | |
349 | if (changed[idx]) | |
350 | stac9460_dac_mute(ice, STAC946X_MASTER_VOLUME + idx, 1); | |
351 | } | |
7cda8ba9 | 352 | mutex_unlock(&spec->mute_mutex); |
6632d64b PH |
353 | } |
354 | ||
1da177e4 | 355 | |
0cb29ea0 TI |
356 | static const DECLARE_TLV_DB_SCALE(db_scale_dac, -19125, 75, 0); |
357 | static const DECLARE_TLV_DB_SCALE(db_scale_adc, 0, 150, 0); | |
f640c320 | 358 | |
1da177e4 LT |
359 | /* |
360 | * mixers | |
361 | */ | |
362 | ||
e23e7a14 | 363 | static struct snd_kcontrol_new stac_controls[] = { |
1da177e4 LT |
364 | { |
365 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | |
366 | .name = "Master Playback Switch", | |
367 | .info = stac9460_dac_mute_info, | |
368 | .get = stac9460_dac_mute_get, | |
369 | .put = stac9460_dac_mute_put, | |
370 | .private_value = 1, | |
f640c320 | 371 | .tlv = { .p = db_scale_dac } |
1da177e4 LT |
372 | }, |
373 | { | |
374 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | |
f640c320 TI |
375 | .access = (SNDRV_CTL_ELEM_ACCESS_READWRITE | |
376 | SNDRV_CTL_ELEM_ACCESS_TLV_READ), | |
1da177e4 LT |
377 | .name = "Master Playback Volume", |
378 | .info = stac9460_dac_vol_info, | |
379 | .get = stac9460_dac_vol_get, | |
380 | .put = stac9460_dac_vol_put, | |
381 | .private_value = 1, | |
f640c320 | 382 | .tlv = { .p = db_scale_dac } |
1da177e4 LT |
383 | }, |
384 | { | |
385 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | |
386 | .name = "DAC Switch", | |
387 | .count = 6, | |
388 | .info = stac9460_dac_mute_info, | |
389 | .get = stac9460_dac_mute_get, | |
390 | .put = stac9460_dac_mute_put, | |
391 | }, | |
392 | { | |
393 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | |
f640c320 TI |
394 | .access = (SNDRV_CTL_ELEM_ACCESS_READWRITE | |
395 | SNDRV_CTL_ELEM_ACCESS_TLV_READ), | |
1da177e4 LT |
396 | .name = "DAC Volume", |
397 | .count = 6, | |
398 | .info = stac9460_dac_vol_info, | |
399 | .get = stac9460_dac_vol_get, | |
400 | .put = stac9460_dac_vol_put, | |
f640c320 | 401 | .tlv = { .p = db_scale_dac } |
1da177e4 LT |
402 | }, |
403 | { | |
404 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | |
7d4b4380 | 405 | .name = "ADC Capture Switch", |
1da177e4 LT |
406 | .count = 1, |
407 | .info = stac9460_adc_mute_info, | |
408 | .get = stac9460_adc_mute_get, | |
409 | .put = stac9460_adc_mute_put, | |
410 | ||
411 | }, | |
412 | { | |
413 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | |
f640c320 TI |
414 | .access = (SNDRV_CTL_ELEM_ACCESS_READWRITE | |
415 | SNDRV_CTL_ELEM_ACCESS_TLV_READ), | |
7d4b4380 | 416 | .name = "ADC Capture Volume", |
1da177e4 LT |
417 | .count = 1, |
418 | .info = stac9460_adc_vol_info, | |
419 | .get = stac9460_adc_vol_get, | |
420 | .put = stac9460_adc_vol_put, | |
f640c320 | 421 | .tlv = { .p = db_scale_adc } |
1da177e4 | 422 | }, |
7d4b4380 PH |
423 | { |
424 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | |
425 | .name = "Analog Capture Input", | |
426 | .info = stac9460_mic_sw_info, | |
427 | .get = stac9460_mic_sw_get, | |
428 | .put = stac9460_mic_sw_put, | |
429 | ||
430 | }, | |
1da177e4 LT |
431 | }; |
432 | ||
7d4b4380 PH |
433 | /* AK4114 - ICE1724 connections on Prodigy192 + MI/ODI/O */ |
434 | /* CDTO (pin 32) -- GPIO11 pin 86 | |
435 | * CDTI (pin 33) -- GPIO10 pin 77 | |
436 | * CCLK (pin 34) -- GPIO9 pin 76 | |
437 | * CSN (pin 35) -- GPIO8 pin 75 | |
438 | */ | |
439 | #define AK4114_ADDR 0x00 /* C1-C0: Chip Address | |
440 | * (According to datasheet fixed to “00”) | |
441 | */ | |
442 | ||
443 | /* | |
444 | * 4wire ak4114 protocol - writing data | |
445 | */ | |
446 | static void write_data(struct snd_ice1712 *ice, unsigned int gpio, | |
447 | unsigned int data, int idx) | |
448 | { | |
449 | for (; idx >= 0; idx--) { | |
450 | /* drop clock */ | |
451 | gpio &= ~VT1724_PRODIGY192_CCLK; | |
452 | snd_ice1712_gpio_write(ice, gpio); | |
453 | udelay(1); | |
454 | /* set data */ | |
455 | if (data & (1 << idx)) | |
456 | gpio |= VT1724_PRODIGY192_CDOUT; | |
457 | else | |
458 | gpio &= ~VT1724_PRODIGY192_CDOUT; | |
459 | snd_ice1712_gpio_write(ice, gpio); | |
460 | udelay(1); | |
461 | /* raise clock */ | |
462 | gpio |= VT1724_PRODIGY192_CCLK; | |
463 | snd_ice1712_gpio_write(ice, gpio); | |
464 | udelay(1); | |
465 | } | |
466 | } | |
467 | ||
468 | /* | |
469 | * 4wire ak4114 protocol - reading data | |
470 | */ | |
471 | static unsigned char read_data(struct snd_ice1712 *ice, unsigned int gpio, | |
472 | int idx) | |
473 | { | |
474 | unsigned char data = 0; | |
475 | ||
476 | for (; idx >= 0; idx--) { | |
477 | /* drop clock */ | |
478 | gpio &= ~VT1724_PRODIGY192_CCLK; | |
479 | snd_ice1712_gpio_write(ice, gpio); | |
480 | udelay(1); | |
481 | /* read data */ | |
482 | if (snd_ice1712_gpio_read(ice) & VT1724_PRODIGY192_CDIN) | |
483 | data |= (1 << idx); | |
484 | udelay(1); | |
485 | /* raise clock */ | |
486 | gpio |= VT1724_PRODIGY192_CCLK; | |
487 | snd_ice1712_gpio_write(ice, gpio); | |
488 | udelay(1); | |
489 | } | |
490 | return data; | |
491 | } | |
492 | /* | |
493 | * 4wire ak4114 protocol - starting sequence | |
494 | */ | |
495 | static unsigned int prodigy192_4wire_start(struct snd_ice1712 *ice) | |
496 | { | |
497 | unsigned int tmp; | |
498 | ||
499 | snd_ice1712_save_gpio_status(ice); | |
500 | tmp = snd_ice1712_gpio_read(ice); | |
501 | ||
502 | tmp |= VT1724_PRODIGY192_CCLK; /* high at init */ | |
503 | tmp &= ~VT1724_PRODIGY192_CS; /* drop chip select */ | |
504 | snd_ice1712_gpio_write(ice, tmp); | |
505 | udelay(1); | |
506 | return tmp; | |
507 | } | |
508 | ||
509 | /* | |
510 | * 4wire ak4114 protocol - final sequence | |
511 | */ | |
512 | static void prodigy192_4wire_finish(struct snd_ice1712 *ice, unsigned int tmp) | |
513 | { | |
514 | tmp |= VT1724_PRODIGY192_CS; /* raise chip select */ | |
515 | snd_ice1712_gpio_write(ice, tmp); | |
516 | udelay(1); | |
517 | snd_ice1712_restore_gpio_status(ice); | |
518 | } | |
519 | ||
520 | /* | |
521 | * Write data to addr register of ak4114 | |
522 | */ | |
523 | static void prodigy192_ak4114_write(void *private_data, unsigned char addr, | |
524 | unsigned char data) | |
525 | { | |
526 | struct snd_ice1712 *ice = private_data; | |
527 | unsigned int tmp, addrdata; | |
528 | tmp = prodigy192_4wire_start(ice); | |
529 | addrdata = (AK4114_ADDR << 6) | 0x20 | (addr & 0x1f); | |
530 | addrdata = (addrdata << 8) | data; | |
531 | write_data(ice, tmp, addrdata, 15); | |
532 | prodigy192_4wire_finish(ice, tmp); | |
533 | } | |
534 | ||
535 | /* | |
536 | * Read data from addr register of ak4114 | |
537 | */ | |
538 | static unsigned char prodigy192_ak4114_read(void *private_data, | |
539 | unsigned char addr) | |
540 | { | |
541 | struct snd_ice1712 *ice = private_data; | |
542 | unsigned int tmp; | |
543 | unsigned char data; | |
544 | ||
545 | tmp = prodigy192_4wire_start(ice); | |
546 | write_data(ice, tmp, (AK4114_ADDR << 6) | (addr & 0x1f), 7); | |
547 | data = read_data(ice, tmp, 7); | |
548 | prodigy192_4wire_finish(ice, tmp); | |
549 | return data; | |
550 | } | |
551 | ||
552 | ||
553 | static int ak4114_input_sw_info(struct snd_kcontrol *kcontrol, | |
554 | struct snd_ctl_elem_info *uinfo) | |
555 | { | |
a2af050f | 556 | static const char * const texts[2] = { "Toslink", "Coax" }; |
7d4b4380 | 557 | |
597da2e4 | 558 | return snd_ctl_enum_info(uinfo, 1, 2, texts); |
7d4b4380 PH |
559 | } |
560 | ||
561 | ||
562 | static int ak4114_input_sw_get(struct snd_kcontrol *kcontrol, | |
563 | struct snd_ctl_elem_value *ucontrol) | |
564 | { | |
565 | struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol); | |
566 | unsigned char val; | |
567 | ||
568 | val = prodigy192_ak4114_read(ice, AK4114_REG_IO1); | |
569 | /* AK4114_IPS0 bit = 0 -> RX0 = Toslink | |
570 | * AK4114_IPS0 bit = 1 -> RX1 = Coax | |
571 | */ | |
572 | ucontrol->value.enumerated.item[0] = (val & AK4114_IPS0) ? 1 : 0; | |
573 | return 0; | |
574 | } | |
575 | ||
576 | static int ak4114_input_sw_put(struct snd_kcontrol *kcontrol, | |
577 | struct snd_ctl_elem_value *ucontrol) | |
578 | { | |
579 | struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol); | |
580 | unsigned char new, old, itemvalue; | |
581 | int change; | |
582 | ||
583 | old = prodigy192_ak4114_read(ice, AK4114_REG_IO1); | |
584 | /* AK4114_IPS0 could be any bit */ | |
585 | itemvalue = (ucontrol->value.enumerated.item[0]) ? 0xff : 0x00; | |
586 | ||
587 | new = (itemvalue & AK4114_IPS0) | (old & ~AK4114_IPS0); | |
588 | change = (new != old); | |
589 | if (change) | |
590 | prodigy192_ak4114_write(ice, AK4114_REG_IO1, new); | |
591 | return change; | |
592 | } | |
593 | ||
594 | ||
e23e7a14 | 595 | static struct snd_kcontrol_new ak4114_controls[] = { |
7d4b4380 PH |
596 | { |
597 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | |
598 | .name = "MIODIO IEC958 Capture Input", | |
599 | .info = ak4114_input_sw_info, | |
600 | .get = ak4114_input_sw_get, | |
601 | .put = ak4114_input_sw_put, | |
602 | ||
603 | } | |
604 | }; | |
605 | ||
606 | ||
607 | static int prodigy192_ak4114_init(struct snd_ice1712 *ice) | |
608 | { | |
609 | static const unsigned char ak4114_init_vals[] = { | |
610 | AK4114_RST | AK4114_PWN | AK4114_OCKS0 | AK4114_OCKS1, | |
c5a30f85 PH |
611 | /* ice1724 expects I2S and provides clock, |
612 | * DEM0 disables the deemphasis filter | |
613 | */ | |
614 | AK4114_DIF_I24I2S | AK4114_DEM0 , | |
7d4b4380 PH |
615 | AK4114_TX1E, |
616 | AK4114_EFH_1024 | AK4114_DIT, /* default input RX0 */ | |
617 | 0, | |
618 | 0 | |
619 | }; | |
620 | static const unsigned char ak4114_init_txcsb[] = { | |
621 | 0x41, 0x02, 0x2c, 0x00, 0x00 | |
622 | }; | |
7cda8ba9 | 623 | struct prodigy192_spec *spec = ice->spec; |
841b23d4 | 624 | int err; |
7d4b4380 | 625 | |
841b23d4 | 626 | err = snd_ak4114_create(ice->card, |
7d4b4380 PH |
627 | prodigy192_ak4114_read, |
628 | prodigy192_ak4114_write, | |
629 | ak4114_init_vals, ak4114_init_txcsb, | |
7cda8ba9 | 630 | ice, &spec->ak4114); |
841b23d4 PH |
631 | if (err < 0) |
632 | return err; | |
633 | /* AK4114 in Prodigy192 cannot detect external rate correctly. | |
634 | * No reason to stop capture stream due to incorrect checks */ | |
635 | spec->ak4114->check_flags = AK4114_CHECK_NO_RATE; | |
636 | return 0; | |
7d4b4380 PH |
637 | } |
638 | ||
6632d64b PH |
639 | static void stac9460_proc_regs_read(struct snd_info_entry *entry, |
640 | struct snd_info_buffer *buffer) | |
641 | { | |
9fe856e4 | 642 | struct snd_ice1712 *ice = entry->private_data; |
6632d64b PH |
643 | int reg, val; |
644 | /* registers 0x0 - 0x14 */ | |
645 | for (reg = 0; reg <= 0x15; reg++) { | |
646 | val = stac9460_get(ice, reg); | |
647 | snd_iprintf(buffer, "0x%02x = 0x%02x\n", reg, val); | |
648 | } | |
649 | } | |
650 | ||
651 | ||
652 | static void stac9460_proc_init(struct snd_ice1712 *ice) | |
653 | { | |
654 | struct snd_info_entry *entry; | |
655 | if (!snd_card_proc_new(ice->card, "stac9460_codec", &entry)) | |
656 | snd_info_set_text_ops(entry, ice, stac9460_proc_regs_read); | |
657 | } | |
658 | ||
659 | ||
e23e7a14 | 660 | static int prodigy192_add_controls(struct snd_ice1712 *ice) |
1da177e4 | 661 | { |
7cda8ba9 | 662 | struct prodigy192_spec *spec = ice->spec; |
1da177e4 LT |
663 | unsigned int i; |
664 | int err; | |
665 | ||
666 | for (i = 0; i < ARRAY_SIZE(stac_controls); i++) { | |
7d4b4380 PH |
667 | err = snd_ctl_add(ice->card, |
668 | snd_ctl_new1(&stac_controls[i], ice)); | |
669 | if (err < 0) | |
670 | return err; | |
671 | } | |
7cda8ba9 | 672 | if (spec->ak4114) { |
7d4b4380 PH |
673 | /* ak4114 is connected */ |
674 | for (i = 0; i < ARRAY_SIZE(ak4114_controls); i++) { | |
675 | err = snd_ctl_add(ice->card, | |
676 | snd_ctl_new1(&ak4114_controls[i], | |
677 | ice)); | |
678 | if (err < 0) | |
679 | return err; | |
680 | } | |
7cda8ba9 | 681 | err = snd_ak4114_build(spec->ak4114, |
7d4b4380 PH |
682 | NULL, /* ak4114 in MIO/DI/O handles no IEC958 output */ |
683 | ice->pcm->streams[SNDRV_PCM_STREAM_CAPTURE].substream); | |
1da177e4 LT |
684 | if (err < 0) |
685 | return err; | |
686 | } | |
6632d64b | 687 | stac9460_proc_init(ice); |
1da177e4 LT |
688 | return 0; |
689 | } | |
690 | ||
7d4b4380 PH |
691 | /* |
692 | * check for presence of MI/ODI/O add-on card with digital inputs | |
693 | */ | |
694 | static int prodigy192_miodio_exists(struct snd_ice1712 *ice) | |
695 | { | |
696 | ||
697 | unsigned char orig_value; | |
698 | const unsigned char test_data = 0xd1; /* random value */ | |
699 | unsigned char addr = AK4114_REG_INT0_MASK; /* random SAFE address */ | |
700 | int exists = 0; | |
701 | ||
702 | orig_value = prodigy192_ak4114_read(ice, addr); | |
703 | prodigy192_ak4114_write(ice, addr, test_data); | |
704 | if (prodigy192_ak4114_read(ice, addr) == test_data) { | |
705 | /* ak4114 seems to communicate, apparently exists */ | |
706 | /* writing back original value */ | |
707 | prodigy192_ak4114_write(ice, addr, orig_value); | |
708 | exists = 1; | |
709 | } | |
710 | return exists; | |
711 | } | |
1da177e4 LT |
712 | |
713 | /* | |
714 | * initialize the chip | |
715 | */ | |
e23e7a14 | 716 | static int prodigy192_init(struct snd_ice1712 *ice) |
1da177e4 | 717 | { |
32b47da0 | 718 | static const unsigned short stac_inits_prodigy[] = { |
1da177e4 | 719 | STAC946X_RESET, 0, |
6632d64b | 720 | STAC946X_MASTER_CLOCKING, 0x11, |
1da177e4 LT |
721 | /* STAC946X_MASTER_VOLUME, 0, |
722 | STAC946X_LF_VOLUME, 0, | |
723 | STAC946X_RF_VOLUME, 0, | |
724 | STAC946X_LR_VOLUME, 0, | |
725 | STAC946X_RR_VOLUME, 0, | |
726 | STAC946X_CENTER_VOLUME, 0, | |
727 | STAC946X_LFE_VOLUME, 0,*/ | |
728 | (unsigned short)-1 | |
729 | }; | |
32b47da0 | 730 | const unsigned short *p; |
7d4b4380 | 731 | int err = 0; |
7cda8ba9 | 732 | struct prodigy192_spec *spec; |
1da177e4 LT |
733 | |
734 | /* prodigy 192 */ | |
735 | ice->num_total_dacs = 6; | |
736 | ice->num_total_adcs = 2; | |
7d4b4380 | 737 | ice->vt1720 = 0; /* ice1724, e.g. 23 GPIOs */ |
1da177e4 | 738 | |
7cda8ba9 TI |
739 | spec = kzalloc(sizeof(*spec), GFP_KERNEL); |
740 | if (!spec) | |
741 | return -ENOMEM; | |
742 | ice->spec = spec; | |
743 | mutex_init(&spec->mute_mutex); | |
744 | ||
1da177e4 LT |
745 | /* initialize codec */ |
746 | p = stac_inits_prodigy; | |
747 | for (; *p != (unsigned short)-1; p += 2) | |
748 | stac9460_put(ice, p[0], p[1]); | |
841b23d4 | 749 | ice->gpio.set_pro_rate = stac9460_set_rate_val; |
1da177e4 | 750 | |
7d4b4380 PH |
751 | /* MI/ODI/O add on card with AK4114 */ |
752 | if (prodigy192_miodio_exists(ice)) { | |
753 | err = prodigy192_ak4114_init(ice); | |
754 | /* from this moment if err = 0 then | |
7cda8ba9 | 755 | * spec->ak4114 should not be null |
7d4b4380 | 756 | */ |
6dfb5aff TI |
757 | dev_dbg(ice->card->dev, |
758 | "AK4114 initialized with status %d\n", err); | |
7d4b4380 | 759 | } else |
6dfb5aff | 760 | dev_dbg(ice->card->dev, "AK4114 not found\n"); |
7d4b4380 | 761 | |
387417b5 | 762 | return err; |
1da177e4 LT |
763 | } |
764 | ||
765 | ||
766 | /* | |
767 | * Aureon boards don't provide the EEPROM data except for the vendor IDs. | |
768 | * hence the driver needs to sets up it properly. | |
769 | */ | |
770 | ||
e23e7a14 | 771 | static unsigned char prodigy71_eeprom[] = { |
7d4b4380 PH |
772 | [ICE_EEP2_SYSCONF] = 0x6a, /* 49MHz crystal, mpu401, |
773 | * spdif-in+ 1 stereo ADC, | |
774 | * 3 stereo DACs | |
775 | */ | |
189bc171 TI |
776 | [ICE_EEP2_ACLINK] = 0x80, /* I2S */ |
777 | [ICE_EEP2_I2S] = 0xf8, /* vol, 96k, 24bit, 192k */ | |
778 | [ICE_EEP2_SPDIF] = 0xc3, /* out-en, out-int, spdif-in */ | |
779 | [ICE_EEP2_GPIO_DIR] = 0xff, | |
7d4b4380 | 780 | [ICE_EEP2_GPIO_DIR1] = ~(VT1724_PRODIGY192_CDIN >> 8) , |
189bc171 TI |
781 | [ICE_EEP2_GPIO_DIR2] = 0xbf, |
782 | [ICE_EEP2_GPIO_MASK] = 0x00, | |
783 | [ICE_EEP2_GPIO_MASK1] = 0x00, | |
784 | [ICE_EEP2_GPIO_MASK2] = 0x00, | |
785 | [ICE_EEP2_GPIO_STATE] = 0x00, | |
786 | [ICE_EEP2_GPIO_STATE1] = 0x00, | |
7d4b4380 PH |
787 | [ICE_EEP2_GPIO_STATE2] = 0x10, /* GPIO20: 0 = CD drive dig. input |
788 | * passthrough, | |
789 | * 1 = SPDIF-OUT from ice1724 | |
790 | */ | |
1da177e4 LT |
791 | }; |
792 | ||
793 | ||
794 | /* entry point */ | |
e23e7a14 | 795 | struct snd_ice1712_card_info snd_vt1724_prodigy192_cards[] = { |
1da177e4 LT |
796 | { |
797 | .subvendor = VT1724_SUBDEVICE_PRODIGY192VE, | |
798 | .name = "Audiotrak Prodigy 192", | |
799 | .model = "prodigy192", | |
800 | .chip_init = prodigy192_init, | |
801 | .build_controls = prodigy192_add_controls, | |
802 | .eeprom_size = sizeof(prodigy71_eeprom), | |
803 | .eeprom_data = prodigy71_eeprom, | |
804 | }, | |
805 | { } /* terminator */ | |
806 | }; |