aboutsummaryrefslogtreecommitdiffstats
path: root/sound/soc/codecs/tlv320dac33.c
diff options
context:
space:
mode:
authorPeter Ujfalusi <peter.ujfalusi@nokia.com>2010-04-30 07:59:36 -0400
committerLiam Girdwood <lrg@slimlogic.co.uk>2010-05-03 07:55:54 -0400
commitad05c03b1c4c1fb4db066a7bd502b674148ccd89 (patch)
treea5b2e357a36cfbb12ba89b0973eca91ee8e014e6 /sound/soc/codecs/tlv320dac33.c
parent0b61d2b9f2f78fc55faaedcc37f622ffd4103d14 (diff)
ASoC: tlv320dac33: Support for turning off the codec
Let the codec to hit OFF instead of STANDBY, when there is no activity. When the codec is off, than the associated regulator can be also turned off (if the number of users on the regulator is 0). After initialization, the codec remains in power off, it is only turned on for reading the ID registers (also testing the regulators). The codec power is enabled, when the codec is moving from BIAS_OFF to BIAS_STANDBY. The codec is turned off, when it hits BIAS_OFF. There are few scenarios, which has to be taken care:: 1. Analog bypass caused BIAS_OFF -> BIAS_ON We need to power on the codec, and do the chip init, but we does not need to execute the playback related configuration 2. Playback caused BIAS_OFF -> BIAS_ON We need to power on the codec, and do the chip init, and also we need to execute the playback related configuration. 3. Playback start, while Analog bypass is on (BIAS_ON -> BIAS_ON) We need to execute the playback related configuration. The codec is already on. 4. Analog bypass enable, while playback (BIAS_ON -> BIAS_ON) Nothing need to be done. 5. Playback start withing soc power down timeout (BIAS_ON -> BIAS_ON) We need to execute the playback related configuration. The codec is still on. Since the power up, and the codec init is optimized, the added overhead in stream start is minimal. Withing this patch, the hard_power function is now only doing what it supposed to: only handle the powers, and GPIO reset line. The codec initialization and state restore has been moved out. Signed-off-by: Peter Ujfalusi <peter.ujfalusi@nokia.com> Acked-by: Mark Brown <broonie@opensource.wolfsonmicro.com> Signed-off-by: Liam Girdwood <lrg@slimlogic.co.uk>
Diffstat (limited to 'sound/soc/codecs/tlv320dac33.c')
-rw-r--r--sound/soc/codecs/tlv320dac33.c66
1 files changed, 45 insertions, 21 deletions
diff --git a/sound/soc/codecs/tlv320dac33.c b/sound/soc/codecs/tlv320dac33.c
index 50d152215abd..68b7ccbf2e7c 100644
--- a/sound/soc/codecs/tlv320dac33.c
+++ b/sound/soc/codecs/tlv320dac33.c
@@ -61,6 +61,8 @@
61#define US_TO_SAMPLES(rate, us) \ 61#define US_TO_SAMPLES(rate, us) \
62 (rate / (1000000 / us)) 62 (rate / (1000000 / us))
63 63
64static void dac33_calculate_times(struct snd_pcm_substream *substream);
65static int dac33_prepare_chip(struct snd_pcm_substream *substream);
64 66
65static struct snd_soc_codec *tlv320dac33_codec; 67static struct snd_soc_codec *tlv320dac33_codec;
66 68
@@ -355,9 +357,17 @@ static inline void dac33_soft_power(struct snd_soc_codec *codec, int power)
355static int dac33_hard_power(struct snd_soc_codec *codec, int power) 357static int dac33_hard_power(struct snd_soc_codec *codec, int power)
356{ 358{
357 struct tlv320dac33_priv *dac33 = snd_soc_codec_get_drvdata(codec); 359 struct tlv320dac33_priv *dac33 = snd_soc_codec_get_drvdata(codec);
358 int ret; 360 int ret = 0;
359 361
360 mutex_lock(&dac33->mutex); 362 mutex_lock(&dac33->mutex);
363
364 /* Safety check */
365 if (unlikely(power == dac33->chip_power)) {
366 dev_warn(codec->dev, "Trying to set the same power state: %s\n",
367 power ? "ON" : "OFF");
368 goto exit;
369 }
370
361 if (power) { 371 if (power) {
362 ret = regulator_bulk_enable(ARRAY_SIZE(dac33->supplies), 372 ret = regulator_bulk_enable(ARRAY_SIZE(dac33->supplies),
363 dac33->supplies); 373 dac33->supplies);
@@ -371,10 +381,6 @@ static int dac33_hard_power(struct snd_soc_codec *codec, int power)
371 gpio_set_value(dac33->power_gpio, 1); 381 gpio_set_value(dac33->power_gpio, 1);
372 382
373 dac33->chip_power = 1; 383 dac33->chip_power = 1;
374
375 dac33_init_chip(codec);
376
377 dac33_soft_power(codec, 1);
378 } else { 384 } else {
379 dac33_soft_power(codec, 0); 385 dac33_soft_power(codec, 0);
380 if (dac33->power_gpio >= 0) 386 if (dac33->power_gpio >= 0)
@@ -396,6 +402,22 @@ exit:
396 return ret; 402 return ret;
397} 403}
398 404
405static int playback_event(struct snd_soc_dapm_widget *w,
406 struct snd_kcontrol *kcontrol, int event)
407{
408 struct tlv320dac33_priv *dac33 = snd_soc_codec_get_drvdata(w->codec);
409
410 switch (event) {
411 case SND_SOC_DAPM_PRE_PMU:
412 if (likely(dac33->substream)) {
413 dac33_calculate_times(dac33->substream);
414 dac33_prepare_chip(dac33->substream);
415 }
416 break;
417 }
418 return 0;
419}
420
399static int dac33_get_nsample(struct snd_kcontrol *kcontrol, 421static int dac33_get_nsample(struct snd_kcontrol *kcontrol,
400 struct snd_ctl_elem_value *ucontrol) 422 struct snd_ctl_elem_value *ucontrol)
401{ 423{
@@ -525,6 +547,8 @@ static const struct snd_soc_dapm_widget dac33_dapm_widgets[] = {
525 DAC33_OUT_AMP_PWR_CTRL, 6, 3, 3, 0), 547 DAC33_OUT_AMP_PWR_CTRL, 6, 3, 3, 0),
526 SND_SOC_DAPM_REG(snd_soc_dapm_mixer, "Output Right Amp Power", 548 SND_SOC_DAPM_REG(snd_soc_dapm_mixer, "Output Right Amp Power",
527 DAC33_OUT_AMP_PWR_CTRL, 4, 3, 3, 0), 549 DAC33_OUT_AMP_PWR_CTRL, 4, 3, 3, 0),
550
551 SND_SOC_DAPM_PRE("Prepare Playback", playback_event),
528}; 552};
529 553
530static const struct snd_soc_dapm_route audio_map[] = { 554static const struct snd_soc_dapm_route audio_map[] = {
@@ -567,18 +591,18 @@ static int dac33_set_bias_level(struct snd_soc_codec *codec,
567 break; 591 break;
568 case SND_SOC_BIAS_STANDBY: 592 case SND_SOC_BIAS_STANDBY:
569 if (codec->bias_level == SND_SOC_BIAS_OFF) { 593 if (codec->bias_level == SND_SOC_BIAS_OFF) {
594 /* Coming from OFF, switch on the codec */
570 ret = dac33_hard_power(codec, 1); 595 ret = dac33_hard_power(codec, 1);
571 if (ret != 0) 596 if (ret != 0)
572 return ret; 597 return ret;
573 }
574 598
575 dac33_soft_power(codec, 0); 599 dac33_init_chip(codec);
600 }
576 break; 601 break;
577 case SND_SOC_BIAS_OFF: 602 case SND_SOC_BIAS_OFF:
578 ret = dac33_hard_power(codec, 0); 603 ret = dac33_hard_power(codec, 0);
579 if (ret != 0) 604 if (ret != 0)
580 return ret; 605 return ret;
581
582 break; 606 break;
583 } 607 }
584 codec->bias_level = level; 608 codec->bias_level = level;
@@ -829,6 +853,16 @@ static int dac33_prepare_chip(struct snd_pcm_substream *substream)
829 } 853 }
830 854
831 mutex_lock(&dac33->mutex); 855 mutex_lock(&dac33->mutex);
856
857 if (!dac33->chip_power) {
858 /*
859 * Chip is not powered yet.
860 * Do the init in the dac33_set_bias_level later.
861 */
862 mutex_unlock(&dac33->mutex);
863 return 0;
864 }
865
832 dac33_soft_power(codec, 0); 866 dac33_soft_power(codec, 0);
833 dac33_soft_power(codec, 1); 867 dac33_soft_power(codec, 1);
834 868
@@ -1035,15 +1069,6 @@ static void dac33_calculate_times(struct snd_pcm_substream *substream)
1035 1069
1036} 1070}
1037 1071
1038static int dac33_pcm_prepare(struct snd_pcm_substream *substream,
1039 struct snd_soc_dai *dai)
1040{
1041 dac33_calculate_times(substream);
1042 dac33_prepare_chip(substream);
1043
1044 return 0;
1045}
1046
1047static int dac33_pcm_trigger(struct snd_pcm_substream *substream, int cmd, 1072static int dac33_pcm_trigger(struct snd_pcm_substream *substream, int cmd,
1048 struct snd_soc_dai *dai) 1073 struct snd_soc_dai *dai)
1049{ 1074{
@@ -1336,9 +1361,6 @@ static int dac33_soc_probe(struct platform_device *pdev)
1336 1361
1337 dac33_add_widgets(codec); 1362 dac33_add_widgets(codec);
1338 1363
1339 /* power on device */
1340 dac33_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
1341
1342 return 0; 1364 return 0;
1343 1365
1344pcm_err: 1366pcm_err:
@@ -1375,6 +1397,8 @@ static int dac33_soc_resume(struct platform_device *pdev)
1375 struct snd_soc_codec *codec = socdev->card->codec; 1397 struct snd_soc_codec *codec = socdev->card->codec;
1376 1398
1377 dac33_set_bias_level(codec, SND_SOC_BIAS_STANDBY); 1399 dac33_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
1400 if (codec->suspend_bias_level == SND_SOC_BIAS_ON)
1401 dac33_set_bias_level(codec, SND_SOC_BIAS_PREPARE);
1378 dac33_set_bias_level(codec, codec->suspend_bias_level); 1402 dac33_set_bias_level(codec, codec->suspend_bias_level);
1379 1403
1380 return 0; 1404 return 0;
@@ -1396,7 +1420,6 @@ static struct snd_soc_dai_ops dac33_dai_ops = {
1396 .startup = dac33_startup, 1420 .startup = dac33_startup,
1397 .shutdown = dac33_shutdown, 1421 .shutdown = dac33_shutdown,
1398 .hw_params = dac33_hw_params, 1422 .hw_params = dac33_hw_params,
1399 .prepare = dac33_pcm_prepare,
1400 .trigger = dac33_pcm_trigger, 1423 .trigger = dac33_pcm_trigger,
1401 .delay = dac33_dai_delay, 1424 .delay = dac33_dai_delay,
1402 .set_sysclk = dac33_set_dai_sysclk, 1425 .set_sysclk = dac33_set_dai_sysclk,
@@ -1450,6 +1473,7 @@ static int __devinit dac33_i2c_probe(struct i2c_client *client,
1450 codec->hw_write = (hw_write_t) i2c_master_send; 1473 codec->hw_write = (hw_write_t) i2c_master_send;
1451 codec->bias_level = SND_SOC_BIAS_OFF; 1474 codec->bias_level = SND_SOC_BIAS_OFF;
1452 codec->set_bias_level = dac33_set_bias_level; 1475 codec->set_bias_level = dac33_set_bias_level;
1476 codec->idle_bias_off = 1;
1453 codec->dai = &dac33_dai; 1477 codec->dai = &dac33_dai;
1454 codec->num_dai = 1; 1478 codec->num_dai = 1;
1455 codec->reg_cache_size = ARRAY_SIZE(dac33_reg); 1479 codec->reg_cache_size = ARRAY_SIZE(dac33_reg);