aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorPeter Ujfalusi <peter.ujfalusi@ti.com>2015-06-04 09:04:28 -0400
committerMark Brown <broonie@kernel.org>2015-06-05 13:53:36 -0400
commit7d78502502f3984894c0bb8d330ef894f2c2c04c (patch)
tree6aeed7ac6dcf8f97fd5ad6d538867cb0d9db16c7
parentdd6ae3bcfe0fa9cf1bdb6f952c617f2070c57b37 (diff)
ASoC: tas2552: Implement startup/stop sequence as per TRM
Certain sequence need to be followed in order to have smooth power up and power down performance. Execute this sequence via DAPM_POST widget. Remove patching the RESERVED_0D register at probe time since it has to be handled every time when we stop or start the amplifier. In order to be able to execute the sequence at the correct time, the driver need to request to ignore the pmdown time. Signed-off-by: Peter Ujfalusi <peter.ujfalusi@ti.com> Signed-off-by: Mark Brown <broonie@kernel.org>
-rw-r--r--sound/soc/codecs/tas2552.c44
1 files changed, 28 insertions, 16 deletions
diff --git a/sound/soc/codecs/tas2552.c b/sound/soc/codecs/tas2552.c
index fe2e4d384a00..9c081344bd90 100644
--- a/sound/soc/codecs/tas2552.c
+++ b/sound/soc/codecs/tas2552.c
@@ -46,7 +46,7 @@ static struct reg_default tas2552_reg_defs[] = {
46 {TAS2552_PDM_CFG, 0x01}, 46 {TAS2552_PDM_CFG, 0x01},
47 {TAS2552_PGA_GAIN, 0x00}, 47 {TAS2552_PGA_GAIN, 0x00},
48 {TAS2552_BOOST_PT_CTRL, 0x0f}, 48 {TAS2552_BOOST_PT_CTRL, 0x0f},
49 {TAS2552_RESERVED_0D, 0x00}, 49 {TAS2552_RESERVED_0D, 0xbe},
50 {TAS2552_LIMIT_RATE_HYS, 0x08}, 50 {TAS2552_LIMIT_RATE_HYS, 0x08},
51 {TAS2552_CFG_2, 0xef}, 51 {TAS2552_CFG_2, 0xef},
52 {TAS2552_SER_CTRL_1, 0x00}, 52 {TAS2552_SER_CTRL_1, 0x00},
@@ -83,6 +83,29 @@ struct tas2552_data {
83 unsigned int tdm_delay; 83 unsigned int tdm_delay;
84}; 84};
85 85
86static int tas2552_post_event(struct snd_soc_dapm_widget *w,
87 struct snd_kcontrol *kcontrol, int event)
88{
89 struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
90
91 switch (event) {
92 case SND_SOC_DAPM_POST_PMU:
93 snd_soc_write(codec, TAS2552_RESERVED_0D, 0xc0);
94 snd_soc_update_bits(codec, TAS2552_LIMIT_RATE_HYS, (1 << 5),
95 (1 << 5));
96 snd_soc_update_bits(codec, TAS2552_CFG_2, 1, 0);
97 snd_soc_update_bits(codec, TAS2552_CFG_1, TAS2552_SWS, 0);
98 break;
99 case SND_SOC_DAPM_POST_PMD:
100 snd_soc_update_bits(codec, TAS2552_CFG_1, TAS2552_SWS,
101 TAS2552_SWS);
102 snd_soc_update_bits(codec, TAS2552_CFG_2, 1, 1);
103 snd_soc_update_bits(codec, TAS2552_LIMIT_RATE_HYS, (1 << 5), 0);
104 snd_soc_write(codec, TAS2552_RESERVED_0D, 0xbe);
105 break;
106 }
107 return 0;
108}
86 109
87/* Input mux controls */ 110/* Input mux controls */
88static const char * const tas2552_input_texts[] = { 111static const char * const tas2552_input_texts[] = {
@@ -105,6 +128,7 @@ static const struct snd_soc_dapm_widget tas2552_dapm_widgets[] =
105 SND_SOC_DAPM_DAC("DAC", NULL, SND_SOC_NOPM, 0, 0), 128 SND_SOC_DAPM_DAC("DAC", NULL, SND_SOC_NOPM, 0, 0),
106 SND_SOC_DAPM_OUT_DRV("ClassD", TAS2552_CFG_2, 7, 0, NULL, 0), 129 SND_SOC_DAPM_OUT_DRV("ClassD", TAS2552_CFG_2, 7, 0, NULL, 0),
107 SND_SOC_DAPM_SUPPLY("PLL", TAS2552_CFG_2, 3, 0, NULL, 0), 130 SND_SOC_DAPM_SUPPLY("PLL", TAS2552_CFG_2, 3, 0, NULL, 0),
131 SND_SOC_DAPM_POST("Post Event", tas2552_post_event),
108 132
109 SND_SOC_DAPM_OUTPUT("OUT") 133 SND_SOC_DAPM_OUTPUT("OUT")
110}; 134};
@@ -413,10 +437,6 @@ static const struct snd_kcontrol_new tas2552_snd_controls[] = {
413 TAS2552_PGA_GAIN, 0, 0x1f, 0, dac_tlv), 437 TAS2552_PGA_GAIN, 0, 0x1f, 0, dac_tlv),
414}; 438};
415 439
416static const struct reg_default tas2552_init_regs[] = {
417 { TAS2552_RESERVED_0D, 0xc0 },
418};
419
420static int tas2552_codec_probe(struct snd_soc_codec *codec) 440static int tas2552_codec_probe(struct snd_soc_codec *codec)
421{ 441{
422 struct tas2552_data *tas2552 = snd_soc_codec_get_drvdata(codec); 442 struct tas2552_data *tas2552 = snd_soc_codec_get_drvdata(codec);
@@ -443,7 +463,7 @@ static int tas2552_codec_probe(struct snd_soc_codec *codec)
443 goto probe_fail; 463 goto probe_fail;
444 } 464 }
445 465
446 snd_soc_write(codec, TAS2552_CFG_1, TAS2552_MUTE); 466 snd_soc_update_bits(codec, TAS2552_CFG_1, TAS2552_MUTE, TAS2552_MUTE);
447 snd_soc_write(codec, TAS2552_CFG_3, TAS2552_I2S_OUT_SEL | 467 snd_soc_write(codec, TAS2552_CFG_3, TAS2552_I2S_OUT_SEL |
448 TAS2552_DIN_SRC_SEL_AVG_L_R | TAS2552_88_96KHZ); 468 TAS2552_DIN_SRC_SEL_AVG_L_R | TAS2552_88_96KHZ);
449 snd_soc_write(codec, TAS2552_DOUT, TAS2552_PDM_DATA_I); 469 snd_soc_write(codec, TAS2552_DOUT, TAS2552_PDM_DATA_I);
@@ -451,21 +471,11 @@ static int tas2552_codec_probe(struct snd_soc_codec *codec)
451 snd_soc_write(codec, TAS2552_BOOST_PT_CTRL, TAS2552_APT_DELAY_200 | 471 snd_soc_write(codec, TAS2552_BOOST_PT_CTRL, TAS2552_APT_DELAY_200 |
452 TAS2552_APT_THRESH_2_1_7); 472 TAS2552_APT_THRESH_2_1_7);
453 473
454 ret = regmap_register_patch(tas2552->regmap, tas2552_init_regs,
455 ARRAY_SIZE(tas2552_init_regs));
456 if (ret != 0) {
457 dev_err(codec->dev, "Failed to write init registers: %d\n",
458 ret);
459 goto patch_fail;
460 }
461
462 snd_soc_write(codec, TAS2552_CFG_2, TAS2552_BOOST_EN | 474 snd_soc_write(codec, TAS2552_CFG_2, TAS2552_BOOST_EN |
463 TAS2552_APT_EN | TAS2552_LIM_EN); 475 TAS2552_APT_EN | TAS2552_LIM_EN);
464 476
465 return 0; 477 return 0;
466 478
467patch_fail:
468 pm_runtime_put(codec->dev);
469probe_fail: 479probe_fail:
470 if (tas2552->enable_gpio) 480 if (tas2552->enable_gpio)
471 gpiod_set_value(tas2552->enable_gpio, 0); 481 gpiod_set_value(tas2552->enable_gpio, 0);
@@ -527,6 +537,8 @@ static struct snd_soc_codec_driver soc_codec_dev_tas2552 = {
527 .remove = tas2552_codec_remove, 537 .remove = tas2552_codec_remove,
528 .suspend = tas2552_suspend, 538 .suspend = tas2552_suspend,
529 .resume = tas2552_resume, 539 .resume = tas2552_resume,
540 .ignore_pmdown_time = true,
541
530 .controls = tas2552_snd_controls, 542 .controls = tas2552_snd_controls,
531 .num_controls = ARRAY_SIZE(tas2552_snd_controls), 543 .num_controls = ARRAY_SIZE(tas2552_snd_controls),
532 .dapm_widgets = tas2552_dapm_widgets, 544 .dapm_widgets = tas2552_dapm_widgets,