1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21#include <linux/kernel.h>
22#include <linux/init.h>
23#include <linux/vmalloc.h>
24#include <linux/io.h>
25#include <sound/core.h>
26#include <sound/control.h>
27#include <sound/pcm.h>
28#include <sound/tlv.h>
29#include "lola.h"
30
31static int lola_init_pin(struct lola *chip, struct lola_pin *pin,
32 int dir, int nid)
33{
34 unsigned int val;
35 int err;
36
37 pin->nid = nid;
38 err = lola_read_param(chip, nid, LOLA_PAR_AUDIO_WIDGET_CAP, &val);
39 if (err < 0) {
40 dev_err(chip->card->dev, "Can't read wcaps for 0x%x\n", nid);
41 return err;
42 }
43 val &= 0x00f00fff;
44 if (val == 0x00400200)
45 pin->is_analog = false;
46 else if (val == 0x0040000a && dir == CAPT)
47 pin->is_analog = true;
48 else if (val == 0x0040000c && dir == PLAY)
49 pin->is_analog = true;
50 else {
51 dev_err(chip->card->dev, "Invalid wcaps 0x%x for 0x%x\n", val, nid);
52 return -EINVAL;
53 }
54
55
56
57 if (!pin->is_analog)
58 return 0;
59
60 if (dir == PLAY)
61 err = lola_read_param(chip, nid, LOLA_PAR_AMP_OUT_CAP, &val);
62 else
63 err = lola_read_param(chip, nid, LOLA_PAR_AMP_IN_CAP, &val);
64 if (err < 0) {
65 dev_err(chip->card->dev, "Can't read AMP-caps for 0x%x\n", nid);
66 return err;
67 }
68
69 pin->amp_mute = LOLA_AMP_MUTE_CAPABLE(val);
70 pin->amp_step_size = LOLA_AMP_STEP_SIZE(val);
71 pin->amp_num_steps = LOLA_AMP_NUM_STEPS(val);
72 if (pin->amp_num_steps) {
73
74 pin->amp_num_steps++;
75 pin->amp_step_size++;
76 }
77 pin->amp_offset = LOLA_AMP_OFFSET(val);
78
79 err = lola_codec_read(chip, nid, LOLA_VERB_GET_MAX_LEVEL, 0, 0, &val,
80 NULL);
81 if (err < 0) {
82 dev_err(chip->card->dev, "Can't get MAX_LEVEL 0x%x\n", nid);
83 return err;
84 }
85 pin->max_level = val & 0x3ff;
86
87 pin->config_default_reg = 0;
88 pin->fixed_gain_list_len = 0;
89 pin->cur_gain_step = 0;
90
91 return 0;
92}
93
94int lola_init_pins(struct lola *chip, int dir, int *nidp)
95{
96 int i, err, nid;
97 nid = *nidp;
98 for (i = 0; i < chip->pin[dir].num_pins; i++, nid++) {
99 err = lola_init_pin(chip, &chip->pin[dir].pins[i], dir, nid);
100 if (err < 0)
101 return err;
102 if (chip->pin[dir].pins[i].is_analog)
103 chip->pin[dir].num_analog_pins++;
104 }
105 *nidp = nid;
106 return 0;
107}
108
109void lola_free_mixer(struct lola *chip)
110{
111 vfree(chip->mixer.array_saved);
112}
113
114int lola_init_mixer_widget(struct lola *chip, int nid)
115{
116 unsigned int val;
117 int err;
118
119 err = lola_read_param(chip, nid, LOLA_PAR_AUDIO_WIDGET_CAP, &val);
120 if (err < 0) {
121 dev_err(chip->card->dev, "Can't read wcaps for 0x%x\n", nid);
122 return err;
123 }
124
125 if ((val & 0xfff00000) != 0x02f00000) {
126 dev_dbg(chip->card->dev, "No valid mixer widget\n");
127 return 0;
128 }
129
130 chip->mixer.nid = nid;
131 chip->mixer.caps = val;
132 chip->mixer.array = (struct lola_mixer_array __iomem *)
133 (chip->bar[BAR1].remap_addr + LOLA_BAR1_SOURCE_GAIN_ENABLE);
134
135
136 chip->mixer.array_saved = vmalloc(sizeof(struct lola_mixer_array));
137
138
139 chip->mixer.src_stream_outs = chip->pcm[PLAY].num_streams;
140 chip->mixer.src_phys_ins = chip->pin[CAPT].num_pins;
141
142
143 chip->mixer.dest_stream_ins = chip->pcm[CAPT].num_streams;
144 chip->mixer.dest_phys_outs = chip->pin[PLAY].num_pins;
145
146
147
148
149 chip->mixer.src_stream_out_ofs = chip->mixer.src_phys_ins +
150 LOLA_MIXER_SRC_INPUT_PLAY_SEPARATION(val);
151 chip->mixer.dest_phys_out_ofs = chip->mixer.dest_stream_ins +
152 LOLA_MIXER_DEST_REC_OUTPUT_SEPARATION(val);
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202 if (chip->mixer.src_stream_out_ofs > MAX_AUDIO_INOUT_COUNT ||
203 chip->mixer.dest_phys_out_ofs > MAX_STREAM_IN_COUNT) {
204 dev_err(chip->card->dev, "Invalid mixer widget size\n");
205 return -EINVAL;
206 }
207
208 chip->mixer.src_mask = ((1U << chip->mixer.src_phys_ins) - 1) |
209 (((1U << chip->mixer.src_stream_outs) - 1)
210 << chip->mixer.src_stream_out_ofs);
211 chip->mixer.dest_mask = ((1U << chip->mixer.dest_stream_ins) - 1) |
212 (((1U << chip->mixer.dest_phys_outs) - 1)
213 << chip->mixer.dest_phys_out_ofs);
214
215 dev_dbg(chip->card->dev, "Mixer src_mask=%x, dest_mask=%x\n",
216 chip->mixer.src_mask, chip->mixer.dest_mask);
217
218 return 0;
219}
220
221static int lola_mixer_set_src_gain(struct lola *chip, unsigned int id,
222 unsigned short gain, bool on)
223{
224 unsigned int oldval, val;
225
226 if (!(chip->mixer.src_mask & (1 << id)))
227 return -EINVAL;
228 oldval = val = readl(&chip->mixer.array->src_gain_enable);
229 if (on)
230 val |= (1 << id);
231 else
232 val &= ~(1 << id);
233
234 if ((val == oldval) &&
235 (gain == readw(&chip->mixer.array->src_gain[id])))
236 return 0;
237
238 dev_dbg(chip->card->dev,
239 "lola_mixer_set_src_gain (id=%d, gain=%d) enable=%x\n",
240 id, gain, val);
241 writew(gain, &chip->mixer.array->src_gain[id]);
242 writel(val, &chip->mixer.array->src_gain_enable);
243 lola_codec_flush(chip);
244
245 return lola_codec_write(chip, chip->mixer.nid,
246 LOLA_VERB_SET_SOURCE_GAIN, id, 0);
247}
248
249#if 0
250static int lola_mixer_set_src_gains(struct lola *chip, unsigned int mask,
251 unsigned short *gains)
252{
253 int i;
254
255 if ((chip->mixer.src_mask & mask) != mask)
256 return -EINVAL;
257 for (i = 0; i < LOLA_MIXER_DIM; i++) {
258 if (mask & (1 << i)) {
259 writew(*gains, &chip->mixer.array->src_gain[i]);
260 gains++;
261 }
262 }
263 writel(mask, &chip->mixer.array->src_gain_enable);
264 lola_codec_flush(chip);
265 if (chip->mixer.caps & LOLA_PEAK_METER_CAN_AGC_MASK) {
266
267 return lola_codec_write(chip, chip->mixer.nid,
268 LOLA_VERB_SET_SOURCE_GAIN, 0x80, 0);
269 }
270
271 for (i = 0; i < LOLA_MIXER_DIM; i++) {
272 if (mask & (1 << i)) {
273 lola_codec_write(chip, chip->mixer.nid,
274 LOLA_VERB_SET_SOURCE_GAIN, i, 0);
275 }
276 }
277 return 0;
278}
279#endif
280
281static int lola_mixer_set_mapping_gain(struct lola *chip,
282 unsigned int src, unsigned int dest,
283 unsigned short gain, bool on)
284{
285 unsigned int val;
286
287 if (!(chip->mixer.src_mask & (1 << src)) ||
288 !(chip->mixer.dest_mask & (1 << dest)))
289 return -EINVAL;
290 if (on)
291 writew(gain, &chip->mixer.array->dest_mix_gain[dest][src]);
292 val = readl(&chip->mixer.array->dest_mix_gain_enable[dest]);
293 if (on)
294 val |= (1 << src);
295 else
296 val &= ~(1 << src);
297 writel(val, &chip->mixer.array->dest_mix_gain_enable[dest]);
298 lola_codec_flush(chip);
299 return lola_codec_write(chip, chip->mixer.nid, LOLA_VERB_SET_MIX_GAIN,
300 src, dest);
301}
302
303#if 0
304static int lola_mixer_set_dest_gains(struct lola *chip, unsigned int id,
305 unsigned int mask, unsigned short *gains)
306{
307 int i;
308
309 if (!(chip->mixer.dest_mask & (1 << id)) ||
310 (chip->mixer.src_mask & mask) != mask)
311 return -EINVAL;
312 for (i = 0; i < LOLA_MIXER_DIM; i++) {
313 if (mask & (1 << i)) {
314 writew(*gains, &chip->mixer.array->dest_mix_gain[id][i]);
315 gains++;
316 }
317 }
318 writel(mask, &chip->mixer.array->dest_mix_gain_enable[id]);
319 lola_codec_flush(chip);
320
321 return lola_codec_write(chip, chip->mixer.nid,
322 LOLA_VERB_SET_DESTINATION_GAIN, id, 0);
323}
324#endif
325
326
327
328
329static int set_analog_volume(struct lola *chip, int dir,
330 unsigned int idx, unsigned int val,
331 bool external_call);
332
333int lola_setup_all_analog_gains(struct lola *chip, int dir, bool mute)
334{
335 struct lola_pin *pin;
336 int idx, max_idx;
337
338 pin = chip->pin[dir].pins;
339 max_idx = chip->pin[dir].num_pins;
340 for (idx = 0; idx < max_idx; idx++) {
341 if (pin[idx].is_analog) {
342 unsigned int val = mute ? 0 : pin[idx].cur_gain_step;
343
344 set_analog_volume(chip, dir, idx, val, false);
345 }
346 }
347 return lola_codec_flush(chip);
348}
349
350void lola_save_mixer(struct lola *chip)
351{
352
353 if (chip->mixer.array_saved) {
354
355 memcpy_fromio(chip->mixer.array_saved, chip->mixer.array,
356 sizeof(*chip->mixer.array));
357 }
358 lola_setup_all_analog_gains(chip, PLAY, true);
359}
360
361void lola_restore_mixer(struct lola *chip)
362{
363 int i;
364
365
366 if (chip->mixer.array_saved) {
367
368 memcpy_toio(chip->mixer.array, chip->mixer.array_saved,
369 sizeof(*chip->mixer.array));
370
371
372
373 for (i = 0; i < chip->mixer.src_phys_ins; i++)
374 lola_codec_write(chip, chip->mixer.nid,
375 LOLA_VERB_SET_SOURCE_GAIN,
376 i, 0);
377 for (i = 0; i < chip->mixer.src_stream_outs; i++)
378 lola_codec_write(chip, chip->mixer.nid,
379 LOLA_VERB_SET_SOURCE_GAIN,
380 chip->mixer.src_stream_out_ofs + i, 0);
381 for (i = 0; i < chip->mixer.dest_stream_ins; i++)
382 lola_codec_write(chip, chip->mixer.nid,
383 LOLA_VERB_SET_DESTINATION_GAIN,
384 i, 0);
385 for (i = 0; i < chip->mixer.dest_phys_outs; i++)
386 lola_codec_write(chip, chip->mixer.nid,
387 LOLA_VERB_SET_DESTINATION_GAIN,
388 chip->mixer.dest_phys_out_ofs + i, 0);
389 lola_codec_flush(chip);
390 }
391}
392
393
394
395
396static int set_analog_volume(struct lola *chip, int dir,
397 unsigned int idx, unsigned int val,
398 bool external_call)
399{
400 struct lola_pin *pin;
401 int err;
402
403 if (idx >= chip->pin[dir].num_pins)
404 return -EINVAL;
405 pin = &chip->pin[dir].pins[idx];
406 if (!pin->is_analog || pin->amp_num_steps <= val)
407 return -EINVAL;
408 if (external_call && pin->cur_gain_step == val)
409 return 0;
410 if (external_call)
411 lola_codec_flush(chip);
412 dev_dbg(chip->card->dev,
413 "set_analog_volume (dir=%d idx=%d, volume=%d)\n",
414 dir, idx, val);
415 err = lola_codec_write(chip, pin->nid,
416 LOLA_VERB_SET_AMP_GAIN_MUTE, val, 0);
417 if (err < 0)
418 return err;
419 if (external_call)
420 pin->cur_gain_step = val;
421 return 0;
422}
423
424int lola_set_src_config(struct lola *chip, unsigned int src_mask, bool update)
425{
426 int ret = 0;
427 int success = 0;
428 int n, err;
429
430
431 if ((chip->input_src_caps_mask & src_mask) != src_mask)
432 return -EINVAL;
433
434 for (n = 0; n < chip->pin[CAPT].num_pins; n += 2) {
435 unsigned int mask = 3U << n;
436 unsigned int new_src, src_state;
437 if (!(chip->input_src_caps_mask & mask))
438 continue;
439
440 new_src = (src_mask & mask) != 0;
441 if (update) {
442 src_state = (chip->input_src_mask & mask) != 0;
443 if (src_state == new_src)
444 continue;
445 }
446 err = lola_codec_write(chip, chip->pcm[CAPT].streams[n].nid,
447 LOLA_VERB_SET_SRC, new_src, 0);
448 if (!err)
449 success++;
450 else
451 ret = err;
452 }
453 if (success)
454 ret = lola_codec_flush(chip);
455 if (!ret)
456 chip->input_src_mask = src_mask;
457 return ret;
458}
459
460
461
462static int init_mixer_values(struct lola *chip)
463{
464 int i;
465
466
467 lola_set_src_config(chip, (1 << chip->pin[CAPT].num_pins) - 1, false);
468
469
470 memset_io(chip->mixer.array, 0, sizeof(*chip->mixer.array));
471
472 for (i = 0; i < chip->mixer.dest_stream_ins; i++)
473 lola_codec_write(chip, chip->mixer.nid,
474 LOLA_VERB_SET_DESTINATION_GAIN,
475 i, 0);
476
477 for (i = 0; i < chip->mixer.dest_phys_outs; i++)
478 lola_codec_write(chip, chip->mixer.nid,
479 LOLA_VERB_SET_DESTINATION_GAIN,
480 chip->mixer.dest_phys_out_ofs + i, 0);
481
482
483 for (i = 0; i < chip->mixer.src_phys_ins; i++)
484 lola_mixer_set_src_gain(chip, i, 336, true);
485
486
487 for (i = 0; i < chip->mixer.src_stream_outs; i++)
488 lola_mixer_set_src_gain(chip,
489 i + chip->mixer.src_stream_out_ofs,
490 336, true);
491
492 for (i = 0; i < chip->mixer.dest_stream_ins; i++) {
493 int src = i % chip->mixer.src_phys_ins;
494 lola_mixer_set_mapping_gain(chip, src, i, 336, true);
495 }
496
497
498
499
500 for (i = 0; i < chip->mixer.src_stream_outs; i++) {
501 int src = chip->mixer.src_stream_out_ofs + i;
502 int dst = chip->mixer.dest_phys_out_ofs +
503 i % chip->mixer.dest_phys_outs;
504 lola_mixer_set_mapping_gain(chip, src, dst, 336, true);
505 }
506 return 0;
507}
508
509
510
511
512static int lola_analog_vol_info(struct snd_kcontrol *kcontrol,
513 struct snd_ctl_elem_info *uinfo)
514{
515 struct lola *chip = snd_kcontrol_chip(kcontrol);
516 int dir = kcontrol->private_value;
517
518 uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
519 uinfo->count = chip->pin[dir].num_pins;
520 uinfo->value.integer.min = 0;
521 uinfo->value.integer.max = chip->pin[dir].pins[0].amp_num_steps;
522 return 0;
523}
524
525static int lola_analog_vol_get(struct snd_kcontrol *kcontrol,
526 struct snd_ctl_elem_value *ucontrol)
527{
528 struct lola *chip = snd_kcontrol_chip(kcontrol);
529 int dir = kcontrol->private_value;
530 int i;
531
532 for (i = 0; i < chip->pin[dir].num_pins; i++)
533 ucontrol->value.integer.value[i] =
534 chip->pin[dir].pins[i].cur_gain_step;
535 return 0;
536}
537
538static int lola_analog_vol_put(struct snd_kcontrol *kcontrol,
539 struct snd_ctl_elem_value *ucontrol)
540{
541 struct lola *chip = snd_kcontrol_chip(kcontrol);
542 int dir = kcontrol->private_value;
543 int i, err;
544
545 for (i = 0; i < chip->pin[dir].num_pins; i++) {
546 err = set_analog_volume(chip, dir, i,
547 ucontrol->value.integer.value[i],
548 true);
549 if (err < 0)
550 return err;
551 }
552 return 0;
553}
554
555static int lola_analog_vol_tlv(struct snd_kcontrol *kcontrol, int op_flag,
556 unsigned int size, unsigned int __user *tlv)
557{
558 struct lola *chip = snd_kcontrol_chip(kcontrol);
559 int dir = kcontrol->private_value;
560 unsigned int val1, val2;
561 struct lola_pin *pin;
562
563 if (size < 4 * sizeof(unsigned int))
564 return -ENOMEM;
565 pin = &chip->pin[dir].pins[0];
566
567 val2 = pin->amp_step_size * 25;
568 val1 = -1 * (int)pin->amp_offset * (int)val2;
569#ifdef TLV_DB_SCALE_MUTE
570 val2 |= TLV_DB_SCALE_MUTE;
571#endif
572 if (put_user(SNDRV_CTL_TLVT_DB_SCALE, tlv))
573 return -EFAULT;
574 if (put_user(2 * sizeof(unsigned int), tlv + 1))
575 return -EFAULT;
576 if (put_user(val1, tlv + 2))
577 return -EFAULT;
578 if (put_user(val2, tlv + 3))
579 return -EFAULT;
580 return 0;
581}
582
583static struct snd_kcontrol_new lola_analog_mixer = {
584 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
585 .access = (SNDRV_CTL_ELEM_ACCESS_READWRITE |
586 SNDRV_CTL_ELEM_ACCESS_TLV_READ |
587 SNDRV_CTL_ELEM_ACCESS_TLV_CALLBACK),
588 .info = lola_analog_vol_info,
589 .get = lola_analog_vol_get,
590 .put = lola_analog_vol_put,
591 .tlv.c = lola_analog_vol_tlv,
592};
593
594static int create_analog_mixer(struct lola *chip, int dir, char *name)
595{
596 if (!chip->pin[dir].num_pins)
597 return 0;
598
599 if (chip->pin[dir].num_pins != chip->pin[dir].num_analog_pins)
600 return 0;
601 lola_analog_mixer.name = name;
602 lola_analog_mixer.private_value = dir;
603 return snd_ctl_add(chip->card,
604 snd_ctl_new1(&lola_analog_mixer, chip));
605}
606
607
608
609
610static int lola_input_src_info(struct snd_kcontrol *kcontrol,
611 struct snd_ctl_elem_info *uinfo)
612{
613 struct lola *chip = snd_kcontrol_chip(kcontrol);
614
615 uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN;
616 uinfo->count = chip->pin[CAPT].num_pins;
617 uinfo->value.integer.min = 0;
618 uinfo->value.integer.max = 1;
619 return 0;
620}
621
622static int lola_input_src_get(struct snd_kcontrol *kcontrol,
623 struct snd_ctl_elem_value *ucontrol)
624{
625 struct lola *chip = snd_kcontrol_chip(kcontrol);
626 int i;
627
628 for (i = 0; i < chip->pin[CAPT].num_pins; i++)
629 ucontrol->value.integer.value[i] =
630 !!(chip->input_src_mask & (1 << i));
631 return 0;
632}
633
634static int lola_input_src_put(struct snd_kcontrol *kcontrol,
635 struct snd_ctl_elem_value *ucontrol)
636{
637 struct lola *chip = snd_kcontrol_chip(kcontrol);
638 int i;
639 unsigned int mask;
640
641 mask = 0;
642 for (i = 0; i < chip->pin[CAPT].num_pins; i++)
643 if (ucontrol->value.integer.value[i])
644 mask |= 1 << i;
645 return lola_set_src_config(chip, mask, true);
646}
647
648static const struct snd_kcontrol_new lola_input_src_mixer = {
649 .name = "Digital SRC Capture Switch",
650 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
651 .info = lola_input_src_info,
652 .get = lola_input_src_get,
653 .put = lola_input_src_put,
654};
655
656
657
658
659
660static int create_input_src_mixer(struct lola *chip)
661{
662 if (!chip->input_src_caps_mask)
663 return 0;
664
665 return snd_ctl_add(chip->card,
666 snd_ctl_new1(&lola_input_src_mixer, chip));
667}
668
669
670
671
672static int lola_src_gain_info(struct snd_kcontrol *kcontrol,
673 struct snd_ctl_elem_info *uinfo)
674{
675 unsigned int count = (kcontrol->private_value >> 8) & 0xff;
676
677 uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
678 uinfo->count = count;
679 uinfo->value.integer.min = 0;
680 uinfo->value.integer.max = 409;
681 return 0;
682}
683
684static int lola_src_gain_get(struct snd_kcontrol *kcontrol,
685 struct snd_ctl_elem_value *ucontrol)
686{
687 struct lola *chip = snd_kcontrol_chip(kcontrol);
688 unsigned int ofs = kcontrol->private_value & 0xff;
689 unsigned int count = (kcontrol->private_value >> 8) & 0xff;
690 unsigned int mask, i;
691
692 mask = readl(&chip->mixer.array->src_gain_enable);
693 for (i = 0; i < count; i++) {
694 unsigned int idx = ofs + i;
695 unsigned short val;
696 if (!(chip->mixer.src_mask & (1 << idx)))
697 return -EINVAL;
698 if (mask & (1 << idx))
699 val = readw(&chip->mixer.array->src_gain[idx]) + 1;
700 else
701 val = 0;
702 ucontrol->value.integer.value[i] = val;
703 }
704 return 0;
705}
706
707static int lola_src_gain_put(struct snd_kcontrol *kcontrol,
708 struct snd_ctl_elem_value *ucontrol)
709{
710 struct lola *chip = snd_kcontrol_chip(kcontrol);
711 unsigned int ofs = kcontrol->private_value & 0xff;
712 unsigned int count = (kcontrol->private_value >> 8) & 0xff;
713 int i, err;
714
715 for (i = 0; i < count; i++) {
716 unsigned int idx = ofs + i;
717 unsigned short val = ucontrol->value.integer.value[i];
718 if (val)
719 val--;
720 err = lola_mixer_set_src_gain(chip, idx, val, !!val);
721 if (err < 0)
722 return err;
723 }
724 return 0;
725}
726
727
728static const DECLARE_TLV_DB_SCALE(lola_src_gain_tlv, -8425, 25, 1);
729
730static struct snd_kcontrol_new lola_src_gain_mixer = {
731 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
732 .access = (SNDRV_CTL_ELEM_ACCESS_READWRITE |
733 SNDRV_CTL_ELEM_ACCESS_TLV_READ),
734 .info = lola_src_gain_info,
735 .get = lola_src_gain_get,
736 .put = lola_src_gain_put,
737 .tlv.p = lola_src_gain_tlv,
738};
739
740static int create_src_gain_mixer(struct lola *chip,
741 int num, int ofs, char *name)
742{
743 lola_src_gain_mixer.name = name;
744 lola_src_gain_mixer.private_value = ofs + (num << 8);
745 return snd_ctl_add(chip->card,
746 snd_ctl_new1(&lola_src_gain_mixer, chip));
747}
748
749#if 0
750
751
752
753static int lola_dest_gain_info(struct snd_kcontrol *kcontrol,
754 struct snd_ctl_elem_info *uinfo)
755{
756 unsigned int src_num = (kcontrol->private_value >> 8) & 0xff;
757
758 uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
759 uinfo->count = src_num;
760 uinfo->value.integer.min = 0;
761 uinfo->value.integer.max = 433;
762 return 0;
763}
764
765static int lola_dest_gain_get(struct snd_kcontrol *kcontrol,
766 struct snd_ctl_elem_value *ucontrol)
767{
768 struct lola *chip = snd_kcontrol_chip(kcontrol);
769 unsigned int src_ofs = kcontrol->private_value & 0xff;
770 unsigned int src_num = (kcontrol->private_value >> 8) & 0xff;
771 unsigned int dst_ofs = (kcontrol->private_value >> 16) & 0xff;
772 unsigned int dst, mask, i;
773
774 dst = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id) + dst_ofs;
775 mask = readl(&chip->mixer.array->dest_mix_gain_enable[dst]);
776 for (i = 0; i < src_num; i++) {
777 unsigned int src = src_ofs + i;
778 unsigned short val;
779 if (!(chip->mixer.src_mask & (1 << src)))
780 return -EINVAL;
781 if (mask & (1 << dst))
782 val = readw(&chip->mixer.array->dest_mix_gain[dst][src]) + 1;
783 else
784 val = 0;
785 ucontrol->value.integer.value[i] = val;
786 }
787 return 0;
788}
789
790static int lola_dest_gain_put(struct snd_kcontrol *kcontrol,
791 struct snd_ctl_elem_value *ucontrol)
792{
793 struct lola *chip = snd_kcontrol_chip(kcontrol);
794 unsigned int src_ofs = kcontrol->private_value & 0xff;
795 unsigned int src_num = (kcontrol->private_value >> 8) & 0xff;
796 unsigned int dst_ofs = (kcontrol->private_value >> 16) & 0xff;
797 unsigned int dst, mask;
798 unsigned short gains[MAX_STREAM_COUNT];
799 int i, num;
800
801 mask = 0;
802 num = 0;
803 for (i = 0; i < src_num; i++) {
804 unsigned short val = ucontrol->value.integer.value[i];
805 if (val) {
806 gains[num++] = val - 1;
807 mask |= 1 << i;
808 }
809 }
810 mask <<= src_ofs;
811 dst = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id) + dst_ofs;
812 return lola_mixer_set_dest_gains(chip, dst, mask, gains);
813}
814
815static const DECLARE_TLV_DB_SCALE(lola_dest_gain_tlv, -8425, 25, 1);
816
817static struct snd_kcontrol_new lola_dest_gain_mixer = {
818 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
819 .access = (SNDRV_CTL_ELEM_ACCESS_READWRITE |
820 SNDRV_CTL_ELEM_ACCESS_TLV_READ),
821 .info = lola_dest_gain_info,
822 .get = lola_dest_gain_get,
823 .put = lola_dest_gain_put,
824 .tlv.p = lola_dest_gain_tlv,
825};
826
827static int create_dest_gain_mixer(struct lola *chip,
828 int src_num, int src_ofs,
829 int num, int ofs, char *name)
830{
831 lola_dest_gain_mixer.count = num;
832 lola_dest_gain_mixer.name = name;
833 lola_dest_gain_mixer.private_value =
834 src_ofs + (src_num << 8) + (ofs << 16) + (num << 24);
835 return snd_ctl_add(chip->card,
836 snd_ctl_new1(&lola_dest_gain_mixer, chip));
837}
838#endif
839
840
841
842int lola_create_mixer(struct lola *chip)
843{
844 int err;
845
846 err = create_analog_mixer(chip, PLAY, "Analog Playback Volume");
847 if (err < 0)
848 return err;
849 err = create_analog_mixer(chip, CAPT, "Analog Capture Volume");
850 if (err < 0)
851 return err;
852 err = create_input_src_mixer(chip);
853 if (err < 0)
854 return err;
855 err = create_src_gain_mixer(chip, chip->mixer.src_phys_ins, 0,
856 "Digital Capture Volume");
857 if (err < 0)
858 return err;
859 err = create_src_gain_mixer(chip, chip->mixer.src_stream_outs,
860 chip->mixer.src_stream_out_ofs,
861 "Digital Playback Volume");
862 if (err < 0)
863 return err;
864#if 0
865
866 err = create_dest_gain_mixer(chip,
867 chip->mixer.src_phys_ins, 0,
868 chip->mixer.dest_stream_ins, 0,
869 "Line Capture Volume");
870 if (err < 0)
871 return err;
872 err = create_dest_gain_mixer(chip,
873 chip->mixer.src_stream_outs,
874 chip->mixer.src_stream_out_ofs,
875 chip->mixer.dest_stream_ins, 0,
876 "Stream-Loopback Capture Volume");
877 if (err < 0)
878 return err;
879 err = create_dest_gain_mixer(chip,
880 chip->mixer.src_phys_ins, 0,
881 chip->mixer.dest_phys_outs,
882 chip->mixer.dest_phys_out_ofs,
883 "Line-Loopback Playback Volume");
884 if (err < 0)
885 return err;
886 err = create_dest_gain_mixer(chip,
887 chip->mixer.src_stream_outs,
888 chip->mixer.src_stream_out_ofs,
889 chip->mixer.dest_phys_outs,
890 chip->mixer.dest_phys_out_ofs,
891 "Stream Playback Volume");
892 if (err < 0)
893 return err;
894#endif
895 return init_mixer_values(chip);
896}
897