Commit | Line | Data |
---|---|---|
e12229b4 MB |
1 | #define __NO_VERSION__ |
2 | /* | |
3 | * Driver for Digigram pcxhr compatible soundcards | |
4 | * | |
5 | * mixer callbacks | |
6 | * | |
7 | * Copyright (c) 2004 by Digigram <alsa@digigram.com> | |
8 | * | |
9 | * This program is free software; you can redistribute it and/or modify | |
10 | * it under the terms of the GNU General Public License as published by | |
11 | * the Free Software Foundation; either version 2 of the License, or | |
12 | * (at your option) any later version. | |
13 | * | |
14 | * This program is distributed in the hope that it will be useful, | |
15 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
16 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
17 | * GNU General Public License for more details. | |
18 | * | |
19 | * You should have received a copy of the GNU General Public License | |
20 | * along with this program; if not, write to the Free Software | |
21 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | |
22 | */ | |
23 | ||
e12229b4 MB |
24 | #include <linux/time.h> |
25 | #include <linux/interrupt.h> | |
26 | #include <linux/init.h> | |
62932df8 | 27 | #include <linux/mutex.h> |
e12229b4 MB |
28 | #include <sound/core.h> |
29 | #include "pcxhr.h" | |
30 | #include "pcxhr_hwdep.h" | |
31 | #include "pcxhr_core.h" | |
32 | #include <sound/control.h> | |
c6ff77f7 | 33 | #include <sound/tlv.h> |
e12229b4 MB |
34 | #include <sound/asoundef.h> |
35 | #include "pcxhr_mixer.h" | |
c0193f39 | 36 | #include "pcxhr_mix22.h" |
e12229b4 | 37 | |
c0193f39 MB |
38 | #define PCXHR_LINE_CAPTURE_LEVEL_MIN 0 /* -112.0 dB */ |
39 | #define PCXHR_LINE_CAPTURE_LEVEL_MAX 255 /* +15.5 dB */ | |
40 | #define PCXHR_LINE_CAPTURE_ZERO_LEVEL 224 /* 0.0 dB ( 0 dBu -> 0 dBFS ) */ | |
e12229b4 | 41 | |
c0193f39 MB |
42 | #define PCXHR_LINE_PLAYBACK_LEVEL_MIN 0 /* -104.0 dB */ |
43 | #define PCXHR_LINE_PLAYBACK_LEVEL_MAX 128 /* +24.0 dB */ | |
44 | #define PCXHR_LINE_PLAYBACK_ZERO_LEVEL 104 /* 0.0 dB ( 0 dBFS -> 0 dBu ) */ | |
e12229b4 | 45 | |
c0193f39 | 46 | static const DECLARE_TLV_DB_SCALE(db_scale_analog_capture, -11200, 50, 1550); |
e6382cf8 | 47 | static const DECLARE_TLV_DB_SCALE(db_scale_analog_playback, -10400, 100, 2400); |
c6ff77f7 | 48 | |
c0193f39 MB |
49 | static const DECLARE_TLV_DB_SCALE(db_scale_a_hr222_capture, -11150, 50, 1600); |
50 | static const DECLARE_TLV_DB_SCALE(db_scale_a_hr222_playback, -2550, 50, 2400); | |
51 | ||
52 | static int pcxhr_update_analog_audio_level(struct snd_pcxhr *chip, | |
53 | int is_capture, int channel) | |
e12229b4 MB |
54 | { |
55 | int err, vol; | |
56 | struct pcxhr_rmh rmh; | |
57 | ||
58 | pcxhr_init_rmh(&rmh, CMD_ACCESS_IO_WRITE); | |
59 | if (is_capture) { | |
60 | rmh.cmd[0] |= IO_NUM_REG_IN_ANA_LEVEL; | |
61 | rmh.cmd[2] = chip->analog_capture_volume[channel]; | |
62 | } else { | |
63 | rmh.cmd[0] |= IO_NUM_REG_OUT_ANA_LEVEL; | |
64 | if (chip->analog_playback_active[channel]) | |
65 | vol = chip->analog_playback_volume[channel]; | |
66 | else | |
c0193f39 MB |
67 | vol = PCXHR_LINE_PLAYBACK_LEVEL_MIN; |
68 | /* playback analog levels are inversed */ | |
69 | rmh.cmd[2] = PCXHR_LINE_PLAYBACK_LEVEL_MAX - vol; | |
e12229b4 MB |
70 | } |
71 | rmh.cmd[1] = 1 << ((2 * chip->chip_idx) + channel); /* audio mask */ | |
72 | rmh.cmd_len = 3; | |
73 | err = pcxhr_send_msg(chip->mgr, &rmh); | |
74 | if (err < 0) { | |
c0193f39 MB |
75 | snd_printk(KERN_DEBUG "error update_analog_audio_level card(%d)" |
76 | " is_capture(%d) err(%x)\n", | |
77 | chip->chip_idx, is_capture, err); | |
e12229b4 MB |
78 | return -EINVAL; |
79 | } | |
80 | return 0; | |
81 | } | |
82 | ||
83 | /* | |
84 | * analog level control | |
85 | */ | |
86 | static int pcxhr_analog_vol_info(struct snd_kcontrol *kcontrol, | |
87 | struct snd_ctl_elem_info *uinfo) | |
88 | { | |
c0193f39 MB |
89 | struct snd_pcxhr *chip = snd_kcontrol_chip(kcontrol); |
90 | ||
e12229b4 MB |
91 | uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER; |
92 | uinfo->count = 2; | |
93 | if (kcontrol->private_value == 0) { /* playback */ | |
c0193f39 MB |
94 | if (chip->mgr->is_hr_stereo) { |
95 | uinfo->value.integer.min = | |
96 | HR222_LINE_PLAYBACK_LEVEL_MIN; /* -25 dB */ | |
97 | uinfo->value.integer.max = | |
98 | HR222_LINE_PLAYBACK_LEVEL_MAX; /* +24 dB */ | |
99 | } else { | |
100 | uinfo->value.integer.min = | |
101 | PCXHR_LINE_PLAYBACK_LEVEL_MIN; /*-104 dB */ | |
102 | uinfo->value.integer.max = | |
103 | PCXHR_LINE_PLAYBACK_LEVEL_MAX; /* +24 dB */ | |
104 | } | |
e12229b4 | 105 | } else { /* capture */ |
c0193f39 MB |
106 | if (chip->mgr->is_hr_stereo) { |
107 | uinfo->value.integer.min = | |
108 | HR222_LINE_CAPTURE_LEVEL_MIN; /*-112 dB */ | |
109 | uinfo->value.integer.max = | |
110 | HR222_LINE_CAPTURE_LEVEL_MAX; /* +15.5 dB */ | |
111 | } else { | |
112 | uinfo->value.integer.min = | |
113 | PCXHR_LINE_CAPTURE_LEVEL_MIN; /*-112 dB */ | |
114 | uinfo->value.integer.max = | |
115 | PCXHR_LINE_CAPTURE_LEVEL_MAX; /* +15.5 dB */ | |
116 | } | |
e12229b4 MB |
117 | } |
118 | return 0; | |
119 | } | |
120 | ||
121 | static int pcxhr_analog_vol_get(struct snd_kcontrol *kcontrol, | |
122 | struct snd_ctl_elem_value *ucontrol) | |
123 | { | |
124 | struct snd_pcxhr *chip = snd_kcontrol_chip(kcontrol); | |
62932df8 | 125 | mutex_lock(&chip->mgr->mixer_mutex); |
e12229b4 | 126 | if (kcontrol->private_value == 0) { /* playback */ |
c0193f39 MB |
127 | ucontrol->value.integer.value[0] = chip->analog_playback_volume[0]; |
128 | ucontrol->value.integer.value[1] = chip->analog_playback_volume[1]; | |
e12229b4 | 129 | } else { /* capture */ |
c0193f39 MB |
130 | ucontrol->value.integer.value[0] = chip->analog_capture_volume[0]; |
131 | ucontrol->value.integer.value[1] = chip->analog_capture_volume[1]; | |
e12229b4 | 132 | } |
62932df8 | 133 | mutex_unlock(&chip->mgr->mixer_mutex); |
e12229b4 MB |
134 | return 0; |
135 | } | |
136 | ||
137 | static int pcxhr_analog_vol_put(struct snd_kcontrol *kcontrol, | |
138 | struct snd_ctl_elem_value *ucontrol) | |
139 | { | |
140 | struct snd_pcxhr *chip = snd_kcontrol_chip(kcontrol); | |
141 | int changed = 0; | |
142 | int is_capture, i; | |
143 | ||
62932df8 | 144 | mutex_lock(&chip->mgr->mixer_mutex); |
e12229b4 MB |
145 | is_capture = (kcontrol->private_value != 0); |
146 | for (i = 0; i < 2; i++) { | |
147 | int new_volume = ucontrol->value.integer.value[i]; | |
4e98d6a7 TI |
148 | int *stored_volume = is_capture ? |
149 | &chip->analog_capture_volume[i] : | |
e12229b4 | 150 | &chip->analog_playback_volume[i]; |
4e98d6a7 | 151 | if (is_capture) { |
c0193f39 MB |
152 | if (chip->mgr->is_hr_stereo) { |
153 | if (new_volume < HR222_LINE_CAPTURE_LEVEL_MIN || | |
154 | new_volume > HR222_LINE_CAPTURE_LEVEL_MAX) | |
155 | continue; | |
156 | } else { | |
157 | if (new_volume < PCXHR_LINE_CAPTURE_LEVEL_MIN || | |
158 | new_volume > PCXHR_LINE_CAPTURE_LEVEL_MAX) | |
159 | continue; | |
160 | } | |
4e98d6a7 | 161 | } else { |
c0193f39 MB |
162 | if (chip->mgr->is_hr_stereo) { |
163 | if (new_volume < HR222_LINE_PLAYBACK_LEVEL_MIN || | |
164 | new_volume > HR222_LINE_PLAYBACK_LEVEL_MAX) | |
165 | continue; | |
166 | } else { | |
167 | if (new_volume < PCXHR_LINE_PLAYBACK_LEVEL_MIN || | |
168 | new_volume > PCXHR_LINE_PLAYBACK_LEVEL_MAX) | |
169 | continue; | |
170 | } | |
4e98d6a7 | 171 | } |
e12229b4 MB |
172 | if (*stored_volume != new_volume) { |
173 | *stored_volume = new_volume; | |
174 | changed = 1; | |
c0193f39 MB |
175 | if (chip->mgr->is_hr_stereo) |
176 | hr222_update_analog_audio_level(chip, | |
177 | is_capture, i); | |
178 | else | |
179 | pcxhr_update_analog_audio_level(chip, | |
180 | is_capture, i); | |
e12229b4 MB |
181 | } |
182 | } | |
62932df8 | 183 | mutex_unlock(&chip->mgr->mixer_mutex); |
e12229b4 MB |
184 | return changed; |
185 | } | |
186 | ||
187 | static struct snd_kcontrol_new pcxhr_control_analog_level = { | |
188 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | |
c6ff77f7 TI |
189 | .access = (SNDRV_CTL_ELEM_ACCESS_READWRITE | |
190 | SNDRV_CTL_ELEM_ACCESS_TLV_READ), | |
e12229b4 MB |
191 | /* name will be filled later */ |
192 | .info = pcxhr_analog_vol_info, | |
193 | .get = pcxhr_analog_vol_get, | |
194 | .put = pcxhr_analog_vol_put, | |
c6ff77f7 | 195 | /* tlv will be filled later */ |
e12229b4 MB |
196 | }; |
197 | ||
198 | /* shared */ | |
c0193f39 | 199 | |
a5ce8890 | 200 | #define pcxhr_sw_info snd_ctl_boolean_stereo_info |
e12229b4 MB |
201 | |
202 | static int pcxhr_audio_sw_get(struct snd_kcontrol *kcontrol, | |
203 | struct snd_ctl_elem_value *ucontrol) | |
204 | { | |
205 | struct snd_pcxhr *chip = snd_kcontrol_chip(kcontrol); | |
206 | ||
62932df8 | 207 | mutex_lock(&chip->mgr->mixer_mutex); |
e12229b4 MB |
208 | ucontrol->value.integer.value[0] = chip->analog_playback_active[0]; |
209 | ucontrol->value.integer.value[1] = chip->analog_playback_active[1]; | |
62932df8 | 210 | mutex_unlock(&chip->mgr->mixer_mutex); |
e12229b4 MB |
211 | return 0; |
212 | } | |
213 | ||
214 | static int pcxhr_audio_sw_put(struct snd_kcontrol *kcontrol, | |
215 | struct snd_ctl_elem_value *ucontrol) | |
216 | { | |
217 | struct snd_pcxhr *chip = snd_kcontrol_chip(kcontrol); | |
218 | int i, changed = 0; | |
62932df8 | 219 | mutex_lock(&chip->mgr->mixer_mutex); |
e12229b4 | 220 | for(i = 0; i < 2; i++) { |
4e98d6a7 TI |
221 | if (chip->analog_playback_active[i] != |
222 | ucontrol->value.integer.value[i]) { | |
223 | chip->analog_playback_active[i] = | |
224 | !!ucontrol->value.integer.value[i]; | |
e12229b4 | 225 | changed = 1; |
4e98d6a7 | 226 | /* update playback levels */ |
c0193f39 MB |
227 | if (chip->mgr->is_hr_stereo) |
228 | hr222_update_analog_audio_level(chip, 0, i); | |
229 | else | |
230 | pcxhr_update_analog_audio_level(chip, 0, i); | |
e12229b4 MB |
231 | } |
232 | } | |
62932df8 | 233 | mutex_unlock(&chip->mgr->mixer_mutex); |
e12229b4 MB |
234 | return changed; |
235 | } | |
236 | ||
237 | static struct snd_kcontrol_new pcxhr_control_output_switch = { | |
238 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | |
239 | .name = "Master Playback Switch", | |
240 | .info = pcxhr_sw_info, /* shared */ | |
241 | .get = pcxhr_audio_sw_get, | |
242 | .put = pcxhr_audio_sw_put | |
243 | }; | |
244 | ||
245 | ||
246 | #define PCXHR_DIGITAL_LEVEL_MIN 0x000 /* -110 dB */ | |
247 | #define PCXHR_DIGITAL_LEVEL_MAX 0x1ff /* +18 dB */ | |
248 | #define PCXHR_DIGITAL_ZERO_LEVEL 0x1b7 /* 0 dB */ | |
249 | ||
e6382cf8 | 250 | static const DECLARE_TLV_DB_SCALE(db_scale_digital, -10975, 25, 1800); |
e12229b4 MB |
251 | |
252 | #define MORE_THAN_ONE_STREAM_LEVEL 0x000001 | |
253 | #define VALID_STREAM_PAN_LEVEL_MASK 0x800000 | |
254 | #define VALID_STREAM_LEVEL_MASK 0x400000 | |
255 | #define VALID_STREAM_LEVEL_1_MASK 0x200000 | |
256 | #define VALID_STREAM_LEVEL_2_MASK 0x100000 | |
257 | ||
258 | static int pcxhr_update_playback_stream_level(struct snd_pcxhr* chip, int idx) | |
259 | { | |
260 | int err; | |
261 | struct pcxhr_rmh rmh; | |
262 | struct pcxhr_pipe *pipe = &chip->playback_pipe; | |
263 | int left, right; | |
264 | ||
265 | if (chip->digital_playback_active[idx][0]) | |
266 | left = chip->digital_playback_volume[idx][0]; | |
267 | else | |
268 | left = PCXHR_DIGITAL_LEVEL_MIN; | |
269 | if (chip->digital_playback_active[idx][1]) | |
270 | right = chip->digital_playback_volume[idx][1]; | |
271 | else | |
272 | right = PCXHR_DIGITAL_LEVEL_MIN; | |
273 | ||
274 | pcxhr_init_rmh(&rmh, CMD_STREAM_OUT_LEVEL_ADJUST); | |
275 | /* add pipe and stream mask */ | |
276 | pcxhr_set_pipe_cmd_params(&rmh, 0, pipe->first_audio, 0, 1<<idx); | |
277 | /* volume left->left / right->right panoramic level */ | |
278 | rmh.cmd[0] |= MORE_THAN_ONE_STREAM_LEVEL; | |
279 | rmh.cmd[2] = VALID_STREAM_PAN_LEVEL_MASK | VALID_STREAM_LEVEL_1_MASK; | |
280 | rmh.cmd[2] |= (left << 10); | |
281 | rmh.cmd[3] = VALID_STREAM_PAN_LEVEL_MASK | VALID_STREAM_LEVEL_2_MASK; | |
282 | rmh.cmd[3] |= right; | |
283 | rmh.cmd_len = 4; | |
284 | ||
285 | err = pcxhr_send_msg(chip->mgr, &rmh); | |
286 | if (err < 0) { | |
287 | snd_printk(KERN_DEBUG "error update_playback_stream_level " | |
288 | "card(%d) err(%x)\n", chip->chip_idx, err); | |
289 | return -EINVAL; | |
290 | } | |
291 | return 0; | |
292 | } | |
293 | ||
294 | #define AUDIO_IO_HAS_MUTE_LEVEL 0x400000 | |
295 | #define AUDIO_IO_HAS_MUTE_MONITOR_1 0x200000 | |
296 | #define VALID_AUDIO_IO_DIGITAL_LEVEL 0x000001 | |
297 | #define VALID_AUDIO_IO_MONITOR_LEVEL 0x000002 | |
298 | #define VALID_AUDIO_IO_MUTE_LEVEL 0x000004 | |
299 | #define VALID_AUDIO_IO_MUTE_MONITOR_1 0x000008 | |
300 | ||
c0193f39 MB |
301 | static int pcxhr_update_audio_pipe_level(struct snd_pcxhr *chip, |
302 | int capture, int channel) | |
e12229b4 MB |
303 | { |
304 | int err; | |
305 | struct pcxhr_rmh rmh; | |
306 | struct pcxhr_pipe *pipe; | |
307 | ||
308 | if (capture) | |
309 | pipe = &chip->capture_pipe[0]; | |
310 | else | |
311 | pipe = &chip->playback_pipe; | |
312 | ||
313 | pcxhr_init_rmh(&rmh, CMD_AUDIO_LEVEL_ADJUST); | |
314 | /* add channel mask */ | |
c0193f39 MB |
315 | pcxhr_set_pipe_cmd_params(&rmh, capture, 0, 0, |
316 | 1 << (channel + pipe->first_audio)); | |
317 | /* TODO : if mask (3 << pipe->first_audio) is used, left and right | |
318 | * channel will be programmed to the same params */ | |
e12229b4 MB |
319 | if (capture) { |
320 | rmh.cmd[0] |= VALID_AUDIO_IO_DIGITAL_LEVEL; | |
c0193f39 MB |
321 | /* VALID_AUDIO_IO_MUTE_LEVEL not yet handled |
322 | * (capture pipe level) */ | |
e12229b4 MB |
323 | rmh.cmd[2] = chip->digital_capture_volume[channel]; |
324 | } else { | |
c0193f39 MB |
325 | rmh.cmd[0] |= VALID_AUDIO_IO_MONITOR_LEVEL | |
326 | VALID_AUDIO_IO_MUTE_MONITOR_1; | |
327 | /* VALID_AUDIO_IO_DIGITAL_LEVEL and VALID_AUDIO_IO_MUTE_LEVEL | |
328 | * not yet handled (playback pipe level) | |
e12229b4 MB |
329 | */ |
330 | rmh.cmd[2] = chip->monitoring_volume[channel] << 10; | |
331 | if (chip->monitoring_active[channel] == 0) | |
332 | rmh.cmd[2] |= AUDIO_IO_HAS_MUTE_MONITOR_1; | |
333 | } | |
334 | rmh.cmd_len = 3; | |
335 | ||
336 | err = pcxhr_send_msg(chip->mgr, &rmh); | |
c0193f39 MB |
337 | if (err < 0) { |
338 | snd_printk(KERN_DEBUG "error update_audio_level(%d) err=%x\n", | |
e12229b4 MB |
339 | chip->chip_idx, err); |
340 | return -EINVAL; | |
341 | } | |
342 | return 0; | |
343 | } | |
344 | ||
345 | ||
346 | /* shared */ | |
347 | static int pcxhr_digital_vol_info(struct snd_kcontrol *kcontrol, | |
348 | struct snd_ctl_elem_info *uinfo) | |
349 | { | |
350 | uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER; | |
351 | uinfo->count = 2; | |
352 | uinfo->value.integer.min = PCXHR_DIGITAL_LEVEL_MIN; /* -109.5 dB */ | |
353 | uinfo->value.integer.max = PCXHR_DIGITAL_LEVEL_MAX; /* 18.0 dB */ | |
354 | return 0; | |
355 | } | |
356 | ||
357 | ||
358 | static int pcxhr_pcm_vol_get(struct snd_kcontrol *kcontrol, | |
359 | struct snd_ctl_elem_value *ucontrol) | |
360 | { | |
361 | struct snd_pcxhr *chip = snd_kcontrol_chip(kcontrol); | |
c0193f39 | 362 | int idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id); /* index */ |
e12229b4 MB |
363 | int *stored_volume; |
364 | int is_capture = kcontrol->private_value; | |
365 | ||
62932df8 | 366 | mutex_lock(&chip->mgr->mixer_mutex); |
c0193f39 MB |
367 | if (is_capture) /* digital capture */ |
368 | stored_volume = chip->digital_capture_volume; | |
369 | else /* digital playback */ | |
370 | stored_volume = chip->digital_playback_volume[idx]; | |
e12229b4 MB |
371 | ucontrol->value.integer.value[0] = stored_volume[0]; |
372 | ucontrol->value.integer.value[1] = stored_volume[1]; | |
62932df8 | 373 | mutex_unlock(&chip->mgr->mixer_mutex); |
e12229b4 MB |
374 | return 0; |
375 | } | |
376 | ||
377 | static int pcxhr_pcm_vol_put(struct snd_kcontrol *kcontrol, | |
378 | struct snd_ctl_elem_value *ucontrol) | |
379 | { | |
380 | struct snd_pcxhr *chip = snd_kcontrol_chip(kcontrol); | |
c0193f39 | 381 | int idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id); /* index */ |
e12229b4 MB |
382 | int changed = 0; |
383 | int is_capture = kcontrol->private_value; | |
384 | int *stored_volume; | |
385 | int i; | |
386 | ||
62932df8 | 387 | mutex_lock(&chip->mgr->mixer_mutex); |
4e98d6a7 TI |
388 | if (is_capture) /* digital capture */ |
389 | stored_volume = chip->digital_capture_volume; | |
390 | else /* digital playback */ | |
391 | stored_volume = chip->digital_playback_volume[idx]; | |
e12229b4 | 392 | for (i = 0; i < 2; i++) { |
4e98d6a7 TI |
393 | int vol = ucontrol->value.integer.value[i]; |
394 | if (vol < PCXHR_DIGITAL_LEVEL_MIN || | |
395 | vol > PCXHR_DIGITAL_LEVEL_MAX) | |
396 | continue; | |
397 | if (stored_volume[i] != vol) { | |
398 | stored_volume[i] = vol; | |
e12229b4 MB |
399 | changed = 1; |
400 | if (is_capture) /* update capture volume */ | |
401 | pcxhr_update_audio_pipe_level(chip, 1, i); | |
402 | } | |
403 | } | |
4e98d6a7 TI |
404 | if (!is_capture && changed) /* update playback volume */ |
405 | pcxhr_update_playback_stream_level(chip, idx); | |
62932df8 | 406 | mutex_unlock(&chip->mgr->mixer_mutex); |
e12229b4 MB |
407 | return changed; |
408 | } | |
409 | ||
410 | static struct snd_kcontrol_new snd_pcxhr_pcm_vol = | |
411 | { | |
412 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | |
c6ff77f7 TI |
413 | .access = (SNDRV_CTL_ELEM_ACCESS_READWRITE | |
414 | SNDRV_CTL_ELEM_ACCESS_TLV_READ), | |
e12229b4 MB |
415 | /* name will be filled later */ |
416 | /* count will be filled later */ | |
417 | .info = pcxhr_digital_vol_info, /* shared */ | |
418 | .get = pcxhr_pcm_vol_get, | |
419 | .put = pcxhr_pcm_vol_put, | |
c6ff77f7 | 420 | .tlv = { .p = db_scale_digital }, |
e12229b4 MB |
421 | }; |
422 | ||
423 | ||
424 | static int pcxhr_pcm_sw_get(struct snd_kcontrol *kcontrol, | |
425 | struct snd_ctl_elem_value *ucontrol) | |
426 | { | |
427 | struct snd_pcxhr *chip = snd_kcontrol_chip(kcontrol); | |
428 | int idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id); /* index */ | |
429 | ||
62932df8 | 430 | mutex_lock(&chip->mgr->mixer_mutex); |
e12229b4 MB |
431 | ucontrol->value.integer.value[0] = chip->digital_playback_active[idx][0]; |
432 | ucontrol->value.integer.value[1] = chip->digital_playback_active[idx][1]; | |
62932df8 | 433 | mutex_unlock(&chip->mgr->mixer_mutex); |
e12229b4 MB |
434 | return 0; |
435 | } | |
436 | ||
c0193f39 MB |
437 | static int pcxhr_pcm_sw_put(struct snd_kcontrol *kcontrol, |
438 | struct snd_ctl_elem_value *ucontrol) | |
e12229b4 MB |
439 | { |
440 | struct snd_pcxhr *chip = snd_kcontrol_chip(kcontrol); | |
441 | int changed = 0; | |
442 | int idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id); /* index */ | |
443 | int i, j; | |
444 | ||
62932df8 | 445 | mutex_lock(&chip->mgr->mixer_mutex); |
e12229b4 MB |
446 | j = idx; |
447 | for (i = 0; i < 2; i++) { | |
4e98d6a7 TI |
448 | if (chip->digital_playback_active[j][i] != |
449 | ucontrol->value.integer.value[i]) { | |
450 | chip->digital_playback_active[j][i] = | |
451 | !!ucontrol->value.integer.value[i]; | |
e12229b4 MB |
452 | changed = 1; |
453 | } | |
454 | } | |
455 | if (changed) | |
456 | pcxhr_update_playback_stream_level(chip, idx); | |
62932df8 | 457 | mutex_unlock(&chip->mgr->mixer_mutex); |
e12229b4 MB |
458 | return changed; |
459 | } | |
460 | ||
461 | static struct snd_kcontrol_new pcxhr_control_pcm_switch = { | |
462 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | |
463 | .name = "PCM Playback Switch", | |
464 | .count = PCXHR_PLAYBACK_STREAMS, | |
465 | .info = pcxhr_sw_info, /* shared */ | |
466 | .get = pcxhr_pcm_sw_get, | |
467 | .put = pcxhr_pcm_sw_put | |
468 | }; | |
469 | ||
470 | ||
471 | /* | |
472 | * monitoring level control | |
473 | */ | |
474 | ||
475 | static int pcxhr_monitor_vol_get(struct snd_kcontrol *kcontrol, | |
476 | struct snd_ctl_elem_value *ucontrol) | |
477 | { | |
478 | struct snd_pcxhr *chip = snd_kcontrol_chip(kcontrol); | |
62932df8 | 479 | mutex_lock(&chip->mgr->mixer_mutex); |
e12229b4 MB |
480 | ucontrol->value.integer.value[0] = chip->monitoring_volume[0]; |
481 | ucontrol->value.integer.value[1] = chip->monitoring_volume[1]; | |
62932df8 | 482 | mutex_unlock(&chip->mgr->mixer_mutex); |
e12229b4 MB |
483 | return 0; |
484 | } | |
485 | ||
486 | static int pcxhr_monitor_vol_put(struct snd_kcontrol *kcontrol, | |
487 | struct snd_ctl_elem_value *ucontrol) | |
488 | { | |
489 | struct snd_pcxhr *chip = snd_kcontrol_chip(kcontrol); | |
490 | int changed = 0; | |
491 | int i; | |
492 | ||
62932df8 | 493 | mutex_lock(&chip->mgr->mixer_mutex); |
e12229b4 | 494 | for (i = 0; i < 2; i++) { |
4e98d6a7 TI |
495 | if (chip->monitoring_volume[i] != |
496 | ucontrol->value.integer.value[i]) { | |
497 | chip->monitoring_volume[i] = | |
c0193f39 MB |
498 | ucontrol->value.integer.value[i]; |
499 | if (chip->monitoring_active[i]) | |
e12229b4 | 500 | /* update monitoring volume and mute */ |
4e98d6a7 | 501 | /* do only when monitoring is unmuted */ |
e12229b4 MB |
502 | pcxhr_update_audio_pipe_level(chip, 0, i); |
503 | changed = 1; | |
504 | } | |
505 | } | |
62932df8 | 506 | mutex_unlock(&chip->mgr->mixer_mutex); |
e12229b4 MB |
507 | return changed; |
508 | } | |
509 | ||
510 | static struct snd_kcontrol_new pcxhr_control_monitor_vol = { | |
511 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | |
c6ff77f7 TI |
512 | .access = (SNDRV_CTL_ELEM_ACCESS_READWRITE | |
513 | SNDRV_CTL_ELEM_ACCESS_TLV_READ), | |
c0193f39 | 514 | .name = "Monitoring Playback Volume", |
e12229b4 MB |
515 | .info = pcxhr_digital_vol_info, /* shared */ |
516 | .get = pcxhr_monitor_vol_get, | |
517 | .put = pcxhr_monitor_vol_put, | |
c6ff77f7 | 518 | .tlv = { .p = db_scale_digital }, |
e12229b4 MB |
519 | }; |
520 | ||
521 | /* | |
522 | * monitoring switch control | |
523 | */ | |
524 | ||
525 | static int pcxhr_monitor_sw_get(struct snd_kcontrol *kcontrol, | |
526 | struct snd_ctl_elem_value *ucontrol) | |
527 | { | |
528 | struct snd_pcxhr *chip = snd_kcontrol_chip(kcontrol); | |
62932df8 | 529 | mutex_lock(&chip->mgr->mixer_mutex); |
e12229b4 MB |
530 | ucontrol->value.integer.value[0] = chip->monitoring_active[0]; |
531 | ucontrol->value.integer.value[1] = chip->monitoring_active[1]; | |
62932df8 | 532 | mutex_unlock(&chip->mgr->mixer_mutex); |
e12229b4 MB |
533 | return 0; |
534 | } | |
535 | ||
536 | static int pcxhr_monitor_sw_put(struct snd_kcontrol *kcontrol, | |
537 | struct snd_ctl_elem_value *ucontrol) | |
538 | { | |
539 | struct snd_pcxhr *chip = snd_kcontrol_chip(kcontrol); | |
540 | int changed = 0; | |
541 | int i; | |
542 | ||
62932df8 | 543 | mutex_lock(&chip->mgr->mixer_mutex); |
e12229b4 | 544 | for (i = 0; i < 2; i++) { |
4e98d6a7 TI |
545 | if (chip->monitoring_active[i] != |
546 | ucontrol->value.integer.value[i]) { | |
547 | chip->monitoring_active[i] = | |
548 | !!ucontrol->value.integer.value[i]; | |
e12229b4 MB |
549 | changed |= (1<<i); /* mask 0x01 and 0x02 */ |
550 | } | |
551 | } | |
4e98d6a7 | 552 | if (changed & 0x01) |
e12229b4 MB |
553 | /* update left monitoring volume and mute */ |
554 | pcxhr_update_audio_pipe_level(chip, 0, 0); | |
4e98d6a7 | 555 | if (changed & 0x02) |
e12229b4 MB |
556 | /* update right monitoring volume and mute */ |
557 | pcxhr_update_audio_pipe_level(chip, 0, 1); | |
558 | ||
62932df8 | 559 | mutex_unlock(&chip->mgr->mixer_mutex); |
e12229b4 MB |
560 | return (changed != 0); |
561 | } | |
562 | ||
563 | static struct snd_kcontrol_new pcxhr_control_monitor_sw = { | |
564 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | |
c0193f39 | 565 | .name = "Monitoring Playback Switch", |
e12229b4 MB |
566 | .info = pcxhr_sw_info, /* shared */ |
567 | .get = pcxhr_monitor_sw_get, | |
568 | .put = pcxhr_monitor_sw_put | |
569 | }; | |
570 | ||
571 | ||
572 | ||
573 | /* | |
574 | * audio source select | |
575 | */ | |
576 | #define PCXHR_SOURCE_AUDIO01_UER 0x000100 | |
577 | #define PCXHR_SOURCE_AUDIO01_SYNC 0x000200 | |
578 | #define PCXHR_SOURCE_AUDIO23_UER 0x000400 | |
579 | #define PCXHR_SOURCE_AUDIO45_UER 0x001000 | |
580 | #define PCXHR_SOURCE_AUDIO67_UER 0x040000 | |
581 | ||
582 | static int pcxhr_set_audio_source(struct snd_pcxhr* chip) | |
583 | { | |
584 | struct pcxhr_rmh rmh; | |
585 | unsigned int mask, reg; | |
586 | unsigned int codec; | |
c0193f39 | 587 | int err, changed; |
e12229b4 MB |
588 | |
589 | switch (chip->chip_idx) { | |
590 | case 0 : mask = PCXHR_SOURCE_AUDIO01_UER; codec = CS8420_01_CS; break; | |
591 | case 1 : mask = PCXHR_SOURCE_AUDIO23_UER; codec = CS8420_23_CS; break; | |
592 | case 2 : mask = PCXHR_SOURCE_AUDIO45_UER; codec = CS8420_45_CS; break; | |
593 | case 3 : mask = PCXHR_SOURCE_AUDIO67_UER; codec = CS8420_67_CS; break; | |
594 | default: return -EINVAL; | |
595 | } | |
e12229b4 MB |
596 | if (chip->audio_capture_source != 0) { |
597 | reg = mask; /* audio source from digital plug */ | |
c0193f39 MB |
598 | } else { |
599 | reg = 0; /* audio source from analog plug */ | |
e12229b4 MB |
600 | } |
601 | /* set the input source */ | |
602 | pcxhr_write_io_num_reg_cont(chip->mgr, mask, reg, &changed); | |
603 | /* resync them (otherwise channel inversion possible) */ | |
604 | if (changed) { | |
605 | pcxhr_init_rmh(&rmh, CMD_RESYNC_AUDIO_INPUTS); | |
606 | rmh.cmd[0] |= (1 << chip->chip_idx); | |
607 | err = pcxhr_send_msg(chip->mgr, &rmh); | |
608 | if (err) | |
609 | return err; | |
610 | } | |
c0193f39 MB |
611 | if (chip->mgr->board_aes_in_192k) { |
612 | int i; | |
613 | unsigned int src_config = 0xC0; | |
614 | /* update all src configs with one call */ | |
615 | for (i = 0; (i < 4) && (i < chip->mgr->capture_chips); i++) { | |
616 | if (chip->mgr->chip[i]->audio_capture_source == 2) | |
617 | src_config |= (1 << (3 - i)); | |
618 | } | |
619 | /* set codec SRC on off */ | |
620 | pcxhr_init_rmh(&rmh, CMD_ACCESS_IO_WRITE); | |
621 | rmh.cmd_len = 2; | |
622 | rmh.cmd[0] |= IO_NUM_REG_CONFIG_SRC; | |
623 | rmh.cmd[1] = src_config; | |
624 | err = pcxhr_send_msg(chip->mgr, &rmh); | |
625 | } else { | |
626 | int use_src = 0; | |
627 | if (chip->audio_capture_source == 2) | |
628 | use_src = 1; | |
629 | /* set codec SRC on off */ | |
630 | pcxhr_init_rmh(&rmh, CMD_ACCESS_IO_WRITE); | |
631 | rmh.cmd_len = 3; | |
632 | rmh.cmd[0] |= IO_NUM_UER_CHIP_REG; | |
633 | rmh.cmd[1] = codec; | |
634 | rmh.cmd[2] = ((CS8420_DATA_FLOW_CTL & CHIP_SIG_AND_MAP_SPI) | | |
635 | (use_src ? 0x41 : 0x54)); | |
636 | err = pcxhr_send_msg(chip->mgr, &rmh); | |
637 | if (err) | |
638 | return err; | |
639 | rmh.cmd[2] = ((CS8420_CLOCK_SRC_CTL & CHIP_SIG_AND_MAP_SPI) | | |
640 | (use_src ? 0x41 : 0x49)); | |
641 | err = pcxhr_send_msg(chip->mgr, &rmh); | |
642 | } | |
e12229b4 MB |
643 | return err; |
644 | } | |
645 | ||
646 | static int pcxhr_audio_src_info(struct snd_kcontrol *kcontrol, | |
647 | struct snd_ctl_elem_info *uinfo) | |
648 | { | |
c0193f39 MB |
649 | static const char *texts[5] = { |
650 | "Line", "Digital", "Digi+SRC", "Mic", "Line+Mic" | |
651 | }; | |
652 | int i; | |
653 | struct snd_pcxhr *chip = snd_kcontrol_chip(kcontrol); | |
e12229b4 | 654 | |
c0193f39 MB |
655 | i = 2; /* no SRC, no Mic available */ |
656 | if (chip->mgr->board_has_aes1) { | |
657 | i = 3; /* SRC available */ | |
658 | if (chip->mgr->board_has_mic) | |
659 | i = 5; /* Mic and MicroMix available */ | |
660 | } | |
e12229b4 MB |
661 | uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED; |
662 | uinfo->count = 1; | |
c0193f39 MB |
663 | uinfo->value.enumerated.items = i; |
664 | if (uinfo->value.enumerated.item > (i-1)) | |
665 | uinfo->value.enumerated.item = i-1; | |
e12229b4 MB |
666 | strcpy(uinfo->value.enumerated.name, |
667 | texts[uinfo->value.enumerated.item]); | |
668 | return 0; | |
669 | } | |
670 | ||
671 | static int pcxhr_audio_src_get(struct snd_kcontrol *kcontrol, | |
672 | struct snd_ctl_elem_value *ucontrol) | |
673 | { | |
674 | struct snd_pcxhr *chip = snd_kcontrol_chip(kcontrol); | |
675 | ucontrol->value.enumerated.item[0] = chip->audio_capture_source; | |
676 | return 0; | |
677 | } | |
678 | ||
679 | static int pcxhr_audio_src_put(struct snd_kcontrol *kcontrol, | |
680 | struct snd_ctl_elem_value *ucontrol) | |
681 | { | |
682 | struct snd_pcxhr *chip = snd_kcontrol_chip(kcontrol); | |
683 | int ret = 0; | |
c0193f39 MB |
684 | int i = 2; /* no SRC, no Mic available */ |
685 | if (chip->mgr->board_has_aes1) { | |
686 | i = 3; /* SRC available */ | |
687 | if (chip->mgr->board_has_mic) | |
688 | i = 5; /* Mic and MicroMix available */ | |
689 | } | |
690 | if (ucontrol->value.enumerated.item[0] >= i) | |
4e98d6a7 | 691 | return -EINVAL; |
62932df8 | 692 | mutex_lock(&chip->mgr->mixer_mutex); |
e12229b4 MB |
693 | if (chip->audio_capture_source != ucontrol->value.enumerated.item[0]) { |
694 | chip->audio_capture_source = ucontrol->value.enumerated.item[0]; | |
c0193f39 MB |
695 | if (chip->mgr->is_hr_stereo) |
696 | hr222_set_audio_source(chip); | |
697 | else | |
698 | pcxhr_set_audio_source(chip); | |
e12229b4 MB |
699 | ret = 1; |
700 | } | |
62932df8 | 701 | mutex_unlock(&chip->mgr->mixer_mutex); |
e12229b4 MB |
702 | return ret; |
703 | } | |
704 | ||
705 | static struct snd_kcontrol_new pcxhr_control_audio_src = { | |
706 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | |
707 | .name = "Capture Source", | |
708 | .info = pcxhr_audio_src_info, | |
709 | .get = pcxhr_audio_src_get, | |
710 | .put = pcxhr_audio_src_put, | |
711 | }; | |
712 | ||
713 | ||
714 | /* | |
715 | * clock type selection | |
716 | * enum pcxhr_clock_type { | |
c0193f39 MB |
717 | * PCXHR_CLOCK_TYPE_INTERNAL = 0, |
718 | * PCXHR_CLOCK_TYPE_WORD_CLOCK, | |
719 | * PCXHR_CLOCK_TYPE_AES_SYNC, | |
720 | * PCXHR_CLOCK_TYPE_AES_1, | |
721 | * PCXHR_CLOCK_TYPE_AES_2, | |
722 | * PCXHR_CLOCK_TYPE_AES_3, | |
723 | * PCXHR_CLOCK_TYPE_AES_4, | |
724 | * PCXHR_CLOCK_TYPE_MAX = PCXHR_CLOCK_TYPE_AES_4, | |
725 | * HR22_CLOCK_TYPE_INTERNAL = PCXHR_CLOCK_TYPE_INTERNAL, | |
726 | * HR22_CLOCK_TYPE_AES_SYNC, | |
727 | * HR22_CLOCK_TYPE_AES_1, | |
728 | * HR22_CLOCK_TYPE_MAX = HR22_CLOCK_TYPE_AES_1, | |
729 | * }; | |
e12229b4 MB |
730 | */ |
731 | ||
732 | static int pcxhr_clock_type_info(struct snd_kcontrol *kcontrol, | |
733 | struct snd_ctl_elem_info *uinfo) | |
734 | { | |
c0193f39 MB |
735 | static const char *textsPCXHR[7] = { |
736 | "Internal", "WordClock", "AES Sync", | |
737 | "AES 1", "AES 2", "AES 3", "AES 4" | |
738 | }; | |
739 | static const char *textsHR22[3] = { | |
740 | "Internal", "AES Sync", "AES 1" | |
e12229b4 | 741 | }; |
c0193f39 | 742 | const char **texts; |
e12229b4 | 743 | struct pcxhr_mgr *mgr = snd_kcontrol_chip(kcontrol); |
c0193f39 MB |
744 | int clock_items = 2; /* at least Internal and AES Sync clock */ |
745 | if (mgr->board_has_aes1) { | |
746 | clock_items += mgr->capture_chips; /* add AES x */ | |
747 | if (!mgr->is_hr_stereo) | |
748 | clock_items += 1; /* add word clock */ | |
749 | } | |
750 | if (mgr->is_hr_stereo) { | |
751 | texts = textsHR22; | |
752 | snd_BUG_ON(clock_items > (HR22_CLOCK_TYPE_MAX+1)); | |
753 | } else { | |
754 | texts = textsPCXHR; | |
755 | snd_BUG_ON(clock_items > (PCXHR_CLOCK_TYPE_MAX+1)); | |
756 | } | |
e12229b4 MB |
757 | uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED; |
758 | uinfo->count = 1; | |
759 | uinfo->value.enumerated.items = clock_items; | |
760 | if (uinfo->value.enumerated.item >= clock_items) | |
761 | uinfo->value.enumerated.item = clock_items-1; | |
762 | strcpy(uinfo->value.enumerated.name, | |
763 | texts[uinfo->value.enumerated.item]); | |
764 | return 0; | |
765 | } | |
766 | ||
767 | static int pcxhr_clock_type_get(struct snd_kcontrol *kcontrol, | |
768 | struct snd_ctl_elem_value *ucontrol) | |
769 | { | |
770 | struct pcxhr_mgr *mgr = snd_kcontrol_chip(kcontrol); | |
771 | ucontrol->value.enumerated.item[0] = mgr->use_clock_type; | |
772 | return 0; | |
773 | } | |
774 | ||
775 | static int pcxhr_clock_type_put(struct snd_kcontrol *kcontrol, | |
776 | struct snd_ctl_elem_value *ucontrol) | |
777 | { | |
778 | struct pcxhr_mgr *mgr = snd_kcontrol_chip(kcontrol); | |
779 | int rate, ret = 0; | |
c0193f39 MB |
780 | unsigned int clock_items = 2; /* at least Internal and AES Sync clock */ |
781 | if (mgr->board_has_aes1) { | |
782 | clock_items += mgr->capture_chips; /* add AES x */ | |
783 | if (!mgr->is_hr_stereo) | |
784 | clock_items += 1; /* add word clock */ | |
785 | } | |
4e98d6a7 TI |
786 | if (ucontrol->value.enumerated.item[0] >= clock_items) |
787 | return -EINVAL; | |
62932df8 | 788 | mutex_lock(&mgr->mixer_mutex); |
e12229b4 | 789 | if (mgr->use_clock_type != ucontrol->value.enumerated.item[0]) { |
62932df8 | 790 | mutex_lock(&mgr->setup_mutex); |
e12229b4 | 791 | mgr->use_clock_type = ucontrol->value.enumerated.item[0]; |
55aef450 MB |
792 | rate = 0; |
793 | if (mgr->use_clock_type != PCXHR_CLOCK_TYPE_INTERNAL) { | |
c0193f39 MB |
794 | pcxhr_get_external_clock(mgr, mgr->use_clock_type, |
795 | &rate); | |
55aef450 | 796 | } else { |
e12229b4 | 797 | rate = mgr->sample_rate; |
55aef450 MB |
798 | if (!rate) |
799 | rate = 48000; | |
800 | } | |
e12229b4 MB |
801 | if (rate) { |
802 | pcxhr_set_clock(mgr, rate); | |
803 | if (mgr->sample_rate) | |
804 | mgr->sample_rate = rate; | |
805 | } | |
62932df8 | 806 | mutex_unlock(&mgr->setup_mutex); |
c0193f39 | 807 | ret = 1; /* return 1 even if the set was not done. ok ? */ |
e12229b4 | 808 | } |
62932df8 | 809 | mutex_unlock(&mgr->mixer_mutex); |
e12229b4 MB |
810 | return ret; |
811 | } | |
812 | ||
813 | static struct snd_kcontrol_new pcxhr_control_clock_type = { | |
814 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | |
815 | .name = "Clock Mode", | |
816 | .info = pcxhr_clock_type_info, | |
817 | .get = pcxhr_clock_type_get, | |
818 | .put = pcxhr_clock_type_put, | |
819 | }; | |
820 | ||
821 | /* | |
822 | * clock rate control | |
823 | * specific control that scans the sample rates on the external plugs | |
824 | */ | |
825 | static int pcxhr_clock_rate_info(struct snd_kcontrol *kcontrol, | |
826 | struct snd_ctl_elem_info *uinfo) | |
827 | { | |
828 | struct pcxhr_mgr *mgr = snd_kcontrol_chip(kcontrol); | |
829 | uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER; | |
830 | uinfo->count = 3 + mgr->capture_chips; | |
831 | uinfo->value.integer.min = 0; /* clock not present */ | |
832 | uinfo->value.integer.max = 192000; /* max sample rate 192 kHz */ | |
833 | return 0; | |
834 | } | |
835 | ||
836 | static int pcxhr_clock_rate_get(struct snd_kcontrol *kcontrol, | |
837 | struct snd_ctl_elem_value *ucontrol) | |
838 | { | |
839 | struct pcxhr_mgr *mgr = snd_kcontrol_chip(kcontrol); | |
840 | int i, err, rate; | |
841 | ||
62932df8 | 842 | mutex_lock(&mgr->mixer_mutex); |
e12229b4 MB |
843 | for(i = 0; i < 3 + mgr->capture_chips; i++) { |
844 | if (i == PCXHR_CLOCK_TYPE_INTERNAL) | |
845 | rate = mgr->sample_rate_real; | |
846 | else { | |
847 | err = pcxhr_get_external_clock(mgr, i, &rate); | |
848 | if (err) | |
849 | break; | |
850 | } | |
851 | ucontrol->value.integer.value[i] = rate; | |
852 | } | |
62932df8 | 853 | mutex_unlock(&mgr->mixer_mutex); |
e12229b4 MB |
854 | return 0; |
855 | } | |
856 | ||
857 | static struct snd_kcontrol_new pcxhr_control_clock_rate = { | |
858 | .access = SNDRV_CTL_ELEM_ACCESS_READ, | |
859 | .iface = SNDRV_CTL_ELEM_IFACE_CARD, | |
860 | .name = "Clock Rates", | |
861 | .info = pcxhr_clock_rate_info, | |
862 | .get = pcxhr_clock_rate_get, | |
863 | }; | |
864 | ||
865 | /* | |
866 | * IEC958 status bits | |
867 | */ | |
c0193f39 MB |
868 | static int pcxhr_iec958_info(struct snd_kcontrol *kcontrol, |
869 | struct snd_ctl_elem_info *uinfo) | |
e12229b4 MB |
870 | { |
871 | uinfo->type = SNDRV_CTL_ELEM_TYPE_IEC958; | |
872 | uinfo->count = 1; | |
873 | return 0; | |
874 | } | |
875 | ||
c0193f39 MB |
876 | static int pcxhr_iec958_capture_byte(struct snd_pcxhr *chip, |
877 | int aes_idx, unsigned char *aes_bits) | |
e12229b4 MB |
878 | { |
879 | int i, err; | |
880 | unsigned char temp; | |
881 | struct pcxhr_rmh rmh; | |
882 | ||
883 | pcxhr_init_rmh(&rmh, CMD_ACCESS_IO_READ); | |
884 | rmh.cmd[0] |= IO_NUM_UER_CHIP_REG; | |
885 | switch (chip->chip_idx) { | |
c0193f39 MB |
886 | /* instead of CS8420_01_CS use CS8416_01_CS for AES SYNC plug */ |
887 | case 0: rmh.cmd[1] = CS8420_01_CS; break; | |
e12229b4 MB |
888 | case 1: rmh.cmd[1] = CS8420_23_CS; break; |
889 | case 2: rmh.cmd[1] = CS8420_45_CS; break; | |
890 | case 3: rmh.cmd[1] = CS8420_67_CS; break; | |
891 | default: return -EINVAL; | |
892 | } | |
c0193f39 MB |
893 | if (chip->mgr->board_aes_in_192k) { |
894 | switch (aes_idx) { | |
895 | case 0: rmh.cmd[2] = CS8416_CSB0; break; | |
896 | case 1: rmh.cmd[2] = CS8416_CSB1; break; | |
897 | case 2: rmh.cmd[2] = CS8416_CSB2; break; | |
898 | case 3: rmh.cmd[2] = CS8416_CSB3; break; | |
899 | case 4: rmh.cmd[2] = CS8416_CSB4; break; | |
900 | default: return -EINVAL; | |
901 | } | |
902 | } else { | |
903 | switch (aes_idx) { | |
904 | /* instead of CS8420_CSB0 use CS8416_CSBx for AES SYNC plug */ | |
905 | case 0: rmh.cmd[2] = CS8420_CSB0; break; | |
906 | case 1: rmh.cmd[2] = CS8420_CSB1; break; | |
907 | case 2: rmh.cmd[2] = CS8420_CSB2; break; | |
908 | case 3: rmh.cmd[2] = CS8420_CSB3; break; | |
909 | case 4: rmh.cmd[2] = CS8420_CSB4; break; | |
910 | default: return -EINVAL; | |
911 | } | |
e12229b4 | 912 | } |
c0193f39 MB |
913 | /* size and code the chip id for the fpga */ |
914 | rmh.cmd[1] &= 0x0fffff; | |
915 | /* chip signature + map for spi read */ | |
916 | rmh.cmd[2] &= CHIP_SIG_AND_MAP_SPI; | |
e12229b4 MB |
917 | rmh.cmd_len = 3; |
918 | err = pcxhr_send_msg(chip->mgr, &rmh); | |
919 | if (err) | |
920 | return err; | |
c0193f39 MB |
921 | |
922 | if (chip->mgr->board_aes_in_192k) { | |
923 | temp = (unsigned char)rmh.stat[1]; | |
924 | } else { | |
925 | temp = 0; | |
926 | /* reversed bit order (not with CS8416_01_CS) */ | |
927 | for (i = 0; i < 8; i++) { | |
928 | temp <<= 1; | |
929 | if (rmh.stat[1] & (1 << i)) | |
930 | temp |= 1; | |
931 | } | |
e12229b4 | 932 | } |
c0193f39 MB |
933 | snd_printdd("read iec958 AES %d byte %d = 0x%x\n", |
934 | chip->chip_idx, aes_idx, temp); | |
e12229b4 MB |
935 | *aes_bits = temp; |
936 | return 0; | |
937 | } | |
938 | ||
c0193f39 MB |
939 | static int pcxhr_iec958_get(struct snd_kcontrol *kcontrol, |
940 | struct snd_ctl_elem_value *ucontrol) | |
e12229b4 MB |
941 | { |
942 | struct snd_pcxhr *chip = snd_kcontrol_chip(kcontrol); | |
943 | unsigned char aes_bits; | |
944 | int i, err; | |
945 | ||
62932df8 | 946 | mutex_lock(&chip->mgr->mixer_mutex); |
e12229b4 MB |
947 | for(i = 0; i < 5; i++) { |
948 | if (kcontrol->private_value == 0) /* playback */ | |
949 | aes_bits = chip->aes_bits[i]; | |
950 | else { /* capture */ | |
c0193f39 MB |
951 | if (chip->mgr->is_hr_stereo) |
952 | err = hr222_iec958_capture_byte(chip, i, | |
953 | &aes_bits); | |
954 | else | |
955 | err = pcxhr_iec958_capture_byte(chip, i, | |
956 | &aes_bits); | |
e12229b4 MB |
957 | if (err) |
958 | break; | |
959 | } | |
960 | ucontrol->value.iec958.status[i] = aes_bits; | |
961 | } | |
62932df8 | 962 | mutex_unlock(&chip->mgr->mixer_mutex); |
e12229b4 MB |
963 | return 0; |
964 | } | |
965 | ||
966 | static int pcxhr_iec958_mask_get(struct snd_kcontrol *kcontrol, | |
967 | struct snd_ctl_elem_value *ucontrol) | |
968 | { | |
969 | int i; | |
970 | for (i = 0; i < 5; i++) | |
971 | ucontrol->value.iec958.status[i] = 0xff; | |
972 | return 0; | |
973 | } | |
974 | ||
c0193f39 MB |
975 | static int pcxhr_iec958_update_byte(struct snd_pcxhr *chip, |
976 | int aes_idx, unsigned char aes_bits) | |
e12229b4 MB |
977 | { |
978 | int i, err, cmd; | |
979 | unsigned char new_bits = aes_bits; | |
980 | unsigned char old_bits = chip->aes_bits[aes_idx]; | |
981 | struct pcxhr_rmh rmh; | |
982 | ||
983 | for (i = 0; i < 8; i++) { | |
984 | if ((old_bits & 0x01) != (new_bits & 0x01)) { | |
c0193f39 MB |
985 | cmd = chip->chip_idx & 0x03; /* chip index 0..3 */ |
986 | if (chip->chip_idx > 3) | |
e12229b4 MB |
987 | /* new bit used if chip_idx>3 (PCX1222HR) */ |
988 | cmd |= 1 << 22; | |
c0193f39 MB |
989 | cmd |= ((aes_idx << 3) + i) << 2; /* add bit offset */ |
990 | cmd |= (new_bits & 0x01) << 23; /* add bit value */ | |
e12229b4 MB |
991 | pcxhr_init_rmh(&rmh, CMD_ACCESS_IO_WRITE); |
992 | rmh.cmd[0] |= IO_NUM_REG_CUER; | |
993 | rmh.cmd[1] = cmd; | |
994 | rmh.cmd_len = 2; | |
995 | snd_printdd("write iec958 AES %d byte %d bit %d (cmd %x)\n", | |
996 | chip->chip_idx, aes_idx, i, cmd); | |
997 | err = pcxhr_send_msg(chip->mgr, &rmh); | |
998 | if (err) | |
999 | return err; | |
1000 | } | |
1001 | old_bits >>= 1; | |
1002 | new_bits >>= 1; | |
1003 | } | |
1004 | chip->aes_bits[aes_idx] = aes_bits; | |
1005 | return 0; | |
1006 | } | |
1007 | ||
1008 | static int pcxhr_iec958_put(struct snd_kcontrol *kcontrol, | |
1009 | struct snd_ctl_elem_value *ucontrol) | |
1010 | { | |
1011 | struct snd_pcxhr *chip = snd_kcontrol_chip(kcontrol); | |
1012 | int i, changed = 0; | |
1013 | ||
1014 | /* playback */ | |
62932df8 | 1015 | mutex_lock(&chip->mgr->mixer_mutex); |
e12229b4 MB |
1016 | for (i = 0; i < 5; i++) { |
1017 | if (ucontrol->value.iec958.status[i] != chip->aes_bits[i]) { | |
c0193f39 MB |
1018 | if (chip->mgr->is_hr_stereo) |
1019 | hr222_iec958_update_byte(chip, i, | |
1020 | ucontrol->value.iec958.status[i]); | |
1021 | else | |
1022 | pcxhr_iec958_update_byte(chip, i, | |
1023 | ucontrol->value.iec958.status[i]); | |
e12229b4 MB |
1024 | changed = 1; |
1025 | } | |
1026 | } | |
62932df8 | 1027 | mutex_unlock(&chip->mgr->mixer_mutex); |
e12229b4 MB |
1028 | return changed; |
1029 | } | |
1030 | ||
1031 | static struct snd_kcontrol_new pcxhr_control_playback_iec958_mask = { | |
1032 | .access = SNDRV_CTL_ELEM_ACCESS_READ, | |
1033 | .iface = SNDRV_CTL_ELEM_IFACE_PCM, | |
1034 | .name = SNDRV_CTL_NAME_IEC958("",PLAYBACK,MASK), | |
1035 | .info = pcxhr_iec958_info, | |
1036 | .get = pcxhr_iec958_mask_get | |
1037 | }; | |
1038 | static struct snd_kcontrol_new pcxhr_control_playback_iec958 = { | |
1039 | .iface = SNDRV_CTL_ELEM_IFACE_PCM, | |
1040 | .name = SNDRV_CTL_NAME_IEC958("",PLAYBACK,DEFAULT), | |
1041 | .info = pcxhr_iec958_info, | |
1042 | .get = pcxhr_iec958_get, | |
1043 | .put = pcxhr_iec958_put, | |
1044 | .private_value = 0 /* playback */ | |
1045 | }; | |
1046 | ||
1047 | static struct snd_kcontrol_new pcxhr_control_capture_iec958_mask = { | |
1048 | .access = SNDRV_CTL_ELEM_ACCESS_READ, | |
1049 | .iface = SNDRV_CTL_ELEM_IFACE_PCM, | |
1050 | .name = SNDRV_CTL_NAME_IEC958("",CAPTURE,MASK), | |
1051 | .info = pcxhr_iec958_info, | |
1052 | .get = pcxhr_iec958_mask_get | |
1053 | }; | |
1054 | static struct snd_kcontrol_new pcxhr_control_capture_iec958 = { | |
1055 | .access = SNDRV_CTL_ELEM_ACCESS_READ, | |
1056 | .iface = SNDRV_CTL_ELEM_IFACE_PCM, | |
1057 | .name = SNDRV_CTL_NAME_IEC958("",CAPTURE,DEFAULT), | |
1058 | .info = pcxhr_iec958_info, | |
1059 | .get = pcxhr_iec958_get, | |
1060 | .private_value = 1 /* capture */ | |
1061 | }; | |
1062 | ||
1063 | static void pcxhr_init_audio_levels(struct snd_pcxhr *chip) | |
1064 | { | |
1065 | int i; | |
1066 | ||
1067 | for (i = 0; i < 2; i++) { | |
1068 | if (chip->nb_streams_play) { | |
1069 | int j; | |
1070 | /* at boot time the digital volumes are unmuted 0dB */ | |
1071 | for (j = 0; j < PCXHR_PLAYBACK_STREAMS; j++) { | |
1072 | chip->digital_playback_active[j][i] = 1; | |
c0193f39 MB |
1073 | chip->digital_playback_volume[j][i] = |
1074 | PCXHR_DIGITAL_ZERO_LEVEL; | |
e12229b4 | 1075 | } |
c0193f39 MB |
1076 | /* after boot, only two bits are set on the uer |
1077 | * interface | |
1078 | */ | |
1079 | chip->aes_bits[0] = (IEC958_AES0_PROFESSIONAL | | |
1080 | IEC958_AES0_PRO_FS_48000); | |
e12229b4 | 1081 | #ifdef CONFIG_SND_DEBUG |
c0193f39 MB |
1082 | /* analog volumes for playback |
1083 | * (is LEVEL_MIN after boot) | |
1084 | */ | |
e12229b4 | 1085 | chip->analog_playback_active[i] = 1; |
c0193f39 MB |
1086 | if (chip->mgr->is_hr_stereo) |
1087 | chip->analog_playback_volume[i] = | |
1088 | HR222_LINE_PLAYBACK_ZERO_LEVEL; | |
1089 | else { | |
1090 | chip->analog_playback_volume[i] = | |
1091 | PCXHR_LINE_PLAYBACK_ZERO_LEVEL; | |
1092 | pcxhr_update_analog_audio_level(chip, 0, i); | |
1093 | } | |
e12229b4 | 1094 | #endif |
c0193f39 MB |
1095 | /* stereo cards need to be initialised after boot */ |
1096 | if (chip->mgr->is_hr_stereo) | |
1097 | hr222_update_analog_audio_level(chip, 0, i); | |
e12229b4 MB |
1098 | } |
1099 | if (chip->nb_streams_capt) { | |
1100 | /* at boot time the digital volumes are unmuted 0dB */ | |
c0193f39 MB |
1101 | chip->digital_capture_volume[i] = |
1102 | PCXHR_DIGITAL_ZERO_LEVEL; | |
1103 | chip->analog_capture_active = 1; | |
e12229b4 | 1104 | #ifdef CONFIG_SND_DEBUG |
c0193f39 MB |
1105 | /* analog volumes for playback |
1106 | * (is LEVEL_MIN after boot) | |
1107 | */ | |
1108 | if (chip->mgr->is_hr_stereo) | |
1109 | chip->analog_capture_volume[i] = | |
1110 | HR222_LINE_CAPTURE_ZERO_LEVEL; | |
1111 | else { | |
1112 | chip->analog_capture_volume[i] = | |
1113 | PCXHR_LINE_CAPTURE_ZERO_LEVEL; | |
1114 | pcxhr_update_analog_audio_level(chip, 1, i); | |
1115 | } | |
e12229b4 | 1116 | #endif |
c0193f39 MB |
1117 | /* stereo cards need to be initialised after boot */ |
1118 | if (chip->mgr->is_hr_stereo) | |
1119 | hr222_update_analog_audio_level(chip, 1, i); | |
e12229b4 MB |
1120 | } |
1121 | } | |
1122 | ||
1123 | return; | |
1124 | } | |
1125 | ||
1126 | ||
1127 | int pcxhr_create_mixer(struct pcxhr_mgr *mgr) | |
1128 | { | |
1129 | struct snd_pcxhr *chip; | |
1130 | int err, i; | |
1131 | ||
62932df8 | 1132 | mutex_init(&mgr->mixer_mutex); /* can be in another place */ |
e12229b4 MB |
1133 | |
1134 | for (i = 0; i < mgr->num_cards; i++) { | |
1135 | struct snd_kcontrol_new temp; | |
1136 | chip = mgr->chip[i]; | |
1137 | ||
1138 | if (chip->nb_streams_play) { | |
1139 | /* analog output level control */ | |
1140 | temp = pcxhr_control_analog_level; | |
1141 | temp.name = "Master Playback Volume"; | |
1142 | temp.private_value = 0; /* playback */ | |
c0193f39 MB |
1143 | if (mgr->is_hr_stereo) |
1144 | temp.tlv.p = db_scale_a_hr222_playback; | |
1145 | else | |
1146 | temp.tlv.p = db_scale_analog_playback; | |
1147 | err = snd_ctl_add(chip->card, | |
1148 | snd_ctl_new1(&temp, chip)); | |
1149 | if (err < 0) | |
e12229b4 | 1150 | return err; |
c0193f39 | 1151 | |
e12229b4 | 1152 | /* output mute controls */ |
c0193f39 MB |
1153 | err = snd_ctl_add(chip->card, |
1154 | snd_ctl_new1(&pcxhr_control_output_switch, | |
1155 | chip)); | |
1156 | if (err < 0) | |
e12229b4 | 1157 | return err; |
c0193f39 | 1158 | |
e12229b4 MB |
1159 | temp = snd_pcxhr_pcm_vol; |
1160 | temp.name = "PCM Playback Volume"; | |
1161 | temp.count = PCXHR_PLAYBACK_STREAMS; | |
1162 | temp.private_value = 0; /* playback */ | |
c0193f39 MB |
1163 | err = snd_ctl_add(chip->card, |
1164 | snd_ctl_new1(&temp, chip)); | |
1165 | if (err < 0) | |
e12229b4 MB |
1166 | return err; |
1167 | ||
c0193f39 MB |
1168 | err = snd_ctl_add(chip->card, |
1169 | snd_ctl_new1(&pcxhr_control_pcm_switch, chip)); | |
1170 | if (err < 0) | |
e12229b4 MB |
1171 | return err; |
1172 | ||
1173 | /* IEC958 controls */ | |
c0193f39 MB |
1174 | err = snd_ctl_add(chip->card, |
1175 | snd_ctl_new1(&pcxhr_control_playback_iec958_mask, | |
1176 | chip)); | |
1177 | if (err < 0) | |
e12229b4 | 1178 | return err; |
c0193f39 MB |
1179 | |
1180 | err = snd_ctl_add(chip->card, | |
1181 | snd_ctl_new1(&pcxhr_control_playback_iec958, | |
1182 | chip)); | |
1183 | if (err < 0) | |
e12229b4 MB |
1184 | return err; |
1185 | } | |
1186 | if (chip->nb_streams_capt) { | |
c0193f39 | 1187 | /* analog input level control */ |
e12229b4 | 1188 | temp = pcxhr_control_analog_level; |
c0193f39 | 1189 | temp.name = "Line Capture Volume"; |
e12229b4 | 1190 | temp.private_value = 1; /* capture */ |
c0193f39 MB |
1191 | if (mgr->is_hr_stereo) |
1192 | temp.tlv.p = db_scale_a_hr222_capture; | |
1193 | else | |
1194 | temp.tlv.p = db_scale_analog_capture; | |
1195 | ||
1196 | err = snd_ctl_add(chip->card, | |
1197 | snd_ctl_new1(&temp, chip)); | |
1198 | if (err < 0) | |
e12229b4 MB |
1199 | return err; |
1200 | ||
1201 | temp = snd_pcxhr_pcm_vol; | |
1202 | temp.name = "PCM Capture Volume"; | |
1203 | temp.count = 1; | |
1204 | temp.private_value = 1; /* capture */ | |
c0193f39 MB |
1205 | |
1206 | err = snd_ctl_add(chip->card, | |
1207 | snd_ctl_new1(&temp, chip)); | |
1208 | if (err < 0) | |
e12229b4 | 1209 | return err; |
c0193f39 | 1210 | |
e12229b4 | 1211 | /* Audio source */ |
c0193f39 MB |
1212 | err = snd_ctl_add(chip->card, |
1213 | snd_ctl_new1(&pcxhr_control_audio_src, chip)); | |
1214 | if (err < 0) | |
e12229b4 | 1215 | return err; |
c0193f39 | 1216 | |
e12229b4 | 1217 | /* IEC958 controls */ |
c0193f39 MB |
1218 | err = snd_ctl_add(chip->card, |
1219 | snd_ctl_new1(&pcxhr_control_capture_iec958_mask, | |
1220 | chip)); | |
1221 | if (err < 0) | |
e12229b4 | 1222 | return err; |
c0193f39 MB |
1223 | |
1224 | err = snd_ctl_add(chip->card, | |
1225 | snd_ctl_new1(&pcxhr_control_capture_iec958, | |
1226 | chip)); | |
1227 | if (err < 0) | |
e12229b4 | 1228 | return err; |
c0193f39 MB |
1229 | |
1230 | if (mgr->is_hr_stereo) { | |
1231 | err = hr222_add_mic_controls(chip); | |
1232 | if (err < 0) | |
1233 | return err; | |
1234 | } | |
e12229b4 MB |
1235 | } |
1236 | /* monitoring only if playback and capture device available */ | |
1237 | if (chip->nb_streams_capt > 0 && chip->nb_streams_play > 0) { | |
1238 | /* monitoring */ | |
c0193f39 MB |
1239 | err = snd_ctl_add(chip->card, |
1240 | snd_ctl_new1(&pcxhr_control_monitor_vol, chip)); | |
1241 | if (err < 0) | |
e12229b4 | 1242 | return err; |
c0193f39 MB |
1243 | |
1244 | err = snd_ctl_add(chip->card, | |
1245 | snd_ctl_new1(&pcxhr_control_monitor_sw, chip)); | |
1246 | if (err < 0) | |
e12229b4 MB |
1247 | return err; |
1248 | } | |
1249 | ||
1250 | if (i == 0) { | |
1251 | /* clock mode only one control per pcxhr */ | |
c0193f39 MB |
1252 | err = snd_ctl_add(chip->card, |
1253 | snd_ctl_new1(&pcxhr_control_clock_type, mgr)); | |
1254 | if (err < 0) | |
e12229b4 | 1255 | return err; |
c0193f39 MB |
1256 | /* non standard control used to scan |
1257 | * the external clock presence/frequencies | |
1258 | */ | |
1259 | err = snd_ctl_add(chip->card, | |
1260 | snd_ctl_new1(&pcxhr_control_clock_rate, mgr)); | |
1261 | if (err < 0) | |
e12229b4 MB |
1262 | return err; |
1263 | } | |
1264 | ||
1265 | /* init values for the mixer data */ | |
1266 | pcxhr_init_audio_levels(chip); | |
1267 | } | |
1268 | ||
1269 | return 0; | |
1270 | } |