Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
awilliam
GitHub Repository: awilliam/linux-vfio
Path: blob/master/sound/soc/codecs/max9877.c
10817 views
1
/*
2
* max9877.c -- amp driver for max9877
3
*
4
* Copyright (C) 2009 Samsung Electronics Co.Ltd
5
* Author: Joonyoung Shim <[email protected]>
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 <sound/soc.h>
18
#include <sound/tlv.h>
19
20
#include "max9877.h"
21
22
static struct i2c_client *i2c;
23
24
static u8 max9877_regs[5] = { 0x40, 0x00, 0x00, 0x00, 0x49 };
25
26
static void max9877_write_regs(void)
27
{
28
unsigned int i;
29
u8 data[6];
30
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 = 1;
110
111
if (((max9877_regs[reg] >> shift) & mask) == val)
112
change = 0;
113
114
if (((max9877_regs[reg2] >> shift) & mask) == val2)
115
change = 0;
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
182
static const unsigned int max9877_pgain_tlv[] = {
183
TLV_DB_RANGE_HEAD(2),
184
0, 1, TLV_DB_SCALE_ITEM(0, 900, 0),
185
2, 2, TLV_DB_SCALE_ITEM(2000, 0, 0),
186
};
187
188
static const unsigned int max9877_output_tlv[] = {
189
TLV_DB_RANGE_HEAD(4),
190
0, 7, TLV_DB_SCALE_ITEM(-7900, 400, 1),
191
8, 15, TLV_DB_SCALE_ITEM(-4700, 300, 0),
192
16, 23, TLV_DB_SCALE_ITEM(-2300, 200, 0),
193
24, 31, TLV_DB_SCALE_ITEM(-700, 100, 0),
194
};
195
196
static const char *max9877_out_mode[] = {
197
"INA -> SPK",
198
"INA -> HP",
199
"INA -> SPK and HP",
200
"INB -> SPK",
201
"INB -> HP",
202
"INB -> SPK and HP",
203
"INA + INB -> SPK",
204
"INA + INB -> HP",
205
"INA + INB -> SPK and HP",
206
};
207
208
static const char *max9877_osc_mode[] = {
209
"1176KHz",
210
"1100KHz",
211
"700KHz",
212
};
213
214
static const struct soc_enum max9877_enum[] = {
215
SOC_ENUM_SINGLE_EXT(ARRAY_SIZE(max9877_out_mode), max9877_out_mode),
216
SOC_ENUM_SINGLE_EXT(ARRAY_SIZE(max9877_osc_mode), max9877_osc_mode),
217
};
218
219
static const struct snd_kcontrol_new max9877_controls[] = {
220
SOC_SINGLE_EXT_TLV("MAX9877 PGAINA Playback Volume",
221
MAX9877_INPUT_MODE, 0, 2, 0,
222
max9877_get_reg, max9877_set_reg, max9877_pgain_tlv),
223
SOC_SINGLE_EXT_TLV("MAX9877 PGAINB Playback Volume",
224
MAX9877_INPUT_MODE, 2, 2, 0,
225
max9877_get_reg, max9877_set_reg, max9877_pgain_tlv),
226
SOC_SINGLE_EXT_TLV("MAX9877 Amp Speaker Playback Volume",
227
MAX9877_SPK_VOLUME, 0, 31, 0,
228
max9877_get_reg, max9877_set_reg, max9877_output_tlv),
229
SOC_DOUBLE_R_EXT_TLV("MAX9877 Amp HP Playback Volume",
230
MAX9877_HPL_VOLUME, MAX9877_HPR_VOLUME, 0, 31, 0,
231
max9877_get_2reg, max9877_set_2reg, max9877_output_tlv),
232
SOC_SINGLE_EXT("MAX9877 INB Stereo Switch",
233
MAX9877_INPUT_MODE, 4, 1, 1,
234
max9877_get_reg, max9877_set_reg),
235
SOC_SINGLE_EXT("MAX9877 INA Stereo Switch",
236
MAX9877_INPUT_MODE, 5, 1, 1,
237
max9877_get_reg, max9877_set_reg),
238
SOC_SINGLE_EXT("MAX9877 Zero-crossing detection Switch",
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
};
252
253
/* This function is called from ASoC machine driver */
254
int max9877_add_controls(struct snd_soc_codec *codec)
255
{
256
return snd_soc_add_controls(codec, max9877_controls,
257
ARRAY_SIZE(max9877_controls));
258
}
259
EXPORT_SYMBOL_GPL(max9877_add_controls);
260
261
static int __devinit max9877_i2c_probe(struct i2c_client *client,
262
const struct i2c_device_id *id)
263
{
264
i2c = client;
265
266
max9877_write_regs();
267
268
return 0;
269
}
270
271
static __devexit int max9877_i2c_remove(struct i2c_client *client)
272
{
273
i2c = NULL;
274
275
return 0;
276
}
277
278
static const struct i2c_device_id max9877_i2c_id[] = {
279
{ "max9877", 0 },
280
{ }
281
};
282
MODULE_DEVICE_TABLE(i2c, max9877_i2c_id);
283
284
static struct i2c_driver max9877_i2c_driver = {
285
.driver = {
286
.name = "max9877",
287
.owner = THIS_MODULE,
288
},
289
.probe = max9877_i2c_probe,
290
.remove = __devexit_p(max9877_i2c_remove),
291
.id_table = max9877_i2c_id,
292
};
293
294
static int __init max9877_init(void)
295
{
296
return i2c_add_driver(&max9877_i2c_driver);
297
}
298
module_init(max9877_init);
299
300
static void __exit max9877_exit(void)
301
{
302
i2c_del_driver(&max9877_i2c_driver);
303
}
304
module_exit(max9877_exit);
305
306
MODULE_DESCRIPTION("ASoC MAX9877 amp driver");
307
MODULE_AUTHOR("Joonyoung Shim <[email protected]>");
308
MODULE_LICENSE("GPL");
309
310