aboutsummaryrefslogtreecommitdiffstats
path: root/sound/soc/codecs/wm8770.c
diff options
context:
space:
mode:
Diffstat (limited to 'sound/soc/codecs/wm8770.c')
-rw-r--r--sound/soc/codecs/wm8770.c223
1 files changed, 110 insertions, 113 deletions
diff --git a/sound/soc/codecs/wm8770.c b/sound/soc/codecs/wm8770.c
index c7c0034d3966..89a18d82f303 100644
--- a/sound/soc/codecs/wm8770.c
+++ b/sound/soc/codecs/wm8770.c
@@ -17,6 +17,7 @@
17#include <linux/of_device.h> 17#include <linux/of_device.h>
18#include <linux/pm.h> 18#include <linux/pm.h>
19#include <linux/spi/spi.h> 19#include <linux/spi/spi.h>
20#include <linux/regmap.h>
20#include <linux/regulator/consumer.h> 21#include <linux/regulator/consumer.h>
21#include <linux/slab.h> 22#include <linux/slab.h>
22#include <sound/core.h> 23#include <sound/core.h>
@@ -35,19 +36,52 @@ static const char *wm8770_supply_names[WM8770_NUM_SUPPLIES] = {
35 "DVDD" 36 "DVDD"
36}; 37};
37 38
38static const u16 wm8770_reg_defs[WM8770_CACHEREGNUM] = { 39static const struct reg_default wm8770_reg_defaults[] = {
39 0x7f, 0x7f, 0x7f, 0x7f, 40 { 0, 0x7f },
40 0x7f, 0x7f, 0x7f, 0x7f, 41 { 1, 0x7f },
41 0x7f, 0xff, 0xff, 0xff, 42 { 2, 0x7f },
42 0xff, 0xff, 0xff, 0xff, 43 { 3, 0x7f },
43 0xff, 0xff, 0, 0x90, 0, 44 { 4, 0x7f },
44 0, 0x22, 0x22, 0x3e, 45 { 5, 0x7f },
45 0xc, 0xc, 0x100, 0x189, 46 { 6, 0x7f },
46 0x189, 0x8770 47 { 7, 0x7f },
48 { 8, 0x7f },
49 { 9, 0xff },
50 { 10, 0xff },
51 { 11, 0xff },
52 { 12, 0xff },
53 { 13, 0xff },
54 { 14, 0xff },
55 { 15, 0xff },
56 { 16, 0xff },
57 { 17, 0xff },
58 { 18, 0 },
59 { 19, 0x90 },
60 { 20, 0 },
61 { 21, 0 },
62 { 22, 0x22 },
63 { 23, 0x22 },
64 { 24, 0x3e },
65 { 25, 0xc },
66 { 26, 0xc },
67 { 27, 0x100 },
68 { 28, 0x189 },
69 { 29, 0x189 },
70 { 30, 0x8770 },
47}; 71};
48 72
73static bool wm8770_volatile_reg(struct device *dev, unsigned int reg)
74{
75 switch (reg) {
76 case WM8770_RESET:
77 return true;
78 default:
79 return false;
80 }
81}
82
49struct wm8770_priv { 83struct wm8770_priv {
50 enum snd_soc_control_type control_type; 84 struct regmap *regmap;
51 struct regulator_bulk_data supplies[WM8770_NUM_SUPPLIES]; 85 struct regulator_bulk_data supplies[WM8770_NUM_SUPPLIES];
52 struct notifier_block disable_nb[WM8770_NUM_SUPPLIES]; 86 struct notifier_block disable_nb[WM8770_NUM_SUPPLIES];
53 struct snd_soc_codec *codec; 87 struct snd_soc_codec *codec;
@@ -71,7 +105,7 @@ static int wm8770_regulator_event_##n(struct notifier_block *nb, \
71 struct wm8770_priv *wm8770 = container_of(nb, struct wm8770_priv, \ 105 struct wm8770_priv *wm8770 = container_of(nb, struct wm8770_priv, \
72 disable_nb[n]); \ 106 disable_nb[n]); \
73 if (event & REGULATOR_EVENT_DISABLE) { \ 107 if (event & REGULATOR_EVENT_DISABLE) { \
74 wm8770->codec->cache_sync = 1; \ 108 regcache_mark_dirty(wm8770->regmap); \
75 } \ 109 } \
76 return 0; \ 110 return 0; \
77} 111}
@@ -466,24 +500,6 @@ static int wm8770_set_sysclk(struct snd_soc_dai *dai,
466 return 0; 500 return 0;
467} 501}
468 502
469static void wm8770_sync_cache(struct snd_soc_codec *codec)
470{
471 int i;
472 u16 *cache;
473
474 if (!codec->cache_sync)
475 return;
476
477 codec->cache_only = 0;
478 cache = codec->reg_cache;
479 for (i = 0; i < codec->driver->reg_cache_size; i++) {
480 if (i == WM8770_RESET || cache[i] == wm8770_reg_defs[i])
481 continue;
482 snd_soc_write(codec, i, cache[i]);
483 }
484 codec->cache_sync = 0;
485}
486
487static int wm8770_set_bias_level(struct snd_soc_codec *codec, 503static int wm8770_set_bias_level(struct snd_soc_codec *codec,
488 enum snd_soc_bias_level level) 504 enum snd_soc_bias_level level)
489{ 505{
@@ -507,7 +523,9 @@ static int wm8770_set_bias_level(struct snd_soc_codec *codec,
507 ret); 523 ret);
508 return ret; 524 return ret;
509 } 525 }
510 wm8770_sync_cache(codec); 526
527 regcache_sync(wm8770->regmap);
528
511 /* global powerup */ 529 /* global powerup */
512 snd_soc_write(codec, WM8770_PWDNCTRL, 0); 530 snd_soc_write(codec, WM8770_PWDNCTRL, 0);
513 } 531 }
@@ -554,68 +572,25 @@ static struct snd_soc_dai_driver wm8770_dai = {
554 .symmetric_rates = 1 572 .symmetric_rates = 1
555}; 573};
556 574
557#ifdef CONFIG_PM
558static int wm8770_suspend(struct snd_soc_codec *codec)
559{
560 wm8770_set_bias_level(codec, SND_SOC_BIAS_OFF);
561 return 0;
562}
563
564static int wm8770_resume(struct snd_soc_codec *codec)
565{
566 wm8770_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
567 return 0;
568}
569#else
570#define wm8770_suspend NULL
571#define wm8770_resume NULL
572#endif
573
574static int wm8770_probe(struct snd_soc_codec *codec) 575static int wm8770_probe(struct snd_soc_codec *codec)
575{ 576{
576 struct wm8770_priv *wm8770; 577 struct wm8770_priv *wm8770;
577 int ret; 578 int ret;
578 int i;
579 579
580 wm8770 = snd_soc_codec_get_drvdata(codec); 580 wm8770 = snd_soc_codec_get_drvdata(codec);
581 wm8770->codec = codec; 581 wm8770->codec = codec;
582 582
583 ret = snd_soc_codec_set_cache_io(codec, 7, 9, wm8770->control_type); 583 ret = snd_soc_codec_set_cache_io(codec, 7, 9, SND_SOC_REGMAP);
584 if (ret < 0) { 584 if (ret < 0) {
585 dev_err(codec->dev, "Failed to set cache I/O: %d\n", ret); 585 dev_err(codec->dev, "Failed to set cache I/O: %d\n", ret);
586 return ret; 586 return ret;
587 } 587 }
588 588
589 for (i = 0; i < ARRAY_SIZE(wm8770->supplies); i++)
590 wm8770->supplies[i].supply = wm8770_supply_names[i];
591
592 ret = regulator_bulk_get(codec->dev, ARRAY_SIZE(wm8770->supplies),
593 wm8770->supplies);
594 if (ret) {
595 dev_err(codec->dev, "Failed to request supplies: %d\n", ret);
596 return ret;
597 }
598
599 wm8770->disable_nb[0].notifier_call = wm8770_regulator_event_0;
600 wm8770->disable_nb[1].notifier_call = wm8770_regulator_event_1;
601 wm8770->disable_nb[2].notifier_call = wm8770_regulator_event_2;
602
603 /* This should really be moved into the regulator core */
604 for (i = 0; i < ARRAY_SIZE(wm8770->supplies); i++) {
605 ret = regulator_register_notifier(wm8770->supplies[i].consumer,
606 &wm8770->disable_nb[i]);
607 if (ret) {
608 dev_err(codec->dev,
609 "Failed to register regulator notifier: %d\n",
610 ret);
611 }
612 }
613
614 ret = regulator_bulk_enable(ARRAY_SIZE(wm8770->supplies), 589 ret = regulator_bulk_enable(ARRAY_SIZE(wm8770->supplies),
615 wm8770->supplies); 590 wm8770->supplies);
616 if (ret) { 591 if (ret) {
617 dev_err(codec->dev, "Failed to enable supplies: %d\n", ret); 592 dev_err(codec->dev, "Failed to enable supplies: %d\n", ret);
618 goto err_reg_get; 593 return ret;
619 } 594 }
620 595
621 ret = wm8770_reset(codec); 596 ret = wm8770_reset(codec);
@@ -624,8 +599,6 @@ static int wm8770_probe(struct snd_soc_codec *codec)
624 goto err_reg_enable; 599 goto err_reg_enable;
625 } 600 }
626 601
627 wm8770_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
628
629 /* latch the volume update bits */ 602 /* latch the volume update bits */
630 snd_soc_update_bits(codec, WM8770_MSDIGVOL, 0x100, 0x100); 603 snd_soc_update_bits(codec, WM8770_MSDIGVOL, 0x100, 0x100);
631 snd_soc_update_bits(codec, WM8770_MSALGVOL, 0x100, 0x100); 604 snd_soc_update_bits(codec, WM8770_MSALGVOL, 0x100, 0x100);
@@ -641,46 +614,22 @@ static int wm8770_probe(struct snd_soc_codec *codec)
641 /* mute all DACs */ 614 /* mute all DACs */
642 snd_soc_update_bits(codec, WM8770_DACMUTE, 0x10, 0x10); 615 snd_soc_update_bits(codec, WM8770_DACMUTE, 0x10, 0x10);
643 616
644 snd_soc_add_codec_controls(codec, wm8770_snd_controls,
645 ARRAY_SIZE(wm8770_snd_controls));
646 snd_soc_dapm_new_controls(&codec->dapm, wm8770_dapm_widgets,
647 ARRAY_SIZE(wm8770_dapm_widgets));
648 snd_soc_dapm_add_routes(&codec->dapm, wm8770_intercon,
649 ARRAY_SIZE(wm8770_intercon));
650 return 0;
651
652err_reg_enable: 617err_reg_enable:
653 regulator_bulk_disable(ARRAY_SIZE(wm8770->supplies), wm8770->supplies); 618 regulator_bulk_disable(ARRAY_SIZE(wm8770->supplies), wm8770->supplies);
654err_reg_get:
655 regulator_bulk_free(ARRAY_SIZE(wm8770->supplies), wm8770->supplies);
656 return ret; 619 return ret;
657} 620}
658 621
659static int wm8770_remove(struct snd_soc_codec *codec)
660{
661 struct wm8770_priv *wm8770;
662 int i;
663
664 wm8770 = snd_soc_codec_get_drvdata(codec);
665 wm8770_set_bias_level(codec, SND_SOC_BIAS_OFF);
666
667 for (i = 0; i < ARRAY_SIZE(wm8770->supplies); ++i)
668 regulator_unregister_notifier(wm8770->supplies[i].consumer,
669 &wm8770->disable_nb[i]);
670 regulator_bulk_free(ARRAY_SIZE(wm8770->supplies), wm8770->supplies);
671 return 0;
672}
673
674static struct snd_soc_codec_driver soc_codec_dev_wm8770 = { 622static struct snd_soc_codec_driver soc_codec_dev_wm8770 = {
675 .probe = wm8770_probe, 623 .probe = wm8770_probe,
676 .remove = wm8770_remove,
677 .suspend = wm8770_suspend,
678 .resume = wm8770_resume,
679 .set_bias_level = wm8770_set_bias_level, 624 .set_bias_level = wm8770_set_bias_level,
680 .idle_bias_off = true, 625 .idle_bias_off = true,
681 .reg_cache_size = ARRAY_SIZE(wm8770_reg_defs), 626
682 .reg_word_size = sizeof (u16), 627 .controls = wm8770_snd_controls,
683 .reg_cache_default = wm8770_reg_defs 628 .num_controls = ARRAY_SIZE(wm8770_snd_controls),
629 .dapm_widgets = wm8770_dapm_widgets,
630 .num_dapm_widgets = ARRAY_SIZE(wm8770_dapm_widgets),
631 .dapm_routes = wm8770_intercon,
632 .num_dapm_routes = ARRAY_SIZE(wm8770_intercon),
684}; 633};
685 634
686static const struct of_device_id wm8770_of_match[] = { 635static const struct of_device_id wm8770_of_match[] = {
@@ -689,17 +638,57 @@ static const struct of_device_id wm8770_of_match[] = {
689}; 638};
690MODULE_DEVICE_TABLE(of, wm8770_of_match); 639MODULE_DEVICE_TABLE(of, wm8770_of_match);
691 640
692static int __devinit wm8770_spi_probe(struct spi_device *spi) 641static const struct regmap_config wm8770_regmap = {
642 .reg_bits = 7,
643 .val_bits = 9,
644 .max_register = WM8770_RESET,
645
646 .reg_defaults = wm8770_reg_defaults,
647 .num_reg_defaults = ARRAY_SIZE(wm8770_reg_defaults),
648 .cache_type = REGCACHE_RBTREE,
649
650 .volatile_reg = wm8770_volatile_reg,
651};
652
653static int wm8770_spi_probe(struct spi_device *spi)
693{ 654{
694 struct wm8770_priv *wm8770; 655 struct wm8770_priv *wm8770;
695 int ret; 656 int ret, i;
696 657
697 wm8770 = devm_kzalloc(&spi->dev, sizeof(struct wm8770_priv), 658 wm8770 = devm_kzalloc(&spi->dev, sizeof(struct wm8770_priv),
698 GFP_KERNEL); 659 GFP_KERNEL);
699 if (!wm8770) 660 if (!wm8770)
700 return -ENOMEM; 661 return -ENOMEM;
701 662
702 wm8770->control_type = SND_SOC_SPI; 663 for (i = 0; i < ARRAY_SIZE(wm8770->supplies); i++)
664 wm8770->supplies[i].supply = wm8770_supply_names[i];
665
666 ret = devm_regulator_bulk_get(&spi->dev, ARRAY_SIZE(wm8770->supplies),
667 wm8770->supplies);
668 if (ret) {
669 dev_err(&spi->dev, "Failed to request supplies: %d\n", ret);
670 return ret;
671 }
672
673 wm8770->disable_nb[0].notifier_call = wm8770_regulator_event_0;
674 wm8770->disable_nb[1].notifier_call = wm8770_regulator_event_1;
675 wm8770->disable_nb[2].notifier_call = wm8770_regulator_event_2;
676
677 /* This should really be moved into the regulator core */
678 for (i = 0; i < ARRAY_SIZE(wm8770->supplies); i++) {
679 ret = regulator_register_notifier(wm8770->supplies[i].consumer,
680 &wm8770->disable_nb[i]);
681 if (ret) {
682 dev_err(&spi->dev,
683 "Failed to register regulator notifier: %d\n",
684 ret);
685 }
686 }
687
688 wm8770->regmap = devm_regmap_init_spi(spi, &wm8770_regmap);
689 if (IS_ERR(wm8770->regmap))
690 return PTR_ERR(wm8770->regmap);
691
703 spi_set_drvdata(spi, wm8770); 692 spi_set_drvdata(spi, wm8770);
704 693
705 ret = snd_soc_register_codec(&spi->dev, 694 ret = snd_soc_register_codec(&spi->dev,
@@ -708,9 +697,17 @@ static int __devinit wm8770_spi_probe(struct spi_device *spi)
708 return ret; 697 return ret;
709} 698}
710 699
711static int __devexit wm8770_spi_remove(struct spi_device *spi) 700static int wm8770_spi_remove(struct spi_device *spi)
712{ 701{
702 struct wm8770_priv *wm8770 = spi_get_drvdata(spi);
703 int i;
704
705 for (i = 0; i < ARRAY_SIZE(wm8770->supplies); ++i)
706 regulator_unregister_notifier(wm8770->supplies[i].consumer,
707 &wm8770->disable_nb[i]);
708
713 snd_soc_unregister_codec(&spi->dev); 709 snd_soc_unregister_codec(&spi->dev);
710
714 return 0; 711 return 0;
715} 712}
716 713
@@ -721,7 +718,7 @@ static struct spi_driver wm8770_spi_driver = {
721 .of_match_table = wm8770_of_match, 718 .of_match_table = wm8770_of_match,
722 }, 719 },
723 .probe = wm8770_spi_probe, 720 .probe = wm8770_spi_probe,
724 .remove = __devexit_p(wm8770_spi_remove) 721 .remove = wm8770_spi_remove
725}; 722};
726 723
727module_spi_driver(wm8770_spi_driver); 724module_spi_driver(wm8770_spi_driver);