diff options
Diffstat (limited to 'sound/soc/codecs/max9877.c')
-rw-r--r-- | sound/soc/codecs/max9877.c | 294 |
1 files changed, 92 insertions, 202 deletions
diff --git a/sound/soc/codecs/max9877.c b/sound/soc/codecs/max9877.c index 6b6c74cd83e2..29549cdbf4c1 100644 --- a/sound/soc/codecs/max9877.c +++ b/sound/soc/codecs/max9877.c | |||
@@ -14,170 +14,21 @@ | |||
14 | #include <linux/module.h> | 14 | #include <linux/module.h> |
15 | #include <linux/init.h> | 15 | #include <linux/init.h> |
16 | #include <linux/i2c.h> | 16 | #include <linux/i2c.h> |
17 | #include <linux/regmap.h> | ||
17 | #include <sound/soc.h> | 18 | #include <sound/soc.h> |
18 | #include <sound/tlv.h> | 19 | #include <sound/tlv.h> |
19 | 20 | ||
20 | #include "max9877.h" | 21 | #include "max9877.h" |
21 | 22 | ||
22 | static struct i2c_client *i2c; | 23 | static struct regmap *regmap; |
23 | 24 | ||
24 | static u8 max9877_regs[5] = { 0x40, 0x00, 0x00, 0x00, 0x49 }; | 25 | static struct reg_default max9877_regs[] = { |
25 | 26 | { 0, 0x40 }, | |
26 | static void max9877_write_regs(void) | 27 | { 1, 0x00 }, |
27 | { | 28 | { 2, 0x00 }, |
28 | unsigned int i; | 29 | { 3, 0x00 }, |
29 | u8 data[6]; | 30 | { 4, 0x49 }, |
30 | 31 | }; | |
31 | data[0] = MAX9877_INPUT_MODE; | ||
32 | for (i = 0; i < ARRAY_SIZE(max9877_regs); i++) | ||
33 | data[i + 1] = max9877_regs[i]; | ||
34 | |||
35 | if (i2c_master_send(i2c, data, 6) != 6) | ||
36 | dev_err(&i2c->dev, "i2c write failed\n"); | ||
37 | } | ||
38 | |||
39 | static int max9877_get_reg(struct snd_kcontrol *kcontrol, | ||
40 | struct snd_ctl_elem_value *ucontrol) | ||
41 | { | ||
42 | struct soc_mixer_control *mc = | ||
43 | (struct soc_mixer_control *)kcontrol->private_value; | ||
44 | unsigned int reg = mc->reg; | ||
45 | unsigned int shift = mc->shift; | ||
46 | unsigned int mask = mc->max; | ||
47 | unsigned int invert = mc->invert; | ||
48 | |||
49 | ucontrol->value.integer.value[0] = (max9877_regs[reg] >> shift) & mask; | ||
50 | |||
51 | if (invert) | ||
52 | ucontrol->value.integer.value[0] = | ||
53 | mask - ucontrol->value.integer.value[0]; | ||
54 | |||
55 | return 0; | ||
56 | } | ||
57 | |||
58 | static int max9877_set_reg(struct snd_kcontrol *kcontrol, | ||
59 | struct snd_ctl_elem_value *ucontrol) | ||
60 | { | ||
61 | struct soc_mixer_control *mc = | ||
62 | (struct soc_mixer_control *)kcontrol->private_value; | ||
63 | unsigned int reg = mc->reg; | ||
64 | unsigned int shift = mc->shift; | ||
65 | unsigned int mask = mc->max; | ||
66 | unsigned int invert = mc->invert; | ||
67 | unsigned int val = (ucontrol->value.integer.value[0] & mask); | ||
68 | |||
69 | if (invert) | ||
70 | val = mask - val; | ||
71 | |||
72 | if (((max9877_regs[reg] >> shift) & mask) == val) | ||
73 | return 0; | ||
74 | |||
75 | max9877_regs[reg] &= ~(mask << shift); | ||
76 | max9877_regs[reg] |= val << shift; | ||
77 | max9877_write_regs(); | ||
78 | |||
79 | return 1; | ||
80 | } | ||
81 | |||
82 | static int max9877_get_2reg(struct snd_kcontrol *kcontrol, | ||
83 | struct snd_ctl_elem_value *ucontrol) | ||
84 | { | ||
85 | struct soc_mixer_control *mc = | ||
86 | (struct soc_mixer_control *)kcontrol->private_value; | ||
87 | unsigned int reg = mc->reg; | ||
88 | unsigned int reg2 = mc->rreg; | ||
89 | unsigned int shift = mc->shift; | ||
90 | unsigned int mask = mc->max; | ||
91 | |||
92 | ucontrol->value.integer.value[0] = (max9877_regs[reg] >> shift) & mask; | ||
93 | ucontrol->value.integer.value[1] = (max9877_regs[reg2] >> shift) & mask; | ||
94 | |||
95 | return 0; | ||
96 | } | ||
97 | |||
98 | static int max9877_set_2reg(struct snd_kcontrol *kcontrol, | ||
99 | struct snd_ctl_elem_value *ucontrol) | ||
100 | { | ||
101 | struct soc_mixer_control *mc = | ||
102 | (struct soc_mixer_control *)kcontrol->private_value; | ||
103 | unsigned int reg = mc->reg; | ||
104 | unsigned int reg2 = mc->rreg; | ||
105 | unsigned int shift = mc->shift; | ||
106 | unsigned int mask = mc->max; | ||
107 | unsigned int val = (ucontrol->value.integer.value[0] & mask); | ||
108 | unsigned int val2 = (ucontrol->value.integer.value[1] & mask); | ||
109 | unsigned int change = 0; | ||
110 | |||
111 | if (((max9877_regs[reg] >> shift) & mask) != val) | ||
112 | change = 1; | ||
113 | |||
114 | if (((max9877_regs[reg2] >> shift) & mask) != val2) | ||
115 | change = 1; | ||
116 | |||
117 | if (change) { | ||
118 | max9877_regs[reg] &= ~(mask << shift); | ||
119 | max9877_regs[reg] |= val << shift; | ||
120 | max9877_regs[reg2] &= ~(mask << shift); | ||
121 | max9877_regs[reg2] |= val2 << shift; | ||
122 | max9877_write_regs(); | ||
123 | } | ||
124 | |||
125 | return change; | ||
126 | } | ||
127 | |||
128 | static int max9877_get_out_mode(struct snd_kcontrol *kcontrol, | ||
129 | struct snd_ctl_elem_value *ucontrol) | ||
130 | { | ||
131 | u8 value = max9877_regs[MAX9877_OUTPUT_MODE] & MAX9877_OUTMODE_MASK; | ||
132 | |||
133 | if (value) | ||
134 | value -= 1; | ||
135 | |||
136 | ucontrol->value.integer.value[0] = value; | ||
137 | return 0; | ||
138 | } | ||
139 | |||
140 | static int max9877_set_out_mode(struct snd_kcontrol *kcontrol, | ||
141 | struct snd_ctl_elem_value *ucontrol) | ||
142 | { | ||
143 | u8 value = ucontrol->value.integer.value[0]; | ||
144 | |||
145 | value += 1; | ||
146 | |||
147 | if ((max9877_regs[MAX9877_OUTPUT_MODE] & MAX9877_OUTMODE_MASK) == value) | ||
148 | return 0; | ||
149 | |||
150 | max9877_regs[MAX9877_OUTPUT_MODE] &= ~MAX9877_OUTMODE_MASK; | ||
151 | max9877_regs[MAX9877_OUTPUT_MODE] |= value; | ||
152 | max9877_write_regs(); | ||
153 | return 1; | ||
154 | } | ||
155 | |||
156 | static int max9877_get_osc_mode(struct snd_kcontrol *kcontrol, | ||
157 | struct snd_ctl_elem_value *ucontrol) | ||
158 | { | ||
159 | u8 value = (max9877_regs[MAX9877_OUTPUT_MODE] & MAX9877_OSC_MASK); | ||
160 | |||
161 | value = value >> MAX9877_OSC_OFFSET; | ||
162 | |||
163 | ucontrol->value.integer.value[0] = value; | ||
164 | return 0; | ||
165 | } | ||
166 | |||
167 | static int max9877_set_osc_mode(struct snd_kcontrol *kcontrol, | ||
168 | struct snd_ctl_elem_value *ucontrol) | ||
169 | { | ||
170 | u8 value = ucontrol->value.integer.value[0]; | ||
171 | |||
172 | value = value << MAX9877_OSC_OFFSET; | ||
173 | if ((max9877_regs[MAX9877_OUTPUT_MODE] & MAX9877_OSC_MASK) == value) | ||
174 | return 0; | ||
175 | |||
176 | max9877_regs[MAX9877_OUTPUT_MODE] &= ~MAX9877_OSC_MASK; | ||
177 | max9877_regs[MAX9877_OUTPUT_MODE] |= value; | ||
178 | max9877_write_regs(); | ||
179 | return 1; | ||
180 | } | ||
181 | 32 | ||
182 | static const unsigned int max9877_pgain_tlv[] = { | 33 | static const unsigned int max9877_pgain_tlv[] = { |
183 | TLV_DB_RANGE_HEAD(2), | 34 | TLV_DB_RANGE_HEAD(2), |
@@ -212,65 +63,104 @@ static const char *max9877_osc_mode[] = { | |||
212 | }; | 63 | }; |
213 | 64 | ||
214 | static const struct soc_enum max9877_enum[] = { | 65 | static const struct soc_enum max9877_enum[] = { |
215 | SOC_ENUM_SINGLE_EXT(ARRAY_SIZE(max9877_out_mode), max9877_out_mode), | 66 | SOC_ENUM_SINGLE(MAX9877_OUTPUT_MODE, 0, ARRAY_SIZE(max9877_out_mode), |
216 | SOC_ENUM_SINGLE_EXT(ARRAY_SIZE(max9877_osc_mode), max9877_osc_mode), | 67 | max9877_out_mode), |
68 | SOC_ENUM_SINGLE(MAX9877_OUTPUT_MODE, MAX9877_OSC_OFFSET, | ||
69 | ARRAY_SIZE(max9877_osc_mode), max9877_osc_mode), | ||
217 | }; | 70 | }; |
218 | 71 | ||
219 | static const struct snd_kcontrol_new max9877_controls[] = { | 72 | static const struct snd_kcontrol_new max9877_controls[] = { |
220 | SOC_SINGLE_EXT_TLV("MAX9877 PGAINA Playback Volume", | 73 | SOC_SINGLE_TLV("MAX9877 PGAINA Playback Volume", |
221 | MAX9877_INPUT_MODE, 0, 2, 0, | 74 | MAX9877_INPUT_MODE, 0, 2, 0, max9877_pgain_tlv), |
222 | max9877_get_reg, max9877_set_reg, max9877_pgain_tlv), | 75 | SOC_SINGLE_TLV("MAX9877 PGAINB Playback Volume", |
223 | SOC_SINGLE_EXT_TLV("MAX9877 PGAINB Playback Volume", | 76 | MAX9877_INPUT_MODE, 2, 2, 0, max9877_pgain_tlv), |
224 | MAX9877_INPUT_MODE, 2, 2, 0, | 77 | SOC_SINGLE_TLV("MAX9877 Amp Speaker Playback Volume", |
225 | max9877_get_reg, max9877_set_reg, max9877_pgain_tlv), | 78 | MAX9877_SPK_VOLUME, 0, 31, 0, max9877_output_tlv), |
226 | SOC_SINGLE_EXT_TLV("MAX9877 Amp Speaker Playback Volume", | 79 | SOC_DOUBLE_R_TLV("MAX9877 Amp HP Playback Volume", |
227 | MAX9877_SPK_VOLUME, 0, 31, 0, | 80 | MAX9877_HPL_VOLUME, MAX9877_HPR_VOLUME, 0, 31, 0, |
228 | max9877_get_reg, max9877_set_reg, max9877_output_tlv), | 81 | max9877_output_tlv), |
229 | SOC_DOUBLE_R_EXT_TLV("MAX9877 Amp HP Playback Volume", | 82 | SOC_SINGLE("MAX9877 INB Stereo Switch", |
230 | MAX9877_HPL_VOLUME, MAX9877_HPR_VOLUME, 0, 31, 0, | 83 | MAX9877_INPUT_MODE, 4, 1, 1), |
231 | max9877_get_2reg, max9877_set_2reg, max9877_output_tlv), | 84 | SOC_SINGLE("MAX9877 INA Stereo Switch", |
232 | SOC_SINGLE_EXT("MAX9877 INB Stereo Switch", | 85 | MAX9877_INPUT_MODE, 5, 1, 1), |
233 | MAX9877_INPUT_MODE, 4, 1, 1, | 86 | SOC_SINGLE("MAX9877 Zero-crossing detection Switch", |
234 | max9877_get_reg, max9877_set_reg), | 87 | MAX9877_INPUT_MODE, 6, 1, 0), |
235 | SOC_SINGLE_EXT("MAX9877 INA Stereo Switch", | 88 | SOC_SINGLE("MAX9877 Bypass Mode Switch", |
236 | MAX9877_INPUT_MODE, 5, 1, 1, | 89 | MAX9877_OUTPUT_MODE, 6, 1, 0), |
237 | max9877_get_reg, max9877_set_reg), | 90 | SOC_ENUM("MAX9877 Output Mode", max9877_enum[0]), |
238 | SOC_SINGLE_EXT("MAX9877 Zero-crossing detection Switch", | 91 | SOC_ENUM("MAX9877 Oscillator Mode", max9877_enum[1]), |
239 | MAX9877_INPUT_MODE, 6, 1, 0, | ||
240 | max9877_get_reg, max9877_set_reg), | ||
241 | SOC_SINGLE_EXT("MAX9877 Bypass Mode Switch", | ||
242 | MAX9877_OUTPUT_MODE, 6, 1, 0, | ||
243 | max9877_get_reg, max9877_set_reg), | ||
244 | SOC_SINGLE_EXT("MAX9877 Shutdown Mode Switch", | ||
245 | MAX9877_OUTPUT_MODE, 7, 1, 1, | ||
246 | max9877_get_reg, max9877_set_reg), | ||
247 | SOC_ENUM_EXT("MAX9877 Output Mode", max9877_enum[0], | ||
248 | max9877_get_out_mode, max9877_set_out_mode), | ||
249 | SOC_ENUM_EXT("MAX9877 Oscillator Mode", max9877_enum[1], | ||
250 | max9877_get_osc_mode, max9877_set_osc_mode), | ||
251 | }; | 92 | }; |
252 | 93 | ||
253 | /* This function is called from ASoC machine driver */ | 94 | static const struct snd_soc_dapm_widget max9877_dapm_widgets[] = { |
254 | int max9877_add_controls(struct snd_soc_codec *codec) | 95 | SND_SOC_DAPM_INPUT("INA1"), |
255 | { | 96 | SND_SOC_DAPM_INPUT("INA2"), |
256 | return snd_soc_add_codec_controls(codec, max9877_controls, | 97 | SND_SOC_DAPM_INPUT("INB1"), |
257 | ARRAY_SIZE(max9877_controls)); | 98 | SND_SOC_DAPM_INPUT("INB2"), |
258 | } | 99 | SND_SOC_DAPM_INPUT("RXIN+"), |
259 | EXPORT_SYMBOL_GPL(max9877_add_controls); | 100 | SND_SOC_DAPM_INPUT("RXIN-"), |
101 | |||
102 | SND_SOC_DAPM_PGA("SHDN", MAX9877_OUTPUT_MODE, 7, 1, NULL, 0), | ||
103 | |||
104 | SND_SOC_DAPM_OUTPUT("OUT+"), | ||
105 | SND_SOC_DAPM_OUTPUT("OUT-"), | ||
106 | SND_SOC_DAPM_OUTPUT("HPL"), | ||
107 | SND_SOC_DAPM_OUTPUT("HPR"), | ||
108 | }; | ||
109 | |||
110 | static const struct snd_soc_dapm_route max9877_dapm_routes[] = { | ||
111 | { "SHDN", NULL, "INA1" }, | ||
112 | { "SHDN", NULL, "INA2" }, | ||
113 | { "SHDN", NULL, "INB1" }, | ||
114 | { "SHDN", NULL, "INB2" }, | ||
115 | |||
116 | { "OUT+", NULL, "RXIN+" }, | ||
117 | { "OUT+", NULL, "SHDN" }, | ||
118 | |||
119 | { "OUT-", NULL, "SHDN" }, | ||
120 | { "OUT-", NULL, "RXIN-" }, | ||
121 | |||
122 | { "HPL", NULL, "SHDN" }, | ||
123 | { "HPR", NULL, "SHDN" }, | ||
124 | }; | ||
125 | |||
126 | static const struct snd_soc_codec_driver max9877_codec = { | ||
127 | .controls = max9877_controls, | ||
128 | .num_controls = ARRAY_SIZE(max9877_controls), | ||
129 | |||
130 | .dapm_widgets = max9877_dapm_widgets, | ||
131 | .num_dapm_widgets = ARRAY_SIZE(max9877_dapm_widgets), | ||
132 | .dapm_routes = max9877_dapm_routes, | ||
133 | .num_dapm_routes = ARRAY_SIZE(max9877_dapm_routes), | ||
134 | }; | ||
135 | |||
136 | static const struct regmap_config max9877_regmap = { | ||
137 | .reg_bits = 8, | ||
138 | .val_bits = 8, | ||
139 | |||
140 | .reg_defaults = max9877_regs, | ||
141 | .num_reg_defaults = ARRAY_SIZE(max9877_regs), | ||
142 | .cache_type = REGCACHE_RBTREE, | ||
143 | }; | ||
260 | 144 | ||
261 | static int max9877_i2c_probe(struct i2c_client *client, | 145 | static int max9877_i2c_probe(struct i2c_client *client, |
262 | const struct i2c_device_id *id) | 146 | const struct i2c_device_id *id) |
263 | { | 147 | { |
264 | i2c = client; | 148 | int i; |
265 | 149 | ||
266 | max9877_write_regs(); | 150 | regmap = devm_regmap_init_i2c(client, &max9877_regmap); |
151 | if (IS_ERR(regmap)) | ||
152 | return PTR_ERR(regmap); | ||
267 | 153 | ||
268 | return 0; | 154 | /* Ensure the device is in reset state */ |
155 | for (i = 0; i < ARRAY_SIZE(max9877_regs); i++) | ||
156 | regmap_write(regmap, max9877_regs[i].reg, max9877_regs[i].def); | ||
157 | |||
158 | return snd_soc_register_codec(&client->dev, &max9877_codec, NULL, 0); | ||
269 | } | 159 | } |
270 | 160 | ||
271 | static int max9877_i2c_remove(struct i2c_client *client) | 161 | static int max9877_i2c_remove(struct i2c_client *client) |
272 | { | 162 | { |
273 | i2c = NULL; | 163 | snd_soc_unregister_codec(&client->dev); |
274 | 164 | ||
275 | return 0; | 165 | return 0; |
276 | } | 166 | } |