diff options
author | Mark Brown <broonie@opensource.wolfsonmicro.com> | 2011-12-29 16:42:36 -0500 |
---|---|---|
committer | Mark Brown <broonie@opensource.wolfsonmicro.com> | 2012-01-20 08:58:25 -0500 |
commit | 95860fdf0f565f96fc37561b6794177604f89097 (patch) | |
tree | 94c4c877fd2a7c1a6a467f0150f5cf5a4f325cd4 /sound/soc/codecs/wm8955.c | |
parent | 9887cb9e651da91c5bad2578d71e7ff8410e14b7 (diff) |
ASoC: Convert WM8955 to direct regmap API usage
Signed-off-by: Mark Brown <broonie@opensource.wolfsonmicro.com>
Diffstat (limited to 'sound/soc/codecs/wm8955.c')
-rw-r--r-- | sound/soc/codecs/wm8955.c | 198 |
1 files changed, 123 insertions, 75 deletions
diff --git a/sound/soc/codecs/wm8955.c b/sound/soc/codecs/wm8955.c index 559c96b656a4..11fb2dd40c5c 100644 --- a/sound/soc/codecs/wm8955.c +++ b/sound/soc/codecs/wm8955.c | |||
@@ -16,6 +16,7 @@ | |||
16 | #include <linux/delay.h> | 16 | #include <linux/delay.h> |
17 | #include <linux/pm.h> | 17 | #include <linux/pm.h> |
18 | #include <linux/i2c.h> | 18 | #include <linux/i2c.h> |
19 | #include <linux/regmap.h> | ||
19 | #include <linux/regulator/consumer.h> | 20 | #include <linux/regulator/consumer.h> |
20 | #include <linux/slab.h> | 21 | #include <linux/slab.h> |
21 | #include <sound/core.h> | 22 | #include <sound/core.h> |
@@ -38,7 +39,7 @@ static const char *wm8955_supply_names[WM8955_NUM_SUPPLIES] = { | |||
38 | 39 | ||
39 | /* codec private data */ | 40 | /* codec private data */ |
40 | struct wm8955_priv { | 41 | struct wm8955_priv { |
41 | enum snd_soc_control_type control_type; | 42 | struct regmap *regmap; |
42 | 43 | ||
43 | unsigned int mclk_rate; | 44 | unsigned int mclk_rate; |
44 | 45 | ||
@@ -48,69 +49,85 @@ struct wm8955_priv { | |||
48 | struct regulator_bulk_data supplies[WM8955_NUM_SUPPLIES]; | 49 | struct regulator_bulk_data supplies[WM8955_NUM_SUPPLIES]; |
49 | }; | 50 | }; |
50 | 51 | ||
51 | static const u16 wm8955_reg[WM8955_MAX_REGISTER + 1] = { | 52 | static const struct reg_default wm8955_reg_defaults[] = { |
52 | 0x0000, /* R0 */ | 53 | { 2, 0x0079 }, /* R2 - LOUT1 volume */ |
53 | 0x0000, /* R1 */ | 54 | { 3, 0x0079 }, /* R3 - ROUT1 volume */ |
54 | 0x0079, /* R2 - LOUT1 volume */ | 55 | { 5, 0x0008 }, /* R5 - DAC Control */ |
55 | 0x0079, /* R3 - ROUT1 volume */ | 56 | { 7, 0x000A }, /* R7 - Audio Interface */ |
56 | 0x0000, /* R4 */ | 57 | { 8, 0x0000 }, /* R8 - Sample Rate */ |
57 | 0x0008, /* R5 - DAC Control */ | 58 | { 10, 0x00FF }, /* R10 - Left DAC volume */ |
58 | 0x0000, /* R6 */ | 59 | { 11, 0x00FF }, /* R11 - Right DAC volume */ |
59 | 0x000A, /* R7 - Audio Interface */ | 60 | { 12, 0x000F }, /* R12 - Bass control */ |
60 | 0x0000, /* R8 - Sample Rate */ | 61 | { 13, 0x000F }, /* R13 - Treble control */ |
61 | 0x0000, /* R9 */ | 62 | { 23, 0x00C1 }, /* R23 - Additional control (1) */ |
62 | 0x00FF, /* R10 - Left DAC volume */ | 63 | { 24, 0x0000 }, /* R24 - Additional control (2) */ |
63 | 0x00FF, /* R11 - Right DAC volume */ | 64 | { 25, 0x0000 }, /* R25 - Power Management (1) */ |
64 | 0x000F, /* R12 - Bass control */ | 65 | { 26, 0x0000 }, /* R26 - Power Management (2) */ |
65 | 0x000F, /* R13 - Treble control */ | 66 | { 27, 0x0000 }, /* R27 - Additional Control (3) */ |
66 | 0x0000, /* R14 */ | 67 | { 34, 0x0050 }, /* R34 - Left out Mix (1) */ |
67 | 0x0000, /* R15 - Reset */ | 68 | { 35, 0x0050 }, /* R35 - Left out Mix (2) */ |
68 | 0x0000, /* R16 */ | 69 | { 36, 0x0050 }, /* R36 - Right out Mix (1) */ |
69 | 0x0000, /* R17 */ | 70 | { 37, 0x0050 }, /* R37 - Right Out Mix (2) */ |
70 | 0x0000, /* R18 */ | 71 | { 38, 0x0050 }, /* R38 - Mono out Mix (1) */ |
71 | 0x0000, /* R19 */ | 72 | { 39, 0x0050 }, /* R39 - Mono out Mix (2) */ |
72 | 0x0000, /* R20 */ | 73 | { 40, 0x0079 }, /* R40 - LOUT2 volume */ |
73 | 0x0000, /* R21 */ | 74 | { 41, 0x0079 }, /* R41 - ROUT2 volume */ |
74 | 0x0000, /* R22 */ | 75 | { 42, 0x0079 }, /* R42 - MONOOUT volume */ |
75 | 0x00C1, /* R23 - Additional control (1) */ | 76 | { 43, 0x0000 }, /* R43 - Clocking / PLL */ |
76 | 0x0000, /* R24 - Additional control (2) */ | 77 | { 44, 0x0103 }, /* R44 - PLL Control 1 */ |
77 | 0x0000, /* R25 - Power Management (1) */ | 78 | { 45, 0x0024 }, /* R45 - PLL Control 2 */ |
78 | 0x0000, /* R26 - Power Management (2) */ | 79 | { 46, 0x01BA }, /* R46 - PLL Control 3 */ |
79 | 0x0000, /* R27 - Additional Control (3) */ | 80 | { 59, 0x0000 }, /* R59 - PLL Control 4 */ |
80 | 0x0000, /* R28 */ | ||
81 | 0x0000, /* R29 */ | ||
82 | 0x0000, /* R30 */ | ||
83 | 0x0000, /* R31 */ | ||
84 | 0x0000, /* R32 */ | ||
85 | 0x0000, /* R33 */ | ||
86 | 0x0050, /* R34 - Left out Mix (1) */ | ||
87 | 0x0050, /* R35 - Left out Mix (2) */ | ||
88 | 0x0050, /* R36 - Right out Mix (1) */ | ||
89 | 0x0050, /* R37 - Right Out Mix (2) */ | ||
90 | 0x0050, /* R38 - Mono out Mix (1) */ | ||
91 | 0x0050, /* R39 - Mono out Mix (2) */ | ||
92 | 0x0079, /* R40 - LOUT2 volume */ | ||
93 | 0x0079, /* R41 - ROUT2 volume */ | ||
94 | 0x0079, /* R42 - MONOOUT volume */ | ||
95 | 0x0000, /* R43 - Clocking / PLL */ | ||
96 | 0x0103, /* R44 - PLL Control 1 */ | ||
97 | 0x0024, /* R45 - PLL Control 2 */ | ||
98 | 0x01BA, /* R46 - PLL Control 3 */ | ||
99 | 0x0000, /* R47 */ | ||
100 | 0x0000, /* R48 */ | ||
101 | 0x0000, /* R49 */ | ||
102 | 0x0000, /* R50 */ | ||
103 | 0x0000, /* R51 */ | ||
104 | 0x0000, /* R52 */ | ||
105 | 0x0000, /* R53 */ | ||
106 | 0x0000, /* R54 */ | ||
107 | 0x0000, /* R55 */ | ||
108 | 0x0000, /* R56 */ | ||
109 | 0x0000, /* R57 */ | ||
110 | 0x0000, /* R58 */ | ||
111 | 0x0000, /* R59 - PLL Control 4 */ | ||
112 | }; | 81 | }; |
113 | 82 | ||
83 | static bool wm8955_writeable(struct device *dev, unsigned int reg) | ||
84 | { | ||
85 | switch (reg) { | ||
86 | case WM8955_LOUT1_VOLUME: | ||
87 | case WM8955_ROUT1_VOLUME: | ||
88 | case WM8955_DAC_CONTROL: | ||
89 | case WM8955_AUDIO_INTERFACE: | ||
90 | case WM8955_SAMPLE_RATE: | ||
91 | case WM8955_LEFT_DAC_VOLUME: | ||
92 | case WM8955_RIGHT_DAC_VOLUME: | ||
93 | case WM8955_BASS_CONTROL: | ||
94 | case WM8955_TREBLE_CONTROL: | ||
95 | case WM8955_RESET: | ||
96 | case WM8955_ADDITIONAL_CONTROL_1: | ||
97 | case WM8955_ADDITIONAL_CONTROL_2: | ||
98 | case WM8955_POWER_MANAGEMENT_1: | ||
99 | case WM8955_POWER_MANAGEMENT_2: | ||
100 | case WM8955_ADDITIONAL_CONTROL_3: | ||
101 | case WM8955_LEFT_OUT_MIX_1: | ||
102 | case WM8955_LEFT_OUT_MIX_2: | ||
103 | case WM8955_RIGHT_OUT_MIX_1: | ||
104 | case WM8955_RIGHT_OUT_MIX_2: | ||
105 | case WM8955_MONO_OUT_MIX_1: | ||
106 | case WM8955_MONO_OUT_MIX_2: | ||
107 | case WM8955_LOUT2_VOLUME: | ||
108 | case WM8955_ROUT2_VOLUME: | ||
109 | case WM8955_MONOOUT_VOLUME: | ||
110 | case WM8955_CLOCKING_PLL: | ||
111 | case WM8955_PLL_CONTROL_1: | ||
112 | case WM8955_PLL_CONTROL_2: | ||
113 | case WM8955_PLL_CONTROL_3: | ||
114 | case WM8955_PLL_CONTROL_4: | ||
115 | return true; | ||
116 | default: | ||
117 | return false; | ||
118 | } | ||
119 | } | ||
120 | |||
121 | static bool wm8955_volatile(struct device *dev, unsigned int reg) | ||
122 | { | ||
123 | switch (reg) { | ||
124 | case WM8955_RESET: | ||
125 | return true; | ||
126 | default: | ||
127 | return false; | ||
128 | } | ||
129 | } | ||
130 | |||
114 | static int wm8955_reset(struct snd_soc_codec *codec) | 131 | static int wm8955_reset(struct snd_soc_codec *codec) |
115 | { | 132 | { |
116 | return snd_soc_write(codec, WM8955_RESET, 0); | 133 | return snd_soc_write(codec, WM8955_RESET, 0); |
@@ -765,8 +782,7 @@ static int wm8955_set_bias_level(struct snd_soc_codec *codec, | |||
765 | enum snd_soc_bias_level level) | 782 | enum snd_soc_bias_level level) |
766 | { | 783 | { |
767 | struct wm8955_priv *wm8955 = snd_soc_codec_get_drvdata(codec); | 784 | struct wm8955_priv *wm8955 = snd_soc_codec_get_drvdata(codec); |
768 | u16 *reg_cache = codec->reg_cache; | 785 | int ret; |
769 | int ret, i; | ||
770 | 786 | ||
771 | switch (level) { | 787 | switch (level) { |
772 | case SND_SOC_BIAS_ON: | 788 | case SND_SOC_BIAS_ON: |
@@ -795,7 +811,7 @@ static int wm8955_set_bias_level(struct snd_soc_codec *codec, | |||
795 | return ret; | 811 | return ret; |
796 | } | 812 | } |
797 | 813 | ||
798 | snd_soc_cache_sync(codec); | 814 | regcache_sync(wm8955->regmap); |
799 | 815 | ||
800 | /* Enable VREF and VMID */ | 816 | /* Enable VREF and VMID */ |
801 | snd_soc_update_bits(codec, WM8955_POWER_MANAGEMENT_1, | 817 | snd_soc_update_bits(codec, WM8955_POWER_MANAGEMENT_1, |
@@ -869,8 +885,12 @@ static struct snd_soc_dai_driver wm8955_dai = { | |||
869 | #ifdef CONFIG_PM | 885 | #ifdef CONFIG_PM |
870 | static int wm8955_suspend(struct snd_soc_codec *codec) | 886 | static int wm8955_suspend(struct snd_soc_codec *codec) |
871 | { | 887 | { |
888 | struct wm8955_priv *wm8955 = snd_soc_codec_get_drvdata(codec); | ||
889 | |||
872 | wm8955_set_bias_level(codec, SND_SOC_BIAS_OFF); | 890 | wm8955_set_bias_level(codec, SND_SOC_BIAS_OFF); |
873 | 891 | ||
892 | regcache_mark_dirty(wm8955->regmap); | ||
893 | |||
874 | return 0; | 894 | return 0; |
875 | } | 895 | } |
876 | 896 | ||
@@ -889,10 +909,11 @@ static int wm8955_probe(struct snd_soc_codec *codec) | |||
889 | { | 909 | { |
890 | struct wm8955_priv *wm8955 = snd_soc_codec_get_drvdata(codec); | 910 | struct wm8955_priv *wm8955 = snd_soc_codec_get_drvdata(codec); |
891 | struct wm8955_pdata *pdata = dev_get_platdata(codec->dev); | 911 | struct wm8955_pdata *pdata = dev_get_platdata(codec->dev); |
892 | u16 *reg_cache = codec->reg_cache; | ||
893 | int ret, i; | 912 | int ret, i; |
894 | 913 | ||
895 | ret = snd_soc_codec_set_cache_io(codec, 7, 9, wm8955->control_type); | 914 | codec->control_data = wm8955->regmap; |
915 | |||
916 | ret = snd_soc_codec_set_cache_io(codec, 7, 9, SND_SOC_REGMAP); | ||
896 | if (ret != 0) { | 917 | if (ret != 0) { |
897 | dev_err(codec->dev, "Failed to set cache I/O: %d\n", ret); | 918 | dev_err(codec->dev, "Failed to set cache I/O: %d\n", ret); |
898 | return ret; | 919 | return ret; |
@@ -947,12 +968,12 @@ static int wm8955_probe(struct snd_soc_codec *codec) | |||
947 | /* Set platform data values */ | 968 | /* Set platform data values */ |
948 | if (pdata) { | 969 | if (pdata) { |
949 | if (pdata->out2_speaker) | 970 | if (pdata->out2_speaker) |
950 | reg_cache[WM8955_ADDITIONAL_CONTROL_2] | 971 | snd_soc_update_bits(codec, WM8955_ADDITIONAL_CONTROL_2, |
951 | |= WM8955_ROUT2INV; | 972 | WM8955_ROUT2INV, WM8955_ROUT2INV); |
952 | 973 | ||
953 | if (pdata->monoin_diff) | 974 | if (pdata->monoin_diff) |
954 | reg_cache[WM8955_MONO_OUT_MIX_1] | 975 | snd_soc_update_bits(codec, WM8955_MONO_OUT_MIX_1, |
955 | |= WM8955_DMEN; | 976 | WM8955_DMEN, WM8955_DMEN); |
956 | } | 977 | } |
957 | 978 | ||
958 | wm8955_set_bias_level(codec, SND_SOC_BIAS_STANDBY); | 979 | wm8955_set_bias_level(codec, SND_SOC_BIAS_STANDBY); |
@@ -985,9 +1006,19 @@ static struct snd_soc_codec_driver soc_codec_dev_wm8955 = { | |||
985 | .suspend = wm8955_suspend, | 1006 | .suspend = wm8955_suspend, |
986 | .resume = wm8955_resume, | 1007 | .resume = wm8955_resume, |
987 | .set_bias_level = wm8955_set_bias_level, | 1008 | .set_bias_level = wm8955_set_bias_level, |
988 | .reg_cache_size = ARRAY_SIZE(wm8955_reg), | 1009 | }; |
989 | .reg_word_size = sizeof(u16), | 1010 | |
990 | .reg_cache_default = wm8955_reg, | 1011 | static const struct regmap_config wm8955_regmap = { |
1012 | .reg_bits = 7, | ||
1013 | .val_bits = 9, | ||
1014 | |||
1015 | .max_register = WM8955_MAX_REGISTER, | ||
1016 | .volatile_reg = wm8955_volatile, | ||
1017 | .writeable_reg = wm8955_writeable, | ||
1018 | |||
1019 | .cache_type = REGCACHE_RBTREE, | ||
1020 | .reg_defaults = wm8955_reg_defaults, | ||
1021 | .num_reg_defaults = ARRAY_SIZE(wm8955_reg_defaults), | ||
991 | }; | 1022 | }; |
992 | 1023 | ||
993 | static __devinit int wm8955_i2c_probe(struct i2c_client *i2c, | 1024 | static __devinit int wm8955_i2c_probe(struct i2c_client *i2c, |
@@ -1001,18 +1032,35 @@ static __devinit int wm8955_i2c_probe(struct i2c_client *i2c, | |||
1001 | if (wm8955 == NULL) | 1032 | if (wm8955 == NULL) |
1002 | return -ENOMEM; | 1033 | return -ENOMEM; |
1003 | 1034 | ||
1035 | wm8955->regmap = regmap_init_i2c(i2c, &wm8955_regmap); | ||
1036 | if (IS_ERR(wm8955->regmap)) { | ||
1037 | ret = PTR_ERR(wm8955->regmap); | ||
1038 | dev_err(&i2c->dev, "Failed to allocate register map: %d\n", | ||
1039 | ret); | ||
1040 | return ret; | ||
1041 | } | ||
1042 | |||
1004 | i2c_set_clientdata(i2c, wm8955); | 1043 | i2c_set_clientdata(i2c, wm8955); |
1005 | wm8955->control_type = SND_SOC_I2C; | ||
1006 | 1044 | ||
1007 | ret = snd_soc_register_codec(&i2c->dev, | 1045 | ret = snd_soc_register_codec(&i2c->dev, |
1008 | &soc_codec_dev_wm8955, &wm8955_dai, 1); | 1046 | &soc_codec_dev_wm8955, &wm8955_dai, 1); |
1047 | if (ret != 0) | ||
1048 | goto err; | ||
1049 | |||
1050 | return ret; | ||
1009 | 1051 | ||
1052 | err: | ||
1053 | regmap_exit(wm8955->regmap); | ||
1010 | return ret; | 1054 | return ret; |
1011 | } | 1055 | } |
1012 | 1056 | ||
1013 | static __devexit int wm8955_i2c_remove(struct i2c_client *client) | 1057 | static __devexit int wm8955_i2c_remove(struct i2c_client *client) |
1014 | { | 1058 | { |
1059 | struct wm8955_priv *wm8955 = i2c_get_clientdata(client); | ||
1060 | |||
1015 | snd_soc_unregister_codec(&client->dev); | 1061 | snd_soc_unregister_codec(&client->dev); |
1062 | regmap_exit(wm8955->regmap); | ||
1063 | |||
1016 | return 0; | 1064 | return 0; |
1017 | } | 1065 | } |
1018 | 1066 | ||