xref: /linux/sound/soc/codecs/max9877.c (revision 997288e3824e4c6a7ab4ca4f580fe35e138d62e8)
1 /*
2  * max9877.c  --  amp driver for max9877
3  *
4  * Copyright (C) 2009 Samsung Electronics Co.Ltd
5  * Author: Joonyoung Shim <jy0922.shim@samsung.com>
6  *
7  *  This program is free software; you can redistribute  it and/or modify it
8  *  under  the terms of  the GNU General  Public License as published by the
9  *  Free Software Foundation;  either version 2 of the  License, or (at your
10  *  option) any later version.
11  *
12  */
13 
14 #include <linux/module.h>
15 #include <linux/init.h>
16 #include <linux/i2c.h>
17 #include <linux/regmap.h>
18 #include <sound/soc.h>
19 #include <sound/tlv.h>
20 
21 #include "max9877.h"
22 
23 static struct regmap *regmap;
24 
25 static struct reg_default max9877_regs[] = {
26 	{ 0, 0x40 },
27 	{ 1, 0x00 },
28 	{ 2, 0x00 },
29 	{ 3, 0x00 },
30 	{ 4, 0x49 },
31 };
32 
33 static int max9877_get_reg(struct snd_kcontrol *kcontrol,
34 		struct snd_ctl_elem_value *ucontrol)
35 {
36 	struct soc_mixer_control *mc =
37 		(struct soc_mixer_control *)kcontrol->private_value;
38 	unsigned int reg = mc->reg;
39 	unsigned int shift = mc->shift;
40 	unsigned int mask = mc->max;
41 	unsigned int invert = mc->invert;
42 	unsigned int val;
43 	int ret;
44 
45 	ret = regmap_read(regmap, reg, &val);
46 	if (ret != 0)
47 		return ret;
48 
49 	ucontrol->value.integer.value[0] = (val >> 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 	bool change;
69 	int ret;
70 
71 	if (invert)
72 		val = mask - val;
73 
74 	ret = regmap_update_bits_check(regmap, reg, mask << shift,
75 				       val << shift, &change);
76 	if (ret != 0)
77 		return ret;
78 
79 	if (change)
80 		return 1;
81 	else
82 		return 0;
83 }
84 
85 static int max9877_get_2reg(struct snd_kcontrol *kcontrol,
86 		struct snd_ctl_elem_value *ucontrol)
87 {
88 	struct soc_mixer_control *mc =
89 		(struct soc_mixer_control *)kcontrol->private_value;
90 	unsigned int reg = mc->reg;
91 	unsigned int reg2 = mc->rreg;
92 	unsigned int shift = mc->shift;
93 	unsigned int mask = mc->max;
94 	unsigned int val;
95 	int ret;
96 
97 	ret = regmap_read(regmap, reg, &val);
98 	if (ret != 0)
99 		return ret;
100 	ucontrol->value.integer.value[0] = (val >> shift) & mask;
101 
102 	ret = regmap_read(regmap, reg2, &val);
103 	if (ret != 0)
104 		return ret;
105 	ucontrol->value.integer.value[1] = (val >> shift) & mask;
106 
107 	return 0;
108 }
109 
110 static int max9877_set_2reg(struct snd_kcontrol *kcontrol,
111 		struct snd_ctl_elem_value *ucontrol)
112 {
113 	struct soc_mixer_control *mc =
114 		(struct soc_mixer_control *)kcontrol->private_value;
115 	unsigned int reg = mc->reg;
116 	unsigned int reg2 = mc->rreg;
117 	unsigned int shift = mc->shift;
118 	unsigned int mask = mc->max;
119 	unsigned int val = (ucontrol->value.integer.value[0] & mask);
120 	unsigned int val2 = (ucontrol->value.integer.value[1] & mask);
121 	bool change1, change2;
122 	int ret;
123 
124 	ret = regmap_update_bits_check(regmap, reg, mask << shift,
125 				       val << shift, &change1);
126 	if (ret != 0)
127 		return ret;
128 
129 	ret = regmap_update_bits_check(regmap, reg2, mask << shift,
130 				       val2 << shift, &change2);
131 	if (ret != 0)
132 		return ret;
133 
134 	if (change1 || change2)
135 		return 1;
136 	else
137 		return 0;
138 }
139 
140 static int max9877_get_out_mode(struct snd_kcontrol *kcontrol,
141 		struct snd_ctl_elem_value *ucontrol)
142 {
143 	unsigned int val;
144 	int ret;
145 
146 	ret = regmap_read(regmap, MAX9877_OUTPUT_MODE, &val);
147 	if (ret != 0)
148 		return ret;
149 
150 	val &= MAX9877_OUTMODE_MASK;
151 	if (val)
152 		val--;
153 
154 	ucontrol->value.integer.value[0] = val;
155 
156 	return 0;
157 }
158 
159 static int max9877_set_out_mode(struct snd_kcontrol *kcontrol,
160 		struct snd_ctl_elem_value *ucontrol)
161 {
162 	unsigned int val;
163 	bool change;
164 	int ret;
165 
166 	val = ucontrol->value.integer.value[0] + 1;
167 
168 	ret = regmap_update_bits_check(regmap, MAX9877_OUTPUT_MODE,
169 				       MAX9877_OUTMODE_MASK, val, &change);
170 	if (ret != 0)
171 		return ret;
172 
173 	if (change)
174 		return 1;
175 	else
176 		return 0;
177 }
178 
179 static int max9877_get_osc_mode(struct snd_kcontrol *kcontrol,
180 		struct snd_ctl_elem_value *ucontrol)
181 {
182 	unsigned int val;
183 	int ret;
184 
185 	ret = regmap_read(regmap, MAX9877_OUTPUT_MODE, &val);
186 	if (ret != 0)
187 		return ret;
188 
189 	val &= MAX9877_OSC_MASK;
190 	val >>= MAX9877_OSC_OFFSET;
191 
192 	ucontrol->value.integer.value[0] = val;
193 
194 	return 0;
195 }
196 
197 static int max9877_set_osc_mode(struct snd_kcontrol *kcontrol,
198 		struct snd_ctl_elem_value *ucontrol)
199 {
200 	unsigned int val;
201 	bool change;
202 	int ret;
203 
204 	val = ucontrol->value.integer.value[0] << MAX9877_OSC_OFFSET;
205 	ret = regmap_update_bits_check(regmap, MAX9877_OUTPUT_MODE,
206 				       MAX9877_OSC_MASK, val, &change);
207 	if (ret != 0)
208 		return ret;
209 
210 	if (change)
211 		return 1;
212 	else
213 		return 0;
214 }
215 
216 static const unsigned int max9877_pgain_tlv[] = {
217 	TLV_DB_RANGE_HEAD(2),
218 	0, 1, TLV_DB_SCALE_ITEM(0, 900, 0),
219 	2, 2, TLV_DB_SCALE_ITEM(2000, 0, 0),
220 };
221 
222 static const unsigned int max9877_output_tlv[] = {
223 	TLV_DB_RANGE_HEAD(4),
224 	0, 7, TLV_DB_SCALE_ITEM(-7900, 400, 1),
225 	8, 15, TLV_DB_SCALE_ITEM(-4700, 300, 0),
226 	16, 23, TLV_DB_SCALE_ITEM(-2300, 200, 0),
227 	24, 31, TLV_DB_SCALE_ITEM(-700, 100, 0),
228 };
229 
230 static const char *max9877_out_mode[] = {
231 	"INA -> SPK",
232 	"INA -> HP",
233 	"INA -> SPK and HP",
234 	"INB -> SPK",
235 	"INB -> HP",
236 	"INB -> SPK and HP",
237 	"INA + INB -> SPK",
238 	"INA + INB -> HP",
239 	"INA + INB -> SPK and HP",
240 };
241 
242 static const char *max9877_osc_mode[] = {
243 	"1176KHz",
244 	"1100KHz",
245 	"700KHz",
246 };
247 
248 static const struct soc_enum max9877_enum[] = {
249 	SOC_ENUM_SINGLE_EXT(ARRAY_SIZE(max9877_out_mode), max9877_out_mode),
250 	SOC_ENUM_SINGLE_EXT(ARRAY_SIZE(max9877_osc_mode), max9877_osc_mode),
251 };
252 
253 static const struct snd_kcontrol_new max9877_controls[] = {
254 	SOC_SINGLE_EXT_TLV("MAX9877 PGAINA Playback Volume",
255 			MAX9877_INPUT_MODE, 0, 2, 0,
256 			max9877_get_reg, max9877_set_reg, max9877_pgain_tlv),
257 	SOC_SINGLE_EXT_TLV("MAX9877 PGAINB Playback Volume",
258 			MAX9877_INPUT_MODE, 2, 2, 0,
259 			max9877_get_reg, max9877_set_reg, max9877_pgain_tlv),
260 	SOC_SINGLE_EXT_TLV("MAX9877 Amp Speaker Playback Volume",
261 			MAX9877_SPK_VOLUME, 0, 31, 0,
262 			max9877_get_reg, max9877_set_reg, max9877_output_tlv),
263 	SOC_DOUBLE_R_EXT_TLV("MAX9877 Amp HP Playback Volume",
264 			MAX9877_HPL_VOLUME, MAX9877_HPR_VOLUME, 0, 31, 0,
265 			max9877_get_2reg, max9877_set_2reg, max9877_output_tlv),
266 	SOC_SINGLE_EXT("MAX9877 INB Stereo Switch",
267 			MAX9877_INPUT_MODE, 4, 1, 1,
268 			max9877_get_reg, max9877_set_reg),
269 	SOC_SINGLE_EXT("MAX9877 INA Stereo Switch",
270 			MAX9877_INPUT_MODE, 5, 1, 1,
271 			max9877_get_reg, max9877_set_reg),
272 	SOC_SINGLE_EXT("MAX9877 Zero-crossing detection Switch",
273 			MAX9877_INPUT_MODE, 6, 1, 0,
274 			max9877_get_reg, max9877_set_reg),
275 	SOC_SINGLE_EXT("MAX9877 Bypass Mode Switch",
276 			MAX9877_OUTPUT_MODE, 6, 1, 0,
277 			max9877_get_reg, max9877_set_reg),
278 	SOC_SINGLE_EXT("MAX9877 Shutdown Mode Switch",
279 			MAX9877_OUTPUT_MODE, 7, 1, 1,
280 			max9877_get_reg, max9877_set_reg),
281 	SOC_ENUM_EXT("MAX9877 Output Mode", max9877_enum[0],
282 			max9877_get_out_mode, max9877_set_out_mode),
283 	SOC_ENUM_EXT("MAX9877 Oscillator Mode", max9877_enum[1],
284 			max9877_get_osc_mode, max9877_set_osc_mode),
285 };
286 
287 /* This function is called from ASoC machine driver */
288 int max9877_add_controls(struct snd_soc_codec *codec)
289 {
290 	return snd_soc_add_codec_controls(codec, max9877_controls,
291 			ARRAY_SIZE(max9877_controls));
292 }
293 EXPORT_SYMBOL_GPL(max9877_add_controls);
294 
295 static const struct regmap_config max9877_regmap = {
296 	.reg_bits = 8,
297 	.val_bits = 8,
298 
299 	.reg_defaults = max9877_regs,
300 	.num_reg_defaults = ARRAY_SIZE(max9877_regs),
301 	.cache_type = REGCACHE_RBTREE,
302 };
303 
304 static int max9877_i2c_probe(struct i2c_client *client,
305 			     const struct i2c_device_id *id)
306 {
307 	int i;
308 
309 	regmap = devm_regmap_init_i2c(client, &max9877_regmap);
310 	if (IS_ERR(regmap))
311 		return PTR_ERR(regmap);
312 
313 	/* Ensure the device is in reset state */
314 	for (i = 0; i < ARRAY_SIZE(max9877_regs); i++)
315 		regmap_write(regmap, max9877_regs[i].reg, max9877_regs[i].def);
316 
317 	return 0;
318 }
319 
320 static int max9877_i2c_remove(struct i2c_client *client)
321 {
322 	regmap = NULL;
323 
324 	return 0;
325 }
326 
327 static const struct i2c_device_id max9877_i2c_id[] = {
328 	{ "max9877", 0 },
329 	{ }
330 };
331 MODULE_DEVICE_TABLE(i2c, max9877_i2c_id);
332 
333 static struct i2c_driver max9877_i2c_driver = {
334 	.driver = {
335 		.name = "max9877",
336 		.owner = THIS_MODULE,
337 	},
338 	.probe = max9877_i2c_probe,
339 	.remove = max9877_i2c_remove,
340 	.id_table = max9877_i2c_id,
341 };
342 
343 module_i2c_driver(max9877_i2c_driver);
344 
345 MODULE_DESCRIPTION("ASoC MAX9877 amp driver");
346 MODULE_AUTHOR("Joonyoung Shim <jy0922.shim@samsung.com>");
347 MODULE_LICENSE("GPL");
348