Skip to content

Commit 727c979

Browse files
qi-cirrusstuhenderson
authored andcommitted
ASoC: cs48l32: ADC oscillation workaround
The integrator should be force-disabled during ADC enable. A workaround is required for when: A- An input is being enabled. B- An enabled input is being toggled from digital to analog mode. The workaround is: 1- set ADC1L/R_INT_EN_FRC to 1 2- (if A above) set IN1L/R_ENA = 1 2- (if B above) set IN1_MODE = 0 3- usleep_range for 200us to 300us 4- set ADC1L/R_INT_EN_FRC to 0 Change-Id: Ib749127907fe490f3ce6c61b470afa063916380d Signed-off-by: Qi Zhou <[email protected]>
1 parent 695ef6a commit 727c979

File tree

3 files changed

+152
-5
lines changed

3 files changed

+152
-5
lines changed

sound/soc/codecs/cs48l32.c

Lines changed: 148 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -242,6 +242,150 @@ static const struct soc_enum cs48l32_us_det_dcy[] = {
242242
cs48l32_us_det_dcy_texts),
243243
};
244244

245+
static int cs48l32_dmode_put(struct snd_kcontrol *kcontrol,
246+
struct snd_ctl_elem_value *ucontrol)
247+
{
248+
struct snd_soc_codec *codec = snd_soc_dapm_kcontrol_codec(kcontrol);
249+
struct snd_soc_dapm_context *dapm =
250+
snd_soc_dapm_kcontrol_dapm(kcontrol);
251+
struct soc_enum *e = (struct soc_enum *) kcontrol->private_value;
252+
unsigned int mode;
253+
int ret, result;
254+
255+
mode = ucontrol->value.enumerated.item[0];
256+
switch (mode) {
257+
case 0:
258+
ret = snd_soc_component_update_bits(dapm->component,
259+
TACNA_ADC1L_ANA_CONTROL1,
260+
TACNA_ADC1L_INT_ENA_FRC_MASK,
261+
TACNA_ADC1L_INT_ENA_FRC_MASK);
262+
if (ret < 0) {
263+
dev_err(codec->dev,
264+
"Failed to set ADC1L_INT_ENA_FRC: %d\n", ret);
265+
return ret;
266+
}
267+
268+
ret = snd_soc_component_update_bits(dapm->component,
269+
TACNA_ADC1R_ANA_CONTROL1,
270+
TACNA_ADC1R_INT_ENA_FRC_MASK,
271+
TACNA_ADC1R_INT_ENA_FRC_MASK);
272+
if (ret < 0) {
273+
dev_err(codec->dev,
274+
"Failed to set ADC1R_INT_ENA_FRC: %d\n", ret);
275+
return ret;
276+
}
277+
278+
result = snd_soc_component_update_bits(dapm->component,
279+
e->reg,
280+
TACNA_IN1_MODE_MASK,
281+
0);
282+
if (result < 0) {
283+
dev_err(codec->dev,
284+
"Failed to set input mode: %d\n", result);
285+
return result;
286+
}
287+
288+
usleep_range(200, 300);
289+
290+
ret = snd_soc_component_update_bits(dapm->component,
291+
TACNA_ADC1L_ANA_CONTROL1,
292+
TACNA_ADC1L_INT_ENA_FRC_MASK,
293+
0);
294+
if (ret < 0) {
295+
dev_err(codec->dev,
296+
"Failed to clear ADC1L_INT_ENA_FRC: %d\n", ret);
297+
return ret;
298+
}
299+
300+
ret = snd_soc_component_update_bits(dapm->component,
301+
TACNA_ADC1R_ANA_CONTROL1,
302+
TACNA_ADC1R_INT_ENA_FRC_MASK,
303+
0);
304+
if (ret < 0) {
305+
dev_err(codec->dev,
306+
"Failed to clear ADC1R_INT_ENA_FRC: %d\n", ret);
307+
return ret;
308+
}
309+
310+
if (result)
311+
return snd_soc_dapm_mux_update_power(dapm, kcontrol,
312+
mode, e, NULL);
313+
else
314+
return 0;
315+
break;
316+
case 1:
317+
return snd_soc_dapm_put_enum_double(kcontrol, ucontrol);
318+
default:
319+
return -EINVAL;
320+
}
321+
}
322+
323+
static SOC_ENUM_SINGLE_DECL(cs48l32_in1dmode_enum,
324+
TACNA_INPUT1_CONTROL1,
325+
TACNA_IN1_MODE_SHIFT,
326+
tacna_dmode_texts);
327+
328+
static const struct snd_kcontrol_new cs48l32_dmode_mux[] = {
329+
SOC_DAPM_ENUM_EXT("IN1 Mode", cs48l32_in1dmode_enum,
330+
snd_soc_dapm_get_enum_double, cs48l32_dmode_put),
331+
};
332+
333+
static int cs48l32_in_ev(struct snd_soc_dapm_widget *w,
334+
struct snd_kcontrol *kcontrol,
335+
int event)
336+
{
337+
struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
338+
339+
switch (event) {
340+
case SND_SOC_DAPM_PRE_PMU:
341+
switch (w->shift) {
342+
case TACNA_IN1L_EN_SHIFT:
343+
snd_soc_update_bits(codec,
344+
TACNA_ADC1L_ANA_CONTROL1,
345+
TACNA_ADC1L_INT_ENA_FRC_MASK,
346+
TACNA_ADC1L_INT_ENA_FRC_MASK);
347+
break;
348+
case TACNA_IN1R_EN_SHIFT:
349+
snd_soc_update_bits(codec,
350+
TACNA_ADC1R_ANA_CONTROL1,
351+
TACNA_ADC1R_INT_ENA_FRC_MASK,
352+
TACNA_ADC1R_INT_ENA_FRC_MASK);
353+
break;
354+
default:
355+
dev_err(codec->dev,
356+
"Enabling unknown input channel\n");
357+
break;
358+
}
359+
break;
360+
case SND_SOC_DAPM_POST_PMU:
361+
usleep_range(200, 300);
362+
363+
switch (w->shift) {
364+
case TACNA_IN1L_EN_SHIFT:
365+
snd_soc_update_bits(codec,
366+
TACNA_ADC1L_ANA_CONTROL1,
367+
TACNA_ADC1L_INT_ENA_FRC_MASK,
368+
0);
369+
break;
370+
case TACNA_IN1R_EN_SHIFT:
371+
snd_soc_update_bits(codec,
372+
TACNA_ADC1R_ANA_CONTROL1,
373+
TACNA_ADC1R_INT_ENA_FRC_MASK,
374+
0);
375+
break;
376+
377+
default:
378+
dev_err(codec->dev,
379+
"Disabling unknown input channel\n");
380+
break;
381+
}
382+
default:
383+
break;
384+
}
385+
386+
return tacna_in_ev(w, kcontrol, event);
387+
}
388+
245389
static const struct snd_kcontrol_new cs48l32_snd_controls[] = {
246390
SOC_ENUM("IN1 OSR", tacna_in_dmic_osr[0]),
247391
SOC_ENUM("IN2 OSR", tacna_in_dmic_osr[1]),
@@ -600,8 +744,8 @@ SND_SOC_DAPM_OUTPUT("DSP Trigger Out"),
600744
SND_SOC_DAPM_MUX("IN1L Mux", SND_SOC_NOPM, 0, 0, &tacna_inmux[0]),
601745
SND_SOC_DAPM_MUX("IN1R Mux", SND_SOC_NOPM, 0, 0, &tacna_inmux[1]),
602746

603-
SND_SOC_DAPM_MUX("IN1L Mode", SND_SOC_NOPM, 0, 0, &tacna_dmode_mux[0]),
604-
SND_SOC_DAPM_MUX("IN1R Mode", SND_SOC_NOPM, 0, 0, &tacna_dmode_mux[0]),
747+
SND_SOC_DAPM_MUX("IN1L Mode", SND_SOC_NOPM, 0, 0, &cs48l32_dmode_mux[0]),
748+
SND_SOC_DAPM_MUX("IN1R Mode", SND_SOC_NOPM, 0, 0, &cs48l32_dmode_mux[0]),
605749

606750
SND_SOC_DAPM_MUX("IN1L Swap Chan", SND_SOC_NOPM, 0, 0,
607751
&tacna_in_swap_chan[0]),
@@ -667,11 +811,11 @@ SND_SOC_DAPM_PGA("Noise Generator", TACNA_COMFORT_NOISE_GENERATOR,
667811
TACNA_NOISE_GEN_EN_SHIFT, 0, NULL, 0),
668812

669813
SND_SOC_DAPM_PGA_E("IN1L PGA", TACNA_INPUT_CONTROL, TACNA_IN1L_EN_SHIFT,
670-
0, NULL, 0, tacna_in_ev,
814+
0, NULL, 0, cs48l32_in_ev,
671815
SND_SOC_DAPM_PRE_PMD |
672816
SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU),
673817
SND_SOC_DAPM_PGA_E("IN1R PGA", TACNA_INPUT_CONTROL, TACNA_IN1R_EN_SHIFT,
674-
0, NULL, 0, tacna_in_ev,
818+
0, NULL, 0, cs48l32_in_ev,
675819
SND_SOC_DAPM_PRE_PMD |
676820
SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU),
677821
SND_SOC_DAPM_PGA_E("IN2L PGA", TACNA_INPUT_CONTROL, TACNA_IN2L_EN_SHIFT,

sound/soc/codecs/tacna.c

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -713,10 +713,11 @@ const struct snd_kcontrol_new tacna_in_swap_chan[] = {
713713
};
714714
EXPORT_SYMBOL_GPL(tacna_in_swap_chan);
715715

716-
static const char * const tacna_dmode_texts[] = {
716+
const char * const tacna_dmode_texts[] = {
717717
"Analog",
718718
"Digital",
719719
};
720+
EXPORT_SYMBOL_GPL(tacna_dmode_texts);
720721

721722
static SOC_ENUM_SINGLE_DECL(tacna_in1dmode_enum,
722723
TACNA_INPUT1_CONTROL1,

sound/soc/codecs/tacna.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -126,6 +126,7 @@
126126
#define TACNA_SAMPLE_RATE_ENUM_SIZE 17
127127
#define TACNA_DFC_TYPE_ENUM_SIZE 5
128128
#define TACNA_DFC_WIDTH_ENUM_SIZE 25
129+
#define TACNA_DMODE_TEXTS_SIZE 2
129130
#define TACNA_IN_SWAP_CHAN_ENUM_SIZE 4
130131

131132
#define TACNA_US_FREQ_ENUM_SIZE 4
@@ -427,6 +428,7 @@ extern const struct soc_enum tacna_sample_rate[];
427428
extern const struct soc_enum tacna_sample_rate_async[];
428429

429430
extern const struct snd_kcontrol_new tacna_inmux[];
431+
extern const char * const tacna_dmode_texts[TACNA_DMODE_TEXTS_SIZE];
430432
extern const struct snd_kcontrol_new tacna_dmode_mux[];
431433
extern const struct snd_kcontrol_new tacna_in_swap_chan[];
432434
extern const struct soc_enum tacna_in_swap_chan_ctrl[];

0 commit comments

Comments
 (0)