summaryrefslogtreecommitdiffstats
path: root/sound/soc/atmel/mchp-pdmc.c
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@linux-foundation.org>2023-03-04 19:53:59 +0100
committerLinus Torvalds <torvalds@linux-foundation.org>2023-03-04 19:53:59 +0100
commitd172859ebff33598d80089c0bec44471872d2628 (patch)
tree64bdcd7a48e129cd5f5187c8c4a3f23cf41f9e0c /sound/soc/atmel/mchp-pdmc.c
parentMerge tag 'for-v6.3-part2' of git://git.kernel.org/pub/scm/linux/kernel/git/s... (diff)
parentALSA: ice1712: Delete unreachable code in aureon_add_controls() (diff)
downloadlinux-d172859ebff33598d80089c0bec44471872d2628.tar.xz
linux-d172859ebff33598d80089c0bec44471872d2628.zip
Merge tag 'sound-fix-6.3-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/tiwai/sound
Pull sound fixes from Takashi Iwai: "A collection of various small fixes that have been gathered since the last PR. The majority of changes are for ASoC, and there is a small change in ASoC PCM core, but the rest are all for driver- specific fixes / quirks / updates" * tag 'sound-fix-6.3-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/tiwai/sound: (32 commits) ALSA: ice1712: Delete unreachable code in aureon_add_controls() ALSA: ice1712: Do not left ice->gpio_mutex locked in aureon_add_controls() ALSA: hda/realtek: Add quirk for HP EliteDesk 800 G6 Tower PC ALSA: hda/realtek: Improve support for Dell Precision 3260 ASoC: mediatek: mt8195: add missing initialization ASoC: mediatek: mt8188: add missing initialization ASoC: amd: yc: Add DMI entries to support HP OMEN 16-n0xxx (8A43) ASoC: zl38060 add gpiolib dependency ASoC: sam9g20ek: Disable capture unless building with microphone input ASoC: mt8192: Fix range for sidetone positive gain ASoC: mt8192: Report an error if when an invalid sidetone gain is written ASoC: mt8192: Fix event generation for controls ASoC: mt8192: Remove spammy log messages ASoC: mchp-pdmc: fix poc noise at capture startup ASoC: dt-bindings: sama7g5-pdmc: add microchip,startup-delay-us binding ASoC: soc-pcm: add option to start DMA after DAI ASoC: mt8183: Fix event generation for I2S DAI operations ASoC: mt8183: Remove spammy logging from I2S DAI driver ASoC: mt6358: Remove undefined HPx Mux enumeration values ASoC: mt6358: Validate Wake on Voice 2 writes ...
Diffstat (limited to 'sound/soc/atmel/mchp-pdmc.c')
-rw-r--r--sound/soc/atmel/mchp-pdmc.c53
1 files changed, 48 insertions, 5 deletions
diff --git a/sound/soc/atmel/mchp-pdmc.c b/sound/soc/atmel/mchp-pdmc.c
index cf4084dcbd5e..1aed3baa9369 100644
--- a/sound/soc/atmel/mchp-pdmc.c
+++ b/sound/soc/atmel/mchp-pdmc.c
@@ -114,6 +114,7 @@ struct mchp_pdmc {
struct clk *gclk;
u32 pdmcen;
u32 suspend_irq;
+ u32 startup_delay_us;
int mic_no;
int sinc_order;
bool audio_filter_en;
@@ -425,6 +426,7 @@ static const struct snd_soc_component_driver mchp_pdmc_dai_component = {
.open = &mchp_pdmc_open,
.close = &mchp_pdmc_close,
.legacy_dai_naming = 1,
+ .start_dma_last = 1,
};
static const unsigned int mchp_pdmc_1mic[] = {1};
@@ -632,6 +634,29 @@ static int mchp_pdmc_hw_params(struct snd_pcm_substream *substream,
return 0;
}
+static void mchp_pdmc_noise_filter_workaround(struct mchp_pdmc *dd)
+{
+ u32 tmp, steps = 16;
+
+ /*
+ * PDMC doesn't wait for microphones' startup time thus the acquisition
+ * may start before the microphones are ready leading to poc noises at
+ * the beginning of capture. To avoid this, we need to wait 50ms (in
+ * normal startup procedure) or 150 ms (worst case after resume from sleep
+ * states) after microphones are enabled and then clear the FIFOs (by
+ * reading the RHR 16 times) and possible interrupts before continuing.
+ * Also, for this to work the DMA needs to be started after interrupts
+ * are enabled.
+ */
+ usleep_range(dd->startup_delay_us, dd->startup_delay_us + 5);
+
+ while (steps--)
+ regmap_read(dd->regmap, MCHP_PDMC_RHR, &tmp);
+
+ /* Clear interrupts. */
+ regmap_read(dd->regmap, MCHP_PDMC_ISR, &tmp);
+}
+
static int mchp_pdmc_trigger(struct snd_pcm_substream *substream,
int cmd, struct snd_soc_dai *dai)
{
@@ -644,15 +669,17 @@ static int mchp_pdmc_trigger(struct snd_pcm_substream *substream,
switch (cmd) {
case SNDRV_PCM_TRIGGER_RESUME:
case SNDRV_PCM_TRIGGER_START:
- /* Enable overrun and underrun error interrupts */
- regmap_write(dd->regmap, MCHP_PDMC_IER, dd->suspend_irq |
- MCHP_PDMC_IR_RXOVR | MCHP_PDMC_IR_RXUDR);
- dd->suspend_irq = 0;
- fallthrough;
case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
snd_soc_component_update_bits(cpu, MCHP_PDMC_MR,
MCHP_PDMC_MR_PDMCEN_MASK,
dd->pdmcen);
+
+ mchp_pdmc_noise_filter_workaround(dd);
+
+ /* Enable interrupts. */
+ regmap_write(dd->regmap, MCHP_PDMC_IER, dd->suspend_irq |
+ MCHP_PDMC_IR_RXOVR | MCHP_PDMC_IR_RXUDR);
+ dd->suspend_irq = 0;
break;
case SNDRV_PCM_TRIGGER_SUSPEND:
regmap_read(dd->regmap, MCHP_PDMC_IMR, &dd->suspend_irq);
@@ -796,6 +823,7 @@ static bool mchp_pdmc_readable_reg(struct device *dev, unsigned int reg)
case MCHP_PDMC_CFGR:
case MCHP_PDMC_IMR:
case MCHP_PDMC_ISR:
+ case MCHP_PDMC_RHR:
case MCHP_PDMC_VER:
return true;
default:
@@ -817,6 +845,17 @@ static bool mchp_pdmc_writeable_reg(struct device *dev, unsigned int reg)
}
}
+static bool mchp_pdmc_volatile_reg(struct device *dev, unsigned int reg)
+{
+ switch (reg) {
+ case MCHP_PDMC_ISR:
+ case MCHP_PDMC_RHR:
+ return true;
+ default:
+ return false;
+ }
+}
+
static bool mchp_pdmc_precious_reg(struct device *dev, unsigned int reg)
{
switch (reg) {
@@ -836,6 +875,7 @@ static const struct regmap_config mchp_pdmc_regmap_config = {
.readable_reg = mchp_pdmc_readable_reg,
.writeable_reg = mchp_pdmc_writeable_reg,
.precious_reg = mchp_pdmc_precious_reg,
+ .volatile_reg = mchp_pdmc_volatile_reg,
.cache_type = REGCACHE_FLAT,
};
@@ -918,6 +958,9 @@ static int mchp_pdmc_dt_init(struct mchp_pdmc *dd)
dd->channel_mic_map[i].clk_edge = edge;
}
+ dd->startup_delay_us = 150000;
+ of_property_read_u32(np, "microchip,startup-delay-us", &dd->startup_delay_us);
+
return 0;
}