diff options
Diffstat (limited to 'sound/i2c')
-rw-r--r-- | sound/i2c/other/ak4xxx-adda.c | 89 |
1 files changed, 83 insertions, 6 deletions
diff --git a/sound/i2c/other/ak4xxx-adda.c b/sound/i2c/other/ak4xxx-adda.c index 045e32a311e0..f68bd740e1a1 100644 --- a/sound/i2c/other/ak4xxx-adda.c +++ b/sound/i2c/other/ak4xxx-adda.c | |||
@@ -292,6 +292,64 @@ static int snd_akm4xxx_volume_put(struct snd_kcontrol *kcontrol, | |||
292 | return change; | 292 | return change; |
293 | } | 293 | } |
294 | 294 | ||
295 | static int snd_akm4xxx_stereo_volume_info(struct snd_kcontrol *kcontrol, | ||
296 | struct snd_ctl_elem_info *uinfo) | ||
297 | { | ||
298 | unsigned int mask = AK_GET_MASK(kcontrol->private_value); | ||
299 | |||
300 | uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER; | ||
301 | uinfo->count = 2; | ||
302 | uinfo->value.integer.min = 0; | ||
303 | uinfo->value.integer.max = mask; | ||
304 | return 0; | ||
305 | } | ||
306 | |||
307 | static int snd_akm4xxx_stereo_volume_get(struct snd_kcontrol *kcontrol, | ||
308 | struct snd_ctl_elem_value *ucontrol) | ||
309 | { | ||
310 | struct snd_akm4xxx *ak = snd_kcontrol_chip(kcontrol); | ||
311 | int chip = AK_GET_CHIP(kcontrol->private_value); | ||
312 | int addr = AK_GET_ADDR(kcontrol->private_value); | ||
313 | int invert = AK_GET_INVERT(kcontrol->private_value); | ||
314 | unsigned int mask = AK_GET_MASK(kcontrol->private_value); | ||
315 | unsigned char val = snd_akm4xxx_get(ak, chip, addr); | ||
316 | |||
317 | ucontrol->value.integer.value[0] = invert ? mask - val : val; | ||
318 | |||
319 | val = snd_akm4xxx_get(ak, chip, addr+1); | ||
320 | ucontrol->value.integer.value[1] = invert ? mask - val : val; | ||
321 | |||
322 | return 0; | ||
323 | } | ||
324 | |||
325 | static int snd_akm4xxx_stereo_volume_put(struct snd_kcontrol *kcontrol, | ||
326 | struct snd_ctl_elem_value *ucontrol) | ||
327 | { | ||
328 | struct snd_akm4xxx *ak = snd_kcontrol_chip(kcontrol); | ||
329 | int chip = AK_GET_CHIP(kcontrol->private_value); | ||
330 | int addr = AK_GET_ADDR(kcontrol->private_value); | ||
331 | int invert = AK_GET_INVERT(kcontrol->private_value); | ||
332 | unsigned int mask = AK_GET_MASK(kcontrol->private_value); | ||
333 | unsigned char nval = ucontrol->value.integer.value[0] % (mask+1); | ||
334 | int change0, change1; | ||
335 | |||
336 | if (invert) | ||
337 | nval = mask - nval; | ||
338 | change0 = snd_akm4xxx_get(ak, chip, addr) != nval; | ||
339 | if (change0) | ||
340 | snd_akm4xxx_write(ak, chip, addr, nval); | ||
341 | |||
342 | nval = ucontrol->value.integer.value[1] % (mask+1); | ||
343 | if (invert) | ||
344 | nval = mask - nval; | ||
345 | change1 = snd_akm4xxx_get(ak, chip, addr+1) != nval; | ||
346 | if (change1) | ||
347 | snd_akm4xxx_write(ak, chip, addr+1, nval); | ||
348 | |||
349 | |||
350 | return change0 || change1; | ||
351 | } | ||
352 | |||
295 | static int snd_akm4xxx_ipga_gain_info(struct snd_kcontrol *kcontrol, | 353 | static int snd_akm4xxx_ipga_gain_info(struct snd_kcontrol *kcontrol, |
296 | struct snd_ctl_elem_info *uinfo) | 354 | struct snd_ctl_elem_info *uinfo) |
297 | { | 355 | { |
@@ -377,20 +435,35 @@ int snd_akm4xxx_build_controls(struct snd_akm4xxx *ak) | |||
377 | unsigned int idx, num_emphs; | 435 | unsigned int idx, num_emphs; |
378 | struct snd_kcontrol *ctl; | 436 | struct snd_kcontrol *ctl; |
379 | int err; | 437 | int err; |
438 | int mixer_ch = 0; | ||
439 | int num_stereo; | ||
380 | 440 | ||
381 | ctl = kmalloc(sizeof(*ctl), GFP_KERNEL); | 441 | ctl = kmalloc(sizeof(*ctl), GFP_KERNEL); |
382 | if (! ctl) | 442 | if (! ctl) |
383 | return -ENOMEM; | 443 | return -ENOMEM; |
384 | 444 | ||
385 | for (idx = 0; idx < ak->num_dacs; ++idx) { | 445 | for (idx = 0; idx < ak->num_dacs; ) { |
386 | memset(ctl, 0, sizeof(*ctl)); | 446 | memset(ctl, 0, sizeof(*ctl)); |
387 | strcpy(ctl->id.name, "DAC Volume"); | 447 | if (ak->channel_names == NULL) { |
388 | ctl->id.index = idx + ak->idx_offset * 2; | 448 | strcpy(ctl->id.name, "DAC Volume"); |
449 | num_stereo = 1; | ||
450 | ctl->id.index = mixer_ch + ak->idx_offset * 2; | ||
451 | } else { | ||
452 | strcpy(ctl->id.name, ak->channel_names[mixer_ch]); | ||
453 | num_stereo = ak->num_stereo[mixer_ch]; | ||
454 | ctl->id.index = 0; //mixer_ch + ak->idx_offset * 2; | ||
455 | } | ||
389 | ctl->id.iface = SNDRV_CTL_ELEM_IFACE_MIXER; | 456 | ctl->id.iface = SNDRV_CTL_ELEM_IFACE_MIXER; |
390 | ctl->count = 1; | 457 | ctl->count = 1; |
391 | ctl->info = snd_akm4xxx_volume_info; | 458 | if (num_stereo == 2) { |
392 | ctl->get = snd_akm4xxx_volume_get; | 459 | ctl->info = snd_akm4xxx_stereo_volume_info; |
393 | ctl->put = snd_akm4xxx_volume_put; | 460 | ctl->get = snd_akm4xxx_stereo_volume_get; |
461 | ctl->put = snd_akm4xxx_stereo_volume_put; | ||
462 | } else { | ||
463 | ctl->info = snd_akm4xxx_volume_info; | ||
464 | ctl->get = snd_akm4xxx_volume_get; | ||
465 | ctl->put = snd_akm4xxx_volume_put; | ||
466 | } | ||
394 | switch (ak->type) { | 467 | switch (ak->type) { |
395 | case SND_AK4524: | 468 | case SND_AK4524: |
396 | ctl->private_value = AK_COMPOSE(idx/2, (idx%2) + 6, 0, 127); /* register 6 & 7 */ | 469 | ctl->private_value = AK_COMPOSE(idx/2, (idx%2) + 6, 0, 127); /* register 6 & 7 */ |
@@ -419,9 +492,13 @@ int snd_akm4xxx_build_controls(struct snd_akm4xxx *ak) | |||
419 | err = -EINVAL; | 492 | err = -EINVAL; |
420 | goto __error; | 493 | goto __error; |
421 | } | 494 | } |
495 | |||
422 | ctl->private_data = ak; | 496 | ctl->private_data = ak; |
423 | if ((err = snd_ctl_add(ak->card, snd_ctl_new(ctl, SNDRV_CTL_ELEM_ACCESS_READ|SNDRV_CTL_ELEM_ACCESS_WRITE))) < 0) | 497 | if ((err = snd_ctl_add(ak->card, snd_ctl_new(ctl, SNDRV_CTL_ELEM_ACCESS_READ|SNDRV_CTL_ELEM_ACCESS_WRITE))) < 0) |
424 | goto __error; | 498 | goto __error; |
499 | |||
500 | idx += num_stereo; | ||
501 | mixer_ch++; | ||
425 | } | 502 | } |
426 | for (idx = 0; idx < ak->num_adcs && ak->type == SND_AK4524; ++idx) { | 503 | for (idx = 0; idx < ak->num_adcs && ak->type == SND_AK4524; ++idx) { |
427 | memset(ctl, 0, sizeof(*ctl)); | 504 | memset(ctl, 0, sizeof(*ctl)); |