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