diff options
author | Timur Tabi <timur@freescale.com> | 2009-02-03 12:09:32 -0500 |
---|---|---|
committer | Mark Brown <broonie@opensource.wolfsonmicro.com> | 2009-02-13 08:32:51 -0500 |
commit | d5e9ba1d58b6da1c58a91113fc350ece97ec5a0b (patch) | |
tree | c6b9435abab7a889784f76ef6a746316d914a934 /sound/soc/codecs/cs4270.c | |
parent | 9e32ebdb3aa4e5d2366b032baa16b95f3d7788b9 (diff) |
ASoC: add additional controls to the CS4270 codec driver
Update the CS4270 codec driver to allow applications to use the mixer to
control Digital Loopback, Soft Ramp, Zero Cross, Popguard, and Auto-Mute.
Soft Ramp, Zero Cross, and Auto-Mute are disabled by the driver when it first
initializes the hardware, but these features either don't work or interfere
with normal ALSA behavior. However, they can now be re-enabled by an
application if desired.
Remove CONFIG_SND_SOC_CS4270_HWMUTE and always allow ASoC to control the mute
bits. The driver previously and erroneously assumed that these bits
control only external muting circuitry, but they also control internal
muting circuitry, so they should always be used.
Signed-off-by: Timur Tabi <timur@freescale.com>
Signed-off-by: Mark Brown <broonie@opensource.wolfsonmicro.com>
Diffstat (limited to 'sound/soc/codecs/cs4270.c')
-rw-r--r-- | sound/soc/codecs/cs4270.c | 93 |
1 files changed, 40 insertions, 53 deletions
diff --git a/sound/soc/codecs/cs4270.c b/sound/soc/codecs/cs4270.c index 2c79a24186fd..cd4a9ee38e46 100644 --- a/sound/soc/codecs/cs4270.c +++ b/sound/soc/codecs/cs4270.c | |||
@@ -395,17 +395,7 @@ static int cs4270_hw_params(struct snd_pcm_substream *substream, | |||
395 | return -EINVAL; | 395 | return -EINVAL; |
396 | } | 396 | } |
397 | 397 | ||
398 | /* Freeze and power-down the codec */ | 398 | /* Set the sample rate */ |
399 | |||
400 | ret = snd_soc_write(codec, CS4270_PWRCTL, CS4270_PWRCTL_FREEZE | | ||
401 | CS4270_PWRCTL_PDN_ADC | CS4270_PWRCTL_PDN_DAC | | ||
402 | CS4270_PWRCTL_PDN); | ||
403 | if (ret < 0) { | ||
404 | dev_err(codec->dev, "i2c write failed\n"); | ||
405 | return ret; | ||
406 | } | ||
407 | |||
408 | /* Program the mode control register */ | ||
409 | 399 | ||
410 | reg = snd_soc_read(codec, CS4270_MODE); | 400 | reg = snd_soc_read(codec, CS4270_MODE); |
411 | reg &= ~(CS4270_MODE_SPEED_MASK | CS4270_MODE_DIV_MASK); | 401 | reg &= ~(CS4270_MODE_SPEED_MASK | CS4270_MODE_DIV_MASK); |
@@ -417,7 +407,7 @@ static int cs4270_hw_params(struct snd_pcm_substream *substream, | |||
417 | return ret; | 407 | return ret; |
418 | } | 408 | } |
419 | 409 | ||
420 | /* Program the format register */ | 410 | /* Set the DAI format */ |
421 | 411 | ||
422 | reg = snd_soc_read(codec, CS4270_FORMAT); | 412 | reg = snd_soc_read(codec, CS4270_FORMAT); |
423 | reg &= ~(CS4270_FORMAT_DAC_MASK | CS4270_FORMAT_ADC_MASK); | 413 | reg &= ~(CS4270_FORMAT_DAC_MASK | CS4270_FORMAT_ADC_MASK); |
@@ -440,42 +430,9 @@ static int cs4270_hw_params(struct snd_pcm_substream *substream, | |||
440 | return ret; | 430 | return ret; |
441 | } | 431 | } |
442 | 432 | ||
443 | /* Disable auto-mute. This feature appears to be buggy, because in | ||
444 | some situations, auto-mute will not deactivate when it should. */ | ||
445 | |||
446 | reg = snd_soc_read(codec, CS4270_MUTE); | ||
447 | reg &= ~CS4270_MUTE_AUTO; | ||
448 | ret = snd_soc_write(codec, CS4270_MUTE, reg); | ||
449 | if (ret < 0) { | ||
450 | dev_err(codec->dev, "i2c write failed\n"); | ||
451 | return ret; | ||
452 | } | ||
453 | |||
454 | /* Disable automatic volume control. It's enabled by default, and | ||
455 | * it causes volume change commands to be delayed, sometimes until | ||
456 | * after playback has started. | ||
457 | */ | ||
458 | |||
459 | reg = cs4270_read_reg_cache(codec, CS4270_TRANS); | ||
460 | reg &= ~(CS4270_TRANS_SOFT | CS4270_TRANS_ZERO); | ||
461 | ret = cs4270_i2c_write(codec, CS4270_TRANS, reg); | ||
462 | if (ret < 0) { | ||
463 | dev_err(codec->dev, "i2c write failed\n"); | ||
464 | return ret; | ||
465 | } | ||
466 | |||
467 | /* Thaw and power-up the codec */ | ||
468 | |||
469 | ret = snd_soc_write(codec, CS4270_PWRCTL, 0); | ||
470 | if (ret < 0) { | ||
471 | dev_err(codec->dev, "i2c write failed\n"); | ||
472 | return ret; | ||
473 | } | ||
474 | |||
475 | return ret; | 433 | return ret; |
476 | } | 434 | } |
477 | 435 | ||
478 | #ifdef CONFIG_SND_SOC_CS4270_HWMUTE | ||
479 | /** | 436 | /** |
480 | * cs4270_mute - enable/disable the CS4270 external mute | 437 | * cs4270_mute - enable/disable the CS4270 external mute |
481 | * @dai: the SOC DAI | 438 | * @dai: the SOC DAI |
@@ -494,22 +451,23 @@ static int cs4270_mute(struct snd_soc_dai *dai, int mute) | |||
494 | reg6 = snd_soc_read(codec, CS4270_MUTE); | 451 | reg6 = snd_soc_read(codec, CS4270_MUTE); |
495 | 452 | ||
496 | if (mute) | 453 | if (mute) |
497 | reg6 |= CS4270_MUTE_ADC_A | CS4270_MUTE_ADC_B | | 454 | reg6 |= CS4270_MUTE_DAC_A | CS4270_MUTE_DAC_B; |
498 | CS4270_MUTE_DAC_A | CS4270_MUTE_DAC_B; | ||
499 | else | 455 | else |
500 | reg6 &= ~(CS4270_MUTE_ADC_A | CS4270_MUTE_ADC_B | | 456 | reg6 &= ~(CS4270_MUTE_DAC_A | CS4270_MUTE_DAC_B); |
501 | CS4270_MUTE_DAC_A | CS4270_MUTE_DAC_B); | ||
502 | 457 | ||
503 | return snd_soc_write(codec, CS4270_MUTE, reg6); | 458 | return snd_soc_write(codec, CS4270_MUTE, reg6); |
504 | } | 459 | } |
505 | #else | ||
506 | #define cs4270_mute NULL | ||
507 | #endif | ||
508 | 460 | ||
509 | /* A list of non-DAPM controls that the CS4270 supports */ | 461 | /* A list of non-DAPM controls that the CS4270 supports */ |
510 | static const struct snd_kcontrol_new cs4270_snd_controls[] = { | 462 | static const struct snd_kcontrol_new cs4270_snd_controls[] = { |
511 | SOC_DOUBLE_R("Master Playback Volume", | 463 | SOC_DOUBLE_R("Master Playback Volume", |
512 | CS4270_VOLA, CS4270_VOLB, 0, 0xFF, 1) | 464 | CS4270_VOLA, CS4270_VOLB, 0, 0xFF, 1), |
465 | SOC_SINGLE("Digital Sidetone Switch", CS4270_FORMAT, 5, 1, 0), | ||
466 | SOC_SINGLE("Soft Ramp Switch", CS4270_TRANS, 6, 1, 0), | ||
467 | SOC_SINGLE("Zero Cross Switch", CS4270_TRANS, 5, 1, 0), | ||
468 | SOC_SINGLE("Popguard Switch", CS4270_MODE, 0, 1, 1), | ||
469 | SOC_SINGLE("Auto-Mute Switch", CS4270_MUTE, 5, 1, 0), | ||
470 | SOC_DOUBLE("Master Capture Switch", CS4270_MUTE, 3, 4, 1, 0) | ||
513 | }; | 471 | }; |
514 | 472 | ||
515 | /* | 473 | /* |
@@ -637,6 +595,7 @@ static int cs4270_i2c_probe(struct i2c_client *i2c_client, | |||
637 | { | 595 | { |
638 | struct snd_soc_codec *codec; | 596 | struct snd_soc_codec *codec; |
639 | struct cs4270_private *cs4270; | 597 | struct cs4270_private *cs4270; |
598 | unsigned int reg; | ||
640 | int ret; | 599 | int ret; |
641 | 600 | ||
642 | /* For now, we only support one cs4270 device in the system. See the | 601 | /* For now, we only support one cs4270 device in the system. See the |
@@ -702,6 +661,34 @@ static int cs4270_i2c_probe(struct i2c_client *i2c_client, | |||
702 | goto error_free_codec; | 661 | goto error_free_codec; |
703 | } | 662 | } |
704 | 663 | ||
664 | /* Disable auto-mute. This feature appears to be buggy. In some | ||
665 | * situations, auto-mute will not deactivate when it should, so we want | ||
666 | * this feature disabled by default. An application (e.g. alsactl) can | ||
667 | * re-enabled it by using the controls. | ||
668 | */ | ||
669 | |||
670 | reg = cs4270_read_reg_cache(codec, CS4270_MUTE); | ||
671 | reg &= ~CS4270_MUTE_AUTO; | ||
672 | ret = cs4270_i2c_write(codec, CS4270_MUTE, reg); | ||
673 | if (ret < 0) { | ||
674 | dev_err(&i2c_client->dev, "i2c write failed\n"); | ||
675 | return ret; | ||
676 | } | ||
677 | |||
678 | /* Disable automatic volume control. The hardware enables, and it | ||
679 | * causes volume change commands to be delayed, sometimes until after | ||
680 | * playback has started. An application (e.g. alsactl) can | ||
681 | * re-enabled it by using the controls. | ||
682 | */ | ||
683 | |||
684 | reg = cs4270_read_reg_cache(codec, CS4270_TRANS); | ||
685 | reg &= ~(CS4270_TRANS_SOFT | CS4270_TRANS_ZERO); | ||
686 | ret = cs4270_i2c_write(codec, CS4270_TRANS, reg); | ||
687 | if (ret < 0) { | ||
688 | dev_err(&i2c_client->dev, "i2c write failed\n"); | ||
689 | return ret; | ||
690 | } | ||
691 | |||
705 | /* Initialize the DAI. Normally, we'd prefer to have a kmalloc'd DAI | 692 | /* Initialize the DAI. Normally, we'd prefer to have a kmalloc'd DAI |
706 | * structure for each CS4270 device, but the machine driver needs to | 693 | * structure for each CS4270 device, but the machine driver needs to |
707 | * have a pointer to the DAI structure, so for now it must be a global | 694 | * have a pointer to the DAI structure, so for now it must be a global |