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