Commit a60a609b authored by David Lin's avatar David Lin Committed by Mark Brown

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: default avatarDavid Lin <CTLIN0@nuvoton.com>
Link: https://lore.kernel.org/r/20231108061658.1265065-1-CTLIN0@nuvoton.comSigned-off-by: default avatarMark Brown <broonie@kernel.org>
parent 45f2f28b
......@@ -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
......
......@@ -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)
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment