diff options
Diffstat (limited to 'sound/soc/codecs/wm8974.c')
-rw-r--r-- | sound/soc/codecs/wm8974.c | 167 |
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 | ||
53 | struct wm8974_priv { | 53 | struct 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 | ||
58 | static 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 | ||
62 | static const char *wm8974_companding[] = {"Off", "NC", "u-law", "A-law" }; | 60 | static 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 | ||
569 | struct snd_soc_dai wm8974_dai = { | 567 | static 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 | }; |
586 | EXPORT_SYMBOL_GPL(wm8974_dai); | ||
587 | 584 | ||
588 | static int wm8974_suspend(struct platform_device *pdev, pm_message_t state) | 585 | static 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 | ||
597 | static int wm8974_resume(struct platform_device *pdev) | 591 | static 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 | ||
616 | static int wm8974_probe(struct platform_device *pdev) | 608 | static 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 | |||
643 | pcm_err: | ||
644 | return ret; | ||
645 | } | 630 | } |
646 | 631 | ||
647 | /* power down chip */ | 632 | /* power down chip */ |
648 | static int wm8974_remove(struct platform_device *pdev) | 633 | static 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 | ||
658 | struct snd_soc_codec_device soc_codec_dev_wm8974 = { | 639 | static 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 | }; |
664 | EXPORT_SYMBOL_GPL(soc_codec_dev_wm8974); | ||
665 | |||
666 | static __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 | |||
725 | err_codec: | ||
726 | snd_soc_unregister_codec(codec); | ||
727 | err: | ||
728 | kfree(wm8974); | ||
729 | return ret; | ||
730 | } | ||
731 | |||
732 | static __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) | ||
741 | static __devinit int wm8974_i2c_probe(struct i2c_client *i2c, | 651 | static __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 | ||
762 | static __devexit int wm8974_i2c_remove(struct i2c_client *client) | 670 | static __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 | ||
775 | static struct i2c_driver wm8974_i2c_driver = { | 683 | static 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 | ||
785 | static int __init wm8974_modinit(void) | 694 | static 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 | } |
789 | module_init(wm8974_modinit); | 706 | module_init(wm8974_modinit); |
790 | 707 | ||
791 | static void __exit wm8974_exit(void) | 708 | static 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 | } |
795 | module_exit(wm8974_exit); | 714 | module_exit(wm8974_exit); |
796 | 715 | ||