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