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