aboutsummaryrefslogtreecommitdiffstats
path: root/sound/soc/codecs/wm8974.c
diff options
context:
space:
mode:
Diffstat (limited to 'sound/soc/codecs/wm8974.c')
-rw-r--r--sound/soc/codecs/wm8974.c167
1 files changed, 43 insertions, 124 deletions
diff --git a/sound/soc/codecs/wm8974.c b/sound/soc/codecs/wm8974.c
index 1468fe10cbbe..b4363f6d19b3 100644
--- a/sound/soc/codecs/wm8974.c
+++ b/sound/soc/codecs/wm8974.c
@@ -51,12 +51,10 @@ static const u16 wm8974_reg[WM8974_CACHEREGNUM] = {
51#define WM8974_POWER1_BUFIOEN 0x04 51#define WM8974_POWER1_BUFIOEN 0x04
52 52
53struct wm8974_priv { 53struct wm8974_priv {
54 struct snd_soc_codec codec; 54 enum snd_soc_control_type control_type;
55 u16 reg_cache[WM8974_CACHEREGNUM]; 55 u16 reg_cache[WM8974_CACHEREGNUM];
56}; 56};
57 57
58static struct snd_soc_codec *wm8974_codec;
59
60#define wm8974_reset(c) snd_soc_write(c, WM8974_RESET, 0) 58#define wm8974_reset(c) snd_soc_write(c, WM8974_RESET, 0)
61 59
62static const char *wm8974_companding[] = {"Off", "NC", "u-law", "A-law" }; 60static const char *wm8974_companding[] = {"Off", "NC", "u-law", "A-law" };
@@ -566,8 +564,8 @@ static struct snd_soc_dai_ops wm8974_ops = {
566 .set_pll = wm8974_set_dai_pll, 564 .set_pll = wm8974_set_dai_pll,
567}; 565};
568 566
569struct snd_soc_dai wm8974_dai = { 567static struct snd_soc_dai_driver wm8974_dai = {
570 .name = "WM8974 HiFi", 568 .name = "wm8974-hifi",
571 .playback = { 569 .playback = {
572 .stream_name = "Playback", 570 .stream_name = "Playback",
573 .channels_min = 1, 571 .channels_min = 1,
@@ -583,21 +581,15 @@ struct snd_soc_dai wm8974_dai = {
583 .ops = &wm8974_ops, 581 .ops = &wm8974_ops,
584 .symmetric_rates = 1, 582 .symmetric_rates = 1,
585}; 583};
586EXPORT_SYMBOL_GPL(wm8974_dai);
587 584
588static int wm8974_suspend(struct platform_device *pdev, pm_message_t state) 585static int wm8974_suspend(struct snd_soc_codec *codec, pm_message_t state)
589{ 586{
590 struct snd_soc_device *socdev = platform_get_drvdata(pdev);
591 struct snd_soc_codec *codec = socdev->card->codec;
592
593 wm8974_set_bias_level(codec, SND_SOC_BIAS_OFF); 587 wm8974_set_bias_level(codec, SND_SOC_BIAS_OFF);
594 return 0; 588 return 0;
595} 589}
596 590
597static int wm8974_resume(struct platform_device *pdev) 591static int wm8974_resume(struct snd_soc_codec *codec)
598{ 592{
599 struct snd_soc_device *socdev = platform_get_drvdata(pdev);
600 struct snd_soc_codec *codec = socdev->card->codec;
601 int i; 593 int i;
602 u8 data[2]; 594 u8 data[2];
603 u16 *cache = codec->reg_cache; 595 u16 *cache = codec->reg_cache;
@@ -613,156 +605,72 @@ static int wm8974_resume(struct platform_device *pdev)
613 return 0; 605 return 0;
614} 606}
615 607
616static int wm8974_probe(struct platform_device *pdev) 608static int wm8974_probe(struct snd_soc_codec *codec)
617{ 609{
618 struct snd_soc_device *socdev = platform_get_drvdata(pdev);
619 struct snd_soc_codec *codec;
620 int ret = 0; 610 int ret = 0;
621 611
622 if (wm8974_codec == NULL) { 612 ret = snd_soc_codec_set_cache_io(codec, 7, 9, SND_SOC_I2C);
623 dev_err(&pdev->dev, "Codec device not registered\n"); 613 if (ret < 0) {
624 return -ENODEV; 614 dev_err(codec->dev, "Failed to set cache I/O: %d\n", ret);
615 return ret;
625 } 616 }
626 617
627 socdev->card->codec = wm8974_codec; 618 ret = wm8974_reset(codec);
628 codec = wm8974_codec;
629
630 /* register pcms */
631 ret = snd_soc_new_pcms(socdev, SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1);
632 if (ret < 0) { 619 if (ret < 0) {
633 dev_err(codec->dev, "failed to create pcms: %d\n", ret); 620 dev_err(codec->dev, "Failed to issue reset\n");
634 goto pcm_err; 621 return ret;
635 } 622 }
636 623
624 wm8974_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
637 snd_soc_add_controls(codec, wm8974_snd_controls, 625 snd_soc_add_controls(codec, wm8974_snd_controls,
638 ARRAY_SIZE(wm8974_snd_controls)); 626 ARRAY_SIZE(wm8974_snd_controls));
639 wm8974_add_widgets(codec); 627 wm8974_add_widgets(codec);
640 628
641 return ret; 629 return ret;
642
643pcm_err:
644 return ret;
645} 630}
646 631
647/* power down chip */ 632/* power down chip */
648static int wm8974_remove(struct platform_device *pdev) 633static int wm8974_remove(struct snd_soc_codec *codec)
649{ 634{
650 struct snd_soc_device *socdev = platform_get_drvdata(pdev); 635 wm8974_set_bias_level(codec, SND_SOC_BIAS_OFF);
651
652 snd_soc_free_pcms(socdev);
653 snd_soc_dapm_free(socdev);
654
655 return 0; 636 return 0;
656} 637}
657 638
658struct snd_soc_codec_device soc_codec_dev_wm8974 = { 639static struct snd_soc_codec_driver soc_codec_dev_wm8974 = {
659 .probe = wm8974_probe, 640 .probe = wm8974_probe,
660 .remove = wm8974_remove, 641 .remove = wm8974_remove,
661 .suspend = wm8974_suspend, 642 .suspend = wm8974_suspend,
662 .resume = wm8974_resume, 643 .resume = wm8974_resume,
644 .set_bias_level = wm8974_set_bias_level,
645 .reg_cache_size = ARRAY_SIZE(wm8974_reg),
646 .reg_word_size = sizeof(u16),
647 .reg_cache_default = wm8974_reg,
663}; 648};
664EXPORT_SYMBOL_GPL(soc_codec_dev_wm8974);
665
666static __devinit int wm8974_register(struct wm8974_priv *wm8974)
667{
668 int ret;
669 struct snd_soc_codec *codec = &wm8974->codec;
670
671 if (wm8974_codec) {
672 dev_err(codec->dev, "Another WM8974 is registered\n");
673 ret = -EINVAL;
674 goto err;
675 }
676
677 mutex_init(&codec->mutex);
678 INIT_LIST_HEAD(&codec->dapm_widgets);
679 INIT_LIST_HEAD(&codec->dapm_paths);
680
681 snd_soc_codec_set_drvdata(codec, wm8974);
682 codec->name = "WM8974";
683 codec->owner = THIS_MODULE;
684 codec->bias_level = SND_SOC_BIAS_OFF;
685 codec->set_bias_level = wm8974_set_bias_level;
686 codec->dai = &wm8974_dai;
687 codec->num_dai = 1;
688 codec->reg_cache_size = WM8974_CACHEREGNUM;
689 codec->reg_cache = &wm8974->reg_cache;
690
691 ret = snd_soc_codec_set_cache_io(codec, 7, 9, SND_SOC_I2C);
692 if (ret < 0) {
693 dev_err(codec->dev, "Failed to set cache I/O: %d\n", ret);
694 goto err;
695 }
696
697 memcpy(codec->reg_cache, wm8974_reg, sizeof(wm8974_reg));
698
699 ret = wm8974_reset(codec);
700 if (ret < 0) {
701 dev_err(codec->dev, "Failed to issue reset\n");
702 goto err;
703 }
704
705 wm8974_dai.dev = codec->dev;
706
707 wm8974_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
708
709 wm8974_codec = codec;
710
711 ret = snd_soc_register_codec(codec);
712 if (ret != 0) {
713 dev_err(codec->dev, "Failed to register codec: %d\n", ret);
714 goto err;
715 }
716
717 ret = snd_soc_register_dai(&wm8974_dai);
718 if (ret != 0) {
719 dev_err(codec->dev, "Failed to register DAI: %d\n", ret);
720 goto err_codec;
721 }
722
723 return 0;
724
725err_codec:
726 snd_soc_unregister_codec(codec);
727err:
728 kfree(wm8974);
729 return ret;
730}
731
732static __devexit void wm8974_unregister(struct wm8974_priv *wm8974)
733{
734 wm8974_set_bias_level(&wm8974->codec, SND_SOC_BIAS_OFF);
735 snd_soc_unregister_dai(&wm8974_dai);
736 snd_soc_unregister_codec(&wm8974->codec);
737 kfree(wm8974);
738 wm8974_codec = NULL;
739}
740 649
650#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
741static __devinit int wm8974_i2c_probe(struct i2c_client *i2c, 651static __devinit int wm8974_i2c_probe(struct i2c_client *i2c,
742 const struct i2c_device_id *id) 652 const struct i2c_device_id *id)
743{ 653{
744 struct wm8974_priv *wm8974; 654 struct wm8974_priv *wm8974;
745 struct snd_soc_codec *codec; 655 int ret;
746 656
747 wm8974 = kzalloc(sizeof(struct wm8974_priv), GFP_KERNEL); 657 wm8974 = kzalloc(sizeof(struct wm8974_priv), GFP_KERNEL);
748 if (wm8974 == NULL) 658 if (wm8974 == NULL)
749 return -ENOMEM; 659 return -ENOMEM;
750 660
751 codec = &wm8974->codec;
752 codec->hw_write = (hw_write_t)i2c_master_send;
753
754 i2c_set_clientdata(i2c, wm8974); 661 i2c_set_clientdata(i2c, wm8974);
755 codec->control_data = i2c;
756
757 codec->dev = &i2c->dev;
758 662
759 return wm8974_register(wm8974); 663 ret = snd_soc_register_codec(&i2c->dev,
664 &soc_codec_dev_wm8974, &wm8974_dai, 1);
665 if (ret < 0)
666 kfree(wm8974);
667 return ret;
760} 668}
761 669
762static __devexit int wm8974_i2c_remove(struct i2c_client *client) 670static __devexit int wm8974_i2c_remove(struct i2c_client *client)
763{ 671{
764 struct wm8974_priv *wm8974 = i2c_get_clientdata(client); 672 snd_soc_unregister_codec(&client->dev);
765 wm8974_unregister(wm8974); 673 kfree(i2c_get_clientdata(client));
766 return 0; 674 return 0;
767} 675}
768 676
@@ -774,23 +682,34 @@ MODULE_DEVICE_TABLE(i2c, wm8974_i2c_id);
774 682
775static struct i2c_driver wm8974_i2c_driver = { 683static struct i2c_driver wm8974_i2c_driver = {
776 .driver = { 684 .driver = {
777 .name = "WM8974", 685 .name = "wm8974-codec",
778 .owner = THIS_MODULE, 686 .owner = THIS_MODULE,
779 }, 687 },
780 .probe = wm8974_i2c_probe, 688 .probe = wm8974_i2c_probe,
781 .remove = __devexit_p(wm8974_i2c_remove), 689 .remove = __devexit_p(wm8974_i2c_remove),
782 .id_table = wm8974_i2c_id, 690 .id_table = wm8974_i2c_id,
783}; 691};
692#endif
784 693
785static int __init wm8974_modinit(void) 694static int __init wm8974_modinit(void)
786{ 695{
787 return i2c_add_driver(&wm8974_i2c_driver); 696 int ret = 0;
697#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
698 ret = i2c_add_driver(&wm8974_i2c_driver);
699 if (ret != 0) {
700 printk(KERN_ERR "Failed to register wm8974 I2C driver: %d\n",
701 ret);
702 }
703#endif
704 return ret;
788} 705}
789module_init(wm8974_modinit); 706module_init(wm8974_modinit);
790 707
791static void __exit wm8974_exit(void) 708static void __exit wm8974_exit(void)
792{ 709{
710#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
793 i2c_del_driver(&wm8974_i2c_driver); 711 i2c_del_driver(&wm8974_i2c_driver);
712#endif
794} 713}
795module_exit(wm8974_exit); 714module_exit(wm8974_exit);
796 715