@@ -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)
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> --- sound/soc/codecs/nau8540.c | 49 ++++++++++++++++++++++++++++++++++++++ sound/soc/codecs/nau8540.h | 15 ++++++++++++ 2 files changed, 64 insertions(+)