]>
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 PH |
286 | |
287 | uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED; | |
288 | uinfo->count = 1; | |
289 | uinfo->value.enumerated.items = 2; | |
290 | ||
291 | if (uinfo->value.enumerated.item >= uinfo->value.enumerated.items) | |
292 | uinfo->value.enumerated.item = uinfo->value.enumerated.items - 1; | |
293 | strcpy(uinfo->value.enumerated.name, texts[uinfo->value.enumerated.item]); | |
294 | ||
295 | return 0; | |
296 | } | |
297 | ||
298 | ||
299 | static int stac9460_mic_sw_get(struct snd_kcontrol *kcontrol, | |
300 | struct snd_ctl_elem_value *ucontrol) | |
301 | { | |
302 | struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol); | |
303 | unsigned char val; | |
304 | ||
305 | val = stac9460_get(ice, STAC946X_GENERAL_PURPOSE); | |
306 | ucontrol->value.enumerated.item[0] = (val >> 7) & 0x1; | |
307 | return 0; | |
308 | } | |
309 | ||
310 | static int stac9460_mic_sw_put(struct snd_kcontrol *kcontrol, | |
311 | struct snd_ctl_elem_value *ucontrol) | |
312 | { | |
313 | struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol); | |
314 | unsigned char new, old; | |
315 | int change; | |
316 | old = stac9460_get(ice, STAC946X_GENERAL_PURPOSE); | |
317 | new = (ucontrol->value.enumerated.item[0] << 7 & 0x80) | (old & ~0x80); | |
318 | change = (new != old); | |
319 | if (change) | |
320 | stac9460_put(ice, STAC946X_GENERAL_PURPOSE, new); | |
321 | return change; | |
322 | } | |
6632d64b PH |
323 | /* |
324 | * Handler for setting correct codec rate - called when rate change is detected | |
325 | */ | |
841b23d4 | 326 | static void stac9460_set_rate_val(struct snd_ice1712 *ice, unsigned int rate) |
6632d64b PH |
327 | { |
328 | unsigned char old, new; | |
329 | int idx; | |
330 | unsigned char changed[7]; | |
7cda8ba9 | 331 | struct prodigy192_spec *spec = ice->spec; |
6632d64b PH |
332 | |
333 | if (rate == 0) /* no hint - S/PDIF input is master, simply return */ | |
334 | return; | |
335 | else if (rate <= 48000) | |
336 | new = 0x08; /* 256x, base rate mode */ | |
337 | else if (rate <= 96000) | |
338 | new = 0x11; /* 256x, mid rate mode */ | |
339 | else | |
340 | new = 0x12; /* 128x, high rate mode */ | |
341 | old = stac9460_get(ice, STAC946X_MASTER_CLOCKING); | |
342 | if (old == new) | |
343 | return; | |
344 | /* change detected, setting master clock, muting first */ | |
345 | /* due to possible conflicts with mute controls - mutexing */ | |
7cda8ba9 | 346 | mutex_lock(&spec->mute_mutex); |
6632d64b PH |
347 | /* we have to remember current mute status for each DAC */ |
348 | for (idx = 0; idx < 7 ; ++idx) | |
349 | changed[idx] = stac9460_dac_mute(ice, | |
350 | STAC946X_MASTER_VOLUME + idx, 0); | |
6dfb5aff | 351 | /*dev_dbg(ice->card->dev, "Rate change: %d, new MC: 0x%02x\n", rate, new);*/ |
6632d64b PH |
352 | stac9460_put(ice, STAC946X_MASTER_CLOCKING, new); |
353 | udelay(10); | |
354 | /* unmuting - only originally unmuted dacs - | |
355 | * i.e. those changed when muting */ | |
356 | for (idx = 0; idx < 7 ; ++idx) { | |
357 | if (changed[idx]) | |
358 | stac9460_dac_mute(ice, STAC946X_MASTER_VOLUME + idx, 1); | |
359 | } | |
7cda8ba9 | 360 | mutex_unlock(&spec->mute_mutex); |
6632d64b PH |
361 | } |
362 | ||
1da177e4 | 363 | |
0cb29ea0 TI |
364 | static const DECLARE_TLV_DB_SCALE(db_scale_dac, -19125, 75, 0); |
365 | static const DECLARE_TLV_DB_SCALE(db_scale_adc, 0, 150, 0); | |
f640c320 | 366 | |
1da177e4 LT |
367 | /* |
368 | * mixers | |
369 | */ | |
370 | ||
e23e7a14 | 371 | static struct snd_kcontrol_new stac_controls[] = { |
1da177e4 LT |
372 | { |
373 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | |
374 | .name = "Master Playback Switch", | |
375 | .info = stac9460_dac_mute_info, | |
376 | .get = stac9460_dac_mute_get, | |
377 | .put = stac9460_dac_mute_put, | |
378 | .private_value = 1, | |
f640c320 | 379 | .tlv = { .p = db_scale_dac } |
1da177e4 LT |
380 | }, |
381 | { | |
382 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | |
f640c320 TI |
383 | .access = (SNDRV_CTL_ELEM_ACCESS_READWRITE | |
384 | SNDRV_CTL_ELEM_ACCESS_TLV_READ), | |
1da177e4 LT |
385 | .name = "Master Playback Volume", |
386 | .info = stac9460_dac_vol_info, | |
387 | .get = stac9460_dac_vol_get, | |
388 | .put = stac9460_dac_vol_put, | |
389 | .private_value = 1, | |
f640c320 | 390 | .tlv = { .p = db_scale_dac } |
1da177e4 LT |
391 | }, |
392 | { | |
393 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | |
394 | .name = "DAC Switch", | |
395 | .count = 6, | |
396 | .info = stac9460_dac_mute_info, | |
397 | .get = stac9460_dac_mute_get, | |
398 | .put = stac9460_dac_mute_put, | |
399 | }, | |
400 | { | |
401 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | |
f640c320 TI |
402 | .access = (SNDRV_CTL_ELEM_ACCESS_READWRITE | |
403 | SNDRV_CTL_ELEM_ACCESS_TLV_READ), | |
1da177e4 LT |
404 | .name = "DAC Volume", |
405 | .count = 6, | |
406 | .info = stac9460_dac_vol_info, | |
407 | .get = stac9460_dac_vol_get, | |
408 | .put = stac9460_dac_vol_put, | |
f640c320 | 409 | .tlv = { .p = db_scale_dac } |
1da177e4 LT |
410 | }, |
411 | { | |
412 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | |
7d4b4380 | 413 | .name = "ADC Capture Switch", |
1da177e4 LT |
414 | .count = 1, |
415 | .info = stac9460_adc_mute_info, | |
416 | .get = stac9460_adc_mute_get, | |
417 | .put = stac9460_adc_mute_put, | |
418 | ||
419 | }, | |
420 | { | |
421 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | |
f640c320 TI |
422 | .access = (SNDRV_CTL_ELEM_ACCESS_READWRITE | |
423 | SNDRV_CTL_ELEM_ACCESS_TLV_READ), | |
7d4b4380 | 424 | .name = "ADC Capture Volume", |
1da177e4 LT |
425 | .count = 1, |
426 | .info = stac9460_adc_vol_info, | |
427 | .get = stac9460_adc_vol_get, | |
428 | .put = stac9460_adc_vol_put, | |
f640c320 | 429 | .tlv = { .p = db_scale_adc } |
1da177e4 | 430 | }, |
7d4b4380 PH |
431 | { |
432 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | |
433 | .name = "Analog Capture Input", | |
434 | .info = stac9460_mic_sw_info, | |
435 | .get = stac9460_mic_sw_get, | |
436 | .put = stac9460_mic_sw_put, | |
437 | ||
438 | }, | |
1da177e4 LT |
439 | }; |
440 | ||
7d4b4380 PH |
441 | /* AK4114 - ICE1724 connections on Prodigy192 + MI/ODI/O */ |
442 | /* CDTO (pin 32) -- GPIO11 pin 86 | |
443 | * CDTI (pin 33) -- GPIO10 pin 77 | |
444 | * CCLK (pin 34) -- GPIO9 pin 76 | |
445 | * CSN (pin 35) -- GPIO8 pin 75 | |
446 | */ | |
447 | #define AK4114_ADDR 0x00 /* C1-C0: Chip Address | |
448 | * (According to datasheet fixed to “00”) | |
449 | */ | |
450 | ||
451 | /* | |
452 | * 4wire ak4114 protocol - writing data | |
453 | */ | |
454 | static void write_data(struct snd_ice1712 *ice, unsigned int gpio, | |
455 | unsigned int data, int idx) | |
456 | { | |
457 | for (; idx >= 0; idx--) { | |
458 | /* drop clock */ | |
459 | gpio &= ~VT1724_PRODIGY192_CCLK; | |
460 | snd_ice1712_gpio_write(ice, gpio); | |
461 | udelay(1); | |
462 | /* set data */ | |
463 | if (data & (1 << idx)) | |
464 | gpio |= VT1724_PRODIGY192_CDOUT; | |
465 | else | |
466 | gpio &= ~VT1724_PRODIGY192_CDOUT; | |
467 | snd_ice1712_gpio_write(ice, gpio); | |
468 | udelay(1); | |
469 | /* raise clock */ | |
470 | gpio |= VT1724_PRODIGY192_CCLK; | |
471 | snd_ice1712_gpio_write(ice, gpio); | |
472 | udelay(1); | |
473 | } | |
474 | } | |
475 | ||
476 | /* | |
477 | * 4wire ak4114 protocol - reading data | |
478 | */ | |
479 | static unsigned char read_data(struct snd_ice1712 *ice, unsigned int gpio, | |
480 | int idx) | |
481 | { | |
482 | unsigned char data = 0; | |
483 | ||
484 | for (; idx >= 0; idx--) { | |
485 | /* drop clock */ | |
486 | gpio &= ~VT1724_PRODIGY192_CCLK; | |
487 | snd_ice1712_gpio_write(ice, gpio); | |
488 | udelay(1); | |
489 | /* read data */ | |
490 | if (snd_ice1712_gpio_read(ice) & VT1724_PRODIGY192_CDIN) | |
491 | data |= (1 << idx); | |
492 | udelay(1); | |
493 | /* raise clock */ | |
494 | gpio |= VT1724_PRODIGY192_CCLK; | |
495 | snd_ice1712_gpio_write(ice, gpio); | |
496 | udelay(1); | |
497 | } | |
498 | return data; | |
499 | } | |
500 | /* | |
501 | * 4wire ak4114 protocol - starting sequence | |
502 | */ | |
503 | static unsigned int prodigy192_4wire_start(struct snd_ice1712 *ice) | |
504 | { | |
505 | unsigned int tmp; | |
506 | ||
507 | snd_ice1712_save_gpio_status(ice); | |
508 | tmp = snd_ice1712_gpio_read(ice); | |
509 | ||
510 | tmp |= VT1724_PRODIGY192_CCLK; /* high at init */ | |
511 | tmp &= ~VT1724_PRODIGY192_CS; /* drop chip select */ | |
512 | snd_ice1712_gpio_write(ice, tmp); | |
513 | udelay(1); | |
514 | return tmp; | |
515 | } | |
516 | ||
517 | /* | |
518 | * 4wire ak4114 protocol - final sequence | |
519 | */ | |
520 | static void prodigy192_4wire_finish(struct snd_ice1712 *ice, unsigned int tmp) | |
521 | { | |
522 | tmp |= VT1724_PRODIGY192_CS; /* raise chip select */ | |
523 | snd_ice1712_gpio_write(ice, tmp); | |
524 | udelay(1); | |
525 | snd_ice1712_restore_gpio_status(ice); | |
526 | } | |
527 | ||
528 | /* | |
529 | * Write data to addr register of ak4114 | |
530 | */ | |
531 | static void prodigy192_ak4114_write(void *private_data, unsigned char addr, | |
532 | unsigned char data) | |
533 | { | |
534 | struct snd_ice1712 *ice = private_data; | |
535 | unsigned int tmp, addrdata; | |
536 | tmp = prodigy192_4wire_start(ice); | |
537 | addrdata = (AK4114_ADDR << 6) | 0x20 | (addr & 0x1f); | |
538 | addrdata = (addrdata << 8) | data; | |
539 | write_data(ice, tmp, addrdata, 15); | |
540 | prodigy192_4wire_finish(ice, tmp); | |
541 | } | |
542 | ||
543 | /* | |
544 | * Read data from addr register of ak4114 | |
545 | */ | |
546 | static unsigned char prodigy192_ak4114_read(void *private_data, | |
547 | unsigned char addr) | |
548 | { | |
549 | struct snd_ice1712 *ice = private_data; | |
550 | unsigned int tmp; | |
551 | unsigned char data; | |
552 | ||
553 | tmp = prodigy192_4wire_start(ice); | |
554 | write_data(ice, tmp, (AK4114_ADDR << 6) | (addr & 0x1f), 7); | |
555 | data = read_data(ice, tmp, 7); | |
556 | prodigy192_4wire_finish(ice, tmp); | |
557 | return data; | |
558 | } | |
559 | ||
560 | ||
561 | static int ak4114_input_sw_info(struct snd_kcontrol *kcontrol, | |
562 | struct snd_ctl_elem_info *uinfo) | |
563 | { | |
a2af050f | 564 | static const char * const texts[2] = { "Toslink", "Coax" }; |
7d4b4380 PH |
565 | |
566 | uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED; | |
567 | uinfo->count = 1; | |
568 | uinfo->value.enumerated.items = 2; | |
569 | if (uinfo->value.enumerated.item >= uinfo->value.enumerated.items) | |
570 | uinfo->value.enumerated.item = uinfo->value.enumerated.items - 1; | |
571 | strcpy(uinfo->value.enumerated.name, texts[uinfo->value.enumerated.item]); | |
572 | return 0; | |
573 | } | |
574 | ||
575 | ||
576 | static int ak4114_input_sw_get(struct snd_kcontrol *kcontrol, | |
577 | struct snd_ctl_elem_value *ucontrol) | |
578 | { | |
579 | struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol); | |
580 | unsigned char val; | |
581 | ||
582 | val = prodigy192_ak4114_read(ice, AK4114_REG_IO1); | |
583 | /* AK4114_IPS0 bit = 0 -> RX0 = Toslink | |
584 | * AK4114_IPS0 bit = 1 -> RX1 = Coax | |
585 | */ | |
586 | ucontrol->value.enumerated.item[0] = (val & AK4114_IPS0) ? 1 : 0; | |
587 | return 0; | |
588 | } | |
589 | ||
590 | static int ak4114_input_sw_put(struct snd_kcontrol *kcontrol, | |
591 | struct snd_ctl_elem_value *ucontrol) | |
592 | { | |
593 | struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol); | |
594 | unsigned char new, old, itemvalue; | |
595 | int change; | |
596 | ||
597 | old = prodigy192_ak4114_read(ice, AK4114_REG_IO1); | |
598 | /* AK4114_IPS0 could be any bit */ | |
599 | itemvalue = (ucontrol->value.enumerated.item[0]) ? 0xff : 0x00; | |
600 | ||
601 | new = (itemvalue & AK4114_IPS0) | (old & ~AK4114_IPS0); | |
602 | change = (new != old); | |
603 | if (change) | |
604 | prodigy192_ak4114_write(ice, AK4114_REG_IO1, new); | |
605 | return change; | |
606 | } | |
607 | ||
608 | ||
e23e7a14 | 609 | static struct snd_kcontrol_new ak4114_controls[] = { |
7d4b4380 PH |
610 | { |
611 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | |
612 | .name = "MIODIO IEC958 Capture Input", | |
613 | .info = ak4114_input_sw_info, | |
614 | .get = ak4114_input_sw_get, | |
615 | .put = ak4114_input_sw_put, | |
616 | ||
617 | } | |
618 | }; | |
619 | ||
620 | ||
621 | static int prodigy192_ak4114_init(struct snd_ice1712 *ice) | |
622 | { | |
623 | static const unsigned char ak4114_init_vals[] = { | |
624 | AK4114_RST | AK4114_PWN | AK4114_OCKS0 | AK4114_OCKS1, | |
c5a30f85 PH |
625 | /* ice1724 expects I2S and provides clock, |
626 | * DEM0 disables the deemphasis filter | |
627 | */ | |
628 | AK4114_DIF_I24I2S | AK4114_DEM0 , | |
7d4b4380 PH |
629 | AK4114_TX1E, |
630 | AK4114_EFH_1024 | AK4114_DIT, /* default input RX0 */ | |
631 | 0, | |
632 | 0 | |
633 | }; | |
634 | static const unsigned char ak4114_init_txcsb[] = { | |
635 | 0x41, 0x02, 0x2c, 0x00, 0x00 | |
636 | }; | |
7cda8ba9 | 637 | struct prodigy192_spec *spec = ice->spec; |
841b23d4 | 638 | int err; |
7d4b4380 | 639 | |
841b23d4 | 640 | err = snd_ak4114_create(ice->card, |
7d4b4380 PH |
641 | prodigy192_ak4114_read, |
642 | prodigy192_ak4114_write, | |
643 | ak4114_init_vals, ak4114_init_txcsb, | |
7cda8ba9 | 644 | ice, &spec->ak4114); |
841b23d4 PH |
645 | if (err < 0) |
646 | return err; | |
647 | /* AK4114 in Prodigy192 cannot detect external rate correctly. | |
648 | * No reason to stop capture stream due to incorrect checks */ | |
649 | spec->ak4114->check_flags = AK4114_CHECK_NO_RATE; | |
650 | return 0; | |
7d4b4380 PH |
651 | } |
652 | ||
6632d64b PH |
653 | static void stac9460_proc_regs_read(struct snd_info_entry *entry, |
654 | struct snd_info_buffer *buffer) | |
655 | { | |
9fe856e4 | 656 | struct snd_ice1712 *ice = entry->private_data; |
6632d64b PH |
657 | int reg, val; |
658 | /* registers 0x0 - 0x14 */ | |
659 | for (reg = 0; reg <= 0x15; reg++) { | |
660 | val = stac9460_get(ice, reg); | |
661 | snd_iprintf(buffer, "0x%02x = 0x%02x\n", reg, val); | |
662 | } | |
663 | } | |
664 | ||
665 | ||
666 | static void stac9460_proc_init(struct snd_ice1712 *ice) | |
667 | { | |
668 | struct snd_info_entry *entry; | |
669 | if (!snd_card_proc_new(ice->card, "stac9460_codec", &entry)) | |
670 | snd_info_set_text_ops(entry, ice, stac9460_proc_regs_read); | |
671 | } | |
672 | ||
673 | ||
e23e7a14 | 674 | static int prodigy192_add_controls(struct snd_ice1712 *ice) |
1da177e4 | 675 | { |
7cda8ba9 | 676 | struct prodigy192_spec *spec = ice->spec; |
1da177e4 LT |
677 | unsigned int i; |
678 | int err; | |
679 | ||
680 | for (i = 0; i < ARRAY_SIZE(stac_controls); i++) { | |
7d4b4380 PH |
681 | err = snd_ctl_add(ice->card, |
682 | snd_ctl_new1(&stac_controls[i], ice)); | |
683 | if (err < 0) | |
684 | return err; | |
685 | } | |
7cda8ba9 | 686 | if (spec->ak4114) { |
7d4b4380 PH |
687 | /* ak4114 is connected */ |
688 | for (i = 0; i < ARRAY_SIZE(ak4114_controls); i++) { | |
689 | err = snd_ctl_add(ice->card, | |
690 | snd_ctl_new1(&ak4114_controls[i], | |
691 | ice)); | |
692 | if (err < 0) | |
693 | return err; | |
694 | } | |
7cda8ba9 | 695 | err = snd_ak4114_build(spec->ak4114, |
7d4b4380 PH |
696 | NULL, /* ak4114 in MIO/DI/O handles no IEC958 output */ |
697 | ice->pcm->streams[SNDRV_PCM_STREAM_CAPTURE].substream); | |
1da177e4 LT |
698 | if (err < 0) |
699 | return err; | |
700 | } | |
6632d64b | 701 | stac9460_proc_init(ice); |
1da177e4 LT |
702 | return 0; |
703 | } | |
704 | ||
7d4b4380 PH |
705 | /* |
706 | * check for presence of MI/ODI/O add-on card with digital inputs | |
707 | */ | |
708 | static int prodigy192_miodio_exists(struct snd_ice1712 *ice) | |
709 | { | |
710 | ||
711 | unsigned char orig_value; | |
712 | const unsigned char test_data = 0xd1; /* random value */ | |
713 | unsigned char addr = AK4114_REG_INT0_MASK; /* random SAFE address */ | |
714 | int exists = 0; | |
715 | ||
716 | orig_value = prodigy192_ak4114_read(ice, addr); | |
717 | prodigy192_ak4114_write(ice, addr, test_data); | |
718 | if (prodigy192_ak4114_read(ice, addr) == test_data) { | |
719 | /* ak4114 seems to communicate, apparently exists */ | |
720 | /* writing back original value */ | |
721 | prodigy192_ak4114_write(ice, addr, orig_value); | |
722 | exists = 1; | |
723 | } | |
724 | return exists; | |
725 | } | |
1da177e4 LT |
726 | |
727 | /* | |
728 | * initialize the chip | |
729 | */ | |
e23e7a14 | 730 | static int prodigy192_init(struct snd_ice1712 *ice) |
1da177e4 | 731 | { |
32b47da0 | 732 | static const unsigned short stac_inits_prodigy[] = { |
1da177e4 | 733 | STAC946X_RESET, 0, |
6632d64b | 734 | STAC946X_MASTER_CLOCKING, 0x11, |
1da177e4 LT |
735 | /* STAC946X_MASTER_VOLUME, 0, |
736 | STAC946X_LF_VOLUME, 0, | |
737 | STAC946X_RF_VOLUME, 0, | |
738 | STAC946X_LR_VOLUME, 0, | |
739 | STAC946X_RR_VOLUME, 0, | |
740 | STAC946X_CENTER_VOLUME, 0, | |
741 | STAC946X_LFE_VOLUME, 0,*/ | |
742 | (unsigned short)-1 | |
743 | }; | |
32b47da0 | 744 | const unsigned short *p; |
7d4b4380 | 745 | int err = 0; |
7cda8ba9 | 746 | struct prodigy192_spec *spec; |
1da177e4 LT |
747 | |
748 | /* prodigy 192 */ | |
749 | ice->num_total_dacs = 6; | |
750 | ice->num_total_adcs = 2; | |
7d4b4380 | 751 | ice->vt1720 = 0; /* ice1724, e.g. 23 GPIOs */ |
1da177e4 | 752 | |
7cda8ba9 TI |
753 | spec = kzalloc(sizeof(*spec), GFP_KERNEL); |
754 | if (!spec) | |
755 | return -ENOMEM; | |
756 | ice->spec = spec; | |
757 | mutex_init(&spec->mute_mutex); | |
758 | ||
1da177e4 LT |
759 | /* initialize codec */ |
760 | p = stac_inits_prodigy; | |
761 | for (; *p != (unsigned short)-1; p += 2) | |
762 | stac9460_put(ice, p[0], p[1]); | |
841b23d4 | 763 | ice->gpio.set_pro_rate = stac9460_set_rate_val; |
1da177e4 | 764 | |
7d4b4380 PH |
765 | /* MI/ODI/O add on card with AK4114 */ |
766 | if (prodigy192_miodio_exists(ice)) { | |
767 | err = prodigy192_ak4114_init(ice); | |
768 | /* from this moment if err = 0 then | |
7cda8ba9 | 769 | * spec->ak4114 should not be null |
7d4b4380 | 770 | */ |
6dfb5aff TI |
771 | dev_dbg(ice->card->dev, |
772 | "AK4114 initialized with status %d\n", err); | |
7d4b4380 | 773 | } else |
6dfb5aff | 774 | dev_dbg(ice->card->dev, "AK4114 not found\n"); |
7d4b4380 PH |
775 | if (err < 0) |
776 | return err; | |
777 | ||
1da177e4 LT |
778 | return 0; |
779 | } | |
780 | ||
781 | ||
782 | /* | |
783 | * Aureon boards don't provide the EEPROM data except for the vendor IDs. | |
784 | * hence the driver needs to sets up it properly. | |
785 | */ | |
786 | ||
e23e7a14 | 787 | static unsigned char prodigy71_eeprom[] = { |
7d4b4380 PH |
788 | [ICE_EEP2_SYSCONF] = 0x6a, /* 49MHz crystal, mpu401, |
789 | * spdif-in+ 1 stereo ADC, | |
790 | * 3 stereo DACs | |
791 | */ | |
189bc171 TI |
792 | [ICE_EEP2_ACLINK] = 0x80, /* I2S */ |
793 | [ICE_EEP2_I2S] = 0xf8, /* vol, 96k, 24bit, 192k */ | |
794 | [ICE_EEP2_SPDIF] = 0xc3, /* out-en, out-int, spdif-in */ | |
795 | [ICE_EEP2_GPIO_DIR] = 0xff, | |
7d4b4380 | 796 | [ICE_EEP2_GPIO_DIR1] = ~(VT1724_PRODIGY192_CDIN >> 8) , |
189bc171 TI |
797 | [ICE_EEP2_GPIO_DIR2] = 0xbf, |
798 | [ICE_EEP2_GPIO_MASK] = 0x00, | |
799 | [ICE_EEP2_GPIO_MASK1] = 0x00, | |
800 | [ICE_EEP2_GPIO_MASK2] = 0x00, | |
801 | [ICE_EEP2_GPIO_STATE] = 0x00, | |
802 | [ICE_EEP2_GPIO_STATE1] = 0x00, | |
7d4b4380 PH |
803 | [ICE_EEP2_GPIO_STATE2] = 0x10, /* GPIO20: 0 = CD drive dig. input |
804 | * passthrough, | |
805 | * 1 = SPDIF-OUT from ice1724 | |
806 | */ | |
1da177e4 LT |
807 | }; |
808 | ||
809 | ||
810 | /* entry point */ | |
e23e7a14 | 811 | struct snd_ice1712_card_info snd_vt1724_prodigy192_cards[] = { |
1da177e4 LT |
812 | { |
813 | .subvendor = VT1724_SUBDEVICE_PRODIGY192VE, | |
814 | .name = "Audiotrak Prodigy 192", | |
815 | .model = "prodigy192", | |
816 | .chip_init = prodigy192_init, | |
817 | .build_controls = prodigy192_add_controls, | |
818 | .eeprom_size = sizeof(prodigy71_eeprom), | |
819 | .eeprom_data = prodigy71_eeprom, | |
820 | }, | |
821 | { } /* terminator */ | |
822 | }; |