aboutsummaryrefslogtreecommitdiffstats
path: root/sound/soc/codecs/wm8971.c
diff options
context:
space:
mode:
Diffstat (limited to 'sound/soc/codecs/wm8971.c')
-rw-r--r--sound/soc/codecs/wm8971.c99
1 files changed, 30 insertions, 69 deletions
diff --git a/sound/soc/codecs/wm8971.c b/sound/soc/codecs/wm8971.c
index 39ddb9b8834c..f9cbabdc6238 100644
--- a/sound/soc/codecs/wm8971.c
+++ b/sound/soc/codecs/wm8971.c
@@ -31,11 +31,11 @@
31 31
32#define WM8971_REG_COUNT 43 32#define WM8971_REG_COUNT 43
33 33
34static struct workqueue_struct *wm8971_workq = NULL;
35
36/* codec private data */ 34/* codec private data */
37struct wm8971_priv { 35struct wm8971_priv {
38 unsigned int sysclk; 36 unsigned int sysclk;
37 struct delayed_work charge_work;
38 struct regmap *regmap;
39}; 39};
40 40
41/* 41/*
@@ -552,9 +552,19 @@ static int wm8971_mute(struct snd_soc_dai *dai, int mute)
552 return 0; 552 return 0;
553} 553}
554 554
555static void wm8971_charge_work(struct work_struct *work)
556{
557 struct wm8971_priv *wm8971 =
558 container_of(work, struct wm8971_priv, charge_work.work);
559
560 /* Set to 500k */
561 regmap_update_bits(wm8971->regmap, WM8971_PWR1, 0x0180, 0x0100);
562}
563
555static int wm8971_set_bias_level(struct snd_soc_codec *codec, 564static int wm8971_set_bias_level(struct snd_soc_codec *codec,
556 enum snd_soc_bias_level level) 565 enum snd_soc_bias_level level)
557{ 566{
567 struct wm8971_priv *wm8971 = snd_soc_codec_get_drvdata(codec);
558 u16 pwr_reg = snd_soc_read(codec, WM8971_PWR1) & 0xfe3e; 568 u16 pwr_reg = snd_soc_read(codec, WM8971_PWR1) & 0xfe3e;
559 569
560 switch (level) { 570 switch (level) {
@@ -563,15 +573,24 @@ static int wm8971_set_bias_level(struct snd_soc_codec *codec,
563 snd_soc_write(codec, WM8971_PWR1, pwr_reg | 0x00c1); 573 snd_soc_write(codec, WM8971_PWR1, pwr_reg | 0x00c1);
564 break; 574 break;
565 case SND_SOC_BIAS_PREPARE: 575 case SND_SOC_BIAS_PREPARE:
576 /* Wait until fully charged */
577 flush_delayed_work(&wm8971->charge_work);
566 break; 578 break;
567 case SND_SOC_BIAS_STANDBY: 579 case SND_SOC_BIAS_STANDBY:
568 if (codec->dapm.bias_level == SND_SOC_BIAS_OFF) 580 if (codec->dapm.bias_level == SND_SOC_BIAS_OFF) {
569 snd_soc_cache_sync(codec); 581 snd_soc_cache_sync(codec);
582 /* charge output caps - set vmid to 5k for quick power up */
583 snd_soc_write(codec, WM8971_PWR1, pwr_reg | 0x01c0);
584 queue_delayed_work(system_power_efficient_wq,
585 &wm8971->charge_work, msecs_to_jiffies(1000));
586 } else {
587 /* mute dac and set vmid to 500k, enable VREF */
588 snd_soc_write(codec, WM8971_PWR1, pwr_reg | 0x0140);
589 }
570 590
571 /* mute dac and set vmid to 500k, enable VREF */
572 snd_soc_write(codec, WM8971_PWR1, pwr_reg | 0x0140);
573 break; 591 break;
574 case SND_SOC_BIAS_OFF: 592 case SND_SOC_BIAS_OFF:
593 cancel_delayed_work_sync(&wm8971->charge_work);
575 snd_soc_write(codec, WM8971_PWR1, 0x0001); 594 snd_soc_write(codec, WM8971_PWR1, 0x0001);
576 break; 595 break;
577 } 596 }
@@ -610,58 +629,14 @@ static struct snd_soc_dai_driver wm8971_dai = {
610 .ops = &wm8971_dai_ops, 629 .ops = &wm8971_dai_ops,
611}; 630};
612 631
613static void wm8971_work(struct work_struct *work)
614{
615 struct snd_soc_dapm_context *dapm =
616 container_of(work, struct snd_soc_dapm_context,
617 delayed_work.work);
618 struct snd_soc_codec *codec = snd_soc_dapm_to_codec(dapm);
619 wm8971_set_bias_level(codec, codec->dapm.bias_level);
620}
621
622static int wm8971_suspend(struct snd_soc_codec *codec)
623{
624 wm8971_set_bias_level(codec, SND_SOC_BIAS_OFF);
625 return 0;
626}
627
628static int wm8971_resume(struct snd_soc_codec *codec)
629{
630 u16 reg;
631
632 wm8971_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
633
634 /* charge wm8971 caps */
635 if (codec->dapm.suspend_bias_level == SND_SOC_BIAS_ON) {
636 reg = snd_soc_read(codec, WM8971_PWR1) & 0xfe3e;
637 snd_soc_write(codec, WM8971_PWR1, reg | 0x01c0);
638 codec->dapm.bias_level = SND_SOC_BIAS_ON;
639 queue_delayed_work(wm8971_workq, &codec->dapm.delayed_work,
640 msecs_to_jiffies(1000));
641 }
642
643 return 0;
644}
645
646static int wm8971_probe(struct snd_soc_codec *codec) 632static int wm8971_probe(struct snd_soc_codec *codec)
647{ 633{
648 int ret = 0; 634 struct wm8971_priv *wm8971 = snd_soc_codec_get_drvdata(codec);
649 u16 reg;
650 635
651 INIT_DELAYED_WORK(&codec->dapm.delayed_work, wm8971_work); 636 INIT_DELAYED_WORK(&wm8971->charge_work, wm8971_charge_work);
652 wm8971_workq = create_workqueue("wm8971");
653 if (wm8971_workq == NULL)
654 return -ENOMEM;
655 637
656 wm8971_reset(codec); 638 wm8971_reset(codec);
657 639
658 /* charge output caps - set vmid to 5k for quick power up */
659 reg = snd_soc_read(codec, WM8971_PWR1) & 0xfe3e;
660 snd_soc_write(codec, WM8971_PWR1, reg | 0x01c0);
661 codec->dapm.bias_level = SND_SOC_BIAS_STANDBY;
662 queue_delayed_work(wm8971_workq, &codec->dapm.delayed_work,
663 msecs_to_jiffies(1000));
664
665 /* set the update bits */ 640 /* set the update bits */
666 snd_soc_update_bits(codec, WM8971_LDAC, 0x0100, 0x0100); 641 snd_soc_update_bits(codec, WM8971_LDAC, 0x0100, 0x0100);
667 snd_soc_update_bits(codec, WM8971_RDAC, 0x0100, 0x0100); 642 snd_soc_update_bits(codec, WM8971_RDAC, 0x0100, 0x0100);
@@ -672,26 +647,13 @@ static int wm8971_probe(struct snd_soc_codec *codec)
672 snd_soc_update_bits(codec, WM8971_LINVOL, 0x0100, 0x0100); 647 snd_soc_update_bits(codec, WM8971_LINVOL, 0x0100, 0x0100);
673 snd_soc_update_bits(codec, WM8971_RINVOL, 0x0100, 0x0100); 648 snd_soc_update_bits(codec, WM8971_RINVOL, 0x0100, 0x0100);
674 649
675 return ret;
676}
677
678
679/* power down chip */
680static int wm8971_remove(struct snd_soc_codec *codec)
681{
682 wm8971_set_bias_level(codec, SND_SOC_BIAS_OFF);
683
684 if (wm8971_workq)
685 destroy_workqueue(wm8971_workq);
686 return 0; 650 return 0;
687} 651}
688 652
689static struct snd_soc_codec_driver soc_codec_dev_wm8971 = { 653static struct snd_soc_codec_driver soc_codec_dev_wm8971 = {
690 .probe = wm8971_probe, 654 .probe = wm8971_probe,
691 .remove = wm8971_remove,
692 .suspend = wm8971_suspend,
693 .resume = wm8971_resume,
694 .set_bias_level = wm8971_set_bias_level, 655 .set_bias_level = wm8971_set_bias_level,
656 .suspend_bias_off = true,
695 657
696 .controls = wm8971_snd_controls, 658 .controls = wm8971_snd_controls,
697 .num_controls = ARRAY_SIZE(wm8971_snd_controls), 659 .num_controls = ARRAY_SIZE(wm8971_snd_controls),
@@ -715,7 +677,6 @@ static int wm8971_i2c_probe(struct i2c_client *i2c,
715 const struct i2c_device_id *id) 677 const struct i2c_device_id *id)
716{ 678{
717 struct wm8971_priv *wm8971; 679 struct wm8971_priv *wm8971;
718 struct regmap *regmap;
719 int ret; 680 int ret;
720 681
721 wm8971 = devm_kzalloc(&i2c->dev, sizeof(struct wm8971_priv), 682 wm8971 = devm_kzalloc(&i2c->dev, sizeof(struct wm8971_priv),
@@ -723,9 +684,9 @@ static int wm8971_i2c_probe(struct i2c_client *i2c,
723 if (wm8971 == NULL) 684 if (wm8971 == NULL)
724 return -ENOMEM; 685 return -ENOMEM;
725 686
726 regmap = devm_regmap_init_i2c(i2c, &wm8971_regmap); 687 wm8971->regmap = devm_regmap_init_i2c(i2c, &wm8971_regmap);
727 if (IS_ERR(regmap)) 688 if (IS_ERR(wm8971->regmap))
728 return PTR_ERR(regmap); 689 return PTR_ERR(wm8971->regmap);
729 690
730 i2c_set_clientdata(i2c, wm8971); 691 i2c_set_clientdata(i2c, wm8971);
731 692