diff options
author | Takashi Iwai <tiwai@suse.de> | 2010-05-20 06:00:43 -0400 |
---|---|---|
committer | Takashi Iwai <tiwai@suse.de> | 2010-05-20 06:00:43 -0400 |
commit | d71f4cece4bd97d05592836202fc04ff2e7817e3 (patch) | |
tree | 6c877c7a938758b1323d9c97d46b9c536e618c69 /sound/soc/codecs/wm8750.c | |
parent | 19008bdacb9f7841166ebafe0aef361ee582ffbf (diff) | |
parent | ad8332c1302bcb4f80d593fd3eb477be9d7f5604 (diff) |
Merge branch 'topic/asoc' into for-linus
Conflicts:
sound/soc/codecs/ad1938.c
Diffstat (limited to 'sound/soc/codecs/wm8750.c')
-rw-r--r-- | sound/soc/codecs/wm8750.c | 347 |
1 files changed, 147 insertions, 200 deletions
diff --git a/sound/soc/codecs/wm8750.c b/sound/soc/codecs/wm8750.c index 2916ed4d3844..9407e193fcc3 100644 --- a/sound/soc/codecs/wm8750.c +++ b/sound/soc/codecs/wm8750.c | |||
@@ -30,13 +30,6 @@ | |||
30 | 30 | ||
31 | #include "wm8750.h" | 31 | #include "wm8750.h" |
32 | 32 | ||
33 | #define WM8750_VERSION "0.12" | ||
34 | |||
35 | /* codec private data */ | ||
36 | struct wm8750_priv { | ||
37 | unsigned int sysclk; | ||
38 | }; | ||
39 | |||
40 | /* | 33 | /* |
41 | * wm8750 register cache | 34 | * wm8750 register cache |
42 | * We can't read the WM8750 register space when we | 35 | * We can't read the WM8750 register space when we |
@@ -56,6 +49,13 @@ static const u16 wm8750_reg[] = { | |||
56 | 0x0079, 0x0079, 0x0079, /* 40 */ | 49 | 0x0079, 0x0079, 0x0079, /* 40 */ |
57 | }; | 50 | }; |
58 | 51 | ||
52 | /* codec private data */ | ||
53 | struct wm8750_priv { | ||
54 | unsigned int sysclk; | ||
55 | struct snd_soc_codec codec; | ||
56 | u16 reg_cache[ARRAY_SIZE(wm8750_reg)]; | ||
57 | }; | ||
58 | |||
59 | #define wm8750_reset(c) snd_soc_write(c, WM8750_RESET, 0) | 59 | #define wm8750_reset(c) snd_soc_write(c, WM8750_RESET, 0) |
60 | 60 | ||
61 | /* | 61 | /* |
@@ -483,7 +483,7 @@ static int wm8750_set_dai_sysclk(struct snd_soc_dai *codec_dai, | |||
483 | int clk_id, unsigned int freq, int dir) | 483 | int clk_id, unsigned int freq, int dir) |
484 | { | 484 | { |
485 | struct snd_soc_codec *codec = codec_dai->codec; | 485 | struct snd_soc_codec *codec = codec_dai->codec; |
486 | struct wm8750_priv *wm8750 = codec->private_data; | 486 | struct wm8750_priv *wm8750 = snd_soc_codec_get_drvdata(codec); |
487 | 487 | ||
488 | switch (freq) { | 488 | switch (freq) { |
489 | case 11289600: | 489 | case 11289600: |
@@ -562,7 +562,7 @@ static int wm8750_pcm_hw_params(struct snd_pcm_substream *substream, | |||
562 | struct snd_soc_pcm_runtime *rtd = substream->private_data; | 562 | struct snd_soc_pcm_runtime *rtd = substream->private_data; |
563 | struct snd_soc_device *socdev = rtd->socdev; | 563 | struct snd_soc_device *socdev = rtd->socdev; |
564 | struct snd_soc_codec *codec = socdev->card->codec; | 564 | struct snd_soc_codec *codec = socdev->card->codec; |
565 | struct wm8750_priv *wm8750 = codec->private_data; | 565 | struct wm8750_priv *wm8750 = snd_soc_codec_get_drvdata(codec); |
566 | u16 iface = snd_soc_read(codec, WM8750_IFACE) & 0x1f3; | 566 | u16 iface = snd_soc_read(codec, WM8750_IFACE) & 0x1f3; |
567 | u16 srate = snd_soc_read(codec, WM8750_SRATE) & 0x1c0; | 567 | u16 srate = snd_soc_read(codec, WM8750_SRATE) & 0x1c0; |
568 | int coeff = get_coeff(wm8750->sysclk, params_rate(params)); | 568 | int coeff = get_coeff(wm8750->sysclk, params_rate(params)); |
@@ -614,10 +614,16 @@ static int wm8750_set_bias_level(struct snd_soc_codec *codec, | |||
614 | snd_soc_write(codec, WM8750_PWR1, pwr_reg | 0x00c0); | 614 | snd_soc_write(codec, WM8750_PWR1, pwr_reg | 0x00c0); |
615 | break; | 615 | break; |
616 | case SND_SOC_BIAS_PREPARE: | 616 | case SND_SOC_BIAS_PREPARE: |
617 | /* set vmid to 5k for quick power up */ | ||
618 | snd_soc_write(codec, WM8750_PWR1, pwr_reg | 0x01c1); | ||
619 | break; | 617 | break; |
620 | case SND_SOC_BIAS_STANDBY: | 618 | case SND_SOC_BIAS_STANDBY: |
619 | if (codec->bias_level == SND_SOC_BIAS_OFF) { | ||
620 | /* Set VMID to 5k */ | ||
621 | snd_soc_write(codec, WM8750_PWR1, pwr_reg | 0x01c1); | ||
622 | |||
623 | /* ...and ramp */ | ||
624 | msleep(1000); | ||
625 | } | ||
626 | |||
621 | /* mute dac and set vmid to 500k, enable VREF */ | 627 | /* mute dac and set vmid to 500k, enable VREF */ |
622 | snd_soc_write(codec, WM8750_PWR1, pwr_reg | 0x0141); | 628 | snd_soc_write(codec, WM8750_PWR1, pwr_reg | 0x0141); |
623 | break; | 629 | break; |
@@ -661,13 +667,6 @@ struct snd_soc_dai wm8750_dai = { | |||
661 | }; | 667 | }; |
662 | EXPORT_SYMBOL_GPL(wm8750_dai); | 668 | EXPORT_SYMBOL_GPL(wm8750_dai); |
663 | 669 | ||
664 | static void wm8750_work(struct work_struct *work) | ||
665 | { | ||
666 | struct snd_soc_codec *codec = | ||
667 | container_of(work, struct snd_soc_codec, delayed_work.work); | ||
668 | wm8750_set_bias_level(codec, codec->bias_level); | ||
669 | } | ||
670 | |||
671 | static int wm8750_suspend(struct platform_device *pdev, pm_message_t state) | 670 | static int wm8750_suspend(struct platform_device *pdev, pm_message_t state) |
672 | { | 671 | { |
673 | struct snd_soc_device *socdev = platform_get_drvdata(pdev); | 672 | struct snd_soc_device *socdev = platform_get_drvdata(pdev); |
@@ -696,36 +695,92 @@ static int wm8750_resume(struct platform_device *pdev) | |||
696 | 695 | ||
697 | wm8750_set_bias_level(codec, SND_SOC_BIAS_STANDBY); | 696 | wm8750_set_bias_level(codec, SND_SOC_BIAS_STANDBY); |
698 | 697 | ||
699 | /* charge wm8750 caps */ | 698 | return 0; |
700 | if (codec->suspend_bias_level == SND_SOC_BIAS_ON) { | 699 | } |
701 | wm8750_set_bias_level(codec, SND_SOC_BIAS_PREPARE); | 700 | |
702 | codec->bias_level = SND_SOC_BIAS_ON; | 701 | static struct snd_soc_codec *wm8750_codec; |
703 | schedule_delayed_work(&codec->delayed_work, | 702 | |
704 | msecs_to_jiffies(1000)); | 703 | static int wm8750_probe(struct platform_device *pdev) |
704 | { | ||
705 | struct snd_soc_device *socdev = platform_get_drvdata(pdev); | ||
706 | struct snd_soc_codec *codec; | ||
707 | int ret = 0; | ||
708 | |||
709 | if (!wm8750_codec) { | ||
710 | dev_err(&pdev->dev, "WM8750 codec not yet registered\n"); | ||
711 | return -EINVAL; | ||
712 | } | ||
713 | |||
714 | socdev->card->codec = wm8750_codec; | ||
715 | codec = wm8750_codec; | ||
716 | |||
717 | /* register pcms */ | ||
718 | ret = snd_soc_new_pcms(socdev, SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1); | ||
719 | if (ret < 0) { | ||
720 | printk(KERN_ERR "wm8750: failed to create pcms\n"); | ||
721 | goto err; | ||
705 | } | 722 | } |
706 | 723 | ||
724 | snd_soc_add_controls(codec, wm8750_snd_controls, | ||
725 | ARRAY_SIZE(wm8750_snd_controls)); | ||
726 | wm8750_add_widgets(codec); | ||
727 | |||
728 | return 0; | ||
729 | |||
730 | err: | ||
731 | return ret; | ||
732 | } | ||
733 | |||
734 | /* power down chip */ | ||
735 | static int wm8750_remove(struct platform_device *pdev) | ||
736 | { | ||
737 | struct snd_soc_device *socdev = platform_get_drvdata(pdev); | ||
738 | |||
739 | snd_soc_free_pcms(socdev); | ||
740 | snd_soc_dapm_free(socdev); | ||
741 | |||
707 | return 0; | 742 | return 0; |
708 | } | 743 | } |
709 | 744 | ||
745 | struct snd_soc_codec_device soc_codec_dev_wm8750 = { | ||
746 | .probe = wm8750_probe, | ||
747 | .remove = wm8750_remove, | ||
748 | .suspend = wm8750_suspend, | ||
749 | .resume = wm8750_resume, | ||
750 | }; | ||
751 | EXPORT_SYMBOL_GPL(soc_codec_dev_wm8750); | ||
752 | |||
710 | /* | 753 | /* |
711 | * initialise the WM8750 driver | 754 | * initialise the WM8750 driver |
712 | * register the mixer and dsp interfaces with the kernel | 755 | * register the mixer and dsp interfaces with the kernel |
713 | */ | 756 | */ |
714 | static int wm8750_init(struct snd_soc_device *socdev, | 757 | static int wm8750_register(struct wm8750_priv *wm8750, |
715 | enum snd_soc_control_type control) | 758 | enum snd_soc_control_type control) |
716 | { | 759 | { |
717 | struct snd_soc_codec *codec = socdev->card->codec; | 760 | struct snd_soc_codec *codec = &wm8750->codec; |
718 | int reg, ret = 0; | 761 | int reg, ret = 0; |
719 | 762 | ||
763 | if (wm8750_codec) { | ||
764 | dev_err(codec->dev, "Multiple WM8750 devices not supported\n"); | ||
765 | ret = -EINVAL; | ||
766 | goto err; | ||
767 | } | ||
768 | |||
769 | mutex_init(&codec->mutex); | ||
770 | INIT_LIST_HEAD(&codec->dapm_widgets); | ||
771 | INIT_LIST_HEAD(&codec->dapm_paths); | ||
772 | |||
720 | codec->name = "WM8750"; | 773 | codec->name = "WM8750"; |
721 | codec->owner = THIS_MODULE; | 774 | codec->owner = THIS_MODULE; |
775 | codec->bias_level = SND_SOC_BIAS_STANDBY; | ||
722 | codec->set_bias_level = wm8750_set_bias_level; | 776 | codec->set_bias_level = wm8750_set_bias_level; |
723 | codec->dai = &wm8750_dai; | 777 | codec->dai = &wm8750_dai; |
724 | codec->num_dai = 1; | 778 | codec->num_dai = 1; |
725 | codec->reg_cache_size = ARRAY_SIZE(wm8750_reg); | 779 | codec->reg_cache_size = ARRAY_SIZE(wm8750->reg_cache) + 1; |
726 | codec->reg_cache = kmemdup(wm8750_reg, sizeof(wm8750_reg), GFP_KERNEL); | 780 | codec->reg_cache = &wm8750->reg_cache; |
727 | if (codec->reg_cache == NULL) | 781 | snd_soc_codec_set_drvdata(codec, wm8750); |
728 | return -ENOMEM; | 782 | |
783 | memcpy(codec->reg_cache, wm8750_reg, sizeof(wm8750->reg_cache)); | ||
729 | 784 | ||
730 | ret = snd_soc_codec_set_cache_io(codec, 7, 9, control); | 785 | ret = snd_soc_codec_set_cache_io(codec, 7, 9, control); |
731 | if (ret < 0) { | 786 | if (ret < 0) { |
@@ -739,17 +794,8 @@ static int wm8750_init(struct snd_soc_device *socdev, | |||
739 | goto err; | 794 | goto err; |
740 | } | 795 | } |
741 | 796 | ||
742 | /* register pcms */ | ||
743 | ret = snd_soc_new_pcms(socdev, SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1); | ||
744 | if (ret < 0) { | ||
745 | printk(KERN_ERR "wm8750: failed to create pcms\n"); | ||
746 | goto err; | ||
747 | } | ||
748 | |||
749 | /* charge output caps */ | 797 | /* charge output caps */ |
750 | wm8750_set_bias_level(codec, SND_SOC_BIAS_PREPARE); | 798 | wm8750_set_bias_level(codec, SND_SOC_BIAS_STANDBY); |
751 | codec->bias_level = SND_SOC_BIAS_STANDBY; | ||
752 | schedule_delayed_work(&codec->delayed_work, msecs_to_jiffies(1000)); | ||
753 | 799 | ||
754 | /* set the update bits */ | 800 | /* set the update bits */ |
755 | reg = snd_soc_read(codec, WM8750_LDAC); | 801 | reg = snd_soc_read(codec, WM8750_LDAC); |
@@ -769,19 +815,37 @@ static int wm8750_init(struct snd_soc_device *socdev, | |||
769 | reg = snd_soc_read(codec, WM8750_RINVOL); | 815 | reg = snd_soc_read(codec, WM8750_RINVOL); |
770 | snd_soc_write(codec, WM8750_RINVOL, reg | 0x0100); | 816 | snd_soc_write(codec, WM8750_RINVOL, reg | 0x0100); |
771 | 817 | ||
772 | snd_soc_add_controls(codec, wm8750_snd_controls, | 818 | wm8750_codec = codec; |
773 | ARRAY_SIZE(wm8750_snd_controls)); | ||
774 | wm8750_add_widgets(codec); | ||
775 | return ret; | ||
776 | 819 | ||
820 | ret = snd_soc_register_codec(codec); | ||
821 | if (ret != 0) { | ||
822 | dev_err(codec->dev, "Failed to register codec: %d\n", ret); | ||
823 | goto err; | ||
824 | } | ||
825 | |||
826 | ret = snd_soc_register_dais(&wm8750_dai, 1); | ||
827 | if (ret != 0) { | ||
828 | dev_err(codec->dev, "Failed to register DAIs: %d\n", ret); | ||
829 | goto err_codec; | ||
830 | } | ||
831 | |||
832 | return 0; | ||
833 | |||
834 | err_codec: | ||
835 | snd_soc_unregister_codec(codec); | ||
777 | err: | 836 | err: |
778 | kfree(codec->reg_cache); | 837 | kfree(wm8750); |
779 | return ret; | 838 | return ret; |
780 | } | 839 | } |
781 | 840 | ||
782 | /* If the i2c layer weren't so broken, we could pass this kind of data | 841 | static void wm8750_unregister(struct wm8750_priv *wm8750) |
783 | around */ | 842 | { |
784 | static struct snd_soc_device *wm8750_socdev; | 843 | wm8750_set_bias_level(&wm8750->codec, SND_SOC_BIAS_OFF); |
844 | snd_soc_unregister_dais(&wm8750_dai, 1); | ||
845 | snd_soc_unregister_codec(&wm8750->codec); | ||
846 | kfree(wm8750); | ||
847 | wm8750_codec = NULL; | ||
848 | } | ||
785 | 849 | ||
786 | #if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE) | 850 | #if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE) |
787 | 851 | ||
@@ -795,24 +859,26 @@ static struct snd_soc_device *wm8750_socdev; | |||
795 | static int wm8750_i2c_probe(struct i2c_client *i2c, | 859 | static int wm8750_i2c_probe(struct i2c_client *i2c, |
796 | const struct i2c_device_id *id) | 860 | const struct i2c_device_id *id) |
797 | { | 861 | { |
798 | struct snd_soc_device *socdev = wm8750_socdev; | 862 | struct snd_soc_codec *codec; |
799 | struct snd_soc_codec *codec = socdev->card->codec; | 863 | struct wm8750_priv *wm8750; |
800 | int ret; | 864 | |
865 | wm8750 = kzalloc(sizeof(struct wm8750_priv), GFP_KERNEL); | ||
866 | if (wm8750 == NULL) | ||
867 | return -ENOMEM; | ||
801 | 868 | ||
802 | i2c_set_clientdata(i2c, codec); | 869 | codec = &wm8750->codec; |
803 | codec->control_data = i2c; | 870 | codec->control_data = i2c; |
871 | i2c_set_clientdata(i2c, wm8750); | ||
804 | 872 | ||
805 | ret = wm8750_init(socdev, SND_SOC_I2C); | 873 | codec->dev = &i2c->dev; |
806 | if (ret < 0) | ||
807 | pr_err("failed to initialise WM8750\n"); | ||
808 | 874 | ||
809 | return ret; | 875 | return wm8750_register(wm8750, SND_SOC_I2C); |
810 | } | 876 | } |
811 | 877 | ||
812 | static int wm8750_i2c_remove(struct i2c_client *client) | 878 | static int wm8750_i2c_remove(struct i2c_client *client) |
813 | { | 879 | { |
814 | struct snd_soc_codec *codec = i2c_get_clientdata(client); | 880 | struct wm8750_priv *wm8750 = i2c_get_clientdata(client); |
815 | kfree(codec->reg_cache); | 881 | wm8750_unregister(wm8750); |
816 | return 0; | 882 | return 0; |
817 | } | 883 | } |
818 | 884 | ||
@@ -831,66 +897,31 @@ static struct i2c_driver wm8750_i2c_driver = { | |||
831 | .remove = wm8750_i2c_remove, | 897 | .remove = wm8750_i2c_remove, |
832 | .id_table = wm8750_i2c_id, | 898 | .id_table = wm8750_i2c_id, |
833 | }; | 899 | }; |
834 | |||
835 | static int wm8750_add_i2c_device(struct platform_device *pdev, | ||
836 | const struct wm8750_setup_data *setup) | ||
837 | { | ||
838 | struct i2c_board_info info; | ||
839 | struct i2c_adapter *adapter; | ||
840 | struct i2c_client *client; | ||
841 | int ret; | ||
842 | |||
843 | ret = i2c_add_driver(&wm8750_i2c_driver); | ||
844 | if (ret != 0) { | ||
845 | dev_err(&pdev->dev, "can't add i2c driver\n"); | ||
846 | return ret; | ||
847 | } | ||
848 | |||
849 | memset(&info, 0, sizeof(struct i2c_board_info)); | ||
850 | info.addr = setup->i2c_address; | ||
851 | strlcpy(info.type, "wm8750", I2C_NAME_SIZE); | ||
852 | |||
853 | adapter = i2c_get_adapter(setup->i2c_bus); | ||
854 | if (!adapter) { | ||
855 | dev_err(&pdev->dev, "can't get i2c adapter %d\n", | ||
856 | setup->i2c_bus); | ||
857 | goto err_driver; | ||
858 | } | ||
859 | |||
860 | client = i2c_new_device(adapter, &info); | ||
861 | i2c_put_adapter(adapter); | ||
862 | if (!client) { | ||
863 | dev_err(&pdev->dev, "can't add i2c device at 0x%x\n", | ||
864 | (unsigned int)info.addr); | ||
865 | goto err_driver; | ||
866 | } | ||
867 | |||
868 | return 0; | ||
869 | |||
870 | err_driver: | ||
871 | i2c_del_driver(&wm8750_i2c_driver); | ||
872 | return -ENODEV; | ||
873 | } | ||
874 | #endif | 900 | #endif |
875 | 901 | ||
876 | #if defined(CONFIG_SPI_MASTER) | 902 | #if defined(CONFIG_SPI_MASTER) |
877 | static int __devinit wm8750_spi_probe(struct spi_device *spi) | 903 | static int __devinit wm8750_spi_probe(struct spi_device *spi) |
878 | { | 904 | { |
879 | struct snd_soc_device *socdev = wm8750_socdev; | 905 | struct snd_soc_codec *codec; |
880 | struct snd_soc_codec *codec = socdev->card->codec; | 906 | struct wm8750_priv *wm8750; |
881 | int ret; | 907 | |
908 | wm8750 = kzalloc(sizeof(struct wm8750_priv), GFP_KERNEL); | ||
909 | if (wm8750 == NULL) | ||
910 | return -ENOMEM; | ||
882 | 911 | ||
912 | codec = &wm8750->codec; | ||
883 | codec->control_data = spi; | 913 | codec->control_data = spi; |
914 | codec->dev = &spi->dev; | ||
884 | 915 | ||
885 | ret = wm8750_init(socdev, SND_SOC_SPI); | 916 | dev_set_drvdata(&spi->dev, wm8750); |
886 | if (ret < 0) | ||
887 | dev_err(&spi->dev, "failed to initialise WM8750\n"); | ||
888 | 917 | ||
889 | return ret; | 918 | return wm8750_register(wm8750, SND_SOC_SPI); |
890 | } | 919 | } |
891 | 920 | ||
892 | static int __devexit wm8750_spi_remove(struct spi_device *spi) | 921 | static int __devexit wm8750_spi_remove(struct spi_device *spi) |
893 | { | 922 | { |
923 | struct wm8750_priv *wm8750 = dev_get_drvdata(&spi->dev); | ||
924 | wm8750_unregister(wm8750); | ||
894 | return 0; | 925 | return 0; |
895 | } | 926 | } |
896 | 927 | ||
@@ -905,115 +936,31 @@ static struct spi_driver wm8750_spi_driver = { | |||
905 | }; | 936 | }; |
906 | #endif | 937 | #endif |
907 | 938 | ||
908 | static int wm8750_probe(struct platform_device *pdev) | 939 | static int __init wm8750_modinit(void) |
909 | { | 940 | { |
910 | struct snd_soc_device *socdev = platform_get_drvdata(pdev); | ||
911 | struct wm8750_setup_data *setup = socdev->codec_data; | ||
912 | struct snd_soc_codec *codec; | ||
913 | struct wm8750_priv *wm8750; | ||
914 | int ret; | 941 | int ret; |
915 | |||
916 | pr_info("WM8750 Audio Codec %s", WM8750_VERSION); | ||
917 | codec = kzalloc(sizeof(struct snd_soc_codec), GFP_KERNEL); | ||
918 | if (codec == NULL) | ||
919 | return -ENOMEM; | ||
920 | |||
921 | wm8750 = kzalloc(sizeof(struct wm8750_priv), GFP_KERNEL); | ||
922 | if (wm8750 == NULL) { | ||
923 | kfree(codec); | ||
924 | return -ENOMEM; | ||
925 | } | ||
926 | |||
927 | codec->private_data = wm8750; | ||
928 | socdev->card->codec = codec; | ||
929 | mutex_init(&codec->mutex); | ||
930 | INIT_LIST_HEAD(&codec->dapm_widgets); | ||
931 | INIT_LIST_HEAD(&codec->dapm_paths); | ||
932 | wm8750_socdev = socdev; | ||
933 | INIT_DELAYED_WORK(&codec->delayed_work, wm8750_work); | ||
934 | |||
935 | ret = -ENODEV; | ||
936 | |||
937 | #if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE) | 942 | #if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE) |
938 | if (setup->i2c_address) { | 943 | ret = i2c_add_driver(&wm8750_i2c_driver); |
939 | ret = wm8750_add_i2c_device(pdev, setup); | 944 | if (ret != 0) |
940 | } | 945 | pr_err("Failed to register WM8750 I2C driver: %d\n", ret); |
941 | #endif | 946 | #endif |
942 | #if defined(CONFIG_SPI_MASTER) | 947 | #if defined(CONFIG_SPI_MASTER) |
943 | if (setup->spi) { | 948 | ret = spi_register_driver(&wm8750_spi_driver); |
944 | ret = spi_register_driver(&wm8750_spi_driver); | 949 | if (ret != 0) |
945 | if (ret != 0) | 950 | pr_err("Failed to register WM8750 SPI driver: %d\n", ret); |
946 | printk(KERN_ERR "can't add spi driver"); | ||
947 | } | ||
948 | #endif | 951 | #endif |
949 | 952 | return 0; | |
950 | if (ret != 0) { | ||
951 | kfree(codec->private_data); | ||
952 | kfree(codec); | ||
953 | } | ||
954 | return ret; | ||
955 | } | ||
956 | |||
957 | /* | ||
958 | * This function forces any delayed work to be queued and run. | ||
959 | */ | ||
960 | static int run_delayed_work(struct delayed_work *dwork) | ||
961 | { | ||
962 | int ret; | ||
963 | |||
964 | /* cancel any work waiting to be queued. */ | ||
965 | ret = cancel_delayed_work(dwork); | ||
966 | |||
967 | /* if there was any work waiting then we run it now and | ||
968 | * wait for it's completion */ | ||
969 | if (ret) { | ||
970 | schedule_delayed_work(dwork, 0); | ||
971 | flush_scheduled_work(); | ||
972 | } | ||
973 | return ret; | ||
974 | } | 953 | } |
954 | module_init(wm8750_modinit); | ||
975 | 955 | ||
976 | /* power down chip */ | 956 | static void __exit wm8750_exit(void) |
977 | static int wm8750_remove(struct platform_device *pdev) | ||
978 | { | 957 | { |
979 | struct snd_soc_device *socdev = platform_get_drvdata(pdev); | ||
980 | struct snd_soc_codec *codec = socdev->card->codec; | ||
981 | |||
982 | if (codec->control_data) | ||
983 | wm8750_set_bias_level(codec, SND_SOC_BIAS_OFF); | ||
984 | run_delayed_work(&codec->delayed_work); | ||
985 | snd_soc_free_pcms(socdev); | ||
986 | snd_soc_dapm_free(socdev); | ||
987 | #if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE) | 958 | #if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE) |
988 | i2c_unregister_device(codec->control_data); | ||
989 | i2c_del_driver(&wm8750_i2c_driver); | 959 | i2c_del_driver(&wm8750_i2c_driver); |
990 | #endif | 960 | #endif |
991 | #if defined(CONFIG_SPI_MASTER) | 961 | #if defined(CONFIG_SPI_MASTER) |
992 | spi_unregister_driver(&wm8750_spi_driver); | 962 | spi_unregister_driver(&wm8750_spi_driver); |
993 | #endif | 963 | #endif |
994 | kfree(codec->private_data); | ||
995 | kfree(codec); | ||
996 | |||
997 | return 0; | ||
998 | } | ||
999 | |||
1000 | struct snd_soc_codec_device soc_codec_dev_wm8750 = { | ||
1001 | .probe = wm8750_probe, | ||
1002 | .remove = wm8750_remove, | ||
1003 | .suspend = wm8750_suspend, | ||
1004 | .resume = wm8750_resume, | ||
1005 | }; | ||
1006 | EXPORT_SYMBOL_GPL(soc_codec_dev_wm8750); | ||
1007 | |||
1008 | static int __init wm8750_modinit(void) | ||
1009 | { | ||
1010 | return snd_soc_register_dai(&wm8750_dai); | ||
1011 | } | ||
1012 | module_init(wm8750_modinit); | ||
1013 | |||
1014 | static void __exit wm8750_exit(void) | ||
1015 | { | ||
1016 | snd_soc_unregister_dai(&wm8750_dai); | ||
1017 | } | 964 | } |
1018 | module_exit(wm8750_exit); | 965 | module_exit(wm8750_exit); |
1019 | 966 | ||