diff options
Diffstat (limited to 'sound/soc/codecs/wm8580.c')
-rw-r--r-- | sound/soc/codecs/wm8580.c | 381 |
1 files changed, 179 insertions, 202 deletions
diff --git a/sound/soc/codecs/wm8580.c b/sound/soc/codecs/wm8580.c index d004e5845298..442ea6f160fc 100644 --- a/sound/soc/codecs/wm8580.c +++ b/sound/soc/codecs/wm8580.c | |||
@@ -1,7 +1,7 @@ | |||
1 | /* | 1 | /* |
2 | * wm8580.c -- WM8580 ALSA Soc Audio driver | 2 | * wm8580.c -- WM8580 ALSA Soc Audio driver |
3 | * | 3 | * |
4 | * Copyright 2008 Wolfson Microelectronics PLC. | 4 | * Copyright 2008, 2009 Wolfson Microelectronics PLC. |
5 | * | 5 | * |
6 | * This program is free software; you can redistribute it and/or modify it | 6 | * This program is free software; you can redistribute it and/or modify it |
7 | * under the terms of the GNU General Public License as published by the | 7 | * under the terms of the GNU General Public License as published by the |
@@ -35,19 +35,6 @@ | |||
35 | 35 | ||
36 | #include "wm8580.h" | 36 | #include "wm8580.h" |
37 | 37 | ||
38 | #define WM8580_VERSION "0.1" | ||
39 | |||
40 | struct pll_state { | ||
41 | unsigned int in; | ||
42 | unsigned int out; | ||
43 | }; | ||
44 | |||
45 | /* codec private data */ | ||
46 | struct wm8580_priv { | ||
47 | struct pll_state a; | ||
48 | struct pll_state b; | ||
49 | }; | ||
50 | |||
51 | /* WM8580 register space */ | 38 | /* WM8580 register space */ |
52 | #define WM8580_PLLA1 0x00 | 39 | #define WM8580_PLLA1 0x00 |
53 | #define WM8580_PLLA2 0x01 | 40 | #define WM8580_PLLA2 0x01 |
@@ -102,6 +89,8 @@ struct wm8580_priv { | |||
102 | #define WM8580_READBACK 0x34 | 89 | #define WM8580_READBACK 0x34 |
103 | #define WM8580_RESET 0x35 | 90 | #define WM8580_RESET 0x35 |
104 | 91 | ||
92 | #define WM8580_MAX_REGISTER 0x35 | ||
93 | |||
105 | /* PLLB4 (register 7h) */ | 94 | /* PLLB4 (register 7h) */ |
106 | #define WM8580_PLLB4_MCLKOUTSRC_MASK 0x60 | 95 | #define WM8580_PLLB4_MCLKOUTSRC_MASK 0x60 |
107 | #define WM8580_PLLB4_MCLKOUTSRC_PLLA 0x20 | 96 | #define WM8580_PLLB4_MCLKOUTSRC_PLLA 0x20 |
@@ -193,6 +182,20 @@ static const u16 wm8580_reg[] = { | |||
193 | 0x0000, 0x0000 /*R53*/ | 182 | 0x0000, 0x0000 /*R53*/ |
194 | }; | 183 | }; |
195 | 184 | ||
185 | struct pll_state { | ||
186 | unsigned int in; | ||
187 | unsigned int out; | ||
188 | }; | ||
189 | |||
190 | /* codec private data */ | ||
191 | struct wm8580_priv { | ||
192 | struct snd_soc_codec codec; | ||
193 | u16 reg_cache[WM8580_MAX_REGISTER + 1]; | ||
194 | struct pll_state a; | ||
195 | struct pll_state b; | ||
196 | }; | ||
197 | |||
198 | |||
196 | /* | 199 | /* |
197 | * read wm8580 register cache | 200 | * read wm8580 register cache |
198 | */ | 201 | */ |
@@ -200,7 +203,7 @@ static inline unsigned int wm8580_read_reg_cache(struct snd_soc_codec *codec, | |||
200 | unsigned int reg) | 203 | unsigned int reg) |
201 | { | 204 | { |
202 | u16 *cache = codec->reg_cache; | 205 | u16 *cache = codec->reg_cache; |
203 | BUG_ON(reg > ARRAY_SIZE(wm8580_reg)); | 206 | BUG_ON(reg >= ARRAY_SIZE(wm8580_reg)); |
204 | return cache[reg]; | 207 | return cache[reg]; |
205 | } | 208 | } |
206 | 209 | ||
@@ -223,7 +226,7 @@ static int wm8580_write(struct snd_soc_codec *codec, unsigned int reg, | |||
223 | { | 226 | { |
224 | u8 data[2]; | 227 | u8 data[2]; |
225 | 228 | ||
226 | BUG_ON(reg > ARRAY_SIZE(wm8580_reg)); | 229 | BUG_ON(reg >= ARRAY_SIZE(wm8580_reg)); |
227 | 230 | ||
228 | /* Registers are 9 bits wide */ | 231 | /* Registers are 9 bits wide */ |
229 | value &= 0x1ff; | 232 | value &= 0x1ff; |
@@ -330,20 +333,6 @@ SOC_DOUBLE("ADC Mute Switch", WM8580_ADC_CONTROL1, 0, 1, 1, 0), | |||
330 | SOC_SINGLE("ADC High-Pass Filter Switch", WM8580_ADC_CONTROL1, 4, 1, 0), | 333 | SOC_SINGLE("ADC High-Pass Filter Switch", WM8580_ADC_CONTROL1, 4, 1, 0), |
331 | }; | 334 | }; |
332 | 335 | ||
333 | /* Add non-DAPM controls */ | ||
334 | static int wm8580_add_controls(struct snd_soc_codec *codec) | ||
335 | { | ||
336 | int err, i; | ||
337 | |||
338 | for (i = 0; i < ARRAY_SIZE(wm8580_snd_controls); i++) { | ||
339 | err = snd_ctl_add(codec->card, | ||
340 | snd_soc_cnew(&wm8580_snd_controls[i], | ||
341 | codec, NULL)); | ||
342 | if (err < 0) | ||
343 | return err; | ||
344 | } | ||
345 | return 0; | ||
346 | } | ||
347 | static const struct snd_soc_dapm_widget wm8580_dapm_widgets[] = { | 336 | static const struct snd_soc_dapm_widget wm8580_dapm_widgets[] = { |
348 | SND_SOC_DAPM_DAC("DAC1", "Playback", WM8580_PWRDN1, 2, 1), | 337 | SND_SOC_DAPM_DAC("DAC1", "Playback", WM8580_PWRDN1, 2, 1), |
349 | SND_SOC_DAPM_DAC("DAC2", "Playback", WM8580_PWRDN1, 3, 1), | 338 | SND_SOC_DAPM_DAC("DAC2", "Playback", WM8580_PWRDN1, 3, 1), |
@@ -553,7 +542,7 @@ static int wm8580_paif_hw_params(struct snd_pcm_substream *substream, | |||
553 | { | 542 | { |
554 | struct snd_soc_pcm_runtime *rtd = substream->private_data; | 543 | struct snd_soc_pcm_runtime *rtd = substream->private_data; |
555 | struct snd_soc_device *socdev = rtd->socdev; | 544 | struct snd_soc_device *socdev = rtd->socdev; |
556 | struct snd_soc_codec *codec = socdev->codec; | 545 | struct snd_soc_codec *codec = socdev->card->codec; |
557 | u16 paifb = wm8580_read(codec, WM8580_PAIF3 + dai->id); | 546 | u16 paifb = wm8580_read(codec, WM8580_PAIF3 + dai->id); |
558 | 547 | ||
559 | paifb &= ~WM8580_AIF_LENGTH_MASK; | 548 | paifb &= ~WM8580_AIF_LENGTH_MASK; |
@@ -771,8 +760,22 @@ static int wm8580_set_bias_level(struct snd_soc_codec *codec, | |||
771 | switch (level) { | 760 | switch (level) { |
772 | case SND_SOC_BIAS_ON: | 761 | case SND_SOC_BIAS_ON: |
773 | case SND_SOC_BIAS_PREPARE: | 762 | case SND_SOC_BIAS_PREPARE: |
763 | break; | ||
764 | |||
774 | case SND_SOC_BIAS_STANDBY: | 765 | case SND_SOC_BIAS_STANDBY: |
766 | if (codec->bias_level == SND_SOC_BIAS_OFF) { | ||
767 | /* Power up and get individual control of the DACs */ | ||
768 | reg = wm8580_read(codec, WM8580_PWRDN1); | ||
769 | reg &= ~(WM8580_PWRDN1_PWDN | WM8580_PWRDN1_ALLDACPD); | ||
770 | wm8580_write(codec, WM8580_PWRDN1, reg); | ||
771 | |||
772 | /* Make VMID high impedence */ | ||
773 | reg = wm8580_read(codec, WM8580_ADC_CONTROL1); | ||
774 | reg &= ~0x100; | ||
775 | wm8580_write(codec, WM8580_ADC_CONTROL1, reg); | ||
776 | } | ||
775 | break; | 777 | break; |
778 | |||
776 | case SND_SOC_BIAS_OFF: | 779 | case SND_SOC_BIAS_OFF: |
777 | reg = wm8580_read(codec, WM8580_PWRDN1); | 780 | reg = wm8580_read(codec, WM8580_PWRDN1); |
778 | wm8580_write(codec, WM8580_PWRDN1, reg | WM8580_PWRDN1_PWDN); | 781 | wm8580_write(codec, WM8580_PWRDN1, reg | WM8580_PWRDN1_PWDN); |
@@ -785,6 +788,21 @@ static int wm8580_set_bias_level(struct snd_soc_codec *codec, | |||
785 | #define WM8580_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S20_3LE |\ | 788 | #define WM8580_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S20_3LE |\ |
786 | SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S32_LE) | 789 | SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S32_LE) |
787 | 790 | ||
791 | static struct snd_soc_dai_ops wm8580_dai_ops_playback = { | ||
792 | .hw_params = wm8580_paif_hw_params, | ||
793 | .set_fmt = wm8580_set_paif_dai_fmt, | ||
794 | .set_clkdiv = wm8580_set_dai_clkdiv, | ||
795 | .set_pll = wm8580_set_dai_pll, | ||
796 | .digital_mute = wm8580_digital_mute, | ||
797 | }; | ||
798 | |||
799 | static struct snd_soc_dai_ops wm8580_dai_ops_capture = { | ||
800 | .hw_params = wm8580_paif_hw_params, | ||
801 | .set_fmt = wm8580_set_paif_dai_fmt, | ||
802 | .set_clkdiv = wm8580_set_dai_clkdiv, | ||
803 | .set_pll = wm8580_set_dai_pll, | ||
804 | }; | ||
805 | |||
788 | struct snd_soc_dai wm8580_dai[] = { | 806 | struct snd_soc_dai wm8580_dai[] = { |
789 | { | 807 | { |
790 | .name = "WM8580 PAIFRX", | 808 | .name = "WM8580 PAIFRX", |
@@ -796,13 +814,7 @@ struct snd_soc_dai wm8580_dai[] = { | |||
796 | .rates = SNDRV_PCM_RATE_8000_192000, | 814 | .rates = SNDRV_PCM_RATE_8000_192000, |
797 | .formats = WM8580_FORMATS, | 815 | .formats = WM8580_FORMATS, |
798 | }, | 816 | }, |
799 | .ops = { | 817 | .ops = &wm8580_dai_ops_playback, |
800 | .hw_params = wm8580_paif_hw_params, | ||
801 | .set_fmt = wm8580_set_paif_dai_fmt, | ||
802 | .set_clkdiv = wm8580_set_dai_clkdiv, | ||
803 | .set_pll = wm8580_set_dai_pll, | ||
804 | .digital_mute = wm8580_digital_mute, | ||
805 | }, | ||
806 | }, | 818 | }, |
807 | { | 819 | { |
808 | .name = "WM8580 PAIFTX", | 820 | .name = "WM8580 PAIFTX", |
@@ -814,109 +826,168 @@ struct snd_soc_dai wm8580_dai[] = { | |||
814 | .rates = SNDRV_PCM_RATE_8000_192000, | 826 | .rates = SNDRV_PCM_RATE_8000_192000, |
815 | .formats = WM8580_FORMATS, | 827 | .formats = WM8580_FORMATS, |
816 | }, | 828 | }, |
817 | .ops = { | 829 | .ops = &wm8580_dai_ops_capture, |
818 | .hw_params = wm8580_paif_hw_params, | ||
819 | .set_fmt = wm8580_set_paif_dai_fmt, | ||
820 | .set_clkdiv = wm8580_set_dai_clkdiv, | ||
821 | .set_pll = wm8580_set_dai_pll, | ||
822 | }, | ||
823 | }, | 830 | }, |
824 | }; | 831 | }; |
825 | EXPORT_SYMBOL_GPL(wm8580_dai); | 832 | EXPORT_SYMBOL_GPL(wm8580_dai); |
826 | 833 | ||
827 | /* | 834 | static struct snd_soc_codec *wm8580_codec; |
828 | * initialise the WM8580 driver | 835 | |
829 | * register the mixer and dsp interfaces with the kernel | 836 | static int wm8580_probe(struct platform_device *pdev) |
830 | */ | ||
831 | static int wm8580_init(struct snd_soc_device *socdev) | ||
832 | { | 837 | { |
833 | struct snd_soc_codec *codec = socdev->codec; | 838 | struct snd_soc_device *socdev = platform_get_drvdata(pdev); |
839 | struct snd_soc_codec *codec; | ||
834 | int ret = 0; | 840 | int ret = 0; |
835 | 841 | ||
836 | codec->name = "WM8580"; | 842 | if (wm8580_codec == NULL) { |
837 | codec->owner = THIS_MODULE; | 843 | dev_err(&pdev->dev, "Codec device not registered\n"); |
838 | codec->read = wm8580_read_reg_cache; | 844 | return -ENODEV; |
839 | codec->write = wm8580_write; | 845 | } |
840 | codec->set_bias_level = wm8580_set_bias_level; | ||
841 | codec->dai = wm8580_dai; | ||
842 | codec->num_dai = ARRAY_SIZE(wm8580_dai); | ||
843 | codec->reg_cache_size = ARRAY_SIZE(wm8580_reg); | ||
844 | codec->reg_cache = kmemdup(wm8580_reg, sizeof(wm8580_reg), | ||
845 | GFP_KERNEL); | ||
846 | |||
847 | if (codec->reg_cache == NULL) | ||
848 | return -ENOMEM; | ||
849 | |||
850 | /* Get the codec into a known state */ | ||
851 | wm8580_write(codec, WM8580_RESET, 0); | ||
852 | |||
853 | /* Power up and get individual control of the DACs */ | ||
854 | wm8580_write(codec, WM8580_PWRDN1, wm8580_read(codec, WM8580_PWRDN1) & | ||
855 | ~(WM8580_PWRDN1_PWDN | WM8580_PWRDN1_ALLDACPD)); | ||
856 | 846 | ||
857 | /* Make VMID high impedence */ | 847 | socdev->card->codec = wm8580_codec; |
858 | wm8580_write(codec, WM8580_ADC_CONTROL1, | 848 | codec = wm8580_codec; |
859 | wm8580_read(codec, WM8580_ADC_CONTROL1) & ~0x100); | ||
860 | 849 | ||
861 | /* register pcms */ | 850 | /* register pcms */ |
862 | ret = snd_soc_new_pcms(socdev, SNDRV_DEFAULT_IDX1, | 851 | ret = snd_soc_new_pcms(socdev, SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1); |
863 | SNDRV_DEFAULT_STR1); | ||
864 | if (ret < 0) { | 852 | if (ret < 0) { |
865 | printk(KERN_ERR "wm8580: failed to create pcms\n"); | 853 | dev_err(codec->dev, "failed to create pcms: %d\n", ret); |
866 | goto pcm_err; | 854 | goto pcm_err; |
867 | } | 855 | } |
868 | 856 | ||
869 | wm8580_add_controls(codec); | 857 | snd_soc_add_controls(codec, wm8580_snd_controls, |
858 | ARRAY_SIZE(wm8580_snd_controls)); | ||
870 | wm8580_add_widgets(codec); | 859 | wm8580_add_widgets(codec); |
871 | |||
872 | ret = snd_soc_init_card(socdev); | 860 | ret = snd_soc_init_card(socdev); |
873 | if (ret < 0) { | 861 | if (ret < 0) { |
874 | printk(KERN_ERR "wm8580: failed to register card\n"); | 862 | dev_err(codec->dev, "failed to register card: %d\n", ret); |
875 | goto card_err; | 863 | goto card_err; |
876 | } | 864 | } |
865 | |||
877 | return ret; | 866 | return ret; |
878 | 867 | ||
879 | card_err: | 868 | card_err: |
880 | snd_soc_free_pcms(socdev); | 869 | snd_soc_free_pcms(socdev); |
881 | snd_soc_dapm_free(socdev); | 870 | snd_soc_dapm_free(socdev); |
882 | pcm_err: | 871 | pcm_err: |
883 | kfree(codec->reg_cache); | ||
884 | return ret; | 872 | return ret; |
885 | } | 873 | } |
886 | 874 | ||
887 | /* If the i2c layer weren't so broken, we could pass this kind of data | 875 | /* power down chip */ |
888 | around */ | 876 | static int wm8580_remove(struct platform_device *pdev) |
889 | static struct snd_soc_device *wm8580_socdev; | 877 | { |
878 | struct snd_soc_device *socdev = platform_get_drvdata(pdev); | ||
879 | |||
880 | snd_soc_free_pcms(socdev); | ||
881 | snd_soc_dapm_free(socdev); | ||
890 | 882 | ||
891 | #if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE) | 883 | return 0; |
884 | } | ||
892 | 885 | ||
893 | /* | 886 | struct snd_soc_codec_device soc_codec_dev_wm8580 = { |
894 | * WM8580 2 wire address is determined by GPIO5 | 887 | .probe = wm8580_probe, |
895 | * state during powerup. | 888 | .remove = wm8580_remove, |
896 | * low = 0x1a | 889 | }; |
897 | * high = 0x1b | 890 | EXPORT_SYMBOL_GPL(soc_codec_dev_wm8580); |
898 | */ | 891 | |
892 | static int wm8580_register(struct wm8580_priv *wm8580) | ||
893 | { | ||
894 | int ret, i; | ||
895 | struct snd_soc_codec *codec = &wm8580->codec; | ||
896 | |||
897 | if (wm8580_codec) { | ||
898 | dev_err(codec->dev, "Another WM8580 is registered\n"); | ||
899 | ret = -EINVAL; | ||
900 | goto err; | ||
901 | } | ||
902 | |||
903 | mutex_init(&codec->mutex); | ||
904 | INIT_LIST_HEAD(&codec->dapm_widgets); | ||
905 | INIT_LIST_HEAD(&codec->dapm_paths); | ||
899 | 906 | ||
907 | codec->private_data = wm8580; | ||
908 | codec->name = "WM8580"; | ||
909 | codec->owner = THIS_MODULE; | ||
910 | codec->read = wm8580_read_reg_cache; | ||
911 | codec->write = wm8580_write; | ||
912 | codec->bias_level = SND_SOC_BIAS_OFF; | ||
913 | codec->set_bias_level = wm8580_set_bias_level; | ||
914 | codec->dai = wm8580_dai; | ||
915 | codec->num_dai = ARRAY_SIZE(wm8580_dai); | ||
916 | codec->reg_cache_size = ARRAY_SIZE(wm8580->reg_cache); | ||
917 | codec->reg_cache = &wm8580->reg_cache; | ||
918 | |||
919 | memcpy(codec->reg_cache, wm8580_reg, sizeof(wm8580_reg)); | ||
920 | |||
921 | /* Get the codec into a known state */ | ||
922 | ret = wm8580_write(codec, WM8580_RESET, 0); | ||
923 | if (ret != 0) { | ||
924 | dev_err(codec->dev, "Failed to reset codec: %d\n", ret); | ||
925 | goto err; | ||
926 | } | ||
927 | |||
928 | for (i = 0; i < ARRAY_SIZE(wm8580_dai); i++) | ||
929 | wm8580_dai[i].dev = codec->dev; | ||
930 | |||
931 | wm8580_set_bias_level(codec, SND_SOC_BIAS_STANDBY); | ||
932 | |||
933 | wm8580_codec = codec; | ||
934 | |||
935 | ret = snd_soc_register_codec(codec); | ||
936 | if (ret != 0) { | ||
937 | dev_err(codec->dev, "Failed to register codec: %d\n", ret); | ||
938 | goto err; | ||
939 | } | ||
940 | |||
941 | ret = snd_soc_register_dais(wm8580_dai, ARRAY_SIZE(wm8580_dai)); | ||
942 | if (ret != 0) { | ||
943 | dev_err(codec->dev, "Failed to register DAI: %d\n", ret); | ||
944 | goto err_codec; | ||
945 | } | ||
946 | |||
947 | return 0; | ||
948 | |||
949 | err_codec: | ||
950 | snd_soc_unregister_codec(codec); | ||
951 | err: | ||
952 | kfree(wm8580); | ||
953 | return ret; | ||
954 | } | ||
955 | |||
956 | static void wm8580_unregister(struct wm8580_priv *wm8580) | ||
957 | { | ||
958 | wm8580_set_bias_level(&wm8580->codec, SND_SOC_BIAS_OFF); | ||
959 | snd_soc_unregister_dais(wm8580_dai, ARRAY_SIZE(wm8580_dai)); | ||
960 | snd_soc_unregister_codec(&wm8580->codec); | ||
961 | kfree(wm8580); | ||
962 | wm8580_codec = NULL; | ||
963 | } | ||
964 | |||
965 | #if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE) | ||
900 | static int wm8580_i2c_probe(struct i2c_client *i2c, | 966 | static int wm8580_i2c_probe(struct i2c_client *i2c, |
901 | const struct i2c_device_id *id) | 967 | const struct i2c_device_id *id) |
902 | { | 968 | { |
903 | struct snd_soc_device *socdev = wm8580_socdev; | 969 | struct wm8580_priv *wm8580; |
904 | struct snd_soc_codec *codec = socdev->codec; | 970 | struct snd_soc_codec *codec; |
905 | int ret; | ||
906 | 971 | ||
907 | i2c_set_clientdata(i2c, codec); | 972 | wm8580 = kzalloc(sizeof(struct wm8580_priv), GFP_KERNEL); |
973 | if (wm8580 == NULL) | ||
974 | return -ENOMEM; | ||
975 | |||
976 | codec = &wm8580->codec; | ||
977 | codec->hw_write = (hw_write_t)i2c_master_send; | ||
978 | |||
979 | i2c_set_clientdata(i2c, wm8580); | ||
908 | codec->control_data = i2c; | 980 | codec->control_data = i2c; |
909 | 981 | ||
910 | ret = wm8580_init(socdev); | 982 | codec->dev = &i2c->dev; |
911 | if (ret < 0) | 983 | |
912 | dev_err(&i2c->dev, "failed to initialise WM8580\n"); | 984 | return wm8580_register(wm8580); |
913 | return ret; | ||
914 | } | 985 | } |
915 | 986 | ||
916 | static int wm8580_i2c_remove(struct i2c_client *client) | 987 | static int wm8580_i2c_remove(struct i2c_client *client) |
917 | { | 988 | { |
918 | struct snd_soc_codec *codec = i2c_get_clientdata(client); | 989 | struct wm8580_priv *wm8580 = i2c_get_clientdata(client); |
919 | kfree(codec->reg_cache); | 990 | wm8580_unregister(wm8580); |
920 | return 0; | 991 | return 0; |
921 | } | 992 | } |
922 | 993 | ||
@@ -928,129 +999,35 @@ MODULE_DEVICE_TABLE(i2c, wm8580_i2c_id); | |||
928 | 999 | ||
929 | static struct i2c_driver wm8580_i2c_driver = { | 1000 | static struct i2c_driver wm8580_i2c_driver = { |
930 | .driver = { | 1001 | .driver = { |
931 | .name = "WM8580 I2C Codec", | 1002 | .name = "wm8580", |
932 | .owner = THIS_MODULE, | 1003 | .owner = THIS_MODULE, |
933 | }, | 1004 | }, |
934 | .probe = wm8580_i2c_probe, | 1005 | .probe = wm8580_i2c_probe, |
935 | .remove = wm8580_i2c_remove, | 1006 | .remove = wm8580_i2c_remove, |
936 | .id_table = wm8580_i2c_id, | 1007 | .id_table = wm8580_i2c_id, |
937 | }; | 1008 | }; |
1009 | #endif | ||
938 | 1010 | ||
939 | static int wm8580_add_i2c_device(struct platform_device *pdev, | 1011 | static int __init wm8580_modinit(void) |
940 | const struct wm8580_setup_data *setup) | ||
941 | { | 1012 | { |
942 | struct i2c_board_info info; | ||
943 | struct i2c_adapter *adapter; | ||
944 | struct i2c_client *client; | ||
945 | int ret; | 1013 | int ret; |
946 | 1014 | ||
1015 | #if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE) | ||
947 | ret = i2c_add_driver(&wm8580_i2c_driver); | 1016 | ret = i2c_add_driver(&wm8580_i2c_driver); |
948 | if (ret != 0) { | 1017 | if (ret != 0) { |
949 | dev_err(&pdev->dev, "can't add i2c driver\n"); | 1018 | pr_err("Failed to register WM8580 I2C driver: %d\n", ret); |
950 | return ret; | ||
951 | } | ||
952 | |||
953 | memset(&info, 0, sizeof(struct i2c_board_info)); | ||
954 | info.addr = setup->i2c_address; | ||
955 | strlcpy(info.type, "wm8580", I2C_NAME_SIZE); | ||
956 | |||
957 | adapter = i2c_get_adapter(setup->i2c_bus); | ||
958 | if (!adapter) { | ||
959 | dev_err(&pdev->dev, "can't get i2c adapter %d\n", | ||
960 | setup->i2c_bus); | ||
961 | goto err_driver; | ||
962 | } | ||
963 | |||
964 | client = i2c_new_device(adapter, &info); | ||
965 | i2c_put_adapter(adapter); | ||
966 | if (!client) { | ||
967 | dev_err(&pdev->dev, "can't add i2c device at 0x%x\n", | ||
968 | (unsigned int)info.addr); | ||
969 | goto err_driver; | ||
970 | } | 1019 | } |
971 | |||
972 | return 0; | ||
973 | |||
974 | err_driver: | ||
975 | i2c_del_driver(&wm8580_i2c_driver); | ||
976 | return -ENODEV; | ||
977 | } | ||
978 | #endif | 1020 | #endif |
979 | 1021 | ||
980 | static int wm8580_probe(struct platform_device *pdev) | ||
981 | { | ||
982 | struct snd_soc_device *socdev = platform_get_drvdata(pdev); | ||
983 | struct wm8580_setup_data *setup; | ||
984 | struct snd_soc_codec *codec; | ||
985 | struct wm8580_priv *wm8580; | ||
986 | int ret = 0; | ||
987 | |||
988 | pr_info("WM8580 Audio Codec %s\n", WM8580_VERSION); | ||
989 | |||
990 | setup = socdev->codec_data; | ||
991 | codec = kzalloc(sizeof(struct snd_soc_codec), GFP_KERNEL); | ||
992 | if (codec == NULL) | ||
993 | return -ENOMEM; | ||
994 | |||
995 | wm8580 = kzalloc(sizeof(struct wm8580_priv), GFP_KERNEL); | ||
996 | if (wm8580 == NULL) { | ||
997 | kfree(codec); | ||
998 | return -ENOMEM; | ||
999 | } | ||
1000 | |||
1001 | codec->private_data = wm8580; | ||
1002 | socdev->codec = codec; | ||
1003 | mutex_init(&codec->mutex); | ||
1004 | INIT_LIST_HEAD(&codec->dapm_widgets); | ||
1005 | INIT_LIST_HEAD(&codec->dapm_paths); | ||
1006 | wm8580_socdev = socdev; | ||
1007 | |||
1008 | #if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE) | ||
1009 | if (setup->i2c_address) { | ||
1010 | codec->hw_write = (hw_write_t)i2c_master_send; | ||
1011 | ret = wm8580_add_i2c_device(pdev, setup); | ||
1012 | } | ||
1013 | #else | ||
1014 | /* Add other interfaces here */ | ||
1015 | #endif | ||
1016 | return ret; | ||
1017 | } | ||
1018 | |||
1019 | /* power down chip */ | ||
1020 | static int wm8580_remove(struct platform_device *pdev) | ||
1021 | { | ||
1022 | struct snd_soc_device *socdev = platform_get_drvdata(pdev); | ||
1023 | struct snd_soc_codec *codec = socdev->codec; | ||
1024 | |||
1025 | if (codec->control_data) | ||
1026 | wm8580_set_bias_level(codec, SND_SOC_BIAS_OFF); | ||
1027 | snd_soc_free_pcms(socdev); | ||
1028 | snd_soc_dapm_free(socdev); | ||
1029 | #if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE) | ||
1030 | i2c_unregister_device(codec->control_data); | ||
1031 | i2c_del_driver(&wm8580_i2c_driver); | ||
1032 | #endif | ||
1033 | kfree(codec->private_data); | ||
1034 | kfree(codec); | ||
1035 | |||
1036 | return 0; | 1022 | return 0; |
1037 | } | 1023 | } |
1038 | |||
1039 | struct snd_soc_codec_device soc_codec_dev_wm8580 = { | ||
1040 | .probe = wm8580_probe, | ||
1041 | .remove = wm8580_remove, | ||
1042 | }; | ||
1043 | EXPORT_SYMBOL_GPL(soc_codec_dev_wm8580); | ||
1044 | |||
1045 | static int __init wm8580_modinit(void) | ||
1046 | { | ||
1047 | return snd_soc_register_dais(wm8580_dai, ARRAY_SIZE(wm8580_dai)); | ||
1048 | } | ||
1049 | module_init(wm8580_modinit); | 1024 | module_init(wm8580_modinit); |
1050 | 1025 | ||
1051 | static void __exit wm8580_exit(void) | 1026 | static void __exit wm8580_exit(void) |
1052 | { | 1027 | { |
1053 | snd_soc_unregister_dais(wm8580_dai, ARRAY_SIZE(wm8580_dai)); | 1028 | #if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE) |
1029 | i2c_del_driver(&wm8580_i2c_driver); | ||
1030 | #endif | ||
1054 | } | 1031 | } |
1055 | module_exit(wm8580_exit); | 1032 | module_exit(wm8580_exit); |
1056 | 1033 | ||