diff options
Diffstat (limited to 'sound/soc/codecs/wm8988.c')
-rw-r--r-- | sound/soc/codecs/wm8988.c | 171 |
1 files changed, 134 insertions, 37 deletions
diff --git a/sound/soc/codecs/wm8988.c b/sound/soc/codecs/wm8988.c index ab52963dd04c..6cdf6a2bc283 100644 --- a/sound/soc/codecs/wm8988.c +++ b/sound/soc/codecs/wm8988.c | |||
@@ -33,24 +33,89 @@ | |||
33 | * We can't read the WM8988 register space when we | 33 | * We can't read the WM8988 register space when we |
34 | * are using 2 wire for device control, so we cache them instead. | 34 | * are using 2 wire for device control, so we cache them instead. |
35 | */ | 35 | */ |
36 | static const u16 wm8988_reg[] = { | 36 | static const struct reg_default wm8988_reg_defaults[] = { |
37 | 0x0097, 0x0097, 0x0079, 0x0079, /* 0 */ | 37 | { 0, 0x0097 }, |
38 | 0x0000, 0x0008, 0x0000, 0x000a, /* 4 */ | 38 | { 1, 0x0097 }, |
39 | 0x0000, 0x0000, 0x00ff, 0x00ff, /* 8 */ | 39 | { 2, 0x0079 }, |
40 | 0x000f, 0x000f, 0x0000, 0x0000, /* 12 */ | 40 | { 3, 0x0079 }, |
41 | 0x0000, 0x007b, 0x0000, 0x0032, /* 16 */ | 41 | { 5, 0x0008 }, |
42 | 0x0000, 0x00c3, 0x00c3, 0x00c0, /* 20 */ | 42 | { 7, 0x000a }, |
43 | 0x0000, 0x0000, 0x0000, 0x0000, /* 24 */ | 43 | { 8, 0x0000 }, |
44 | 0x0000, 0x0000, 0x0000, 0x0000, /* 28 */ | 44 | { 10, 0x00ff }, |
45 | 0x0000, 0x0000, 0x0050, 0x0050, /* 32 */ | 45 | { 11, 0x00ff }, |
46 | 0x0050, 0x0050, 0x0050, 0x0050, /* 36 */ | 46 | { 12, 0x000f }, |
47 | 0x0079, 0x0079, 0x0079, /* 40 */ | 47 | { 13, 0x000f }, |
48 | { 16, 0x0000 }, | ||
49 | { 17, 0x007b }, | ||
50 | { 18, 0x0000 }, | ||
51 | { 19, 0x0032 }, | ||
52 | { 20, 0x0000 }, | ||
53 | { 21, 0x00c3 }, | ||
54 | { 22, 0x00c3 }, | ||
55 | { 23, 0x00c0 }, | ||
56 | { 24, 0x0000 }, | ||
57 | { 25, 0x0000 }, | ||
58 | { 26, 0x0000 }, | ||
59 | { 27, 0x0000 }, | ||
60 | { 31, 0x0000 }, | ||
61 | { 32, 0x0000 }, | ||
62 | { 33, 0x0000 }, | ||
63 | { 34, 0x0050 }, | ||
64 | { 35, 0x0050 }, | ||
65 | { 36, 0x0050 }, | ||
66 | { 37, 0x0050 }, | ||
67 | { 40, 0x0079 }, | ||
68 | { 41, 0x0079 }, | ||
69 | { 42, 0x0079 }, | ||
48 | }; | 70 | }; |
49 | 71 | ||
72 | static bool wm8988_writeable(struct device *dev, unsigned int reg) | ||
73 | { | ||
74 | switch (reg) { | ||
75 | case WM8988_LINVOL: | ||
76 | case WM8988_RINVOL: | ||
77 | case WM8988_LOUT1V: | ||
78 | case WM8988_ROUT1V: | ||
79 | case WM8988_ADCDAC: | ||
80 | case WM8988_IFACE: | ||
81 | case WM8988_SRATE: | ||
82 | case WM8988_LDAC: | ||
83 | case WM8988_RDAC: | ||
84 | case WM8988_BASS: | ||
85 | case WM8988_TREBLE: | ||
86 | case WM8988_RESET: | ||
87 | case WM8988_3D: | ||
88 | case WM8988_ALC1: | ||
89 | case WM8988_ALC2: | ||
90 | case WM8988_ALC3: | ||
91 | case WM8988_NGATE: | ||
92 | case WM8988_LADC: | ||
93 | case WM8988_RADC: | ||
94 | case WM8988_ADCTL1: | ||
95 | case WM8988_ADCTL2: | ||
96 | case WM8988_PWR1: | ||
97 | case WM8988_PWR2: | ||
98 | case WM8988_ADCTL3: | ||
99 | case WM8988_ADCIN: | ||
100 | case WM8988_LADCIN: | ||
101 | case WM8988_RADCIN: | ||
102 | case WM8988_LOUTM1: | ||
103 | case WM8988_LOUTM2: | ||
104 | case WM8988_ROUTM1: | ||
105 | case WM8988_ROUTM2: | ||
106 | case WM8988_LOUT2V: | ||
107 | case WM8988_ROUT2V: | ||
108 | case WM8988_LPPB: | ||
109 | return true; | ||
110 | default: | ||
111 | return false; | ||
112 | } | ||
113 | } | ||
114 | |||
50 | /* codec private data */ | 115 | /* codec private data */ |
51 | struct wm8988_priv { | 116 | struct wm8988_priv { |
117 | struct regmap *regmap; | ||
52 | unsigned int sysclk; | 118 | unsigned int sysclk; |
53 | enum snd_soc_control_type control_type; | ||
54 | struct snd_pcm_hw_constraint_list *sysclk_constraints; | 119 | struct snd_pcm_hw_constraint_list *sysclk_constraints; |
55 | }; | 120 | }; |
56 | 121 | ||
@@ -317,7 +382,7 @@ static const struct snd_soc_dapm_widget wm8988_dapm_widgets[] = { | |||
317 | SND_SOC_DAPM_INPUT("RINPUT2"), | 382 | SND_SOC_DAPM_INPUT("RINPUT2"), |
318 | }; | 383 | }; |
319 | 384 | ||
320 | static const struct snd_soc_dapm_route audio_map[] = { | 385 | static const struct snd_soc_dapm_route wm8988_dapm_routes[] = { |
321 | 386 | ||
322 | { "Left Line Mux", "Line 1", "LINPUT1" }, | 387 | { "Left Line Mux", "Line 1", "LINPUT1" }, |
323 | { "Left Line Mux", "Line 2", "LINPUT2" }, | 388 | { "Left Line Mux", "Line 2", "LINPUT2" }, |
@@ -661,6 +726,7 @@ static int wm8988_mute(struct snd_soc_dai *dai, int mute) | |||
661 | static int wm8988_set_bias_level(struct snd_soc_codec *codec, | 726 | static int wm8988_set_bias_level(struct snd_soc_codec *codec, |
662 | enum snd_soc_bias_level level) | 727 | enum snd_soc_bias_level level) |
663 | { | 728 | { |
729 | struct wm8988_priv *wm8988 = snd_soc_codec_get_drvdata(codec); | ||
664 | u16 pwr_reg = snd_soc_read(codec, WM8988_PWR1) & ~0x1c1; | 730 | u16 pwr_reg = snd_soc_read(codec, WM8988_PWR1) & ~0x1c1; |
665 | 731 | ||
666 | switch (level) { | 732 | switch (level) { |
@@ -674,7 +740,7 @@ static int wm8988_set_bias_level(struct snd_soc_codec *codec, | |||
674 | 740 | ||
675 | case SND_SOC_BIAS_STANDBY: | 741 | case SND_SOC_BIAS_STANDBY: |
676 | if (codec->dapm.bias_level == SND_SOC_BIAS_OFF) { | 742 | if (codec->dapm.bias_level == SND_SOC_BIAS_OFF) { |
677 | snd_soc_cache_sync(codec); | 743 | regcache_sync(wm8988->regmap); |
678 | 744 | ||
679 | /* VREF, VMID=2x5k */ | 745 | /* VREF, VMID=2x5k */ |
680 | snd_soc_write(codec, WM8988_PWR1, pwr_reg | 0x1c1); | 746 | snd_soc_write(codec, WM8988_PWR1, pwr_reg | 0x1c1); |
@@ -730,7 +796,10 @@ static struct snd_soc_dai_driver wm8988_dai = { | |||
730 | 796 | ||
731 | static int wm8988_suspend(struct snd_soc_codec *codec) | 797 | static int wm8988_suspend(struct snd_soc_codec *codec) |
732 | { | 798 | { |
799 | struct wm8988_priv *wm8988 = snd_soc_codec_get_drvdata(codec); | ||
800 | |||
733 | wm8988_set_bias_level(codec, SND_SOC_BIAS_OFF); | 801 | wm8988_set_bias_level(codec, SND_SOC_BIAS_OFF); |
802 | regcache_mark_dirty(wm8988->regmap); | ||
734 | return 0; | 803 | return 0; |
735 | } | 804 | } |
736 | 805 | ||
@@ -743,10 +812,10 @@ static int wm8988_resume(struct snd_soc_codec *codec) | |||
743 | static int wm8988_probe(struct snd_soc_codec *codec) | 812 | static int wm8988_probe(struct snd_soc_codec *codec) |
744 | { | 813 | { |
745 | struct wm8988_priv *wm8988 = snd_soc_codec_get_drvdata(codec); | 814 | struct wm8988_priv *wm8988 = snd_soc_codec_get_drvdata(codec); |
746 | struct snd_soc_dapm_context *dapm = &codec->dapm; | ||
747 | int ret = 0; | 815 | int ret = 0; |
748 | 816 | ||
749 | ret = snd_soc_codec_set_cache_io(codec, 7, 9, wm8988->control_type); | 817 | codec->control_data = wm8988->regmap; |
818 | ret = snd_soc_codec_set_cache_io(codec, 7, 9, SND_SOC_REGMAP); | ||
750 | if (ret < 0) { | 819 | if (ret < 0) { |
751 | dev_err(codec->dev, "Failed to set cache I/O: %d\n", ret); | 820 | dev_err(codec->dev, "Failed to set cache I/O: %d\n", ret); |
752 | return ret; | 821 | return ret; |
@@ -767,12 +836,6 @@ static int wm8988_probe(struct snd_soc_codec *codec) | |||
767 | 836 | ||
768 | wm8988_set_bias_level(codec, SND_SOC_BIAS_STANDBY); | 837 | wm8988_set_bias_level(codec, SND_SOC_BIAS_STANDBY); |
769 | 838 | ||
770 | snd_soc_add_controls(codec, wm8988_snd_controls, | ||
771 | ARRAY_SIZE(wm8988_snd_controls)); | ||
772 | snd_soc_dapm_new_controls(dapm, wm8988_dapm_widgets, | ||
773 | ARRAY_SIZE(wm8988_dapm_widgets)); | ||
774 | snd_soc_dapm_add_routes(dapm, audio_map, ARRAY_SIZE(audio_map)); | ||
775 | |||
776 | return 0; | 839 | return 0; |
777 | } | 840 | } |
778 | 841 | ||
@@ -788,9 +851,25 @@ static struct snd_soc_codec_driver soc_codec_dev_wm8988 = { | |||
788 | .suspend = wm8988_suspend, | 851 | .suspend = wm8988_suspend, |
789 | .resume = wm8988_resume, | 852 | .resume = wm8988_resume, |
790 | .set_bias_level = wm8988_set_bias_level, | 853 | .set_bias_level = wm8988_set_bias_level, |
791 | .reg_cache_size = ARRAY_SIZE(wm8988_reg), | 854 | |
792 | .reg_word_size = sizeof(u16), | 855 | .controls = wm8988_snd_controls, |
793 | .reg_cache_default = wm8988_reg, | 856 | .num_controls = ARRAY_SIZE(wm8988_snd_controls), |
857 | .dapm_widgets = wm8988_dapm_widgets, | ||
858 | .num_dapm_widgets = ARRAY_SIZE(wm8988_dapm_widgets), | ||
859 | .dapm_routes = wm8988_dapm_routes, | ||
860 | .num_dapm_routes = ARRAY_SIZE(wm8988_dapm_routes), | ||
861 | }; | ||
862 | |||
863 | static struct regmap_config wm8988_regmap = { | ||
864 | .reg_bits = 7, | ||
865 | .val_bits = 9, | ||
866 | |||
867 | .max_register = WM8988_LPPB, | ||
868 | .writeable_reg = wm8988_writeable, | ||
869 | |||
870 | .cache_type = REGCACHE_RBTREE, | ||
871 | .reg_defaults = wm8988_reg_defaults, | ||
872 | .num_reg_defaults = ARRAY_SIZE(wm8988_reg_defaults), | ||
794 | }; | 873 | }; |
795 | 874 | ||
796 | #if defined(CONFIG_SPI_MASTER) | 875 | #if defined(CONFIG_SPI_MASTER) |
@@ -799,24 +878,33 @@ static int __devinit wm8988_spi_probe(struct spi_device *spi) | |||
799 | struct wm8988_priv *wm8988; | 878 | struct wm8988_priv *wm8988; |
800 | int ret; | 879 | int ret; |
801 | 880 | ||
802 | wm8988 = kzalloc(sizeof(struct wm8988_priv), GFP_KERNEL); | 881 | wm8988 = devm_kzalloc(&spi->dev, sizeof(struct wm8988_priv), |
882 | GFP_KERNEL); | ||
803 | if (wm8988 == NULL) | 883 | if (wm8988 == NULL) |
804 | return -ENOMEM; | 884 | return -ENOMEM; |
805 | 885 | ||
806 | wm8988->control_type = SND_SOC_SPI; | 886 | wm8988->regmap = regmap_init_spi(spi, &wm8988_regmap); |
887 | if (IS_ERR(wm8988->regmap)) { | ||
888 | ret = PTR_ERR(wm8988->regmap); | ||
889 | dev_err(&spi->dev, "Failed to init regmap: %d\n", ret); | ||
890 | return ret; | ||
891 | } | ||
892 | |||
807 | spi_set_drvdata(spi, wm8988); | 893 | spi_set_drvdata(spi, wm8988); |
808 | 894 | ||
809 | ret = snd_soc_register_codec(&spi->dev, | 895 | ret = snd_soc_register_codec(&spi->dev, |
810 | &soc_codec_dev_wm8988, &wm8988_dai, 1); | 896 | &soc_codec_dev_wm8988, &wm8988_dai, 1); |
811 | if (ret < 0) | 897 | if (ret != 0) |
812 | kfree(wm8988); | 898 | regmap_exit(wm8988->regmap); |
899 | |||
813 | return ret; | 900 | return ret; |
814 | } | 901 | } |
815 | 902 | ||
816 | static int __devexit wm8988_spi_remove(struct spi_device *spi) | 903 | static int __devexit wm8988_spi_remove(struct spi_device *spi) |
817 | { | 904 | { |
905 | struct wm8988_priv *wm8988 = spi_get_drvdata(spi); | ||
818 | snd_soc_unregister_codec(&spi->dev); | 906 | snd_soc_unregister_codec(&spi->dev); |
819 | kfree(spi_get_drvdata(spi)); | 907 | regmap_exit(wm8988->regmap); |
820 | return 0; | 908 | return 0; |
821 | } | 909 | } |
822 | 910 | ||
@@ -837,24 +925,33 @@ static __devinit int wm8988_i2c_probe(struct i2c_client *i2c, | |||
837 | struct wm8988_priv *wm8988; | 925 | struct wm8988_priv *wm8988; |
838 | int ret; | 926 | int ret; |
839 | 927 | ||
840 | wm8988 = kzalloc(sizeof(struct wm8988_priv), GFP_KERNEL); | 928 | wm8988 = devm_kzalloc(&i2c->dev, sizeof(struct wm8988_priv), |
929 | GFP_KERNEL); | ||
841 | if (wm8988 == NULL) | 930 | if (wm8988 == NULL) |
842 | return -ENOMEM; | 931 | return -ENOMEM; |
843 | 932 | ||
844 | i2c_set_clientdata(i2c, wm8988); | 933 | i2c_set_clientdata(i2c, wm8988); |
845 | wm8988->control_type = SND_SOC_I2C; | 934 | |
935 | wm8988->regmap = regmap_init_i2c(i2c, &wm8988_regmap); | ||
936 | if (IS_ERR(wm8988->regmap)) { | ||
937 | ret = PTR_ERR(wm8988->regmap); | ||
938 | dev_err(&i2c->dev, "Failed to init regmap: %d\n", ret); | ||
939 | return ret; | ||
940 | } | ||
846 | 941 | ||
847 | ret = snd_soc_register_codec(&i2c->dev, | 942 | ret = snd_soc_register_codec(&i2c->dev, |
848 | &soc_codec_dev_wm8988, &wm8988_dai, 1); | 943 | &soc_codec_dev_wm8988, &wm8988_dai, 1); |
849 | if (ret < 0) | 944 | if (ret != 0) |
850 | kfree(wm8988); | 945 | regmap_exit(wm8988->regmap); |
946 | |||
851 | return ret; | 947 | return ret; |
852 | } | 948 | } |
853 | 949 | ||
854 | static __devexit int wm8988_i2c_remove(struct i2c_client *client) | 950 | static __devexit int wm8988_i2c_remove(struct i2c_client *client) |
855 | { | 951 | { |
952 | struct wm8988_priv *wm8988 = i2c_get_clientdata(client); | ||
856 | snd_soc_unregister_codec(&client->dev); | 953 | snd_soc_unregister_codec(&client->dev); |
857 | kfree(i2c_get_clientdata(client)); | 954 | regmap_exit(wm8988->regmap); |
858 | return 0; | 955 | return 0; |
859 | } | 956 | } |
860 | 957 | ||
@@ -866,7 +963,7 @@ MODULE_DEVICE_TABLE(i2c, wm8988_i2c_id); | |||
866 | 963 | ||
867 | static struct i2c_driver wm8988_i2c_driver = { | 964 | static struct i2c_driver wm8988_i2c_driver = { |
868 | .driver = { | 965 | .driver = { |
869 | .name = "wm8988-codec", | 966 | .name = "wm8988", |
870 | .owner = THIS_MODULE, | 967 | .owner = THIS_MODULE, |
871 | }, | 968 | }, |
872 | .probe = wm8988_i2c_probe, | 969 | .probe = wm8988_i2c_probe, |