aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--sound/soc/codecs/da7210.c110
1 files changed, 110 insertions, 0 deletions
diff --git a/sound/soc/codecs/da7210.c b/sound/soc/codecs/da7210.c
index 4aad01c10c53..e9ee6a4faa26 100644
--- a/sound/soc/codecs/da7210.c
+++ b/sound/soc/codecs/da7210.c
@@ -26,11 +26,15 @@
26#include <sound/tlv.h> 26#include <sound/tlv.h>
27 27
28/* DA7210 register space */ 28/* DA7210 register space */
29#define DA7210_CONTROL 0x01
29#define DA7210_STATUS 0x02 30#define DA7210_STATUS 0x02
30#define DA7210_STARTUP1 0x03 31#define DA7210_STARTUP1 0x03
31#define DA7210_MIC_L 0x07 32#define DA7210_MIC_L 0x07
32#define DA7210_MIC_R 0x08 33#define DA7210_MIC_R 0x08
34#define DA7210_AUX1_L 0x09
35#define DA7210_AUX1_R 0x0A
33#define DA7210_AUX2 0x0B 36#define DA7210_AUX2 0x0B
37#define DA7210_IN_GAIN 0x0C
34#define DA7210_INMIX_L 0x0D 38#define DA7210_INMIX_L 0x0D
35#define DA7210_INMIX_R 0x0E 39#define DA7210_INMIX_R 0x0E
36#define DA7210_ADC_HPF 0x0F 40#define DA7210_ADC_HPF 0x0F
@@ -59,6 +63,12 @@
59#define DA7210_PLL_DIV2 0x2A 63#define DA7210_PLL_DIV2 0x2A
60#define DA7210_PLL_DIV3 0x2B 64#define DA7210_PLL_DIV3 0x2B
61#define DA7210_PLL 0x2C 65#define DA7210_PLL 0x2C
66#define DA7210_ALC_MAX 0x83
67#define DA7210_ALC_MIN 0x84
68#define DA7210_ALC_NOIS 0x85
69#define DA7210_ALC_ATT 0x86
70#define DA7210_ALC_REL 0x87
71#define DA7210_ALC_DEL 0x88
62#define DA7210_A_HID_UNLOCK 0x8A 72#define DA7210_A_HID_UNLOCK 0x8A
63#define DA7210_A_TEST_UNLOCK 0x8B 73#define DA7210_A_TEST_UNLOCK 0x8B
64#define DA7210_A_PLL1 0x90 74#define DA7210_A_PLL1 0x90
@@ -81,6 +91,7 @@
81#define DA7210_IN_R_EN (1 << 7) 91#define DA7210_IN_R_EN (1 << 7)
82 92
83/* ADC bit fields */ 93/* ADC bit fields */
94#define DA7210_ADC_ALC_EN (1 << 0)
84#define DA7210_ADC_L_EN (1 << 3) 95#define DA7210_ADC_L_EN (1 << 3)
85#define DA7210_ADC_R_EN (1 << 7) 96#define DA7210_ADC_R_EN (1 << 7)
86 97
@@ -150,6 +161,29 @@
150/* SOFTMUTE bit fields */ 161/* SOFTMUTE bit fields */
151#define DA7210_RAMP_EN (1 << 6) 162#define DA7210_RAMP_EN (1 << 6)
152 163
164/* CONTROL bit fields */
165#define DA7210_NOISE_SUP_EN (1 << 3)
166
167/* IN_GAIN bit fields */
168#define DA7210_INPGA_L_VOL (0x0F << 0)
169#define DA7210_INPGA_R_VOL (0xF0 << 0)
170
171/* ZERO_CROSS bit fields */
172#define DA7210_AUX1_L_ZC (1 << 0)
173#define DA7210_AUX1_R_ZC (1 << 1)
174#define DA7210_HP_L_ZC (1 << 6)
175#define DA7210_HP_R_ZC (1 << 7)
176
177/* AUX1_L bit fields */
178#define DA7210_AUX1_L_VOL (0x3F << 0)
179
180/* AUX1_R bit fields */
181#define DA7210_AUX1_R_VOL (0x3F << 0)
182
183/* Minimum INPGA and AUX1 volume to enable noise suppression */
184#define DA7210_INPGA_MIN_VOL_NS 0x0A /* 10.5dB */
185#define DA7210_AUX1_MIN_VOL_NS 0x35 /* 6dB */
186
153#define DA7210_VERSION "0.0.1" 187#define DA7210_VERSION "0.0.1"
154 188
155/* 189/*
@@ -202,6 +236,69 @@ static const char *da7210_hp_mode_txt[] = {
202static const struct soc_enum da7210_hp_mode_sel = 236static const struct soc_enum da7210_hp_mode_sel =
203 SOC_ENUM_SINGLE(DA7210_HP_CFG, 0, 2, da7210_hp_mode_txt); 237 SOC_ENUM_SINGLE(DA7210_HP_CFG, 0, 2, da7210_hp_mode_txt);
204 238
239/* ALC can be enabled only if noise suppression is disabled */
240static int da7210_put_alc_sw(struct snd_kcontrol *kcontrol,
241 struct snd_ctl_elem_value *ucontrol)
242{
243 struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
244
245 if (ucontrol->value.integer.value[0]) {
246 /* Check if noise suppression is enabled */
247 if (snd_soc_read(codec, DA7210_CONTROL) & DA7210_NOISE_SUP_EN) {
248 dev_dbg(codec->dev,
249 "Disable noise suppression to enable ALC\n");
250 return -EINVAL;
251 }
252 }
253 /* If all conditions are met or we are actually disabling ALC */
254 return snd_soc_put_volsw(kcontrol, ucontrol);
255}
256
257/* Noise suppression can be enabled only if following conditions are met
258 * ALC disabled
259 * ZC enabled for HP and AUX1 PGA
260 * INPGA_L_VOL and INPGA_R_VOL >= 10.5 dB
261 * AUX1_L_VOL and AUX1_R_VOL >= 6 dB
262 */
263static int da7210_put_noise_sup_sw(struct snd_kcontrol *kcontrol,
264 struct snd_ctl_elem_value *ucontrol)
265{
266 struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
267 u8 val;
268
269 if (ucontrol->value.integer.value[0]) {
270 /* Check if ALC is enabled */
271 if (snd_soc_read(codec, DA7210_ADC) & DA7210_ADC_ALC_EN)
272 goto err;
273
274 /* Check ZC for HP and AUX1 PGA */
275 if ((snd_soc_read(codec, DA7210_ZERO_CROSS) &
276 (DA7210_AUX1_L_ZC | DA7210_AUX1_R_ZC | DA7210_HP_L_ZC |
277 DA7210_HP_R_ZC)) != (DA7210_AUX1_L_ZC |
278 DA7210_AUX1_R_ZC | DA7210_HP_L_ZC | DA7210_HP_R_ZC))
279 goto err;
280
281 /* Check INPGA_L_VOL and INPGA_R_VOL */
282 val = snd_soc_read(codec, DA7210_IN_GAIN);
283 if (((val & DA7210_INPGA_L_VOL) < DA7210_INPGA_MIN_VOL_NS) ||
284 (((val & DA7210_INPGA_R_VOL) >> 4) <
285 DA7210_INPGA_MIN_VOL_NS))
286 goto err;
287
288 /* Check AUX1_L_VOL and AUX1_R_VOL */
289 if (((snd_soc_read(codec, DA7210_AUX1_L) & DA7210_AUX1_L_VOL) <
290 DA7210_AUX1_MIN_VOL_NS) ||
291 ((snd_soc_read(codec, DA7210_AUX1_R) & DA7210_AUX1_R_VOL) <
292 DA7210_AUX1_MIN_VOL_NS))
293 goto err;
294 }
295 /* If all conditions are met or we are actually disabling Noise sup */
296 return snd_soc_put_volsw(kcontrol, ucontrol);
297
298err:
299 return -EINVAL;
300}
301
205static const struct snd_kcontrol_new da7210_snd_controls[] = { 302static const struct snd_kcontrol_new da7210_snd_controls[] = {
206 303
207 SOC_DOUBLE_R_TLV("HeadPhone Playback Volume", 304 SOC_DOUBLE_R_TLV("HeadPhone Playback Volume",
@@ -260,6 +357,19 @@ static const struct snd_kcontrol_new da7210_snd_controls[] = {
260 SOC_DOUBLE("Headphone ZC Switch", DA7210_ZERO_CROSS, 6, 7, 1, 0), 357 SOC_DOUBLE("Headphone ZC Switch", DA7210_ZERO_CROSS, 6, 7, 1, 0),
261 358
262 SOC_ENUM("Headphone Class", da7210_hp_mode_sel), 359 SOC_ENUM("Headphone Class", da7210_hp_mode_sel),
360
361 /* ALC controls */
362 SOC_SINGLE_EXT("ALC Enable Switch", DA7210_ADC, 0, 1, 0,
363 snd_soc_get_volsw, da7210_put_alc_sw),
364 SOC_SINGLE("ALC Capture Max Volume", DA7210_ALC_MAX, 0, 0x3F, 0),
365 SOC_SINGLE("ALC Capture Min Volume", DA7210_ALC_MIN, 0, 0x3F, 0),
366 SOC_SINGLE("ALC Capture Noise Volume", DA7210_ALC_NOIS, 0, 0x3F, 0),
367 SOC_SINGLE("ALC Capture Attack Rate", DA7210_ALC_ATT, 0, 0xFF, 0),
368 SOC_SINGLE("ALC Capture Release Rate", DA7210_ALC_REL, 0, 0xFF, 0),
369 SOC_SINGLE("ALC Capture Release Delay", DA7210_ALC_DEL, 0, 0xFF, 0),
370
371 SOC_SINGLE_EXT("Noise Suppression Enable Switch", DA7210_CONTROL, 3, 1,
372 0, snd_soc_get_volsw, da7210_put_noise_sup_sw),
263}; 373};
264 374
265/* Codec private data */ 375/* Codec private data */