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