diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2022-12-13 22:27:26 +0300 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2022-12-13 22:27:26 +0300 |
commit | 102f9d3d455870844c47b82322c2dfc0a35eb745 (patch) | |
tree | 31e2c500794f0827d1319fa28c71a0616c598971 /sound/soc/fsl | |
parent | 8715c6d3100fc7c6edddf29af4a399a1c12d028c (diff) | |
parent | 8ec2d95f50c06f5cf2a2b94bcdf47f494f91ad55 (diff) | |
download | linux-102f9d3d455870844c47b82322c2dfc0a35eb745.tar.xz |
Merge tag 'sound-6.2-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/tiwai/sound
Pull sound updates from Takashi Iwai:
"This looks like a relatively calm development cycle; there have been
only few changes in ALSA and ASoC core sides while we get lots of
device-specific fixes and updates as usual. Most of commits are about
ASoC, including Intel SOF/AVS and many device tree updates.
Below are some highlights:
Core:
- Improvement in memalloc helper for fallback allocations
- More cleanups of ASoC DAPM code
ASoC:
- Factoring out of mapping hw_params onto SoundWire configuration
- The ever ongoing overhauls of the Intel DSP code continue,
including support for loading libraries and probes with IPC4 on
SOF.
- Support for more sample formats on JZ4740
- Lots of device tree conversions and fixups
- Support for Allwinner D1, a range of AMD and Intel systems,
Mediatek systems with multiple DMICs, Nuvoton NAU8318, NXP
fsl_rpmsg and i.MX93, Qualcomm AudioReach Enable, MFC and SAL,
RealTek RT1318 and Rockchip RK3588
ALSA:
- Addition of PCM kselftest; still minimalistic but can be extended
in future
- Fixes for corner-case XRUNs with USB-audio implicit feedback mode
- Usual device-specific quirk updates for USB- and HD-audio
- FireWire DICE updates
This also contains a few cross-tree updates:
- Some OMAP board file updates for removal of relevant OMAP platforms
- A new I2C API update for I2C probe API adaption
- A DRM update for the further hdmi-codec updates"
* tag 'sound-6.2-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/tiwai/sound: (417 commits)
ALSA: mts64: fix possible null-ptr-defer in snd_mts64_interrupt
ALSA: patch_realtek: Fix Dell Inspiron Plus 16
ALSA: hda/cirrus: Add extra 10 ms delay to allow PLL settle and lock.
ASoC: dt-bindings: Correct Alexandre Belloni email
ASoC: dt-bindings: maxim,max98504: Convert to DT schema
ASoC: dt-bindings: maxim,max98357a: Convert to DT schema
ASoC: dt-bindings: Reference common DAI properties
ASoC: dt-bindings: Extend name-prefix.yaml into common DAI properties
ASoC: rt715: Make read-only arrays capture_reg_H and capture_reg_L static const
ASoC: uniphier: aio-core: Make some read-only arrays static const
ASoC: wcd938x: Make read-only array minCode_param static const
ASoC: qcom: lpass-sc7280: Add maybe_unused tag for system PM ops
ASoC : SOF: amd: Add support for IPC and DSP dumps
ASoC: SOF: amd: Use poll function instead to read ACP_SHA_DSP_FW_QUALIFIER
ALSA: usb-audio: Workaround for XRUN at prepare
ALSA: pcm: Handle XRUN at trigger START
ALSA: pcm: Set missing stop_operating flag at undoing trigger start
drm: tda99x: Don't advertise non-existent capture support
ASoC: hdmi-codec: Allow playback and capture to be disabled
kselftest/alsa: Add more coverage of sample rates and channel counts
...
Diffstat (limited to 'sound/soc/fsl')
-rw-r--r-- | sound/soc/fsl/fsl_micfil.c | 447 | ||||
-rw-r--r-- | sound/soc/fsl/fsl_micfil.h | 6 | ||||
-rw-r--r-- | sound/soc/fsl/fsl_rpmsg.c | 6 | ||||
-rw-r--r-- | sound/soc/fsl/fsl_sai.c | 23 | ||||
-rw-r--r-- | sound/soc/fsl/fsl_sai.h | 1 | ||||
-rw-r--r-- | sound/soc/fsl/fsl_xcvr.c | 40 | ||||
-rw-r--r-- | sound/soc/fsl/fsl_xcvr.h | 21 | ||||
-rw-r--r-- | sound/soc/fsl/imx-audio-rpmsg.c | 3 | ||||
-rw-r--r-- | sound/soc/fsl/imx-pcm-rpmsg.c | 10 | ||||
-rw-r--r-- | sound/soc/fsl/imx-rpmsg.c | 6 |
10 files changed, 550 insertions, 13 deletions
diff --git a/sound/soc/fsl/fsl_micfil.c b/sound/soc/fsl/fsl_micfil.c index 4b86ef82fd93..7b17f152bbf3 100644 --- a/sound/soc/fsl/fsl_micfil.c +++ b/sound/soc/fsl/fsl_micfil.c @@ -47,11 +47,15 @@ struct fsl_micfil { struct clk *pll11k_clk; struct snd_dmaengine_dai_dma_data dma_params_rx; struct sdma_peripheral_config sdmacfg; + struct snd_soc_card *card; unsigned int dataline; char name[32]; int irq[MICFIL_IRQ_LINES]; enum quality quality; int dc_remover; + int vad_init_mode; + int vad_enabled; + int vad_detected; }; struct fsl_micfil_soc_data { @@ -59,6 +63,7 @@ struct fsl_micfil_soc_data { unsigned int fifo_depth; unsigned int dataline; bool imx; + bool use_edma; u64 formats; }; @@ -78,9 +83,19 @@ static struct fsl_micfil_soc_data fsl_micfil_imx8mp = { .formats = SNDRV_PCM_FMTBIT_S32_LE, }; +static struct fsl_micfil_soc_data fsl_micfil_imx93 = { + .imx = true, + .fifos = 8, + .fifo_depth = 32, + .dataline = 0xf, + .formats = SNDRV_PCM_FMTBIT_S32_LE, + .use_edma = true, +}; + static const struct of_device_id fsl_micfil_dt_ids[] = { { .compatible = "fsl,imx8mm-micfil", .data = &fsl_micfil_imx8mm }, { .compatible = "fsl,imx8mp-micfil", .data = &fsl_micfil_imx8mp }, + { .compatible = "fsl,imx93-micfil", .data = &fsl_micfil_imx93 }, {} }; MODULE_DEVICE_TABLE(of, fsl_micfil_dt_ids); @@ -152,6 +167,152 @@ static int micfil_quality_set(struct snd_kcontrol *kcontrol, return micfil_set_quality(micfil); } +static const char * const micfil_hwvad_enable[] = { + "Disable (Record only)", + "Enable (Record with Vad)", +}; + +static const char * const micfil_hwvad_init_mode[] = { + "Envelope mode", "Energy mode", +}; + +static const char * const micfil_hwvad_hpf_texts[] = { + "Filter bypass", + "Cut-off @1750Hz", + "Cut-off @215Hz", + "Cut-off @102Hz", +}; + +/* + * DC Remover Control + * Filter Bypassed 1 1 + * Cut-off @21Hz 0 0 + * Cut-off @83Hz 0 1 + * Cut-off @152HZ 1 0 + */ +static const char * const micfil_dc_remover_texts[] = { + "Cut-off @21Hz", "Cut-off @83Hz", + "Cut-off @152Hz", "Bypass", +}; + +static const struct soc_enum hwvad_enable_enum = + SOC_ENUM_SINGLE_EXT(ARRAY_SIZE(micfil_hwvad_enable), + micfil_hwvad_enable); +static const struct soc_enum hwvad_init_mode_enum = + SOC_ENUM_SINGLE_EXT(ARRAY_SIZE(micfil_hwvad_init_mode), + micfil_hwvad_init_mode); +static const struct soc_enum hwvad_hpf_enum = + SOC_ENUM_SINGLE(REG_MICFIL_VAD0_CTRL2, 0, + ARRAY_SIZE(micfil_hwvad_hpf_texts), + micfil_hwvad_hpf_texts); +static const struct soc_enum fsl_micfil_dc_remover_enum = + SOC_ENUM_SINGLE_EXT(ARRAY_SIZE(micfil_dc_remover_texts), + micfil_dc_remover_texts); + +static int micfil_put_dc_remover_state(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct soc_enum *e = (struct soc_enum *)kcontrol->private_value; + struct snd_soc_component *comp = snd_kcontrol_chip(kcontrol); + struct fsl_micfil *micfil = snd_soc_component_get_drvdata(comp); + unsigned int *item = ucontrol->value.enumerated.item; + int val = snd_soc_enum_item_to_val(e, item[0]); + int i = 0, ret = 0; + u32 reg_val = 0; + + if (val < 0 || val > 3) + return -EINVAL; + + micfil->dc_remover = val; + + /* Calculate total value for all channels */ + for (i = 0; i < MICFIL_OUTPUT_CHANNELS; i++) + reg_val |= val << MICFIL_DC_CHX_SHIFT(i); + + /* Update DC Remover mode for all channels */ + ret = snd_soc_component_update_bits(comp, REG_MICFIL_DC_CTRL, + MICFIL_DC_CTRL_CONFIG, reg_val); + if (ret < 0) + return ret; + + return 0; +} + +static int micfil_get_dc_remover_state(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_component *comp = snd_kcontrol_chip(kcontrol); + struct fsl_micfil *micfil = snd_soc_component_get_drvdata(comp); + + ucontrol->value.enumerated.item[0] = micfil->dc_remover; + + return 0; +} + +static int hwvad_put_enable(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_component *comp = snd_kcontrol_chip(kcontrol); + struct soc_enum *e = (struct soc_enum *)kcontrol->private_value; + unsigned int *item = ucontrol->value.enumerated.item; + struct fsl_micfil *micfil = snd_soc_component_get_drvdata(comp); + int val = snd_soc_enum_item_to_val(e, item[0]); + + micfil->vad_enabled = val; + + return 0; +} + +static int hwvad_get_enable(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_component *comp = snd_kcontrol_chip(kcontrol); + struct fsl_micfil *micfil = snd_soc_component_get_drvdata(comp); + + ucontrol->value.enumerated.item[0] = micfil->vad_enabled; + + return 0; +} + +static int hwvad_put_init_mode(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_component *comp = snd_kcontrol_chip(kcontrol); + struct soc_enum *e = (struct soc_enum *)kcontrol->private_value; + unsigned int *item = ucontrol->value.enumerated.item; + struct fsl_micfil *micfil = snd_soc_component_get_drvdata(comp); + int val = snd_soc_enum_item_to_val(e, item[0]); + + /* 0 - Envelope-based Mode + * 1 - Energy-based Mode + */ + micfil->vad_init_mode = val; + + return 0; +} + +static int hwvad_get_init_mode(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_component *comp = snd_kcontrol_chip(kcontrol); + struct fsl_micfil *micfil = snd_soc_component_get_drvdata(comp); + + ucontrol->value.enumerated.item[0] = micfil->vad_init_mode; + + return 0; +} + +static int hwvad_detected(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_component *comp = snd_kcontrol_chip(kcontrol); + struct fsl_micfil *micfil = snd_soc_component_get_drvdata(comp); + + ucontrol->value.enumerated.item[0] = micfil->vad_detected; + + return 0; +} + static const struct snd_kcontrol_new fsl_micfil_snd_controls[] = { SOC_SINGLE_SX_TLV("CH0 Volume", REG_MICFIL_OUT_CTRL, MICFIL_OUTGAIN_CHX_SHIFT(0), 0xF, 0x7, gain_tlv), @@ -172,6 +333,27 @@ static const struct snd_kcontrol_new fsl_micfil_snd_controls[] = { SOC_ENUM_EXT("MICFIL Quality Select", fsl_micfil_quality_enum, micfil_quality_get, micfil_quality_set), + SOC_ENUM_EXT("HWVAD Enablement Switch", hwvad_enable_enum, + hwvad_get_enable, hwvad_put_enable), + SOC_ENUM_EXT("HWVAD Initialization Mode", hwvad_init_mode_enum, + hwvad_get_init_mode, hwvad_put_init_mode), + SOC_ENUM("HWVAD High-Pass Filter", hwvad_hpf_enum), + SOC_SINGLE("HWVAD ZCD Switch", REG_MICFIL_VAD0_ZCD, 0, 1, 0), + SOC_SINGLE("HWVAD ZCD Auto Threshold Switch", + REG_MICFIL_VAD0_ZCD, 2, 1, 0), + SOC_ENUM_EXT("MICFIL DC Remover Control", fsl_micfil_dc_remover_enum, + micfil_get_dc_remover_state, micfil_put_dc_remover_state), + SOC_SINGLE("HWVAD Input Gain", REG_MICFIL_VAD0_CTRL2, 8, 15, 0), + SOC_SINGLE("HWVAD Sound Gain", REG_MICFIL_VAD0_SCONFIG, 0, 15, 0), + SOC_SINGLE("HWVAD Noise Gain", REG_MICFIL_VAD0_NCONFIG, 0, 15, 0), + SOC_SINGLE_RANGE("HWVAD Detector Frame Time", REG_MICFIL_VAD0_CTRL2, 16, 0, 63, 0), + SOC_SINGLE("HWVAD Detector Initialization Time", REG_MICFIL_VAD0_CTRL1, 8, 31, 0), + SOC_SINGLE("HWVAD Noise Filter Adjustment", REG_MICFIL_VAD0_NCONFIG, 8, 31, 0), + SOC_SINGLE("HWVAD ZCD Threshold", REG_MICFIL_VAD0_ZCD, 16, 1023, 0), + SOC_SINGLE("HWVAD ZCD Adjustment", REG_MICFIL_VAD0_ZCD, 8, 15, 0), + SOC_SINGLE("HWVAD ZCD And Behavior Switch", + REG_MICFIL_VAD0_ZCD, 4, 1, 0), + SOC_SINGLE_BOOL_EXT("VAD Detected", 0, hwvad_detected, NULL), }; /* The SRES is a self-negated bit which provides the CPU with the @@ -229,6 +411,167 @@ static int fsl_micfil_startup(struct snd_pcm_substream *substream, return 0; } +/* Enable/disable hwvad interrupts */ +static int fsl_micfil_configure_hwvad_interrupts(struct fsl_micfil *micfil, int enable) +{ + u32 vadie_reg = enable ? MICFIL_VAD0_CTRL1_IE : 0; + u32 vaderie_reg = enable ? MICFIL_VAD0_CTRL1_ERIE : 0; + + /* Voice Activity Detector Error Interruption */ + regmap_update_bits(micfil->regmap, REG_MICFIL_VAD0_CTRL1, + MICFIL_VAD0_CTRL1_ERIE, vaderie_reg); + + /* Voice Activity Detector Interruption */ + regmap_update_bits(micfil->regmap, REG_MICFIL_VAD0_CTRL1, + MICFIL_VAD0_CTRL1_IE, vadie_reg); + + return 0; +} + +/* Configuration done only in energy-based initialization mode */ +static int fsl_micfil_init_hwvad_energy_mode(struct fsl_micfil *micfil) +{ + /* Keep the VADFRENDIS bitfield cleared. */ + regmap_clear_bits(micfil->regmap, REG_MICFIL_VAD0_CTRL2, + MICFIL_VAD0_CTRL2_FRENDIS); + + /* Keep the VADPREFEN bitfield cleared. */ + regmap_clear_bits(micfil->regmap, REG_MICFIL_VAD0_CTRL2, + MICFIL_VAD0_CTRL2_PREFEN); + + /* Keep the VADSFILEN bitfield cleared. */ + regmap_clear_bits(micfil->regmap, REG_MICFIL_VAD0_SCONFIG, + MICFIL_VAD0_SCONFIG_SFILEN); + + /* Keep the VADSMAXEN bitfield cleared. */ + regmap_clear_bits(micfil->regmap, REG_MICFIL_VAD0_SCONFIG, + MICFIL_VAD0_SCONFIG_SMAXEN); + + /* Keep the VADNFILAUTO bitfield asserted. */ + regmap_set_bits(micfil->regmap, REG_MICFIL_VAD0_NCONFIG, + MICFIL_VAD0_NCONFIG_NFILAUT); + + /* Keep the VADNMINEN bitfield cleared. */ + regmap_clear_bits(micfil->regmap, REG_MICFIL_VAD0_NCONFIG, + MICFIL_VAD0_NCONFIG_NMINEN); + + /* Keep the VADNDECEN bitfield cleared. */ + regmap_clear_bits(micfil->regmap, REG_MICFIL_VAD0_NCONFIG, + MICFIL_VAD0_NCONFIG_NDECEN); + + /* Keep the VADNOREN bitfield cleared. */ + regmap_clear_bits(micfil->regmap, REG_MICFIL_VAD0_NCONFIG, + MICFIL_VAD0_NCONFIG_NOREN); + + return 0; +} + +/* Configuration done only in envelope-based initialization mode */ +static int fsl_micfil_init_hwvad_envelope_mode(struct fsl_micfil *micfil) +{ + /* Assert the VADFRENDIS bitfield */ + regmap_set_bits(micfil->regmap, REG_MICFIL_VAD0_CTRL2, + MICFIL_VAD0_CTRL2_FRENDIS); + + /* Assert the VADPREFEN bitfield. */ + regmap_set_bits(micfil->regmap, REG_MICFIL_VAD0_CTRL2, + MICFIL_VAD0_CTRL2_PREFEN); + + /* Assert the VADSFILEN bitfield. */ + regmap_set_bits(micfil->regmap, REG_MICFIL_VAD0_SCONFIG, + MICFIL_VAD0_SCONFIG_SFILEN); + + /* Assert the VADSMAXEN bitfield. */ + regmap_set_bits(micfil->regmap, REG_MICFIL_VAD0_SCONFIG, + MICFIL_VAD0_SCONFIG_SMAXEN); + + /* Clear the VADNFILAUTO bitfield */ + regmap_clear_bits(micfil->regmap, REG_MICFIL_VAD0_NCONFIG, + MICFIL_VAD0_NCONFIG_NFILAUT); + + /* Assert the VADNMINEN bitfield. */ + regmap_set_bits(micfil->regmap, REG_MICFIL_VAD0_NCONFIG, + MICFIL_VAD0_NCONFIG_NMINEN); + + /* Assert the VADNDECEN bitfield. */ + regmap_set_bits(micfil->regmap, REG_MICFIL_VAD0_NCONFIG, + MICFIL_VAD0_NCONFIG_NDECEN); + + /* Assert VADNOREN bitfield. */ + regmap_set_bits(micfil->regmap, REG_MICFIL_VAD0_NCONFIG, + MICFIL_VAD0_NCONFIG_NOREN); + + return 0; +} + +/* + * Hardware Voice Active Detection: The HWVAD takes data from the input + * of a selected PDM microphone to detect if there is any + * voice activity. When a voice activity is detected, an interrupt could + * be delivered to the system. Initialization in section 8.4: + * Can work in two modes: + * -> Eneveope-based mode (section 8.4.1) + * -> Energy-based mode (section 8.4.2) + * + * It is important to remark that the HWVAD detector could be enabled + * or reset only when the MICFIL isn't running i.e. when the BSY_FIL + * bit in STAT register is cleared + */ +static int fsl_micfil_hwvad_enable(struct fsl_micfil *micfil) +{ + int ret; + + micfil->vad_detected = 0; + + /* envelope-based specific initialization */ + if (micfil->vad_init_mode == MICFIL_HWVAD_ENVELOPE_MODE) + ret = fsl_micfil_init_hwvad_envelope_mode(micfil); + else + ret = fsl_micfil_init_hwvad_energy_mode(micfil); + if (ret) + return ret; + + /* Voice Activity Detector Internal Filters Initialization*/ + regmap_set_bits(micfil->regmap, REG_MICFIL_VAD0_CTRL1, + MICFIL_VAD0_CTRL1_ST10); + + /* Voice Activity Detector Internal Filter */ + regmap_clear_bits(micfil->regmap, REG_MICFIL_VAD0_CTRL1, + MICFIL_VAD0_CTRL1_ST10); + + /* Enable Interrupts */ + ret = fsl_micfil_configure_hwvad_interrupts(micfil, 1); + if (ret) + return ret; + + /* Voice Activity Detector Reset */ + regmap_set_bits(micfil->regmap, REG_MICFIL_VAD0_CTRL1, + MICFIL_VAD0_CTRL1_RST); + + /* Voice Activity Detector Enabled */ + regmap_set_bits(micfil->regmap, REG_MICFIL_VAD0_CTRL1, + MICFIL_VAD0_CTRL1_EN); + + return 0; +} + +static int fsl_micfil_hwvad_disable(struct fsl_micfil *micfil) +{ + struct device *dev = &micfil->pdev->dev; + int ret = 0; + + /* Disable HWVAD */ + regmap_clear_bits(micfil->regmap, REG_MICFIL_VAD0_CTRL1, + MICFIL_VAD0_CTRL1_EN); + + /* Disable hwvad interrupts */ + ret = fsl_micfil_configure_hwvad_interrupts(micfil, 0); + if (ret) + dev_err(dev, "Failed to disable interrupts\n"); + + return ret; +} + static int fsl_micfil_trigger(struct snd_pcm_substream *substream, int cmd, struct snd_soc_dai *dai) { @@ -264,10 +607,16 @@ static int fsl_micfil_trigger(struct snd_pcm_substream *substream, int cmd, if (ret) return ret; + if (micfil->vad_enabled) + fsl_micfil_hwvad_enable(micfil); + break; case SNDRV_PCM_TRIGGER_STOP: case SNDRV_PCM_TRIGGER_SUSPEND: case SNDRV_PCM_TRIGGER_PAUSE_PUSH: + if (micfil->vad_enabled) + fsl_micfil_hwvad_disable(micfil); + /* Disable the module */ ret = regmap_clear_bits(micfil->regmap, REG_MICFIL_CTRL1, MICFIL_CTRL1_PDMIEN); @@ -347,11 +696,23 @@ static int fsl_micfil_hw_params(struct snd_pcm_substream *substream, FIELD_PREP(MICFIL_CTRL2_CLKDIV, clk_div) | FIELD_PREP(MICFIL_CTRL2_CICOSR, 16 - osr)); + /* Configure CIC OSR in VADCICOSR */ + regmap_update_bits(micfil->regmap, REG_MICFIL_VAD0_CTRL1, + MICFIL_VAD0_CTRL1_CICOSR, + FIELD_PREP(MICFIL_VAD0_CTRL1_CICOSR, 16 - osr)); + + /* Configure source channel in VADCHSEL */ + regmap_update_bits(micfil->regmap, REG_MICFIL_VAD0_CTRL1, + MICFIL_VAD0_CTRL1_CHSEL, + FIELD_PREP(MICFIL_VAD0_CTRL1_CHSEL, (channels - 1))); + micfil->dma_params_rx.peripheral_config = &micfil->sdmacfg; micfil->dma_params_rx.peripheral_size = sizeof(micfil->sdmacfg); micfil->sdmacfg.n_fifos_src = channels; micfil->sdmacfg.sw_done = true; micfil->dma_params_rx.maxburst = channels * MICFIL_DMA_MAXBURST_RX; + if (micfil->soc->use_edma) + micfil->dma_params_rx.maxburst = channels; return 0; } @@ -370,6 +731,7 @@ static int fsl_micfil_dai_probe(struct snd_soc_dai *cpu_dai) int ret, i; micfil->quality = QUALITY_VLOW0; + micfil->card = cpu_dai->component->card; /* set default gain to 2 */ regmap_write(micfil->regmap, REG_MICFIL_OUT_CTRL, 0x22222222); @@ -604,6 +966,71 @@ static irqreturn_t micfil_err_isr(int irq, void *devid) return IRQ_HANDLED; } +static irqreturn_t voice_detected_fn(int irq, void *devid) +{ + struct fsl_micfil *micfil = (struct fsl_micfil *)devid; + struct snd_kcontrol *kctl; + + if (!micfil->card) + return IRQ_HANDLED; + + kctl = snd_soc_card_get_kcontrol(micfil->card, "VAD Detected"); + if (!kctl) + return IRQ_HANDLED; + + if (micfil->vad_detected) + snd_ctl_notify(micfil->card->snd_card, + SNDRV_CTL_EVENT_MASK_VALUE, + &kctl->id); + + return IRQ_HANDLED; +} + +static irqreturn_t hwvad_isr(int irq, void *devid) +{ + struct fsl_micfil *micfil = (struct fsl_micfil *)devid; + struct device *dev = &micfil->pdev->dev; + u32 vad0_reg; + int ret; + + regmap_read(micfil->regmap, REG_MICFIL_VAD0_STAT, &vad0_reg); + + /* + * The only difference between MICFIL_VAD0_STAT_EF and + * MICFIL_VAD0_STAT_IF is that the former requires Write + * 1 to Clear. Since both flags are set, it is enough + * to only read one of them + */ + if (vad0_reg & MICFIL_VAD0_STAT_IF) { + /* Write 1 to clear */ + regmap_write_bits(micfil->regmap, REG_MICFIL_VAD0_STAT, + MICFIL_VAD0_STAT_IF, + MICFIL_VAD0_STAT_IF); + + micfil->vad_detected = 1; + } + + ret = fsl_micfil_hwvad_disable(micfil); + if (ret) + dev_err(dev, "Failed to disable hwvad\n"); + + return IRQ_WAKE_THREAD; +} + +static irqreturn_t hwvad_err_isr(int irq, void *devid) +{ + struct fsl_micfil *micfil = (struct fsl_micfil *)devid; + struct device *dev = &micfil->pdev->dev; + u32 vad0_reg; + + regmap_read(micfil->regmap, REG_MICFIL_VAD0_STAT, &vad0_reg); + + if (vad0_reg & MICFIL_VAD0_STAT_INSATF) + dev_dbg(dev, "voice activity input overflow/underflow detected\n"); + + return IRQ_HANDLED; +} + static int fsl_micfil_probe(struct platform_device *pdev) { struct device_node *np = pdev->dev.of_node; @@ -696,6 +1123,26 @@ static int fsl_micfil_probe(struct platform_device *pdev) return ret; } + /* Digital Microphone interface voice activity detector event */ + ret = devm_request_threaded_irq(&pdev->dev, micfil->irq[2], + hwvad_isr, voice_detected_fn, + IRQF_SHARED, micfil->name, micfil); + if (ret) { + dev_err(&pdev->dev, "failed to claim hwvad event irq %u\n", + micfil->irq[0]); + return ret; + } + + /* Digital Microphone interface voice activity detector error */ + ret = devm_request_irq(&pdev->dev, micfil->irq[3], + hwvad_err_isr, IRQF_SHARED, + micfil->name, micfil); + if (ret) { + dev_err(&pdev->dev, "failed to claim hwvad error irq %u\n", + micfil->irq[1]); + return ret; + } + micfil->dma_params_rx.chan_name = "rx"; micfil->dma_params_rx.addr = res->start + REG_MICFIL_DATACH0; micfil->dma_params_rx.maxburst = MICFIL_DMA_MAXBURST_RX; diff --git a/sound/soc/fsl/fsl_micfil.h b/sound/soc/fsl/fsl_micfil.h index d60285dd07bc..9237a1c4cb8f 100644 --- a/sound/soc/fsl/fsl_micfil.h +++ b/sound/soc/fsl/fsl_micfil.h @@ -136,10 +136,14 @@ #define FIFO_PTRWID 3 #define FIFO_LEN BIT(FIFO_PTRWID) -#define MICFIL_IRQ_LINES 2 +#define MICFIL_IRQ_LINES 4 #define MICFIL_MAX_RETRY 25 #define MICFIL_SLEEP_MIN 90000 /* in us */ #define MICFIL_SLEEP_MAX 100000 /* in us */ #define MICFIL_DMA_MAXBURST_RX 6 +/* HWVAD Constants */ +#define MICFIL_HWVAD_ENVELOPE_MODE 0 +#define MICFIL_HWVAD_ENERGY_MODE 1 + #endif /* _FSL_MICFIL_H */ diff --git a/sound/soc/fsl/fsl_rpmsg.c b/sound/soc/fsl/fsl_rpmsg.c index bf94838bdbef..46c7868a2653 100644 --- a/sound/soc/fsl/fsl_rpmsg.c +++ b/sound/soc/fsl/fsl_rpmsg.c @@ -117,14 +117,14 @@ static struct snd_soc_dai_driver fsl_rpmsg_dai = { .playback = { .stream_name = "CPU-Playback", .channels_min = 2, - .channels_max = 2, + .channels_max = 32, .rates = SNDRV_PCM_RATE_KNOT, .formats = FSL_RPMSG_FORMATS, }, .capture = { .stream_name = "CPU-Capture", .channels_min = 2, - .channels_max = 2, + .channels_max = 32, .rates = SNDRV_PCM_RATE_KNOT, .formats = FSL_RPMSG_FORMATS, }, @@ -235,7 +235,7 @@ static int fsl_rpmsg_probe(struct platform_device *pdev) rpmsg->card_pdev = platform_device_register_data(&pdev->dev, "imx-audio-rpmsg", - PLATFORM_DEVID_NONE, + PLATFORM_DEVID_AUTO, NULL, 0); if (IS_ERR(rpmsg->card_pdev)) { diff --git a/sound/soc/fsl/fsl_sai.c b/sound/soc/fsl/fsl_sai.c index e60c7b344562..1c9be8a5dcb1 100644 --- a/sound/soc/fsl/fsl_sai.c +++ b/sound/soc/fsl/fsl_sai.c @@ -872,10 +872,10 @@ static int fsl_sai_dai_probe(struct snd_soc_dai *cpu_dai) regmap_update_bits(sai->regmap, FSL_SAI_TCR1(ofs), FSL_SAI_CR1_RFW_MASK(sai->soc_data->fifo_depth), - sai->soc_data->fifo_depth - FSL_SAI_MAXBURST_TX); + sai->soc_data->fifo_depth - sai->dma_params_tx.maxburst); regmap_update_bits(sai->regmap, FSL_SAI_RCR1(ofs), FSL_SAI_CR1_RFW_MASK(sai->soc_data->fifo_depth), - FSL_SAI_MAXBURST_RX - 1); + sai->dma_params_rx.maxburst - 1); snd_soc_dai_init_dma_data(cpu_dai, &sai->dma_params_tx, &sai->dma_params_rx); @@ -1416,8 +1416,10 @@ static int fsl_sai_probe(struct platform_device *pdev) sai->dma_params_rx.addr = sai->res->start + FSL_SAI_RDR0; sai->dma_params_tx.addr = sai->res->start + FSL_SAI_TDR0; - sai->dma_params_rx.maxburst = FSL_SAI_MAXBURST_RX; - sai->dma_params_tx.maxburst = FSL_SAI_MAXBURST_TX; + sai->dma_params_rx.maxburst = + sai->soc_data->max_burst[RX] ? sai->soc_data->max_burst[RX] : FSL_SAI_MAXBURST_RX; + sai->dma_params_tx.maxburst = + sai->soc_data->max_burst[TX] ? sai->soc_data->max_burst[TX] : FSL_SAI_MAXBURST_TX; sai->pinctrl = devm_pinctrl_get(&pdev->dev); @@ -1579,6 +1581,18 @@ static const struct fsl_sai_soc_data fsl_sai_imx8ulp_data = { .max_register = FSL_SAI_RTCAP, }; +static const struct fsl_sai_soc_data fsl_sai_imx93_data = { + .use_imx_pcm = true, + .use_edma = true, + .fifo_depth = 128, + .reg_offset = 8, + .mclk0_is_mclk1 = false, + .pins = 4, + .flags = 0, + .max_register = FSL_SAI_MCTL, + .max_burst = {8, 8}, +}; + static const struct of_device_id fsl_sai_ids[] = { { .compatible = "fsl,vf610-sai", .data = &fsl_sai_vf610_data }, { .compatible = "fsl,imx6sx-sai", .data = &fsl_sai_imx6sx_data }, @@ -1590,6 +1604,7 @@ static const struct of_device_id fsl_sai_ids[] = { { .compatible = "fsl,imx8mp-sai", .data = &fsl_sai_imx8mp_data }, { .compatible = "fsl,imx8ulp-sai", .data = &fsl_sai_imx8ulp_data }, { .compatible = "fsl,imx8mn-sai", .data = &fsl_sai_imx8mp_data }, + { .compatible = "fsl,imx93-sai", .data = &fsl_sai_imx93_data }, { /* sentinel */ } }; MODULE_DEVICE_TABLE(of, fsl_sai_ids); diff --git a/sound/soc/fsl/fsl_sai.h b/sound/soc/fsl/fsl_sai.h index 697f6690068c..197748a888d5 100644 --- a/sound/soc/fsl/fsl_sai.h +++ b/sound/soc/fsl/fsl_sai.h @@ -235,6 +235,7 @@ struct fsl_sai_soc_data { unsigned int reg_offset; unsigned int flags; unsigned int max_register; + unsigned int max_burst[2]; }; /** diff --git a/sound/soc/fsl/fsl_xcvr.c b/sound/soc/fsl/fsl_xcvr.c index c043efe4548d..2a6802fb2a8b 100644 --- a/sound/soc/fsl/fsl_xcvr.c +++ b/sound/soc/fsl/fsl_xcvr.c @@ -934,6 +934,14 @@ static const struct reg_default fsl_xcvr_reg_defaults[] = { { FSL_XCVR_RX_DPTH_CTRL_SET, 0x00002C89 }, { FSL_XCVR_RX_DPTH_CTRL_CLR, 0x00002C89 }, { FSL_XCVR_RX_DPTH_CTRL_TOG, 0x00002C89 }, + { FSL_XCVR_RX_DPTH_CNTR_CTRL, 0x00000000 }, + { FSL_XCVR_RX_DPTH_CNTR_CTRL_SET, 0x00000000 }, + { FSL_XCVR_RX_DPTH_CNTR_CTRL_CLR, 0x00000000 }, + { FSL_XCVR_RX_DPTH_CNTR_CTRL_TOG, 0x00000000 }, + { FSL_XCVR_RX_DPTH_TSCR, 0x00000000 }, + { FSL_XCVR_RX_DPTH_BCR, 0x00000000 }, + { FSL_XCVR_RX_DPTH_BCTR, 0x00000000 }, + { FSL_XCVR_RX_DPTH_BCRR, 0x00000000 }, { FSL_XCVR_TX_DPTH_CTRL, 0x00000000 }, { FSL_XCVR_TX_DPTH_CTRL_SET, 0x00000000 }, { FSL_XCVR_TX_DPTH_CTRL_CLR, 0x00000000 }, @@ -944,6 +952,14 @@ static const struct reg_default fsl_xcvr_reg_defaults[] = { { FSL_XCVR_TX_CS_DATA_3, 0x00000000 }, { FSL_XCVR_TX_CS_DATA_4, 0x00000000 }, { FSL_XCVR_TX_CS_DATA_5, 0x00000000 }, + { FSL_XCVR_TX_DPTH_CNTR_CTRL, 0x00000000 }, + { FSL_XCVR_TX_DPTH_CNTR_CTRL_SET, 0x00000000 }, + { FSL_XCVR_TX_DPTH_CNTR_CTRL_CLR, 0x00000000 }, + { FSL_XCVR_TX_DPTH_CNTR_CTRL_TOG, 0x00000000 }, + { FSL_XCVR_TX_DPTH_TSCR, 0x00000000 }, + { FSL_XCVR_TX_DPTH_BCR, 0x00000000 }, + { FSL_XCVR_TX_DPTH_BCTR, 0x00000000 }, + { FSL_XCVR_TX_DPTH_BCRR, 0x00000000 }, { FSL_XCVR_DEBUG_REG_0, 0x00000000 }, { FSL_XCVR_DEBUG_REG_1, 0x00000000 }, }; @@ -975,6 +991,14 @@ static bool fsl_xcvr_readable_reg(struct device *dev, unsigned int reg) case FSL_XCVR_RX_DPTH_CTRL_SET: case FSL_XCVR_RX_DPTH_CTRL_CLR: case FSL_XCVR_RX_DPTH_CTRL_TOG: + case FSL_XCVR_RX_DPTH_CNTR_CTRL: + case FSL_XCVR_RX_DPTH_CNTR_CTRL_SET: + case FSL_XCVR_RX_DPTH_CNTR_CTRL_CLR: + case FSL_XCVR_RX_DPTH_CNTR_CTRL_TOG: + case FSL_XCVR_RX_DPTH_TSCR: + case FSL_XCVR_RX_DPTH_BCR: + case FSL_XCVR_RX_DPTH_BCTR: + case FSL_XCVR_RX_DPTH_BCRR: case FSL_XCVR_TX_DPTH_CTRL: case FSL_XCVR_TX_DPTH_CTRL_SET: case FSL_XCVR_TX_DPTH_CTRL_CLR: @@ -985,6 +1009,14 @@ static bool fsl_xcvr_readable_reg(struct device *dev, unsigned int reg) case FSL_XCVR_TX_CS_DATA_3: case FSL_XCVR_TX_CS_DATA_4: case FSL_XCVR_TX_CS_DATA_5: + case FSL_XCVR_TX_DPTH_CNTR_CTRL: + case FSL_XCVR_TX_DPTH_CNTR_CTRL_SET: + case FSL_XCVR_TX_DPTH_CNTR_CTRL_CLR: + case FSL_XCVR_TX_DPTH_CNTR_CTRL_TOG: + case FSL_XCVR_TX_DPTH_TSCR: + case FSL_XCVR_TX_DPTH_BCR: + case FSL_XCVR_TX_DPTH_BCTR: + case FSL_XCVR_TX_DPTH_BCRR: case FSL_XCVR_DEBUG_REG_0: case FSL_XCVR_DEBUG_REG_1: return true; @@ -1017,6 +1049,10 @@ static bool fsl_xcvr_writeable_reg(struct device *dev, unsigned int reg) case FSL_XCVR_RX_DPTH_CTRL_SET: case FSL_XCVR_RX_DPTH_CTRL_CLR: case FSL_XCVR_RX_DPTH_CTRL_TOG: + case FSL_XCVR_RX_DPTH_CNTR_CTRL: + case FSL_XCVR_RX_DPTH_CNTR_CTRL_SET: + case FSL_XCVR_RX_DPTH_CNTR_CTRL_CLR: + case FSL_XCVR_RX_DPTH_CNTR_CTRL_TOG: case FSL_XCVR_TX_DPTH_CTRL_SET: case FSL_XCVR_TX_DPTH_CTRL_CLR: case FSL_XCVR_TX_DPTH_CTRL_TOG: @@ -1026,6 +1062,10 @@ static bool fsl_xcvr_writeable_reg(struct device *dev, unsigned int reg) case FSL_XCVR_TX_CS_DATA_3: case FSL_XCVR_TX_CS_DATA_4: case FSL_XCVR_TX_CS_DATA_5: + case FSL_XCVR_TX_DPTH_CNTR_CTRL: + case FSL_XCVR_TX_DPTH_CNTR_CTRL_SET: + case FSL_XCVR_TX_DPTH_CNTR_CTRL_CLR: + case FSL_XCVR_TX_DPTH_CNTR_CTRL_TOG: return true; default: return false; diff --git a/sound/soc/fsl/fsl_xcvr.h b/sound/soc/fsl/fsl_xcvr.h index 7f2853c60085..4769b0fca21d 100644 --- a/sound/soc/fsl/fsl_xcvr.h +++ b/sound/soc/fsl/fsl_xcvr.h @@ -49,6 +49,16 @@ #define FSL_XCVR_RX_DPTH_CTRL_CLR 0x188 #define FSL_XCVR_RX_DPTH_CTRL_TOG 0x18c +#define FSL_XCVR_RX_DPTH_CNTR_CTRL 0x1C0 +#define FSL_XCVR_RX_DPTH_CNTR_CTRL_SET 0x1C4 +#define FSL_XCVR_RX_DPTH_CNTR_CTRL_CLR 0x1C8 +#define FSL_XCVR_RX_DPTH_CNTR_CTRL_TOG 0x1CC + +#define FSL_XCVR_RX_DPTH_TSCR 0x1D0 +#define FSL_XCVR_RX_DPTH_BCR 0x1D4 +#define FSL_XCVR_RX_DPTH_BCTR 0x1D8 +#define FSL_XCVR_RX_DPTH_BCRR 0x1DC + #define FSL_XCVR_TX_DPTH_CTRL 0x220 /* TX datapath ctrl reg */ #define FSL_XCVR_TX_DPTH_CTRL_SET 0x224 #define FSL_XCVR_TX_DPTH_CTRL_CLR 0x228 @@ -59,6 +69,17 @@ #define FSL_XCVR_TX_CS_DATA_3 0x23C #define FSL_XCVR_TX_CS_DATA_4 0x240 #define FSL_XCVR_TX_CS_DATA_5 0x244 + +#define FSL_XCVR_TX_DPTH_CNTR_CTRL 0x260 +#define FSL_XCVR_TX_DPTH_CNTR_CTRL_SET 0x264 +#define FSL_XCVR_TX_DPTH_CNTR_CTRL_CLR 0x268 +#define FSL_XCVR_TX_DPTH_CNTR_CTRL_TOG 0x26C + +#define FSL_XCVR_TX_DPTH_TSCR 0x270 +#define FSL_XCVR_TX_DPTH_BCR 0x274 +#define FSL_XCVR_TX_DPTH_BCTR 0x278 +#define FSL_XCVR_TX_DPTH_BCRR 0x27C + #define FSL_XCVR_DEBUG_REG_0 0x2E0 #define FSL_XCVR_DEBUG_REG_1 0x2F0 diff --git a/sound/soc/fsl/imx-audio-rpmsg.c b/sound/soc/fsl/imx-audio-rpmsg.c index 905c3a071300..d5234ac4b09b 100644 --- a/sound/soc/fsl/imx-audio-rpmsg.c +++ b/sound/soc/fsl/imx-audio-rpmsg.c @@ -88,7 +88,7 @@ static int imx_audio_rpmsg_probe(struct rpmsg_device *rpdev) /* Register platform driver for rpmsg routine */ data->rpmsg_pdev = platform_device_register_data(&rpdev->dev, IMX_PCM_DRV_NAME, - PLATFORM_DEVID_NONE, + PLATFORM_DEVID_AUTO, NULL, 0); if (IS_ERR(data->rpmsg_pdev)) { dev_err(&rpdev->dev, "failed to register rpmsg platform.\n"); @@ -110,6 +110,7 @@ static void imx_audio_rpmsg_remove(struct rpmsg_device *rpdev) static struct rpmsg_device_id imx_audio_rpmsg_id_table[] = { { .name = "rpmsg-audio-channel" }, + { .name = "rpmsg-micfil-channel" }, { }, }; diff --git a/sound/soc/fsl/imx-pcm-rpmsg.c b/sound/soc/fsl/imx-pcm-rpmsg.c index 35049043e532..2f310994f7ee 100644 --- a/sound/soc/fsl/imx-pcm-rpmsg.c +++ b/sound/soc/fsl/imx-pcm-rpmsg.c @@ -178,7 +178,7 @@ static int imx_rpmsg_pcm_hw_params(struct snd_soc_component *component, msg->s_msg.param.channels = RPMSG_CH_STEREO; break; default: - ret = -EINVAL; + msg->s_msg.param.channels = params_channels(params); break; } @@ -684,7 +684,7 @@ static int imx_rpmsg_pcm_probe(struct platform_device *pdev) info->rpdev = container_of(pdev->dev.parent, struct rpmsg_device, dev); info->dev = &pdev->dev; /* Setup work queue */ - info->rpmsg_wq = alloc_ordered_workqueue("rpmsg_audio", + info->rpmsg_wq = alloc_ordered_workqueue(info->rpdev->id.name, WQ_HIGHPRI | WQ_UNBOUND | WQ_FREEZABLE); @@ -723,11 +723,15 @@ static int imx_rpmsg_pcm_probe(struct platform_device *pdev) if (ret) goto fail; - component = snd_soc_lookup_component(&pdev->dev, IMX_PCM_DRV_NAME); + component = snd_soc_lookup_component(&pdev->dev, NULL); if (!component) { ret = -EINVAL; goto fail; } + + /* platform component name is used by machine driver to link with */ + component->name = info->rpdev->id.name; + #ifdef CONFIG_DEBUG_FS component->debugfs_prefix = "rpmsg"; #endif diff --git a/sound/soc/fsl/imx-rpmsg.c b/sound/soc/fsl/imx-rpmsg.c index 4d99f4858a14..89178106fe2c 100644 --- a/sound/soc/fsl/imx-rpmsg.c +++ b/sound/soc/fsl/imx-rpmsg.c @@ -58,6 +58,7 @@ static int imx_rpmsg_probe(struct platform_device *pdev) struct platform_device *rpmsg_pdev = to_platform_device(dev); struct device_node *np = rpmsg_pdev->dev.of_node; struct of_phandle_args args; + const char *platform_name; struct imx_rpmsg *data; int ret = 0; @@ -109,7 +110,10 @@ static int imx_rpmsg_probe(struct platform_device *pdev) } data->dai.cpus->dai_name = dev_name(&rpmsg_pdev->dev); - data->dai.platforms->name = IMX_PCM_DRV_NAME; + if (!of_property_read_string(np, "fsl,rpmsg-channel-name", &platform_name)) + data->dai.platforms->name = platform_name; + else + data->dai.platforms->name = "rpmsg-audio-channel"; data->dai.playback_only = true; data->dai.capture_only = true; data->card.num_links = 1; |