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 printk(KERN_ERR SFX "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 printk(KERN_ERR SFX "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 printk(KERN_ERR SFX "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 printk(KERN_ERR SFX "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 if (chip->mixer.array_saved)
112 vfree(chip->mixer.array_saved);
113}
114
115int lola_init_mixer_widget(struct lola *chip, int nid)
116{
117 unsigned int val;
118 int err;
119
120 err = lola_read_param(chip, nid, LOLA_PAR_AUDIO_WIDGET_CAP, &val);
121 if (err < 0) {
122 printk(KERN_ERR SFX "Can't read wcaps for 0x%x\n", nid);
123 return err;
124 }
125
126 if ((val & 0xfff00000) != 0x02f00000) {
127 snd_printdd("No valid mixer widget\n");
128 return 0;
129 }
130
131 chip->mixer.nid = nid;
132 chip->mixer.caps = val;
133 chip->mixer.array = (struct lola_mixer_array __iomem *)
134 (chip->bar[BAR1].remap_addr + LOLA_BAR1_SOURCE_GAIN_ENABLE);
135
136
137 chip->mixer.array_saved = vmalloc(sizeof(struct lola_mixer_array));
138
139
140 chip->mixer.src_stream_outs = chip->pcm[PLAY].num_streams;
141 chip->mixer.src_phys_ins = chip->pin[CAPT].num_pins;
142
143
144 chip->mixer.dest_stream_ins = chip->pcm[CAPT].num_streams;
145 chip->mixer.dest_phys_outs = chip->pin[PLAY].num_pins;
146
147
148
149
150 chip->mixer.src_stream_out_ofs = chip->mixer.src_phys_ins +
151 LOLA_MIXER_SRC_INPUT_PLAY_SEPARATION(val);
152 chip->mixer.dest_phys_out_ofs = chip->mixer.dest_stream_ins +
153 LOLA_MIXER_DEST_REC_OUTPUT_SEPARATION(val);
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
203 if (chip->mixer.src_stream_out_ofs > MAX_AUDIO_INOUT_COUNT ||
204 chip->mixer.dest_phys_out_ofs > MAX_STREAM_IN_COUNT) {
205 printk(KERN_ERR SFX "Invalid mixer widget size\n");
206 return -EINVAL;
207 }
208
209 chip->mixer.src_mask = ((1U << chip->mixer.src_phys_ins) - 1) |
210 (((1U << chip->mixer.src_stream_outs) - 1)
211 << chip->mixer.src_stream_out_ofs);
212 chip->mixer.dest_mask = ((1U << chip->mixer.dest_stream_ins) - 1) |
213 (((1U << chip->mixer.dest_phys_outs) - 1)
214 << chip->mixer.dest_phys_out_ofs);
215
216 snd_printdd("Mixer src_mask=%x, dest_mask=%x\n",
217 chip->mixer.src_mask, chip->mixer.dest_mask);
218
219 return 0;
220}
221
222static int lola_mixer_set_src_gain(struct lola *chip, unsigned int id,
223 unsigned short gain, bool on)
224{
225 unsigned int oldval, val;
226
227 if (!(chip->mixer.src_mask & (1 << id)))
228 return -EINVAL;
229 oldval = val = readl(&chip->mixer.array->src_gain_enable);
230 if (on)
231 val |= (1 << id);
232 else
233 val &= ~(1 << id);
234
235 if ((val == oldval) &&
236 (gain == readw(&chip->mixer.array->src_gain[id])))
237 return 0;
238
239 snd_printdd("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 snd_printdd("set_analog_volume (dir=%d idx=%d, volume=%d)\n",
413 dir, idx, val);
414 err = lola_codec_write(chip, pin->nid,
415 LOLA_VERB_SET_AMP_GAIN_MUTE, val, 0);
416 if (err < 0)
417 return err;
418 if (external_call)
419 pin->cur_gain_step = val;
420 return 0;
421}
422
423int lola_set_src_config(struct lola *chip, unsigned int src_mask, bool update)
424{
425 int ret = 0;
426 int success = 0;
427 int n, err;
428
429
430 if ((chip->input_src_caps_mask & src_mask) != src_mask)
431 return -EINVAL;
432
433 for (n = 0; n < chip->pin[CAPT].num_pins; n += 2) {
434 unsigned int mask = 3U << n;
435 unsigned int new_src, src_state;
436 if (!(chip->input_src_caps_mask & mask))
437 continue;
438
439 new_src = (src_mask & mask) != 0;
440 if (update) {
441 src_state = (chip->input_src_mask & mask) != 0;
442 if (src_state == new_src)
443 continue;
444 }
445 err = lola_codec_write(chip, chip->pcm[CAPT].streams[n].nid,
446 LOLA_VERB_SET_SRC, new_src, 0);
447 if (!err)
448 success++;
449 else
450 ret = err;
451 }
452 if (success)
453 ret = lola_codec_flush(chip);
454 if (!ret)
455 chip->input_src_mask = src_mask;
456 return ret;
457}
458
459
460
461static int init_mixer_values(struct lola *chip)
462{
463 int i;
464
465
466 lola_set_src_config(chip, (1 << chip->pin[CAPT].num_pins) - 1, false);
467
468
469 memset_io(chip->mixer.array, 0, sizeof(*chip->mixer.array));
470
471 for (i = 0; i < chip->mixer.dest_stream_ins; i++)
472 lola_codec_write(chip, chip->mixer.nid,
473 LOLA_VERB_SET_DESTINATION_GAIN,
474 i, 0);
475
476 for (i = 0; i < chip->mixer.dest_phys_outs; i++)
477 lola_codec_write(chip, chip->mixer.nid,
478 LOLA_VERB_SET_DESTINATION_GAIN,
479 chip->mixer.dest_phys_out_ofs + i, 0);
480
481
482 for (i = 0; i < chip->mixer.src_phys_ins; i++)
483 lola_mixer_set_src_gain(chip, i, 336, true);
484
485
486 for (i = 0; i < chip->mixer.src_stream_outs; i++)
487 lola_mixer_set_src_gain(chip,
488 i + chip->mixer.src_stream_out_ofs,
489 336, true);
490
491 for (i = 0; i < chip->mixer.dest_stream_ins; i++) {
492 int src = i % chip->mixer.src_phys_ins;
493 lola_mixer_set_mapping_gain(chip, src, i, 336, true);
494 }
495
496
497
498
499 for (i = 0; i < chip->mixer.src_stream_outs; i++) {
500 int src = chip->mixer.src_stream_out_ofs + i;
501 int dst = chip->mixer.dest_phys_out_ofs +
502 i % chip->mixer.dest_phys_outs;
503 lola_mixer_set_mapping_gain(chip, src, dst, 336, true);
504 }
505 return 0;
506}
507
508
509
510
511static int lola_analog_vol_info(struct snd_kcontrol *kcontrol,
512 struct snd_ctl_elem_info *uinfo)
513{
514 struct lola *chip = snd_kcontrol_chip(kcontrol);
515 int dir = kcontrol->private_value;
516
517 uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
518 uinfo->count = chip->pin[dir].num_pins;
519 uinfo->value.integer.min = 0;
520 uinfo->value.integer.max = chip->pin[dir].pins[0].amp_num_steps;
521 return 0;
522}
523
524static int lola_analog_vol_get(struct snd_kcontrol *kcontrol,
525 struct snd_ctl_elem_value *ucontrol)
526{
527 struct lola *chip = snd_kcontrol_chip(kcontrol);
528 int dir = kcontrol->private_value;
529 int i;
530
531 for (i = 0; i < chip->pin[dir].num_pins; i++)
532 ucontrol->value.integer.value[i] =
533 chip->pin[dir].pins[i].cur_gain_step;
534 return 0;
535}
536
537static int lola_analog_vol_put(struct snd_kcontrol *kcontrol,
538 struct snd_ctl_elem_value *ucontrol)
539{
540 struct lola *chip = snd_kcontrol_chip(kcontrol);
541 int dir = kcontrol->private_value;
542 int i, err;
543
544 for (i = 0; i < chip->pin[dir].num_pins; i++) {
545 err = set_analog_volume(chip, dir, i,
546 ucontrol->value.integer.value[i],
547 true);
548 if (err < 0)
549 return err;
550 }
551 return 0;
552}
553
554static int lola_analog_vol_tlv(struct snd_kcontrol *kcontrol, int op_flag,
555 unsigned int size, unsigned int __user *tlv)
556{
557 struct lola *chip = snd_kcontrol_chip(kcontrol);
558 int dir = kcontrol->private_value;
559 unsigned int val1, val2;
560 struct lola_pin *pin;
561
562 if (size < 4 * sizeof(unsigned int))
563 return -ENOMEM;
564 pin = &chip->pin[dir].pins[0];
565
566 val2 = pin->amp_step_size * 25;
567 val1 = -1 * (int)pin->amp_offset * (int)val2;
568#ifdef TLV_DB_SCALE_MUTE
569 val2 |= TLV_DB_SCALE_MUTE;
570#endif
571 if (put_user(SNDRV_CTL_TLVT_DB_SCALE, tlv))
572 return -EFAULT;
573 if (put_user(2 * sizeof(unsigned int), tlv + 1))
574 return -EFAULT;
575 if (put_user(val1, tlv + 2))
576 return -EFAULT;
577 if (put_user(val2, tlv + 3))
578 return -EFAULT;
579 return 0;
580}
581
582static struct snd_kcontrol_new lola_analog_mixer = {
583 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
584 .access = (SNDRV_CTL_ELEM_ACCESS_READWRITE |
585 SNDRV_CTL_ELEM_ACCESS_TLV_READ |
586 SNDRV_CTL_ELEM_ACCESS_TLV_CALLBACK),
587 .info = lola_analog_vol_info,
588 .get = lola_analog_vol_get,
589 .put = lola_analog_vol_put,
590 .tlv.c = lola_analog_vol_tlv,
591};
592
593static int create_analog_mixer(struct lola *chip, int dir, char *name)
594{
595 if (!chip->pin[dir].num_pins)
596 return 0;
597
598 if (chip->pin[dir].num_pins != chip->pin[dir].num_analog_pins)
599 return 0;
600 lola_analog_mixer.name = name;
601 lola_analog_mixer.private_value = dir;
602 return snd_ctl_add(chip->card,
603 snd_ctl_new1(&lola_analog_mixer, chip));
604}
605
606
607
608
609static int lola_input_src_info(struct snd_kcontrol *kcontrol,
610 struct snd_ctl_elem_info *uinfo)
611{
612 struct lola *chip = snd_kcontrol_chip(kcontrol);
613
614 uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN;
615 uinfo->count = chip->pin[CAPT].num_pins;
616 uinfo->value.integer.min = 0;
617 uinfo->value.integer.max = 1;
618 return 0;
619}
620
621static int lola_input_src_get(struct snd_kcontrol *kcontrol,
622 struct snd_ctl_elem_value *ucontrol)
623{
624 struct lola *chip = snd_kcontrol_chip(kcontrol);
625 int i;
626
627 for (i = 0; i < chip->pin[CAPT].num_pins; i++)
628 ucontrol->value.integer.value[i] =
629 !!(chip->input_src_mask & (1 << i));
630 return 0;
631}
632
633static int lola_input_src_put(struct snd_kcontrol *kcontrol,
634 struct snd_ctl_elem_value *ucontrol)
635{
636 struct lola *chip = snd_kcontrol_chip(kcontrol);
637 int i;
638 unsigned int mask;
639
640 mask = 0;
641 for (i = 0; i < chip->pin[CAPT].num_pins; i++)
642 if (ucontrol->value.integer.value[i])
643 mask |= 1 << i;
644 return lola_set_src_config(chip, mask, true);
645}
646
647static struct snd_kcontrol_new lola_input_src_mixer = {
648 .name = "Digital SRC Capture Switch",
649 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
650 .info = lola_input_src_info,
651 .get = lola_input_src_get,
652 .put = lola_input_src_put,
653};
654
655
656
657
658
659static int create_input_src_mixer(struct lola *chip)
660{
661 if (!chip->input_src_caps_mask)
662 return 0;
663
664 return snd_ctl_add(chip->card,
665 snd_ctl_new1(&lola_input_src_mixer, chip));
666}
667
668
669
670
671static int lola_src_gain_info(struct snd_kcontrol *kcontrol,
672 struct snd_ctl_elem_info *uinfo)
673{
674 unsigned int count = (kcontrol->private_value >> 8) & 0xff;
675
676 uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
677 uinfo->count = count;
678 uinfo->value.integer.min = 0;
679 uinfo->value.integer.max = 409;
680 return 0;
681}
682
683static int lola_src_gain_get(struct snd_kcontrol *kcontrol,
684 struct snd_ctl_elem_value *ucontrol)
685{
686 struct lola *chip = snd_kcontrol_chip(kcontrol);
687 unsigned int ofs = kcontrol->private_value & 0xff;
688 unsigned int count = (kcontrol->private_value >> 8) & 0xff;
689 unsigned int mask, i;
690
691 mask = readl(&chip->mixer.array->src_gain_enable);
692 for (i = 0; i < count; i++) {
693 unsigned int idx = ofs + i;
694 unsigned short val;
695 if (!(chip->mixer.src_mask & (1 << idx)))
696 return -EINVAL;
697 if (mask & (1 << idx))
698 val = readw(&chip->mixer.array->src_gain[idx]) + 1;
699 else
700 val = 0;
701 ucontrol->value.integer.value[i] = val;
702 }
703 return 0;
704}
705
706static int lola_src_gain_put(struct snd_kcontrol *kcontrol,
707 struct snd_ctl_elem_value *ucontrol)
708{
709 struct lola *chip = snd_kcontrol_chip(kcontrol);
710 unsigned int ofs = kcontrol->private_value & 0xff;
711 unsigned int count = (kcontrol->private_value >> 8) & 0xff;
712 int i, err;
713
714 for (i = 0; i < count; i++) {
715 unsigned int idx = ofs + i;
716 unsigned short val = ucontrol->value.integer.value[i];
717 if (val)
718 val--;
719 err = lola_mixer_set_src_gain(chip, idx, val, !!val);
720 if (err < 0)
721 return err;
722 }
723 return 0;
724}
725
726
727static const DECLARE_TLV_DB_SCALE(lola_src_gain_tlv, -8425, 25, 1);
728
729static struct snd_kcontrol_new lola_src_gain_mixer = {
730 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
731 .access = (SNDRV_CTL_ELEM_ACCESS_READWRITE |
732 SNDRV_CTL_ELEM_ACCESS_TLV_READ),
733 .info = lola_src_gain_info,
734 .get = lola_src_gain_get,
735 .put = lola_src_gain_put,
736 .tlv.p = lola_src_gain_tlv,
737};
738
739static int create_src_gain_mixer(struct lola *chip,
740 int num, int ofs, char *name)
741{
742 lola_src_gain_mixer.name = name;
743 lola_src_gain_mixer.private_value = ofs + (num << 8);
744 return snd_ctl_add(chip->card,
745 snd_ctl_new1(&lola_src_gain_mixer, chip));
746}
747
748#if 0
749
750
751
752static int lola_dest_gain_info(struct snd_kcontrol *kcontrol,
753 struct snd_ctl_elem_info *uinfo)
754{
755 unsigned int src_num = (kcontrol->private_value >> 8) & 0xff;
756
757 uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
758 uinfo->count = src_num;
759 uinfo->value.integer.min = 0;
760 uinfo->value.integer.max = 433;
761 return 0;
762}
763
764static int lola_dest_gain_get(struct snd_kcontrol *kcontrol,
765 struct snd_ctl_elem_value *ucontrol)
766{
767 struct lola *chip = snd_kcontrol_chip(kcontrol);
768 unsigned int src_ofs = kcontrol->private_value & 0xff;
769 unsigned int src_num = (kcontrol->private_value >> 8) & 0xff;
770 unsigned int dst_ofs = (kcontrol->private_value >> 16) & 0xff;
771 unsigned int dst, mask, i;
772
773 dst = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id) + dst_ofs;
774 mask = readl(&chip->mixer.array->dest_mix_gain_enable[dst]);
775 for (i = 0; i < src_num; i++) {
776 unsigned int src = src_ofs + i;
777 unsigned short val;
778 if (!(chip->mixer.src_mask & (1 << src)))
779 return -EINVAL;
780 if (mask & (1 << dst))
781 val = readw(&chip->mixer.array->dest_mix_gain[dst][src]) + 1;
782 else
783 val = 0;
784 ucontrol->value.integer.value[i] = val;
785 }
786 return 0;
787}
788
789static int lola_dest_gain_put(struct snd_kcontrol *kcontrol,
790 struct snd_ctl_elem_value *ucontrol)
791{
792 struct lola *chip = snd_kcontrol_chip(kcontrol);
793 unsigned int src_ofs = kcontrol->private_value & 0xff;
794 unsigned int src_num = (kcontrol->private_value >> 8) & 0xff;
795 unsigned int dst_ofs = (kcontrol->private_value >> 16) & 0xff;
796 unsigned int dst, mask;
797 unsigned short gains[MAX_STREAM_COUNT];
798 int i, num;
799
800 mask = 0;
801 num = 0;
802 for (i = 0; i < src_num; i++) {
803 unsigned short val = ucontrol->value.integer.value[i];
804 if (val) {
805 gains[num++] = val - 1;
806 mask |= 1 << i;
807 }
808 }
809 mask <<= src_ofs;
810 dst = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id) + dst_ofs;
811 return lola_mixer_set_dest_gains(chip, dst, mask, gains);
812}
813
814static const DECLARE_TLV_DB_SCALE(lola_dest_gain_tlv, -8425, 25, 1);
815
816static struct snd_kcontrol_new lola_dest_gain_mixer = {
817 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
818 .access = (SNDRV_CTL_ELEM_ACCESS_READWRITE |
819 SNDRV_CTL_ELEM_ACCESS_TLV_READ),
820 .info = lola_dest_gain_info,
821 .get = lola_dest_gain_get,
822 .put = lola_dest_gain_put,
823 .tlv.p = lola_dest_gain_tlv,
824};
825
826static int create_dest_gain_mixer(struct lola *chip,
827 int src_num, int src_ofs,
828 int num, int ofs, char *name)
829{
830 lola_dest_gain_mixer.count = num;
831 lola_dest_gain_mixer.name = name;
832 lola_dest_gain_mixer.private_value =
833 src_ofs + (src_num << 8) + (ofs << 16) + (num << 24);
834 return snd_ctl_add(chip->card,
835 snd_ctl_new1(&lola_dest_gain_mixer, chip));
836}
837#endif
838
839
840
841int lola_create_mixer(struct lola *chip)
842{
843 int err;
844
845 err = create_analog_mixer(chip, PLAY, "Analog Playback Volume");
846 if (err < 0)
847 return err;
848 err = create_analog_mixer(chip, CAPT, "Analog Capture Volume");
849 if (err < 0)
850 return err;
851 err = create_input_src_mixer(chip);
852 if (err < 0)
853 return err;
854 err = create_src_gain_mixer(chip, chip->mixer.src_phys_ins, 0,
855 "Digital Capture Volume");
856 if (err < 0)
857 return err;
858 err = create_src_gain_mixer(chip, chip->mixer.src_stream_outs,
859 chip->mixer.src_stream_out_ofs,
860 "Digital Playback Volume");
861 if (err < 0)
862 return err;
863#if 0
864
865 err = create_dest_gain_mixer(chip,
866 chip->mixer.src_phys_ins, 0,
867 chip->mixer.dest_stream_ins, 0,
868 "Line Capture Volume");
869 if (err < 0)
870 return err;
871 err = create_dest_gain_mixer(chip,
872 chip->mixer.src_stream_outs,
873 chip->mixer.src_stream_out_ofs,
874 chip->mixer.dest_stream_ins, 0,
875 "Stream-Loopback Capture Volume");
876 if (err < 0)
877 return err;
878 err = create_dest_gain_mixer(chip,
879 chip->mixer.src_phys_ins, 0,
880 chip->mixer.dest_phys_outs,
881 chip->mixer.dest_phys_out_ofs,
882 "Line-Loopback Playback Volume");
883 if (err < 0)
884 return err;
885 err = create_dest_gain_mixer(chip,
886 chip->mixer.src_stream_outs,
887 chip->mixer.src_stream_out_ofs,
888 chip->mixer.dest_phys_outs,
889 chip->mixer.dest_phys_out_ofs,
890 "Stream Playback Volume");
891 if (err < 0)
892 return err;
893#endif
894 return init_mixer_values(chip);
895}
896