ASoC: nau8540: Add self recovery to improve capture quility

Reading the peak data to detect abnormal data in the ADC channel.
If abnormal data occurs, the driver takes recovery actions to
refresh the ADC channel.

Signed-off-by: David Lin <CTLIN0@nuvoton.com>
Link: https://lore.kernel.org/r/20231108061658.1265065-1-CTLIN0@nuvoton.com
Signed-off-by: Mark Brown <broonie@kernel.org>
This commit is contained in:
David Lin 2023-11-08 14:16:59 +08:00 committed by Mark Brown
parent 45f2f28bd4
commit a60a609b7f
No known key found for this signature in database
GPG Key ID: 24D68B725D5487D0
2 changed files with 64 additions and 0 deletions

View File

@ -530,12 +530,61 @@ static int nau8540_set_tdm_slot(struct snd_soc_dai *dai,
return 0;
}
static int nau8540_dai_trigger(struct snd_pcm_substream *substream,
int cmd, struct snd_soc_dai *dai)
{
struct snd_soc_component *component = dai->component;
struct nau8540 *nau8540 = snd_soc_component_get_drvdata(component);
struct regmap *regmap = nau8540->regmap;
unsigned int val;
int ret = 0;
/* Reading the peak data to detect abnormal data in the ADC channel.
* If abnormal data happens, the driver takes recovery actions to
* refresh the ADC channel.
*/
switch (cmd) {
case SNDRV_PCM_TRIGGER_START:
regmap_update_bits(regmap, NAU8540_REG_CLOCK_CTRL,
NAU8540_CLK_AGC_EN, NAU8540_CLK_AGC_EN);
regmap_update_bits(regmap, NAU8540_REG_ALC_CONTROL_3,
NAU8540_ALC_CH_ALL_EN, NAU8540_ALC_CH_ALL_EN);
regmap_read(regmap, NAU8540_REG_PEAK_CH1, &val);
dev_dbg(nau8540->dev, "1.ADC CH1 peak data %x", val);
if (!val) {
regmap_update_bits(regmap, NAU8540_REG_MUTE,
NAU8540_PGA_CH_ALL_MUTE, NAU8540_PGA_CH_ALL_MUTE);
regmap_update_bits(regmap, NAU8540_REG_MUTE,
NAU8540_PGA_CH_ALL_MUTE, 0);
regmap_write(regmap, NAU8540_REG_RST, 0x1);
regmap_write(regmap, NAU8540_REG_RST, 0);
regmap_read(regmap, NAU8540_REG_PEAK_CH1, &val);
dev_dbg(nau8540->dev, "2.ADC CH1 peak data %x", val);
if (!val) {
dev_err(nau8540->dev, "Channel recovery failed!!");
ret = -EIO;
}
}
regmap_update_bits(regmap, NAU8540_REG_CLOCK_CTRL,
NAU8540_CLK_AGC_EN, 0);
regmap_update_bits(regmap, NAU8540_REG_ALC_CONTROL_3,
NAU8540_ALC_CH_ALL_EN, 0);
break;
default:
break;
}
return ret;
}
static const struct snd_soc_dai_ops nau8540_dai_ops = {
.startup = nau8540_dai_startup,
.hw_params = nau8540_hw_params,
.set_fmt = nau8540_set_fmt,
.set_tdm_slot = nau8540_set_tdm_slot,
.trigger = nau8540_dai_trigger,
};
#define NAU8540_RATES SNDRV_PCM_RATE_8000_48000

View File

@ -85,6 +85,7 @@
/* CLOCK_CTRL (0x02) */
#define NAU8540_CLK_ADC_EN (0x1 << 15)
#define NAU8540_CLK_AGC_EN (0x1 << 3)
#define NAU8540_CLK_I2S_EN (0x1 << 1)
/* CLOCK_SRC (0x03) */
@ -168,6 +169,13 @@
#define NAU8540_TDM_OFFSET_EN (0x1 << 14)
#define NAU8540_TDM_TX_MASK 0xf
/* ALC_CONTROL_3 (0x22) */
#define NAU8540_ALC_CH1_EN (0x1 << 12)
#define NAU8540_ALC_CH2_EN (0x1 << 13)
#define NAU8540_ALC_CH3_EN (0x1 << 14)
#define NAU8540_ALC_CH4_EN (0x1 << 15)
#define NAU8540_ALC_CH_ALL_EN (0xf << 12)
/* ADC_SAMPLE_RATE (0x3A) */
#define NAU8540_CH_SYNC (0x1 << 14)
#define NAU8540_ADC_OSR_MASK 0x3
@ -181,6 +189,13 @@
#define NAU8540_VMID_SEL_SFT 4
#define NAU8540_VMID_SEL_MASK (0x3 << NAU8540_VMID_SEL_SFT)
/* MUTE (0x61) */
#define NAU8540_PGA_CH1_MUTE 0x1
#define NAU8540_PGA_CH2_MUTE 0x2
#define NAU8540_PGA_CH3_MUTE 0x4
#define NAU8540_PGA_CH4_MUTE 0x8
#define NAU8540_PGA_CH_ALL_MUTE 0xf
/* MIC_BIAS (0x67) */
#define NAU8540_PU_PRE (0x1 << 8)