From 7fb08871c38ba9e871d20d64f3a27409baf7b754 Mon Sep 17 00:00:00 2001 From: Jack Yu Date: Mon, 22 Feb 2021 17:00:56 +0800 Subject: [PATCH 001/587] ASoC: rt1015: fix i2c communication error Remove 0x100 cache re-sync to solve i2c communication error. Signed-off-by: Jack Yu Link: https://lore.kernel.org/r/20210222090057.29532-1-jack.yu@realtek.com Signed-off-by: Mark Brown --- sound/soc/codecs/rt1015.c | 1 + 1 file changed, 1 insertion(+) diff --git a/sound/soc/codecs/rt1015.c b/sound/soc/codecs/rt1015.c index 37b5795b00d1..90767490af82 100644 --- a/sound/soc/codecs/rt1015.c +++ b/sound/soc/codecs/rt1015.c @@ -209,6 +209,7 @@ static bool rt1015_volatile_register(struct device *dev, unsigned int reg) case RT1015_VENDOR_ID: case RT1015_DEVICE_ID: case RT1015_PRO_ALT: + case RT1015_MAN_I2C: case RT1015_DAC3: case RT1015_VBAT_TEST_OUT1: case RT1015_VBAT_TEST_OUT2: From 2979ef760e73e2a1a34cd4da5d2c78371dfe1028 Mon Sep 17 00:00:00 2001 From: Jack Yu Date: Mon, 22 Feb 2021 17:00:57 +0800 Subject: [PATCH 002/587] ASoC: rt1015: enable BCLK detection after calibration Enable BCLK detection after calibration. Signed-off-by: Jack Yu Link: https://lore.kernel.org/r/20210222090057.29532-2-jack.yu@realtek.com Signed-off-by: Mark Brown --- sound/soc/codecs/rt1015.c | 1 + 1 file changed, 1 insertion(+) diff --git a/sound/soc/codecs/rt1015.c b/sound/soc/codecs/rt1015.c index 90767490af82..844e4079d176 100644 --- a/sound/soc/codecs/rt1015.c +++ b/sound/soc/codecs/rt1015.c @@ -514,6 +514,7 @@ static void rt1015_calibrate(struct rt1015_priv *rt1015) msleep(300); regmap_write(regmap, RT1015_PWR_STATE_CTRL, 0x0008); regmap_write(regmap, RT1015_SYS_RST1, 0x05F5); + regmap_write(regmap, RT1015_CLK_DET, 0x8000); regcache_cache_bypass(regmap, false); regcache_mark_dirty(regmap); From 2d003ec15396cc8ffa2a887605c98a967de3078d Mon Sep 17 00:00:00 2001 From: Colin Ian King Date: Mon, 15 Feb 2021 16:33:13 +0000 Subject: [PATCH 003/587] ASoC: codecs: lpass-rx-macro: Fix uninitialized variable ec_tx There is potential read of the uninitialized variable ec_tx if the call to snd_soc_component_read fails or returns an unrecognized w->name. To avoid this corner case, initialize ec_tx to -1 so that it is caught later when ec_tx is bounds checked. Addresses-Coverity: ("Uninitialized scalar variable") Fixes: 4f692926f562 ("ASoC: codecs: lpass-rx-macro: add dapm widgets and route") Signed-off-by: Colin Ian King Link: https://lore.kernel.org/r/20210215163313.84026-1-colin.king@canonical.com Signed-off-by: Mark Brown --- sound/soc/codecs/lpass-rx-macro.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sound/soc/codecs/lpass-rx-macro.c b/sound/soc/codecs/lpass-rx-macro.c index c9c21d22c2c4..8c04b3b2c907 100644 --- a/sound/soc/codecs/lpass-rx-macro.c +++ b/sound/soc/codecs/lpass-rx-macro.c @@ -2895,7 +2895,7 @@ static int rx_macro_enable_echo(struct snd_soc_dapm_widget *w, { struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm); u16 val, ec_hq_reg; - int ec_tx; + int ec_tx = -1; val = snd_soc_component_read(component, CDC_RX_INP_MUX_RX_MIX_CFG4); From 9fd914d917da05641b42cab7d40bdf8ab06dac3b Mon Sep 17 00:00:00 2001 From: Alexander Shiyan Date: Tue, 16 Feb 2021 14:42:21 +0300 Subject: [PATCH 004/587] ASoC: fsl_ssi: Fix TDM slot setup for I2S mode When using the driver in I2S TDM mode, the _fsl_ssi_set_dai_fmt() function rewrites the number of slots previously set by the fsl_ssi_set_dai_tdm_slot() function to 2 by default. To fix this, let's use the saved slot count value or, if TDM is not used and the slot count is not set, proceed as before. Fixes: 4f14f5c11db1 ("ASoC: fsl_ssi: Fix number of words per frame for I2S-slave mode") Signed-off-by: Alexander Shiyan Acked-by: Nicolin Chen Link: https://lore.kernel.org/r/20210216114221.26635-1-shc_work@mail.ru Signed-off-by: Mark Brown --- sound/soc/fsl/fsl_ssi.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/sound/soc/fsl/fsl_ssi.c b/sound/soc/fsl/fsl_ssi.c index 57811743c294..ad8af3f450e2 100644 --- a/sound/soc/fsl/fsl_ssi.c +++ b/sound/soc/fsl/fsl_ssi.c @@ -878,6 +878,7 @@ static int fsl_ssi_hw_free(struct snd_pcm_substream *substream, static int _fsl_ssi_set_dai_fmt(struct fsl_ssi *ssi, unsigned int fmt) { u32 strcr = 0, scr = 0, stcr, srcr, mask; + unsigned int slots; ssi->dai_fmt = fmt; @@ -909,10 +910,11 @@ static int _fsl_ssi_set_dai_fmt(struct fsl_ssi *ssi, unsigned int fmt) return -EINVAL; } + slots = ssi->slots ? : 2; regmap_update_bits(ssi->regs, REG_SSI_STCCR, - SSI_SxCCR_DC_MASK, SSI_SxCCR_DC(2)); + SSI_SxCCR_DC_MASK, SSI_SxCCR_DC(slots)); regmap_update_bits(ssi->regs, REG_SSI_SRCCR, - SSI_SxCCR_DC_MASK, SSI_SxCCR_DC(2)); + SSI_SxCCR_DC_MASK, SSI_SxCCR_DC(slots)); /* Data on rising edge of bclk, frame low, 1clk before data */ strcr |= SSI_STCR_TFSI | SSI_STCR_TSCKP | SSI_STCR_TEFS; From 30be2641848b2450f0f1b62e3a8aea42e14db640 Mon Sep 17 00:00:00 2001 From: Hans de Goede Date: Mon, 15 Feb 2021 15:21:15 +0100 Subject: [PATCH 005/587] ASoC: rt5670: Remove 'OUT Channel Switch' control The "OUT Channel Switch" control is a left over from code copied from thr rt5640 codec driver. With the rt5640 codec driver the output volume controls have 2 pairs of mute bits: bit 7, 15: Mute Control for Spk/Headphone/Line Output Port bit 6, 14: Mute Control for Spk/Headphone/Line Volume Channel Bits 7 and 15 are normal mute bits on the rt5670/5672 which are controlled by 2 dapm widgets: SND_SOC_DAPM_SWITCH("LOUT L Playback", SND_SOC_NOPM, 0, 0, &lout_l_enable_control), SND_SOC_DAPM_SWITCH("LOUT R Playback", SND_SOC_NOPM, 0, 0, &lout_r_enable_control), But on the 5670/5672 bit 6 is always reserved, where as bit 14 is "LOUT Differential Mode" on the 5670 and also reserved on the 5672. So the "OUT Channel Switch" control which is controlling bits 6+14 of the "LINE Output Control" register is bogus -> remove it. This should not cause any issues for userspace. AFAICT the rt567x codecs are only used on x86/ACPI devices and the UCM profiles used there do not use the "OUT Channel Switch" control. Signed-off-by: Hans de Goede Link: https://lore.kernel.org/r/20210215142118.308516-2-hdegoede@redhat.com Signed-off-by: Mark Brown --- sound/soc/codecs/rt5670.c | 2 -- sound/soc/codecs/rt5670.h | 4 ---- 2 files changed, 6 deletions(-) diff --git a/sound/soc/codecs/rt5670.c b/sound/soc/codecs/rt5670.c index c29317ea5df2..2e799e21dbda 100644 --- a/sound/soc/codecs/rt5670.c +++ b/sound/soc/codecs/rt5670.c @@ -637,8 +637,6 @@ static const struct snd_kcontrol_new rt5670_snd_controls[] = { RT5670_L_VOL_SFT, RT5670_R_VOL_SFT, 39, 1, out_vol_tlv), /* OUTPUT Control */ - SOC_DOUBLE("OUT Channel Switch", RT5670_LOUT1, - RT5670_VOL_L_SFT, RT5670_VOL_R_SFT, 1, 1), SOC_DOUBLE_TLV("OUT Playback Volume", RT5670_LOUT1, RT5670_L_VOL_SFT, RT5670_R_VOL_SFT, 39, 1, out_vol_tlv), /* DAC Digital Volume */ diff --git a/sound/soc/codecs/rt5670.h b/sound/soc/codecs/rt5670.h index 56b13fe6bd3c..f9c4db156c80 100644 --- a/sound/soc/codecs/rt5670.h +++ b/sound/soc/codecs/rt5670.h @@ -212,12 +212,8 @@ /* global definition */ #define RT5670_L_MUTE (0x1 << 15) #define RT5670_L_MUTE_SFT 15 -#define RT5670_VOL_L_MUTE (0x1 << 14) -#define RT5670_VOL_L_SFT 14 #define RT5670_R_MUTE (0x1 << 7) #define RT5670_R_MUTE_SFT 7 -#define RT5670_VOL_R_MUTE (0x1 << 6) -#define RT5670_VOL_R_SFT 6 #define RT5670_L_VOL_MASK (0x3f << 8) #define RT5670_L_VOL_SFT 8 #define RT5670_R_VOL_MASK (0x3f) From 8022f09883e827855d86173756caa07b891100f0 Mon Sep 17 00:00:00 2001 From: Hans de Goede Date: Mon, 15 Feb 2021 15:21:16 +0100 Subject: [PATCH 006/587] ASoC: rt5670: Remove 'HP Playback Switch' control The RT5670_L_MUTE_SFT and RT5670_R_MUTE_SFT bits (bits 15 and 7) of the RT5670_HP_VOL register are set / unset by the headphones deplop code run by rt5670_hp_event() on SND_SOC_DAPM_POST_PMU / SND_SOC_DAPM_PRE_PMD. So we should not also export a control to userspace which toggles these same bits. This should not cause any issues for userspace. AFAICT the rt567x codecs are only used on x86/ACPI devices and the UCM profiles used there do not use the "HP Playback Switch" control. Signed-off-by: Hans de Goede Link: https://lore.kernel.org/r/20210215142118.308516-3-hdegoede@redhat.com Signed-off-by: Mark Brown --- sound/soc/codecs/rt5670.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/sound/soc/codecs/rt5670.c b/sound/soc/codecs/rt5670.c index 2e799e21dbda..932e4cd1e9a6 100644 --- a/sound/soc/codecs/rt5670.c +++ b/sound/soc/codecs/rt5670.c @@ -631,8 +631,6 @@ static SOC_ENUM_SINGLE_DECL(rt5670_if2_adc_enum, RT5670_DIG_INF1_DATA, static const struct snd_kcontrol_new rt5670_snd_controls[] = { /* Headphone Output Volume */ - SOC_DOUBLE("HP Playback Switch", RT5670_HP_VOL, - RT5670_L_MUTE_SFT, RT5670_R_MUTE_SFT, 1, 1), SOC_DOUBLE_TLV("HP Playback Volume", RT5670_HP_VOL, RT5670_L_VOL_SFT, RT5670_R_VOL_SFT, 39, 1, out_vol_tlv), From 674e4ff4c2326c6e3f8ddc73c61910bf32228720 Mon Sep 17 00:00:00 2001 From: Hans de Goede Date: Mon, 15 Feb 2021 15:21:17 +0100 Subject: [PATCH 007/587] ASoC: rt5670: Remove ADC vol-ctrl mute bits poking from Sto1 ADC mixer settings The SND_SOC_DAPM_MIXER declaration for "Sto1 ADC MIXL" and "Sto1 ADC MIXR" was using the mute bits from the RT5670_STO1_ADC_DIG_VOL control as mixer master mute bits. But these bits are already exposed to userspace as controls as part of the "ADC Capture Volume" / "ADC Capture Switch" control pair: SOC_DOUBLE("ADC Capture Switch", RT5670_STO1_ADC_DIG_VOL, RT5670_L_MUTE_SFT, RT5670_R_MUTE_SFT, 1, 1), SOC_DOUBLE_TLV("ADC Capture Volume", RT5670_STO1_ADC_DIG_VOL, RT5670_L_VOL_SFT, RT5670_R_VOL_SFT, 127, 0, adc_vol_tlv), Both the fact that the mute bits belong to the same reg as the vol-ctrl and the "Digital Mixer Path" diagram in the datasheet clearly shows that these mute bits are not part of the mixer and having 2 separate controls poking at the same bits is a bad idea. Remove the master-mute bits settings from the "Sto1 ADC MIXL" and "Sto1 ADC MIXR" DAPM widget declarations, avoiding these bits getting poked from 2 different places. This should not cause any issues for userspace. AFAICT the rt567x codecs are only used on x86/ACPI devices and the UCM profiles used there already set the "ADC Capture Switch" as needed. Signed-off-by: Hans de Goede Link: https://lore.kernel.org/r/20210215142118.308516-4-hdegoede@redhat.com Signed-off-by: Mark Brown --- sound/soc/codecs/rt5670.c | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/sound/soc/codecs/rt5670.c b/sound/soc/codecs/rt5670.c index 932e4cd1e9a6..2f015c24c637 100644 --- a/sound/soc/codecs/rt5670.c +++ b/sound/soc/codecs/rt5670.c @@ -1652,12 +1652,10 @@ static const struct snd_soc_dapm_widget rt5670_dapm_widgets[] = { RT5670_PWR_ADC_S1F_BIT, 0, NULL, 0), SND_SOC_DAPM_SUPPLY("ADC Stereo2 Filter", RT5670_PWR_DIG2, RT5670_PWR_ADC_S2F_BIT, 0, NULL, 0), - SND_SOC_DAPM_MIXER("Sto1 ADC MIXL", RT5670_STO1_ADC_DIG_VOL, - RT5670_L_MUTE_SFT, 1, rt5670_sto1_adc_l_mix, - ARRAY_SIZE(rt5670_sto1_adc_l_mix)), - SND_SOC_DAPM_MIXER("Sto1 ADC MIXR", RT5670_STO1_ADC_DIG_VOL, - RT5670_R_MUTE_SFT, 1, rt5670_sto1_adc_r_mix, - ARRAY_SIZE(rt5670_sto1_adc_r_mix)), + SND_SOC_DAPM_MIXER("Sto1 ADC MIXL", SND_SOC_NOPM, 0, 0, + rt5670_sto1_adc_l_mix, ARRAY_SIZE(rt5670_sto1_adc_l_mix)), + SND_SOC_DAPM_MIXER("Sto1 ADC MIXR", SND_SOC_NOPM, 0, 0, + rt5670_sto1_adc_r_mix, ARRAY_SIZE(rt5670_sto1_adc_r_mix)), SND_SOC_DAPM_MIXER("Sto2 ADC MIXL", SND_SOC_NOPM, 0, 0, rt5670_sto2_adc_l_mix, ARRAY_SIZE(rt5670_sto2_adc_l_mix)), From 982042931c255e2e7f196c24f1e5d6de780e04f9 Mon Sep 17 00:00:00 2001 From: Hans de Goede Date: Mon, 15 Feb 2021 15:21:18 +0100 Subject: [PATCH 008/587] ASoC: rt5670: Add emulated 'DAC1 Playback Switch' control For reliable output-mute LED control we need a "DAC1 Playback Switch" control. The "DAC Playback volume" control is the only control in the path from the DAC1 data input to the speaker output, so the UCM profile for the speaker output will have its PlaybackMixerElem set to "DAC1". But userspace (pulseaudio) will set the "DAC1 Playback Volume" control to its softest setting (which is not fully muted) while still showing the speaker as being enabled at a low volume in the UI. If we were to set the SNDRV_CTL_ELEM_ACCESS_SPK_LED on the "DAC1 Playback Volume" control, this would mean then what pressing KEY_VOLUMEDOWN the speaker-mute LED (embedded in the volume-mute toggle key) would light while the UI is still showing the speaker as being enabled at a low volume, meaning that the UI and the LED are out of sync. Only after an _extra_ KEY_VOLUMEDOWN press would the UI show the speaker as being muted. The path from DAC1 data input to the speaker output does have a digital mixer with DAC1's data as one of its inputs direclty after the "DAC1 Playback Volume" control. This commit adds an emulated "DAC1 Playback Switch" control by: 1. Declaring the enable flag for that mixers DAC1 input as well as the "DAC1 Playback Switch" control both as SND_SOC_NOPM controls. 2. Storing the settings of both controls as driver-private data 3. Only clearing the mute flag for the DAC1 input of that mixer if the stored values indicate both controls are enabled. This is a preparation patch for adding "audio-mute" LED trigger support. Signed-off-by: Hans de Goede Link: https://lore.kernel.org/r/20210215142118.308516-5-hdegoede@redhat.com Signed-off-by: Mark Brown --- sound/soc/codecs/rt5670.c | 96 +++++++++++++++++++++++++++++++++++++-- sound/soc/codecs/rt5670.h | 5 ++ 2 files changed, 97 insertions(+), 4 deletions(-) diff --git a/sound/soc/codecs/rt5670.c b/sound/soc/codecs/rt5670.c index 2f015c24c637..4063aac2a443 100644 --- a/sound/soc/codecs/rt5670.c +++ b/sound/soc/codecs/rt5670.c @@ -629,6 +629,56 @@ static SOC_ENUM_SINGLE_DECL(rt5670_if2_dac_enum, RT5670_DIG_INF1_DATA, static SOC_ENUM_SINGLE_DECL(rt5670_if2_adc_enum, RT5670_DIG_INF1_DATA, RT5670_IF2_ADC_SEL_SFT, rt5670_data_select); +/* + * For reliable output-mute LED control we need a "DAC1 Playback Switch" control. + * We emulate this by only clearing the RT5670_M_DAC1_L/_R AD_DA_MIXER register + * bits when both our emulated DAC1 Playback Switch control and the DAC1 MIXL/R + * DAPM-mixer DAC1 input are enabled. + */ +static void rt5670_update_ad_da_mixer_dac1_m_bits(struct rt5670_priv *rt5670) +{ + int val = RT5670_M_DAC1_L | RT5670_M_DAC1_R; + + if (rt5670->dac1_mixl_dac1_switch && rt5670->dac1_playback_switch_l) + val &= ~RT5670_M_DAC1_L; + + if (rt5670->dac1_mixr_dac1_switch && rt5670->dac1_playback_switch_r) + val &= ~RT5670_M_DAC1_R; + + regmap_update_bits(rt5670->regmap, RT5670_AD_DA_MIXER, + RT5670_M_DAC1_L | RT5670_M_DAC1_R, val); +} + +static int rt5670_dac1_playback_switch_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol); + struct rt5670_priv *rt5670 = snd_soc_component_get_drvdata(component); + + ucontrol->value.integer.value[0] = rt5670->dac1_playback_switch_l; + ucontrol->value.integer.value[1] = rt5670->dac1_playback_switch_r; + + return 0; +} + +static int rt5670_dac1_playback_switch_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol); + struct rt5670_priv *rt5670 = snd_soc_component_get_drvdata(component); + + if (rt5670->dac1_playback_switch_l == ucontrol->value.integer.value[0] && + rt5670->dac1_playback_switch_r == ucontrol->value.integer.value[1]) + return 0; + + rt5670->dac1_playback_switch_l = ucontrol->value.integer.value[0]; + rt5670->dac1_playback_switch_r = ucontrol->value.integer.value[1]; + + rt5670_update_ad_da_mixer_dac1_m_bits(rt5670); + + return 1; +} + static const struct snd_kcontrol_new rt5670_snd_controls[] = { /* Headphone Output Volume */ SOC_DOUBLE_TLV("HP Playback Volume", RT5670_HP_VOL, @@ -640,6 +690,8 @@ static const struct snd_kcontrol_new rt5670_snd_controls[] = { /* DAC Digital Volume */ SOC_DOUBLE("DAC2 Playback Switch", RT5670_DAC_CTRL, RT5670_M_DAC_L2_VOL_SFT, RT5670_M_DAC_R2_VOL_SFT, 1, 1), + SOC_DOUBLE_EXT("DAC1 Playback Switch", SND_SOC_NOPM, 0, 1, 1, 0, + rt5670_dac1_playback_switch_get, rt5670_dac1_playback_switch_put), SOC_DOUBLE_TLV("DAC1 Playback Volume", RT5670_DAC1_DIG_VOL, RT5670_L_VOL_SFT, RT5670_R_VOL_SFT, 175, 0, dac_vol_tlv), @@ -909,18 +961,44 @@ static const struct snd_kcontrol_new rt5670_mono_adc_r_mix[] = { RT5670_M_MONO_ADC_R2_SFT, 1, 1), }; +/* See comment above rt5670_update_ad_da_mixer_dac1_m_bits() */ +static int rt5670_put_dac1_mix_dac1_switch(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct soc_mixer_control *mc = (struct soc_mixer_control *)kcontrol->private_value; + struct snd_soc_component *component = snd_soc_dapm_kcontrol_component(kcontrol); + struct rt5670_priv *rt5670 = snd_soc_component_get_drvdata(component); + int ret; + + if (mc->shift == 0) + rt5670->dac1_mixl_dac1_switch = ucontrol->value.integer.value[0]; + else + rt5670->dac1_mixr_dac1_switch = ucontrol->value.integer.value[0]; + + /* Apply the update (if any) */ + ret = snd_soc_dapm_put_volsw(kcontrol, ucontrol); + if (ret == 0) + return 0; + + rt5670_update_ad_da_mixer_dac1_m_bits(rt5670); + + return 1; +} + +#define SOC_DAPM_SINGLE_RT5670_DAC1_SW(name, shift) \ + SOC_SINGLE_EXT(name, SND_SOC_NOPM, shift, 1, 0, \ + snd_soc_dapm_get_volsw, rt5670_put_dac1_mix_dac1_switch) + static const struct snd_kcontrol_new rt5670_dac_l_mix[] = { SOC_DAPM_SINGLE("Stereo ADC Switch", RT5670_AD_DA_MIXER, RT5670_M_ADCMIX_L_SFT, 1, 1), - SOC_DAPM_SINGLE("DAC1 Switch", RT5670_AD_DA_MIXER, - RT5670_M_DAC1_L_SFT, 1, 1), + SOC_DAPM_SINGLE_RT5670_DAC1_SW("DAC1 Switch", 0), }; static const struct snd_kcontrol_new rt5670_dac_r_mix[] = { SOC_DAPM_SINGLE("Stereo ADC Switch", RT5670_AD_DA_MIXER, RT5670_M_ADCMIX_R_SFT, 1, 1), - SOC_DAPM_SINGLE("DAC1 Switch", RT5670_AD_DA_MIXER, - RT5670_M_DAC1_R_SFT, 1, 1), + SOC_DAPM_SINGLE_RT5670_DAC1_SW("DAC1 Switch", 1), }; static const struct snd_kcontrol_new rt5670_sto_dac_l_mix[] = { @@ -2993,6 +3071,16 @@ static int rt5670_i2c_probe(struct i2c_client *i2c, dev_info(&i2c->dev, "quirk JD mode 3\n"); } + /* + * Enable the emulated "DAC1 Playback Switch" by default to avoid + * muting the output with older UCM profiles. + */ + rt5670->dac1_playback_switch_l = true; + rt5670->dac1_playback_switch_r = true; + /* The Power-On-Reset values for the DAC1 mixer have the DAC1 input enabled. */ + rt5670->dac1_mixl_dac1_switch = true; + rt5670->dac1_mixr_dac1_switch = true; + rt5670->regmap = devm_regmap_init_i2c(i2c, &rt5670_regmap); if (IS_ERR(rt5670->regmap)) { ret = PTR_ERR(rt5670->regmap); diff --git a/sound/soc/codecs/rt5670.h b/sound/soc/codecs/rt5670.h index f9c4db156c80..6fb3c369ee98 100644 --- a/sound/soc/codecs/rt5670.h +++ b/sound/soc/codecs/rt5670.h @@ -2013,6 +2013,11 @@ struct rt5670_priv { int dsp_rate; int jack_type; int jack_type_saved; + + bool dac1_mixl_dac1_switch; + bool dac1_mixr_dac1_switch; + bool dac1_playback_switch_l; + bool dac1_playback_switch_r; }; void rt5670_jack_suspend(struct snd_soc_component *component); From f84b4524005238fc9fd5cf615bb426fa40a99494 Mon Sep 17 00:00:00 2001 From: Shengjiu Wang Date: Wed, 24 Feb 2021 14:57:51 +0800 Subject: [PATCH 009/587] ASoC: ak4458: Add MODULE_DEVICE_TABLE Add missed MODULE_DEVICE_TABLE for the driver can be loaded automatically at boot. Fixes: 08660086eff9 ("ASoC: ak4458: Add support for AK4458 DAC driver") Cc: Signed-off-by: Shengjiu Wang Link: https://lore.kernel.org/r/1614149872-25510-1-git-send-email-shengjiu.wang@nxp.com Signed-off-by: Mark Brown --- sound/soc/codecs/ak4458.c | 1 + 1 file changed, 1 insertion(+) diff --git a/sound/soc/codecs/ak4458.c b/sound/soc/codecs/ak4458.c index 472caad17012..85a1d00894a9 100644 --- a/sound/soc/codecs/ak4458.c +++ b/sound/soc/codecs/ak4458.c @@ -812,6 +812,7 @@ static const struct of_device_id ak4458_of_match[] = { { .compatible = "asahi-kasei,ak4497", .data = &ak4497_drvdata}, { }, }; +MODULE_DEVICE_TABLE(of, ak4458_of_match); static struct i2c_driver ak4458_i2c_driver = { .driver = { From 741c8397e5d0b339fb3e614a9ff5cb4bf7ae1a65 Mon Sep 17 00:00:00 2001 From: Shengjiu Wang Date: Wed, 24 Feb 2021 14:57:52 +0800 Subject: [PATCH 010/587] ASoC: ak5558: Add MODULE_DEVICE_TABLE Add missed MODULE_DEVICE_TABLE for the driver can be loaded automatically at boot. Fixes: 920884777480 ("ASoC: ak5558: Add support for AK5558 ADC driver") Cc: Signed-off-by: Shengjiu Wang Link: https://lore.kernel.org/r/1614149872-25510-2-git-send-email-shengjiu.wang@nxp.com Signed-off-by: Mark Brown --- sound/soc/codecs/ak5558.c | 1 + 1 file changed, 1 insertion(+) diff --git a/sound/soc/codecs/ak5558.c b/sound/soc/codecs/ak5558.c index 8a32b0139cb0..85bdd0534180 100644 --- a/sound/soc/codecs/ak5558.c +++ b/sound/soc/codecs/ak5558.c @@ -419,6 +419,7 @@ static const struct of_device_id ak5558_i2c_dt_ids[] __maybe_unused = { { .compatible = "asahi-kasei,ak5558"}, { } }; +MODULE_DEVICE_TABLE(of, ak5558_i2c_dt_ids); static struct i2c_driver ak5558_i2c_driver = { .driver = { From 1045a5c04e16716870cc953872e703258e7896de Mon Sep 17 00:00:00 2001 From: Hans de Goede Date: Wed, 24 Feb 2021 11:50:52 +0100 Subject: [PATCH 011/587] ASoC: Intel: bytcr_rt5640: Fix HP Pavilion x2 10-p0XX OVCD current threshold When I added the quirk for the "HP Pavilion x2 10-p0XX" I copied the byt_rt5640_quirk_table[] entry for the HP Pavilion x2 10-k0XX / 10-n0XX models since these use almost the same settings. While doing this I accidentally also copied and kept the non-standard OVCD_TH_1500UA setting used on those models. This too low threshold is causing headsets to often be seen as headphones (without a headset-mic) and when correctly identified it is causing ghost play/pause button-presses to get detected. Correct the HP Pavilion x2 10-p0XX quirk to use the default OVCD_TH_2000UA setting, fixing these problems. Fixes: fbdae7d6d04d ("ASoC: Intel: bytcr_rt5640: Fix HP Pavilion x2 Detachable quirks") Signed-off-by: Hans de Goede Acked-by: Pierre-Louis Bossart Link: https://lore.kernel.org/r/20210224105052.42116-1-hdegoede@redhat.com Signed-off-by: Mark Brown --- sound/soc/intel/boards/bytcr_rt5640.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sound/soc/intel/boards/bytcr_rt5640.c b/sound/soc/intel/boards/bytcr_rt5640.c index 782f2b4d72ad..5d48cc359c3d 100644 --- a/sound/soc/intel/boards/bytcr_rt5640.c +++ b/sound/soc/intel/boards/bytcr_rt5640.c @@ -581,7 +581,7 @@ static const struct dmi_system_id byt_rt5640_quirk_table[] = { }, .driver_data = (void *)(BYT_RT5640_DMIC1_MAP | BYT_RT5640_JD_SRC_JD1_IN4P | - BYT_RT5640_OVCD_TH_1500UA | + BYT_RT5640_OVCD_TH_2000UA | BYT_RT5640_OVCD_SF_0P75 | BYT_RT5640_MCLK_EN), }, From d6e68c57e35b69b31d9fa5a61b37c840973db362 Mon Sep 17 00:00:00 2001 From: George Harker Date: Fri, 26 Feb 2021 21:24:56 +0000 Subject: [PATCH 012/587] ALSA: usb-audio: use usb headers rather than define structs locally Use struct definitions from linux/usb/midi.h rather than locally define the structs in sound/usb/midi.c. Signed-off-by: George Harker Link: https://lore.kernel.org/r/20210226212457.24538-1-george@george-graphics.co.uk Signed-off-by: Takashi Iwai --- sound/usb/midi.c | 20 ++------------------ 1 file changed, 2 insertions(+), 18 deletions(-) diff --git a/sound/usb/midi.c b/sound/usb/midi.c index 0c23fa6d8525..610cf54eefd9 100644 --- a/sound/usb/midi.c +++ b/sound/usb/midi.c @@ -47,6 +47,7 @@ #include #include #include +#include #include #include @@ -77,23 +78,6 @@ MODULE_AUTHOR("Clemens Ladisch "); MODULE_DESCRIPTION("USB Audio/MIDI helper module"); MODULE_LICENSE("Dual BSD/GPL"); - -struct usb_ms_header_descriptor { - __u8 bLength; - __u8 bDescriptorType; - __u8 bDescriptorSubtype; - __u8 bcdMSC[2]; - __le16 wTotalLength; -} __attribute__ ((packed)); - -struct usb_ms_endpoint_descriptor { - __u8 bLength; - __u8 bDescriptorType; - __u8 bDescriptorSubtype; - __u8 bNumEmbMIDIJack; - __u8 baAssocJackID[]; -} __attribute__ ((packed)); - struct snd_usb_midi_in_endpoint; struct snd_usb_midi_out_endpoint; struct snd_usb_midi_endpoint; @@ -1875,7 +1859,7 @@ static int snd_usbmidi_get_ms_info(struct snd_usb_midi *umidi, ms_header->bDescriptorType == USB_DT_CS_INTERFACE && ms_header->bDescriptorSubtype == UAC_HEADER) dev_dbg(&umidi->dev->dev, "MIDIStreaming version %02x.%02x\n", - ms_header->bcdMSC[1], ms_header->bcdMSC[0]); + ((uint8_t *)&ms_header->bcdMSC)[1], ((uint8_t *)&ms_header->bcdMSC)[0]); else dev_warn(&umidi->dev->dev, "MIDIStreaming interface descriptor not found\n"); From eb596e0fd13c83b4a66559a45b57b71aac340d30 Mon Sep 17 00:00:00 2001 From: George Harker Date: Fri, 26 Feb 2021 21:26:16 +0000 Subject: [PATCH 013/587] ALSA: usb-audio: generate midi streaming substream names from jack names A number of devices have named substreams which are hard to remember / decypher from MIDI n names. Eg. Korg puts a pass through on one substream and iConnectivity devices name the connections. This makes it easier to connect to the correct device. Devices which handle naming through quirks are unaffected by this change. Addresses TODO comment in sound/usb/midi.c Signed-off-by: George Harker Link: https://lore.kernel.org/r/20210226212617.24616-1-george@george-graphics.co.uk Signed-off-by: Takashi Iwai --- sound/usb/midi.c | 103 ++++++++++++++++++++++++++++++++++++++++++++--- sound/usb/midi.h | 2 + 2 files changed, 100 insertions(+), 5 deletions(-) diff --git a/sound/usb/midi.c b/sound/usb/midi.c index 610cf54eefd9..9efda4b06acb 100644 --- a/sound/usb/midi.c +++ b/sound/usb/midi.c @@ -1740,12 +1740,68 @@ static void snd_usbmidi_get_port_info(struct snd_rawmidi *rmidi, int number, } } +static struct usb_midi_in_jack_descriptor *find_usb_in_jack_descriptor( + struct usb_host_interface *hostif, uint8_t jack_id) +{ + unsigned char *extra = hostif->extra; + int extralen = hostif->extralen; + + while (extralen > 4) { + struct usb_midi_in_jack_descriptor *injd = + (struct usb_midi_in_jack_descriptor *)extra; + + if (injd->bLength > 4 && + injd->bDescriptorType == USB_DT_CS_INTERFACE && + injd->bDescriptorSubtype == UAC_MIDI_IN_JACK && + injd->bJackID == jack_id) + return injd; + if (!extra[0]) + break; + extralen -= extra[0]; + extra += extra[0]; + } + return NULL; +} + +static struct usb_midi_out_jack_descriptor *find_usb_out_jack_descriptor( + struct usb_host_interface *hostif, uint8_t jack_id) +{ + unsigned char *extra = hostif->extra; + int extralen = hostif->extralen; + + while (extralen > 4) { + struct usb_midi_out_jack_descriptor *outjd = + (struct usb_midi_out_jack_descriptor *)extra; + + if (outjd->bLength > 4 && + outjd->bDescriptorType == USB_DT_CS_INTERFACE && + outjd->bDescriptorSubtype == UAC_MIDI_OUT_JACK && + outjd->bJackID == jack_id) + return outjd; + if (!extra[0]) + break; + extralen -= extra[0]; + extra += extra[0]; + } + return NULL; +} + static void snd_usbmidi_init_substream(struct snd_usb_midi *umidi, - int stream, int number, + int stream, int number, int jack_id, struct snd_rawmidi_substream **rsubstream) { struct port_info *port_info; const char *name_format; + struct usb_interface *intf; + struct usb_host_interface *hostif; + struct usb_midi_in_jack_descriptor *injd; + struct usb_midi_out_jack_descriptor *outjd; + uint8_t jack_name_buf[32]; + uint8_t *default_jack_name = "MIDI"; + uint8_t *jack_name = default_jack_name; + uint8_t iJack; + size_t sz; + int res; struct snd_rawmidi_substream *substream = snd_usbmidi_find_substream(umidi, stream, number); @@ -1755,11 +1811,36 @@ static void snd_usbmidi_init_substream(struct snd_usb_midi *umidi, return; } - /* TODO: read port name from jack descriptor */ + intf = umidi->iface; + if (intf && jack_id >= 0) { + hostif = intf->cur_altsetting; + iJack = 0; + if (stream != SNDRV_RAWMIDI_STREAM_OUTPUT) { + /* in jacks connect to outs */ + outjd = find_usb_out_jack_descriptor(hostif, jack_id); + if (outjd) { + sz = USB_DT_MIDI_OUT_SIZE(outjd->bNrInputPins); + iJack = *(((uint8_t *) outjd) + sz - sizeof(uint8_t)); + } + } else { + /* and out jacks connect to ins */ + injd = find_usb_in_jack_descriptor(hostif, jack_id); + if (injd) + iJack = injd->iJack; + } + if (iJack != 0) { + res = usb_string(umidi->dev, iJack, jack_name_buf, + ARRAY_SIZE(jack_name_buf)); + if (res) + jack_name = jack_name_buf; + } + } + port_info = find_port_info(umidi, number); - name_format = port_info ? port_info->name : "%s MIDI %d"; + name_format = port_info ? port_info->name : + (jack_name != default_jack_name ? "%s %s" : "%s %s %d"); snprintf(substream->name, sizeof(substream->name), - name_format, umidi->card->shortname, number + 1); + name_format, umidi->card->shortname, jack_name, number + 1); *rsubstream = substream; } @@ -1794,6 +1875,7 @@ static int snd_usbmidi_create_endpoints(struct snd_usb_midi *umidi, snd_usbmidi_init_substream(umidi, SNDRV_RAWMIDI_STREAM_OUTPUT, out_ports, + endpoints[i].assoc_out_jacks[j], &umidi->endpoints[i].out->ports[j].substream); ++out_ports; } @@ -1801,6 +1883,7 @@ static int snd_usbmidi_create_endpoints(struct snd_usb_midi *umidi, snd_usbmidi_init_substream(umidi, SNDRV_RAWMIDI_STREAM_INPUT, in_ports, + endpoints[i].assoc_in_jacks[j], &umidi->endpoints[i].in->ports[j].substream); ++in_ports; } @@ -1846,7 +1929,7 @@ static int snd_usbmidi_get_ms_info(struct snd_usb_midi *umidi, struct usb_host_endpoint *hostep; struct usb_endpoint_descriptor *ep; struct usb_ms_endpoint_descriptor *ms_ep; - int i, epidx; + int i, j, epidx; intf = umidi->iface; if (!intf) @@ -1895,6 +1978,10 @@ static int snd_usbmidi_get_ms_info(struct snd_usb_midi *umidi, endpoints[epidx].out_interval = 1; endpoints[epidx].out_cables = (1 << ms_ep->bNumEmbMIDIJack) - 1; + for (j = 0; j < ms_ep->bNumEmbMIDIJack; ++j) + endpoints[epidx].assoc_out_jacks[j] = ms_ep->baAssocJackID[j]; + for (; j < ARRAY_SIZE(endpoints[epidx].assoc_out_jacks); ++j) + endpoints[epidx].assoc_out_jacks[j] = -1; dev_dbg(&umidi->dev->dev, "EP %02X: %d jack(s)\n", ep->bEndpointAddress, ms_ep->bNumEmbMIDIJack); } else { @@ -1912,6 +1999,10 @@ static int snd_usbmidi_get_ms_info(struct snd_usb_midi *umidi, endpoints[epidx].in_interval = 1; endpoints[epidx].in_cables = (1 << ms_ep->bNumEmbMIDIJack) - 1; + for (j = 0; j < ms_ep->bNumEmbMIDIJack; ++j) + endpoints[epidx].assoc_in_jacks[j] = ms_ep->baAssocJackID[j]; + for (; j < ARRAY_SIZE(endpoints[epidx].assoc_in_jacks); ++j) + endpoints[epidx].assoc_in_jacks[j] = -1; dev_dbg(&umidi->dev->dev, "EP %02X: %d jack(s)\n", ep->bEndpointAddress, ms_ep->bNumEmbMIDIJack); } @@ -2228,11 +2319,13 @@ static int snd_usbmidi_create_endpoints_midiman(struct snd_usb_midi *umidi, snd_usbmidi_init_substream(umidi, SNDRV_RAWMIDI_STREAM_OUTPUT, cable, + -1 /* prevent trying to find jack */, &umidi->endpoints[cable & 1].out->ports[cable].substream); if (endpoint->in_cables & (1 << cable)) snd_usbmidi_init_substream(umidi, SNDRV_RAWMIDI_STREAM_INPUT, cable, + -1 /* prevent trying to find jack */, &umidi->endpoints[0].in->ports[cable].substream); } return 0; diff --git a/sound/usb/midi.h b/sound/usb/midi.h index 8c38aec22999..3f153195c841 100644 --- a/sound/usb/midi.h +++ b/sound/usb/midi.h @@ -13,6 +13,8 @@ struct snd_usb_midi_endpoint_info { uint8_t in_interval; uint16_t out_cables; /* bitmask */ uint16_t in_cables; /* bitmask */ + int16_t assoc_in_jacks[16]; + int16_t assoc_out_jacks[16]; }; /* for QUIRK_MIDI_YAMAHA, data is NULL */ From 24a7b77daed8f973bf8a5ed2f83344f44f9f6396 Mon Sep 17 00:00:00 2001 From: Hans de Goede Date: Fri, 26 Feb 2021 15:38:13 +0100 Subject: [PATCH 014/587] ASoC: rt5640: Fix dac- and adc- vol-tlv values being off by a factor of 10 The adc_vol_tlv volume-control has a range from -17.625 dB to +30 dB, not -176.25 dB to + 300 dB. This wrong scale is esp. a problem in userspace apps which translate the dB scale to a linear scale. With the logarithmic dB scale being of by a factor of 10 we loose all precision in the lower area of the range when apps translate things to a linear scale. E.g. the 0 dB default, which corresponds with a value of 47 of the 0 - 127 range for the control, would be shown as 0/100 in alsa-mixer. Since the centi-dB values used in the TLV struct cannot represent the 0.375 dB step size used by these controls, change the TLV definition for them to specify a min and max value instead of min + stepsize. Note this mirrors commit 3f31f7d9b540 ("ASoC: rt5670: Fix dac- and adc- vol-tlv values being off by a factor of 10") which made the exact same change to the rt5670 codec driver. Signed-off-by: Hans de Goede Link: https://lore.kernel.org/r/20210226143817.84287-2-hdegoede@redhat.com Signed-off-by: Mark Brown --- sound/soc/codecs/rt5640.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/sound/soc/codecs/rt5640.c b/sound/soc/codecs/rt5640.c index 1414ad15d01c..a5674c227b3a 100644 --- a/sound/soc/codecs/rt5640.c +++ b/sound/soc/codecs/rt5640.c @@ -339,9 +339,9 @@ static bool rt5640_readable_register(struct device *dev, unsigned int reg) } static const DECLARE_TLV_DB_SCALE(out_vol_tlv, -4650, 150, 0); -static const DECLARE_TLV_DB_SCALE(dac_vol_tlv, -65625, 375, 0); +static const DECLARE_TLV_DB_MINMAX(dac_vol_tlv, -6562, 0); static const DECLARE_TLV_DB_SCALE(in_vol_tlv, -3450, 150, 0); -static const DECLARE_TLV_DB_SCALE(adc_vol_tlv, -17625, 375, 0); +static const DECLARE_TLV_DB_MINMAX(adc_vol_tlv, -1762, 3000); static const DECLARE_TLV_DB_SCALE(adc_bst_tlv, 0, 1200, 0); /* {0, +20, +24, +30, +35, +40, +44, +50, +52} dB */ From e4ffab875d32bf4ffa37b5cd725ace9e15d1707d Mon Sep 17 00:00:00 2001 From: Hans de Goede Date: Fri, 26 Feb 2021 15:38:14 +0100 Subject: [PATCH 015/587] ASoC: rt5651: Fix dac- and adc- vol-tlv values being off by a factor of 10 The adc_vol_tlv volume-control has a range from -17.625 dB to +30 dB, not -176.25 dB to + 300 dB. This wrong scale is esp. a problem in userspace apps which translate the dB scale to a linear scale. With the logarithmic dB scale being of by a factor of 10 we loose all precision in the lower area of the range when apps translate things to a linear scale. E.g. the 0 dB default, which corresponds with a value of 47 of the 0 - 127 range for the control, would be shown as 0/100 in alsa-mixer. Since the centi-dB values used in the TLV struct cannot represent the 0.375 dB step size used by these controls, change the TLV definition for them to specify a min and max value instead of min + stepsize. Note this mirrors commit 3f31f7d9b540 ("ASoC: rt5670: Fix dac- and adc- vol-tlv values being off by a factor of 10") which made the exact same change to the rt5670 codec driver. Signed-off-by: Hans de Goede Link: https://lore.kernel.org/r/20210226143817.84287-3-hdegoede@redhat.com Signed-off-by: Mark Brown --- sound/soc/codecs/rt5651.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/sound/soc/codecs/rt5651.c b/sound/soc/codecs/rt5651.c index d198e191fb0c..e59fdc81dbd4 100644 --- a/sound/soc/codecs/rt5651.c +++ b/sound/soc/codecs/rt5651.c @@ -285,9 +285,9 @@ static bool rt5651_readable_register(struct device *dev, unsigned int reg) } static const DECLARE_TLV_DB_SCALE(out_vol_tlv, -4650, 150, 0); -static const DECLARE_TLV_DB_SCALE(dac_vol_tlv, -65625, 375, 0); +static const DECLARE_TLV_DB_MINMAX(dac_vol_tlv, -6562, 0); static const DECLARE_TLV_DB_SCALE(in_vol_tlv, -3450, 150, 0); -static const DECLARE_TLV_DB_SCALE(adc_vol_tlv, -17625, 375, 0); +static const DECLARE_TLV_DB_MINMAX(adc_vol_tlv, -1762, 3000); static const DECLARE_TLV_DB_SCALE(adc_bst_tlv, 0, 1200, 0); /* {0, +20, +24, +30, +35, +40, +44, +50, +52} dB */ From d74fcdc51afd431ca9d956e032e14d12f0ee4153 Mon Sep 17 00:00:00 2001 From: Benjamin Rood Date: Fri, 19 Feb 2021 13:33:08 -0500 Subject: [PATCH 016/587] ASoC: sgtl5000: set DAP_AVC_CTRL register to correct default value on probe According to the SGTL5000 datasheet [1], the DAP_AVC_CTRL register has the following bit field definitions: | BITS | FIELD | RW | RESET | DEFINITION | | 15 | RSVD | RO | 0x0 | Reserved | | 14 | RSVD | RW | 0x1 | Reserved | | 13:12 | MAX_GAIN | RW | 0x1 | Max Gain of AVC in expander mode | | 11:10 | RSVD | RO | 0x0 | Reserved | | 9:8 | LBI_RESP | RW | 0x1 | Integrator Response | | 7:6 | RSVD | RO | 0x0 | Reserved | | 5 | HARD_LMT_EN | RW | 0x0 | Enable hard limiter mode | | 4:1 | RSVD | RO | 0x0 | Reserved | | 0 | EN | RW | 0x0 | Enable/Disable AVC | The original default value written to the DAP_AVC_CTRL register during sgtl5000_i2c_probe() was 0x0510. This would incorrectly write values to bits 4 and 10, which are defined as RESERVED. It would also not set bits 12 and 14 to their correct RESET values of 0x1, and instead set them to 0x0. While the DAP_AVC module is effectively disabled because the EN bit is 0, this default value is still writing invalid values to registers that are marked as read-only and RESERVED as well as not setting bits 12 and 14 to their correct default values as defined by the datasheet. The correct value that should be written to the DAP_AVC_CTRL register is 0x5100, which configures the register bits to the default values defined by the datasheet, and prevents any writes to bits defined as 'read-only'. Generally speaking, it is best practice to NOT attempt to write values to registers/bits defined as RESERVED, as it generally produces unwanted/undefined behavior, or errors. Also, all credit for this patch should go to my colleague Dan MacDonald for finding this error in the first place. [1] https://www.nxp.com/docs/en/data-sheet/SGTL5000.pdf Signed-off-by: Benjamin Rood Reviewed-by: Fabio Estevam Link: https://lore.kernel.org/r/20210219183308.GA2117@ubuntu-dev Signed-off-by: Mark Brown --- sound/soc/codecs/sgtl5000.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sound/soc/codecs/sgtl5000.c b/sound/soc/codecs/sgtl5000.c index 73551e36695e..6d9bb256a2cf 100644 --- a/sound/soc/codecs/sgtl5000.c +++ b/sound/soc/codecs/sgtl5000.c @@ -71,7 +71,7 @@ static const struct reg_default sgtl5000_reg_defaults[] = { { SGTL5000_DAP_EQ_BASS_BAND4, 0x002f }, { SGTL5000_DAP_MAIN_CHAN, 0x8000 }, { SGTL5000_DAP_MIX_CHAN, 0x0000 }, - { SGTL5000_DAP_AVC_CTRL, 0x0510 }, + { SGTL5000_DAP_AVC_CTRL, 0x5100 }, { SGTL5000_DAP_AVC_THRESHOLD, 0x1473 }, { SGTL5000_DAP_AVC_ATTACK, 0x0028 }, { SGTL5000_DAP_AVC_DECAY, 0x0050 }, From 4d4e677a68e770b84c87d1438d9f4e161658536a Mon Sep 17 00:00:00 2001 From: Hans de Goede Date: Sun, 28 Feb 2021 17:04:41 +0100 Subject: [PATCH 017/587] ASoC: es8316: Simplify adc_pga_gain_tlv table Most steps in this table are steps of 3dB (300 centi-dB), so we can simplify the table. This not only reduces the amount of space it takes inside the kernel, this also makes alsa-lib's mixer code actually accept the table, where as before this change alsa-lib saw the "ADC PGA Gain" control as a control without a dB scale. Signed-off-by: Hans de Goede Link: https://lore.kernel.org/r/20210228160441.241110-1-hdegoede@redhat.com Signed-off-by: Mark Brown --- sound/soc/codecs/es8316.c | 9 ++------- 1 file changed, 2 insertions(+), 7 deletions(-) diff --git a/sound/soc/codecs/es8316.c b/sound/soc/codecs/es8316.c index d632055370e0..067757d1d70a 100644 --- a/sound/soc/codecs/es8316.c +++ b/sound/soc/codecs/es8316.c @@ -63,13 +63,8 @@ static const SNDRV_CTL_TLVD_DECLARE_DB_RANGE(adc_pga_gain_tlv, 1, 1, TLV_DB_SCALE_ITEM(0, 0, 0), 2, 2, TLV_DB_SCALE_ITEM(250, 0, 0), 3, 3, TLV_DB_SCALE_ITEM(450, 0, 0), - 4, 4, TLV_DB_SCALE_ITEM(700, 0, 0), - 5, 5, TLV_DB_SCALE_ITEM(1000, 0, 0), - 6, 6, TLV_DB_SCALE_ITEM(1300, 0, 0), - 7, 7, TLV_DB_SCALE_ITEM(1600, 0, 0), - 8, 8, TLV_DB_SCALE_ITEM(1800, 0, 0), - 9, 9, TLV_DB_SCALE_ITEM(2100, 0, 0), - 10, 10, TLV_DB_SCALE_ITEM(2400, 0, 0), + 4, 7, TLV_DB_SCALE_ITEM(700, 300, 0), + 8, 10, TLV_DB_SCALE_ITEM(1800, 300, 0), ); static const SNDRV_CTL_TLVD_DECLARE_DB_RANGE(hpout_vol_tlv, From a3c30b0cb6d05f5bf66d1a5d42e876f31753a447 Mon Sep 17 00:00:00 2001 From: Nicolas MURE Date: Mon, 1 Mar 2021 16:27:26 +0100 Subject: [PATCH 018/587] ALSA: usb-audio: Add Pioneer DJM-850 to quirks-table Declare the Pioneer DJM-850 interfaces for capture and playback. See https://github.com/nm2107/Pioneer-DJM-850-driver-reverse-engineering/blob/172fb9a61055960c88c67b7c416fe5bf3609807b/doc/usb-device-specifications.md for the complete device spec. Signed-off-by: Nicolas MURE Link: https://lore.kernel.org/r/20210301152729.18094-2-nicolas.mure2019@gmail.com Signed-off-by: Takashi Iwai --- sound/usb/quirks-table.h | 63 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 63 insertions(+) diff --git a/sound/usb/quirks-table.h b/sound/usb/quirks-table.h index 1165a5ac60f2..9716a9f7c095 100644 --- a/sound/usb/quirks-table.h +++ b/sound/usb/quirks-table.h @@ -3817,6 +3817,69 @@ AU0828_DEVICE(0x2040, 0x7270, "Hauppauge", "HVR-950Q"), } } }, +{ + /* + * Pioneer DJ DJM-850 + * 8 channels playback and 8 channels capture @ 44.1/48/96kHz S24LE + * Playback on EP 0x05 + * Capture on EP 0x86 + */ + USB_DEVICE_VENDOR_SPEC(0x08e4, 0x0163), + .driver_info = (unsigned long) &(const struct snd_usb_audio_quirk) { + .ifnum = QUIRK_ANY_INTERFACE, + .type = QUIRK_COMPOSITE, + .data = (const struct snd_usb_audio_quirk[]) { + { + .ifnum = 0, + .type = QUIRK_AUDIO_FIXED_ENDPOINT, + .data = &(const struct audioformat) { + .formats = SNDRV_PCM_FMTBIT_S24_3LE, + .channels = 8, + .iface = 0, + .altsetting = 1, + .altset_idx = 1, + .endpoint = 0x05, + .ep_attr = USB_ENDPOINT_XFER_ISOC| + USB_ENDPOINT_SYNC_ASYNC| + USB_ENDPOINT_USAGE_DATA, + .rates = SNDRV_PCM_RATE_44100| + SNDRV_PCM_RATE_48000| + SNDRV_PCM_RATE_96000, + .rate_min = 44100, + .rate_max = 96000, + .nr_rates = 3, + .rate_table = (unsigned int[]) { 44100, 48000, 96000 } + } + }, + { + .ifnum = 0, + .type = QUIRK_AUDIO_FIXED_ENDPOINT, + .data = &(const struct audioformat) { + .formats = SNDRV_PCM_FMTBIT_S24_3LE, + .channels = 8, + .iface = 0, + .altsetting = 1, + .altset_idx = 1, + .endpoint = 0x86, + .ep_idx = 1, + .ep_attr = USB_ENDPOINT_XFER_ISOC| + USB_ENDPOINT_SYNC_ASYNC| + USB_ENDPOINT_USAGE_DATA, + .rates = SNDRV_PCM_RATE_44100| + SNDRV_PCM_RATE_48000| + SNDRV_PCM_RATE_96000, + .rate_min = 44100, + .rate_max = 96000, + .nr_rates = 3, + .rate_table = (unsigned int[]) { 44100, 48000, 96000 } + } + }, + { + .ifnum = -1 + } + } + } +}, { /* * Pioneer DJ DJM-450 From 7687850b95b4883b7a4778be45576d8288603ee6 Mon Sep 17 00:00:00 2001 From: Nicolas MURE Date: Mon, 1 Mar 2021 16:27:27 +0100 Subject: [PATCH 019/587] ALSA: usb-audio: Declare Pioneer DJM-850 mixer controls Declare audio capture controls to choose the audio source, and also to set the capture level (in dB). See https://github.com/nm2107/Pioneer-DJM-850-driver-reverse-engineering/blob/172fb9a61055960c88c67b7c416fe5bf3609807b/doc/windows-djm-850-setting-utility/mixer-output-tab/README.md Signed-off-by: Nicolas MURE Link: https://lore.kernel.org/r/20210301152729.18094-3-nicolas.mure2019@gmail.com Signed-off-by: Takashi Iwai --- sound/usb/mixer_quirks.c | 32 +++++++++++++++++++++++++++++--- 1 file changed, 29 insertions(+), 3 deletions(-) diff --git a/sound/usb/mixer_quirks.c b/sound/usb/mixer_quirks.c index 08873d2afe4d..b325b6597d91 100644 --- a/sound/usb/mixer_quirks.c +++ b/sound/usb/mixer_quirks.c @@ -2649,9 +2649,11 @@ static int snd_bbfpro_controls_create(struct usb_mixer_interface *mixer) #define SND_DJM_DEVICE_SHIFT 24 // device table index +// used for the snd_djm_devices table, so please update accordingly #define SND_DJM_250MK2_IDX 0x0 #define SND_DJM_750_IDX 0x1 -#define SND_DJM_900NXS2_IDX 0x2 +#define SND_DJM_850_IDX 0x2 +#define SND_DJM_900NXS2_IDX 0x3 #define SND_DJM_CTL(_name, suffix, _default_value, _windex) { \ @@ -2733,11 +2735,12 @@ static const char *snd_djm_get_label(u16 wvalue, u16 windex) } }; - -// DJM-250MK2 +// common DJM capture level option values static const u16 snd_djm_opts_cap_level[] = { 0x0000, 0x0100, 0x0200, 0x0300 }; + +// DJM-250MK2 static const u16 snd_djm_opts_250mk2_cap1[] = { 0x0103, 0x0100, 0x0106, 0x0107, 0x0108, 0x0109, 0x010d, 0x010a }; @@ -2781,6 +2784,25 @@ static const struct snd_djm_ctl snd_djm_ctls_750[] = { }; +// DJM-850 +static const u16 snd_djm_opts_850_cap1[] = { + 0x0100, 0x0103, 0x0106, 0x0107, 0x0108, 0x0109, 0x010a, 0x010f }; +static const u16 snd_djm_opts_850_cap2[] = { + 0x0200, 0x0201, 0x0206, 0x0207, 0x0208, 0x0209, 0x020a, 0x020f }; +static const u16 snd_djm_opts_850_cap3[] = { + 0x0300, 0x0301, 0x0306, 0x0307, 0x0308, 0x0309, 0x030a, 0x030f }; +static const u16 snd_djm_opts_850_cap4[] = { + 0x0400, 0x0403, 0x0406, 0x0407, 0x0408, 0x0409, 0x040a, 0x040f }; + +static const struct snd_djm_ctl snd_djm_ctls_850[] = { + SND_DJM_CTL("Capture Level", cap_level, 0, SND_DJM_WINDEX_CAPLVL), + SND_DJM_CTL("Ch1 Input", 850_cap1, 1, SND_DJM_WINDEX_CAP), + SND_DJM_CTL("Ch2 Input", 850_cap2, 0, SND_DJM_WINDEX_CAP), + SND_DJM_CTL("Ch3 Input", 850_cap3, 0, SND_DJM_WINDEX_CAP), + SND_DJM_CTL("Ch4 Input", 850_cap4, 1, SND_DJM_WINDEX_CAP) +}; + + // DJM-900NXS2 static const u16 snd_djm_opts_900nxs2_cap1[] = { 0x0100, 0x0102, 0x0103, 0x0106, 0x0107, 0x0108, 0x0109, 0x010a }; @@ -2806,6 +2828,7 @@ static const struct snd_djm_ctl snd_djm_ctls_900nxs2[] = { static const struct snd_djm_device snd_djm_devices[] = { SND_DJM_DEVICE(250mk2), SND_DJM_DEVICE(750), + SND_DJM_DEVICE(850), SND_DJM_DEVICE(900nxs2) }; @@ -3045,6 +3068,9 @@ int snd_usb_mixer_apply_create_quirk(struct usb_mixer_interface *mixer) case USB_ID(0x08e4, 0x017f): /* Pioneer DJ DJM-750 */ err = snd_djm_controls_create(mixer, SND_DJM_750_IDX); break; + case USB_ID(0x08e4, 0x0163): /* Pioneer DJ DJM-850 */ + err = snd_djm_controls_create(mixer, SND_DJM_850_IDX); + break; case USB_ID(0x2b73, 0x000a): /* Pioneer DJ DJM-900NXS2 */ err = snd_djm_controls_create(mixer, SND_DJM_900NXS2_IDX); break; From 1a2a94a4392d5d1e5e25cc127573452f4c7fa9b8 Mon Sep 17 00:00:00 2001 From: Nicolas MURE Date: Mon, 1 Mar 2021 16:27:28 +0100 Subject: [PATCH 020/587] ALSA: usb-audio: Configure Pioneer DJM-850 samplerate Send an `URB_CONTROL out` USB frame to the device to configure its samplerate. This should be done before using the device for audio streaming (capture or playback). See https://github.com/nm2107/Pioneer-DJM-850-driver-reverse-engineering/blob/172fb9a61055960c88c67b7c416fe5bf3609807b/doc/windows-dvs/framerate-setting/README.md Signed-off-by: Nicolas MURE Link: https://lore.kernel.org/r/20210301152729.18094-4-nicolas.mure2019@gmail.com Signed-off-by: Takashi Iwai --- sound/usb/quirks.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/sound/usb/quirks.c b/sound/usb/quirks.c index 737b2729c0d3..d02dac5fcd40 100644 --- a/sound/usb/quirks.c +++ b/sound/usb/quirks.c @@ -1503,6 +1503,9 @@ void snd_usb_set_format_quirk(struct snd_usb_substream *subs, case USB_ID(0x2b73, 0x0013): /* Pioneer DJM-450 */ pioneer_djm_set_format_quirk(subs, 0x0082); break; + case USB_ID(0x08e4, 0x0163): /* Pioneer DJM-850 */ + pioneer_djm_set_format_quirk(subs, 0x0086); + break; } } From b8db8be812cb2c08cd8f6d12c6c773c198be83f1 Mon Sep 17 00:00:00 2001 From: Nicolas MURE Date: Mon, 1 Mar 2021 16:27:29 +0100 Subject: [PATCH 021/587] ALSA: usb-audio: fix Pioneer DJM-850 control label info Unlike the other DJM, the value to set the "CD/LINE" and "LINE" capture control options are inverted. This fix makes sure that the displayed info label while using `alsamixer` matches the input switches label on the DJM-850 mixer. Signed-off-by: Nicolas MURE Link: https://lore.kernel.org/r/20210301152729.18094-5-nicolas.mure2019@gmail.com Signed-off-by: Takashi Iwai --- sound/usb/mixer_quirks.c | 28 ++++++++++++++++++++++++---- 1 file changed, 24 insertions(+), 4 deletions(-) diff --git a/sound/usb/mixer_quirks.c b/sound/usb/mixer_quirks.c index b325b6597d91..5b77e8140ba6 100644 --- a/sound/usb/mixer_quirks.c +++ b/sound/usb/mixer_quirks.c @@ -2693,7 +2693,7 @@ static const char *snd_djm_get_label_caplevel(u16 wvalue) } }; -static const char *snd_djm_get_label_cap(u16 wvalue) +static const char *snd_djm_get_label_cap_common(u16 wvalue) { switch (wvalue & 0x00ff) { case SND_DJM_CAP_LINE: return "Control Tone LINE"; @@ -2715,6 +2715,25 @@ static const char *snd_djm_get_label_cap(u16 wvalue) } }; +// The DJM-850 has different values for CD/LINE and LINE capture +// control options than the other DJM declared in this file. +static const char *snd_djm_get_label_cap_850(u16 wvalue) +{ + switch (wvalue & 0x00ff) { + case 0x00: return "Control Tone CD/LINE"; + case 0x01: return "Control Tone LINE"; + default: return snd_djm_get_label_cap_common(wvalue); + } +}; + +static const char *snd_djm_get_label_cap(u8 device_idx, u16 wvalue) +{ + switch (device_idx) { + case SND_DJM_850_IDX: return snd_djm_get_label_cap_850(wvalue); + default: return snd_djm_get_label_cap_common(wvalue); + } +}; + static const char *snd_djm_get_label_pb(u16 wvalue) { switch (wvalue & 0x00ff) { @@ -2725,11 +2744,11 @@ static const char *snd_djm_get_label_pb(u16 wvalue) } }; -static const char *snd_djm_get_label(u16 wvalue, u16 windex) +static const char *snd_djm_get_label(u8 device_idx, u16 wvalue, u16 windex) { switch (windex) { case SND_DJM_WINDEX_CAPLVL: return snd_djm_get_label_caplevel(wvalue); - case SND_DJM_WINDEX_CAP: return snd_djm_get_label_cap(wvalue); + case SND_DJM_WINDEX_CAP: return snd_djm_get_label_cap(device_idx, wvalue); case SND_DJM_WINDEX_PB: return snd_djm_get_label_pb(wvalue); default: return NULL; } @@ -2852,7 +2871,8 @@ static int snd_djm_controls_info(struct snd_kcontrol *kctl, if (info->value.enumerated.item >= noptions) info->value.enumerated.item = noptions - 1; - name = snd_djm_get_label(ctl->options[info->value.enumerated.item], + name = snd_djm_get_label(device_idx, + ctl->options[info->value.enumerated.item], ctl->wIndex); if (!name) return -EINVAL; From d49c3e711c2b79841bc5c5cf5b46144bb681e380 Mon Sep 17 00:00:00 2001 From: dingsenjie Date: Tue, 2 Mar 2021 11:40:53 +0800 Subject: [PATCH 022/587] ALSA: ps3: fix spelling typo of values vaules -> values Signed-off-by: dingsenjie Link: https://lore.kernel.org/r/20210302034053.34524-1-dingsenjie@163.com Signed-off-by: Takashi Iwai --- sound/ppc/snd_ps3_reg.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sound/ppc/snd_ps3_reg.h b/sound/ppc/snd_ps3_reg.h index 566a3189766d..e2212b79335c 100644 --- a/sound/ppc/snd_ps3_reg.h +++ b/sound/ppc/snd_ps3_reg.h @@ -308,7 +308,7 @@ Indicates Interrupt status, which interrupt has occurred, and can clear each interrupt in this register. Writing 1b to a field containing 1b clears field and de-asserts interrupt. Writing 0b to a field has no effect. -Field vaules are the following: +Field values are the following: 0 - Interrupt hasn't occurred. 1 - Interrupt has occurred. From 290c323008db6e3a44d981a46b56f7f166979a04 Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Mon, 1 Mar 2021 18:34:10 -0600 Subject: [PATCH 023/587] ASoC: SOF: Intel: unregister DMIC device on probe error We only unregister the platform device during the .remove operation, but if the probe fails we will never reach this sequence. Suggested-by: Bard Liao Fixes: dd96daca6c83e ("ASoC: SOF: Intel: Add APL/CNL HW DSP support") Signed-off-by: Pierre-Louis Bossart Reviewed-by: Ranjani Sridharan Reviewed-by: Guennadi Liakhovetski Link: https://lore.kernel.org/r/20210302003410.1178535-1-pierre-louis.bossart@linux.intel.com Signed-off-by: Mark Brown --- sound/soc/sof/intel/hda.c | 1 + 1 file changed, 1 insertion(+) diff --git a/sound/soc/sof/intel/hda.c b/sound/soc/sof/intel/hda.c index 0dc3a8c0f5e3..001fc9834a19 100644 --- a/sound/soc/sof/intel/hda.c +++ b/sound/soc/sof/intel/hda.c @@ -895,6 +895,7 @@ free_streams: /* dsp_unmap: not currently used */ iounmap(sdev->bar[HDA_DSP_BAR]); hdac_bus_unmap: + platform_device_unregister(hdev->dmic_dev); iounmap(bus->remap_addr); hda_codec_i915_exit(sdev); err: From 60fd71150391cf6be0276f3be1e71f7196547302 Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Tue, 2 Mar 2021 15:54:28 -0600 Subject: [PATCH 024/587] ALSA: vx: fix kernel-doc warning make W=1 warning: sound/drivers/vx/vx_core.c:410: warning: expecting prototype for snd_vx_boot_xilinx(). Prototype was for snd_vx_load_boot_image() instead Signed-off-by: Pierre-Louis Bossart Link: https://lore.kernel.org/r/20210302215430.87309-2-pierre-louis.bossart@linux.intel.com Signed-off-by: Takashi Iwai --- sound/drivers/vx/vx_core.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sound/drivers/vx/vx_core.c b/sound/drivers/vx/vx_core.c index d5c65cab195b..a22e5b1a5458 100644 --- a/sound/drivers/vx/vx_core.c +++ b/sound/drivers/vx/vx_core.c @@ -402,7 +402,7 @@ int vx_send_rih(struct vx_core *chip, int cmd) #define END_OF_RESET_WAIT_TIME 500 /* us */ /** - * snd_vx_boot_xilinx - boot up the xilinx interface + * snd_vx_load_boot_image - boot up the xilinx interface * @chip: VX core instance * @boot: the boot record to load */ From 06495facbb05126017b2badb78d747a0c5d53295 Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Tue, 2 Mar 2021 15:54:29 -0600 Subject: [PATCH 025/587] ALSA: pci: mixart: fix kernel-doc warning make W=1 warning: sound/pci/mixart/mixart_hwdep.c:36: warning: expecting prototype for exit with a timeout(). Prototype was for mixart_wait_nice_for_register_value() instead Signed-off-by: Pierre-Louis Bossart Link: https://lore.kernel.org/r/20210302215430.87309-3-pierre-louis.bossart@linux.intel.com Signed-off-by: Takashi Iwai --- sound/pci/mixart/mixart_hwdep.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/sound/pci/mixart/mixart_hwdep.c b/sound/pci/mixart/mixart_hwdep.c index 13dcb2fd0a85..f579f7698bba 100644 --- a/sound/pci/mixart/mixart_hwdep.c +++ b/sound/pci/mixart/mixart_hwdep.c @@ -22,7 +22,8 @@ /** - * wait for a value on a peudo register, exit with a timeout + * mixart_wait_nice_for_register_value - wait for a value on a peudo register, + * exit with a timeout * * @mgr: pointer to miXart manager structure * @offset: unsigned pseudo_register base + offset of value From 2c48653c1bc3aa6894e45e6037c7693949008816 Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Tue, 2 Mar 2021 15:54:30 -0600 Subject: [PATCH 026/587] ALSA: pci: vx222: fix kernel-doc warning make W=1 warnings: sound/pci/vx222/vx222_ops.c:86: warning: expecting prototype for snd_vx_inb(). Prototype was for vx2_inb() instead sound/pci/vx222/vx222_ops.c:97: warning: expecting prototype for snd_vx_outb(). Prototype was for vx2_outb() instead sound/pci/vx222/vx222_ops.c:110: warning: expecting prototype for snd_vx_inl(). Prototype was for vx2_inl() instead sound/pci/vx222/vx222_ops.c:121: warning: expecting prototype for snd_vx_outl(). Prototype was for vx2_outl() instead sound/pci/vx222/vx222_ops.c:221: warning: expecting prototype for vx_setup_pseudo_dma(). Prototype was for vx2_setup_pseudo_dma() instead Signed-off-by: Pierre-Louis Bossart Link: https://lore.kernel.org/r/20210302215430.87309-4-pierre-louis.bossart@linux.intel.com Signed-off-by: Takashi Iwai --- sound/pci/vx222/vx222_ops.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/sound/pci/vx222/vx222_ops.c b/sound/pci/vx222/vx222_ops.c index 23d4338dc553..a05537202738 100644 --- a/sound/pci/vx222/vx222_ops.c +++ b/sound/pci/vx222/vx222_ops.c @@ -78,7 +78,7 @@ static inline unsigned long vx2_reg_addr(struct vx_core *_chip, int reg) } /** - * snd_vx_inb - read a byte from the register + * vx2_inb - read a byte from the register * @chip: VX core instance * @offset: register enum */ @@ -88,7 +88,7 @@ static unsigned char vx2_inb(struct vx_core *chip, int offset) } /** - * snd_vx_outb - write a byte on the register + * vx2_outb - write a byte on the register * @chip: VX core instance * @offset: the register offset * @val: the value to write @@ -102,7 +102,7 @@ static void vx2_outb(struct vx_core *chip, int offset, unsigned char val) } /** - * snd_vx_inl - read a 32bit word from the register + * vx2_inl - read a 32bit word from the register * @chip: VX core instance * @offset: register enum */ @@ -112,7 +112,7 @@ static unsigned int vx2_inl(struct vx_core *chip, int offset) } /** - * snd_vx_outl - write a 32bit word on the register + * vx2_outl - write a 32bit word on the register * @chip: VX core instance * @offset: the register enum * @val: the value to write @@ -213,7 +213,7 @@ static int vx2_test_xilinx(struct vx_core *_chip) /** - * vx_setup_pseudo_dma - set up the pseudo dma read/write mode. + * vx2_setup_pseudo_dma - set up the pseudo dma read/write mode. * @chip: VX core instance * @do_write: 0 = read, 1 = set up for DMA write */ From c014170408bcd2e8fc726802ed16794d358742ff Mon Sep 17 00:00:00 2001 From: Jon Hunter Date: Wed, 3 Mar 2021 11:55:26 +0000 Subject: [PATCH 027/587] ASoC: soc-core: Prevent warning if no DMI table is present Many systems do not use ACPI and hence do not provide a DMI table. On non-ACPI systems a warning, such as the following, is printed on boot. WARNING KERN tegra-audio-graph-card sound: ASoC: no DMI vendor name! The variable 'dmi_available' is not exported and so currently cannot be used by kernel modules without adding an accessor. However, it is possible to use the function is_acpi_device_node() to determine if the sound card is an ACPI device and hence indicate if we expect a DMI table to be present. Therefore, call is_acpi_device_node() to see if we are using ACPI and only parse the DMI table if we are booting with ACPI. Signed-off-by: Jon Hunter Link: https://lore.kernel.org/r/20210303115526.419458-1-jonathanh@nvidia.com Signed-off-by: Mark Brown --- sound/soc/soc-core.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/sound/soc/soc-core.c b/sound/soc/soc-core.c index f6d4e99b590c..0cffc9527e28 100644 --- a/sound/soc/soc-core.c +++ b/sound/soc/soc-core.c @@ -31,6 +31,7 @@ #include #include #include +#include #include #include #include @@ -1573,6 +1574,9 @@ int snd_soc_set_dmi_name(struct snd_soc_card *card, const char *flavour) if (card->long_name) return 0; /* long name already set by driver or from DMI */ + if (!is_acpi_device_node(card->dev->fwnode)) + return 0; + /* make up dmi long name as: vendor-product-version-board */ vendor = dmi_get_system_info(DMI_BOARD_VENDOR); if (!vendor || !is_dmi_valid(vendor)) { From 04f7791b7a4ba6ff3f53b3f3978b353924d10e78 Mon Sep 17 00:00:00 2001 From: Hui Wang Date: Fri, 5 Mar 2021 17:26:08 +0800 Subject: [PATCH 028/587] ALSA: hda - bind headset buttons to the headphone jack With the HDA driver, if the headset buttons are supported, an audio Jack will be created for them. This audio Jack is a bit confusing to users since it can't report headphone/mic insertion events but it claims to support these events. And in addition, the driver already builds a headphone Jack and a mic Jack, and most of those buttons are used for headphone playback, so do some change to bind those buttons to the headphone Jack. After this change, the key events are generated from NID 0x55, and are reported to the input layer via headphone jack (NID 0x21). If there is no headphone Jack, then build an audio jack to support those buttons same as previously. Signed-off-by: Hui Wang Link: https://lore.kernel.org/r/20210305092608.109599-1-hui.wang@canonical.com Signed-off-by: Takashi Iwai --- sound/pci/hda/hda_jack.c | 73 ++++++++++++++++++++++++++++++++++- sound/pci/hda/hda_jack.h | 8 ++++ sound/pci/hda/patch_realtek.c | 15 +++++-- 3 files changed, 91 insertions(+), 5 deletions(-) diff --git a/sound/pci/hda/hda_jack.c b/sound/pci/hda/hda_jack.c index b8b568046592..30e9ebf1f341 100644 --- a/sound/pci/hda/hda_jack.c +++ b/sound/pci/hda/hda_jack.c @@ -388,6 +388,69 @@ int snd_hda_jack_set_gating_jack(struct hda_codec *codec, hda_nid_t gated_nid, } EXPORT_SYMBOL_GPL(snd_hda_jack_set_gating_jack); +/** + * snd_hda_jack_bind_keymap - bind keys generated from one NID to another jack. + * @codec: the HDA codec + * @key_nid: key event is generated by this pin NID + * @keymap: map of key type and key code + * @jack_nid: key reports to the jack of this pin NID + * + * This function is used in the case of key is generated from one NID while is + * reported to the jack of another NID. + */ +int snd_hda_jack_bind_keymap(struct hda_codec *codec, hda_nid_t key_nid, + const struct hda_jack_keymap *keymap, + hda_nid_t jack_nid) +{ + const struct hda_jack_keymap *map; + struct hda_jack_tbl *key_gen = snd_hda_jack_tbl_get(codec, key_nid); + struct hda_jack_tbl *report_to = snd_hda_jack_tbl_get(codec, jack_nid); + + WARN_ON(codec->dp_mst); + + if (!key_gen || !report_to || !report_to->jack) + return -EINVAL; + + key_gen->key_report_jack = jack_nid; + + if (keymap) + for (map = keymap; map->type; map++) + snd_jack_set_key(report_to->jack, map->type, map->key); + + return 0; +} +EXPORT_SYMBOL_GPL(snd_hda_jack_bind_keymap); + +/** + * snd_hda_jack_set_button_state - report button event to the hda_jack_tbl button_state. + * @codec: the HDA codec + * @jack_nid: the button event reports to the jack_tbl of this NID + * @button_state: the button event captured by codec + * + * Codec driver calls this function to report the button event. + */ +void snd_hda_jack_set_button_state(struct hda_codec *codec, hda_nid_t jack_nid, + int button_state) +{ + struct hda_jack_tbl *jack = snd_hda_jack_tbl_get(codec, jack_nid); + + if (!jack) + return; + + if (jack->key_report_jack) { + struct hda_jack_tbl *report_to = + snd_hda_jack_tbl_get(codec, jack->key_report_jack); + + if (report_to) { + report_to->button_state = button_state; + return; + } + } + + jack->button_state = button_state; +} +EXPORT_SYMBOL_GPL(snd_hda_jack_set_button_state); + /** * snd_hda_jack_report_sync - sync the states of all jacks and report if changed * @codec: the HDA codec @@ -651,7 +714,15 @@ void snd_hda_jack_unsol_event(struct hda_codec *codec, unsigned int res) } if (!event) return; - event->jack_dirty = 1; + + if (event->key_report_jack) { + struct hda_jack_tbl *report_to = + snd_hda_jack_tbl_get_mst(codec, event->key_report_jack, + event->dev_id); + if (report_to) + report_to->jack_dirty = 1; + } else + event->jack_dirty = 1; call_jack_callback(codec, res, event); snd_hda_jack_report_sync(codec); diff --git a/sound/pci/hda/hda_jack.h b/sound/pci/hda/hda_jack.h index 8ceaf0ef5df1..2abf7aac243a 100644 --- a/sound/pci/hda/hda_jack.h +++ b/sound/pci/hda/hda_jack.h @@ -40,6 +40,7 @@ struct hda_jack_tbl { unsigned int block_report:1; /* in a transitional state - do not report to userspace */ hda_nid_t gating_jack; /* valid when gating jack plugged */ hda_nid_t gated_jack; /* gated is dependent on this jack */ + hda_nid_t key_report_jack; /* key reports to this jack */ int type; int button_state; struct snd_jack *jack; @@ -99,6 +100,13 @@ snd_hda_jack_detect_enable_callback(struct hda_codec *codec, hda_nid_t nid, int snd_hda_jack_set_gating_jack(struct hda_codec *codec, hda_nid_t gated_nid, hda_nid_t gating_nid); +int snd_hda_jack_bind_keymap(struct hda_codec *codec, hda_nid_t key_nid, + const struct hda_jack_keymap *keymap, + hda_nid_t jack_nid); + +void snd_hda_jack_set_button_state(struct hda_codec *codec, hda_nid_t jack_nid, + int button_state); + u32 snd_hda_jack_pin_sense(struct hda_codec *codec, hda_nid_t nid, int dev_id); /* the jack state returned from snd_hda_jack_detect_state() */ diff --git a/sound/pci/hda/patch_realtek.c b/sound/pci/hda/patch_realtek.c index 4871507cd4bf..ee8d70afe636 100644 --- a/sound/pci/hda/patch_realtek.c +++ b/sound/pci/hda/patch_realtek.c @@ -3102,7 +3102,7 @@ static void alc_headset_btn_callback(struct hda_codec *codec, if (jack->unsol_res & (7 << 10)) report |= SND_JACK_BTN_3; - jack->jack->button_state = report; + snd_hda_jack_set_button_state(codec, jack->nid, report); } static void alc_disable_headset_jack_key(struct hda_codec *codec) @@ -3163,16 +3163,23 @@ static void alc_fixup_headset_jack(struct hda_codec *codec, const struct hda_fixup *fix, int action) { struct alc_spec *spec = codec->spec; + hda_nid_t hp_pin; switch (action) { case HDA_FIXUP_ACT_PRE_PROBE: spec->has_hs_key = 1; snd_hda_jack_detect_enable_callback(codec, 0x55, alc_headset_btn_callback); - snd_hda_jack_add_kctl(codec, 0x55, "Headset Jack", false, - SND_JACK_HEADSET, alc_headset_btn_keymap); break; - case HDA_FIXUP_ACT_INIT: + case HDA_FIXUP_ACT_BUILD: + hp_pin = alc_get_hp_pin(spec); + if (!hp_pin || snd_hda_jack_bind_keymap(codec, 0x55, + alc_headset_btn_keymap, + hp_pin)) + snd_hda_jack_add_kctl(codec, 0x55, "Headset Jack", + false, SND_JACK_HEADSET, + alc_headset_btn_keymap); + alc_enable_headset_jack_key(codec); break; } From 0ae0337f929a970ee8d83e0e95e6b8d05562ce3b Mon Sep 17 00:00:00 2001 From: Anton Yakovlev Date: Tue, 2 Mar 2021 17:47:01 +0100 Subject: [PATCH 029/587] uapi: virtio_ids: add a sound device type ID from OASIS spec The OASIS virtio spec defines a sound device type ID that is not present in the header yet. Signed-off-by: Anton Yakovlev Link: https://lore.kernel.org/r/20210302164709.3142702-2-anton.yakovlev@opensynergy.com Signed-off-by: Takashi Iwai --- include/uapi/linux/virtio_ids.h | 1 + 1 file changed, 1 insertion(+) diff --git a/include/uapi/linux/virtio_ids.h b/include/uapi/linux/virtio_ids.h index bc1c0621f5ed..029a2e07a7f9 100644 --- a/include/uapi/linux/virtio_ids.h +++ b/include/uapi/linux/virtio_ids.h @@ -51,6 +51,7 @@ #define VIRTIO_ID_PSTORE 22 /* virtio pstore device */ #define VIRTIO_ID_IOMMU 23 /* virtio IOMMU */ #define VIRTIO_ID_MEM 24 /* virtio mem */ +#define VIRTIO_ID_SOUND 25 /* virtio sound */ #define VIRTIO_ID_FS 26 /* virtio filesystem */ #define VIRTIO_ID_PMEM 27 /* virtio pmem */ #define VIRTIO_ID_MAC80211_HWSIM 29 /* virtio mac80211-hwsim */ From de3a9980d8c34b2479173e809afa820473db676a Mon Sep 17 00:00:00 2001 From: Anton Yakovlev Date: Tue, 2 Mar 2021 17:47:02 +0100 Subject: [PATCH 030/587] ALSA: virtio: add virtio sound driver Introduce skeleton of the virtio sound driver. The driver implements the virtio sound device specification, which has become part of the virtio standard. Initial initialization of the device, virtqueues and creation of an empty ALSA sound device. Signed-off-by: Anton Yakovlev Link: https://lore.kernel.org/r/20210302164709.3142702-3-anton.yakovlev@opensynergy.com Signed-off-by: Takashi Iwai --- MAINTAINERS | 9 + include/uapi/linux/virtio_snd.h | 334 ++++++++++++++++++++++++++++++++ sound/Kconfig | 2 + sound/Makefile | 3 +- sound/virtio/Kconfig | 10 + sound/virtio/Makefile | 7 + sound/virtio/virtio_card.c | 324 +++++++++++++++++++++++++++++++ sound/virtio/virtio_card.h | 65 +++++++ 8 files changed, 753 insertions(+), 1 deletion(-) create mode 100644 include/uapi/linux/virtio_snd.h create mode 100644 sound/virtio/Kconfig create mode 100644 sound/virtio/Makefile create mode 100644 sound/virtio/virtio_card.c create mode 100644 sound/virtio/virtio_card.h diff --git a/MAINTAINERS b/MAINTAINERS index d92f85ca831d..a68c543c28f1 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -19086,6 +19086,15 @@ W: https://virtio-mem.gitlab.io/ F: drivers/virtio/virtio_mem.c F: include/uapi/linux/virtio_mem.h +VIRTIO SOUND DRIVER +M: Anton Yakovlev +M: "Michael S. Tsirkin" +L: virtualization@lists.linux-foundation.org +L: alsa-devel@alsa-project.org (moderated for non-subscribers) +S: Maintained +F: include/uapi/linux/virtio_snd.h +F: sound/virtio/* + VIRTUAL BOX GUEST DEVICE DRIVER M: Hans de Goede M: Arnd Bergmann diff --git a/include/uapi/linux/virtio_snd.h b/include/uapi/linux/virtio_snd.h new file mode 100644 index 000000000000..dfe49547a7b0 --- /dev/null +++ b/include/uapi/linux/virtio_snd.h @@ -0,0 +1,334 @@ +/* SPDX-License-Identifier: BSD-3-Clause */ +/* + * Copyright (C) 2021 OpenSynergy GmbH + */ +#ifndef VIRTIO_SND_IF_H +#define VIRTIO_SND_IF_H + +#include + +/******************************************************************************* + * CONFIGURATION SPACE + */ +struct virtio_snd_config { + /* # of available physical jacks */ + __le32 jacks; + /* # of available PCM streams */ + __le32 streams; + /* # of available channel maps */ + __le32 chmaps; +}; + +enum { + /* device virtqueue indexes */ + VIRTIO_SND_VQ_CONTROL = 0, + VIRTIO_SND_VQ_EVENT, + VIRTIO_SND_VQ_TX, + VIRTIO_SND_VQ_RX, + /* # of device virtqueues */ + VIRTIO_SND_VQ_MAX +}; + +/******************************************************************************* + * COMMON DEFINITIONS + */ + +/* supported dataflow directions */ +enum { + VIRTIO_SND_D_OUTPUT = 0, + VIRTIO_SND_D_INPUT +}; + +enum { + /* jack control request types */ + VIRTIO_SND_R_JACK_INFO = 1, + VIRTIO_SND_R_JACK_REMAP, + + /* PCM control request types */ + VIRTIO_SND_R_PCM_INFO = 0x0100, + VIRTIO_SND_R_PCM_SET_PARAMS, + VIRTIO_SND_R_PCM_PREPARE, + VIRTIO_SND_R_PCM_RELEASE, + VIRTIO_SND_R_PCM_START, + VIRTIO_SND_R_PCM_STOP, + + /* channel map control request types */ + VIRTIO_SND_R_CHMAP_INFO = 0x0200, + + /* jack event types */ + VIRTIO_SND_EVT_JACK_CONNECTED = 0x1000, + VIRTIO_SND_EVT_JACK_DISCONNECTED, + + /* PCM event types */ + VIRTIO_SND_EVT_PCM_PERIOD_ELAPSED = 0x1100, + VIRTIO_SND_EVT_PCM_XRUN, + + /* common status codes */ + VIRTIO_SND_S_OK = 0x8000, + VIRTIO_SND_S_BAD_MSG, + VIRTIO_SND_S_NOT_SUPP, + VIRTIO_SND_S_IO_ERR +}; + +/* common header */ +struct virtio_snd_hdr { + __le32 code; +}; + +/* event notification */ +struct virtio_snd_event { + /* VIRTIO_SND_EVT_XXX */ + struct virtio_snd_hdr hdr; + /* optional event data */ + __le32 data; +}; + +/* common control request to query an item information */ +struct virtio_snd_query_info { + /* VIRTIO_SND_R_XXX_INFO */ + struct virtio_snd_hdr hdr; + /* item start identifier */ + __le32 start_id; + /* item count to query */ + __le32 count; + /* item information size in bytes */ + __le32 size; +}; + +/* common item information header */ +struct virtio_snd_info { + /* function group node id (High Definition Audio Specification 7.1.2) */ + __le32 hda_fn_nid; +}; + +/******************************************************************************* + * JACK CONTROL MESSAGES + */ +struct virtio_snd_jack_hdr { + /* VIRTIO_SND_R_JACK_XXX */ + struct virtio_snd_hdr hdr; + /* 0 ... virtio_snd_config::jacks - 1 */ + __le32 jack_id; +}; + +/* supported jack features */ +enum { + VIRTIO_SND_JACK_F_REMAP = 0 +}; + +struct virtio_snd_jack_info { + /* common header */ + struct virtio_snd_info hdr; + /* supported feature bit map (1 << VIRTIO_SND_JACK_F_XXX) */ + __le32 features; + /* pin configuration (High Definition Audio Specification 7.3.3.31) */ + __le32 hda_reg_defconf; + /* pin capabilities (High Definition Audio Specification 7.3.4.9) */ + __le32 hda_reg_caps; + /* current jack connection status (0: disconnected, 1: connected) */ + __u8 connected; + + __u8 padding[7]; +}; + +/* jack remapping control request */ +struct virtio_snd_jack_remap { + /* .code = VIRTIO_SND_R_JACK_REMAP */ + struct virtio_snd_jack_hdr hdr; + /* selected association number */ + __le32 association; + /* selected sequence number */ + __le32 sequence; +}; + +/******************************************************************************* + * PCM CONTROL MESSAGES + */ +struct virtio_snd_pcm_hdr { + /* VIRTIO_SND_R_PCM_XXX */ + struct virtio_snd_hdr hdr; + /* 0 ... virtio_snd_config::streams - 1 */ + __le32 stream_id; +}; + +/* supported PCM stream features */ +enum { + VIRTIO_SND_PCM_F_SHMEM_HOST = 0, + VIRTIO_SND_PCM_F_SHMEM_GUEST, + VIRTIO_SND_PCM_F_MSG_POLLING, + VIRTIO_SND_PCM_F_EVT_SHMEM_PERIODS, + VIRTIO_SND_PCM_F_EVT_XRUNS +}; + +/* supported PCM sample formats */ +enum { + /* analog formats (width / physical width) */ + VIRTIO_SND_PCM_FMT_IMA_ADPCM = 0, /* 4 / 4 bits */ + VIRTIO_SND_PCM_FMT_MU_LAW, /* 8 / 8 bits */ + VIRTIO_SND_PCM_FMT_A_LAW, /* 8 / 8 bits */ + VIRTIO_SND_PCM_FMT_S8, /* 8 / 8 bits */ + VIRTIO_SND_PCM_FMT_U8, /* 8 / 8 bits */ + VIRTIO_SND_PCM_FMT_S16, /* 16 / 16 bits */ + VIRTIO_SND_PCM_FMT_U16, /* 16 / 16 bits */ + VIRTIO_SND_PCM_FMT_S18_3, /* 18 / 24 bits */ + VIRTIO_SND_PCM_FMT_U18_3, /* 18 / 24 bits */ + VIRTIO_SND_PCM_FMT_S20_3, /* 20 / 24 bits */ + VIRTIO_SND_PCM_FMT_U20_3, /* 20 / 24 bits */ + VIRTIO_SND_PCM_FMT_S24_3, /* 24 / 24 bits */ + VIRTIO_SND_PCM_FMT_U24_3, /* 24 / 24 bits */ + VIRTIO_SND_PCM_FMT_S20, /* 20 / 32 bits */ + VIRTIO_SND_PCM_FMT_U20, /* 20 / 32 bits */ + VIRTIO_SND_PCM_FMT_S24, /* 24 / 32 bits */ + VIRTIO_SND_PCM_FMT_U24, /* 24 / 32 bits */ + VIRTIO_SND_PCM_FMT_S32, /* 32 / 32 bits */ + VIRTIO_SND_PCM_FMT_U32, /* 32 / 32 bits */ + VIRTIO_SND_PCM_FMT_FLOAT, /* 32 / 32 bits */ + VIRTIO_SND_PCM_FMT_FLOAT64, /* 64 / 64 bits */ + /* digital formats (width / physical width) */ + VIRTIO_SND_PCM_FMT_DSD_U8, /* 8 / 8 bits */ + VIRTIO_SND_PCM_FMT_DSD_U16, /* 16 / 16 bits */ + VIRTIO_SND_PCM_FMT_DSD_U32, /* 32 / 32 bits */ + VIRTIO_SND_PCM_FMT_IEC958_SUBFRAME /* 32 / 32 bits */ +}; + +/* supported PCM frame rates */ +enum { + VIRTIO_SND_PCM_RATE_5512 = 0, + VIRTIO_SND_PCM_RATE_8000, + VIRTIO_SND_PCM_RATE_11025, + VIRTIO_SND_PCM_RATE_16000, + VIRTIO_SND_PCM_RATE_22050, + VIRTIO_SND_PCM_RATE_32000, + VIRTIO_SND_PCM_RATE_44100, + VIRTIO_SND_PCM_RATE_48000, + VIRTIO_SND_PCM_RATE_64000, + VIRTIO_SND_PCM_RATE_88200, + VIRTIO_SND_PCM_RATE_96000, + VIRTIO_SND_PCM_RATE_176400, + VIRTIO_SND_PCM_RATE_192000, + VIRTIO_SND_PCM_RATE_384000 +}; + +struct virtio_snd_pcm_info { + /* common header */ + struct virtio_snd_info hdr; + /* supported feature bit map (1 << VIRTIO_SND_PCM_F_XXX) */ + __le32 features; + /* supported sample format bit map (1 << VIRTIO_SND_PCM_FMT_XXX) */ + __le64 formats; + /* supported frame rate bit map (1 << VIRTIO_SND_PCM_RATE_XXX) */ + __le64 rates; + /* dataflow direction (VIRTIO_SND_D_XXX) */ + __u8 direction; + /* minimum # of supported channels */ + __u8 channels_min; + /* maximum # of supported channels */ + __u8 channels_max; + + __u8 padding[5]; +}; + +/* set PCM stream format */ +struct virtio_snd_pcm_set_params { + /* .code = VIRTIO_SND_R_PCM_SET_PARAMS */ + struct virtio_snd_pcm_hdr hdr; + /* size of the hardware buffer */ + __le32 buffer_bytes; + /* size of the hardware period */ + __le32 period_bytes; + /* selected feature bit map (1 << VIRTIO_SND_PCM_F_XXX) */ + __le32 features; + /* selected # of channels */ + __u8 channels; + /* selected sample format (VIRTIO_SND_PCM_FMT_XXX) */ + __u8 format; + /* selected frame rate (VIRTIO_SND_PCM_RATE_XXX) */ + __u8 rate; + + __u8 padding; +}; + +/******************************************************************************* + * PCM I/O MESSAGES + */ + +/* I/O request header */ +struct virtio_snd_pcm_xfer { + /* 0 ... virtio_snd_config::streams - 1 */ + __le32 stream_id; +}; + +/* I/O request status */ +struct virtio_snd_pcm_status { + /* VIRTIO_SND_S_XXX */ + __le32 status; + /* current device latency */ + __le32 latency_bytes; +}; + +/******************************************************************************* + * CHANNEL MAP CONTROL MESSAGES + */ +struct virtio_snd_chmap_hdr { + /* VIRTIO_SND_R_CHMAP_XXX */ + struct virtio_snd_hdr hdr; + /* 0 ... virtio_snd_config::chmaps - 1 */ + __le32 chmap_id; +}; + +/* standard channel position definition */ +enum { + VIRTIO_SND_CHMAP_NONE = 0, /* undefined */ + VIRTIO_SND_CHMAP_NA, /* silent */ + VIRTIO_SND_CHMAP_MONO, /* mono stream */ + VIRTIO_SND_CHMAP_FL, /* front left */ + VIRTIO_SND_CHMAP_FR, /* front right */ + VIRTIO_SND_CHMAP_RL, /* rear left */ + VIRTIO_SND_CHMAP_RR, /* rear right */ + VIRTIO_SND_CHMAP_FC, /* front center */ + VIRTIO_SND_CHMAP_LFE, /* low frequency (LFE) */ + VIRTIO_SND_CHMAP_SL, /* side left */ + VIRTIO_SND_CHMAP_SR, /* side right */ + VIRTIO_SND_CHMAP_RC, /* rear center */ + VIRTIO_SND_CHMAP_FLC, /* front left center */ + VIRTIO_SND_CHMAP_FRC, /* front right center */ + VIRTIO_SND_CHMAP_RLC, /* rear left center */ + VIRTIO_SND_CHMAP_RRC, /* rear right center */ + VIRTIO_SND_CHMAP_FLW, /* front left wide */ + VIRTIO_SND_CHMAP_FRW, /* front right wide */ + VIRTIO_SND_CHMAP_FLH, /* front left high */ + VIRTIO_SND_CHMAP_FCH, /* front center high */ + VIRTIO_SND_CHMAP_FRH, /* front right high */ + VIRTIO_SND_CHMAP_TC, /* top center */ + VIRTIO_SND_CHMAP_TFL, /* top front left */ + VIRTIO_SND_CHMAP_TFR, /* top front right */ + VIRTIO_SND_CHMAP_TFC, /* top front center */ + VIRTIO_SND_CHMAP_TRL, /* top rear left */ + VIRTIO_SND_CHMAP_TRR, /* top rear right */ + VIRTIO_SND_CHMAP_TRC, /* top rear center */ + VIRTIO_SND_CHMAP_TFLC, /* top front left center */ + VIRTIO_SND_CHMAP_TFRC, /* top front right center */ + VIRTIO_SND_CHMAP_TSL, /* top side left */ + VIRTIO_SND_CHMAP_TSR, /* top side right */ + VIRTIO_SND_CHMAP_LLFE, /* left LFE */ + VIRTIO_SND_CHMAP_RLFE, /* right LFE */ + VIRTIO_SND_CHMAP_BC, /* bottom center */ + VIRTIO_SND_CHMAP_BLC, /* bottom left center */ + VIRTIO_SND_CHMAP_BRC /* bottom right center */ +}; + +/* maximum possible number of channels */ +#define VIRTIO_SND_CHMAP_MAX_SIZE 18 + +struct virtio_snd_chmap_info { + /* common header */ + struct virtio_snd_info hdr; + /* dataflow direction (VIRTIO_SND_D_XXX) */ + __u8 direction; + /* # of valid channel position values */ + __u8 channels; + /* channel position values (VIRTIO_SND_CHMAP_XXX) */ + __u8 positions[VIRTIO_SND_CHMAP_MAX_SIZE]; +}; + +#endif /* VIRTIO_SND_IF_H */ diff --git a/sound/Kconfig b/sound/Kconfig index 36785410fbe1..e56d96d2b11c 100644 --- a/sound/Kconfig +++ b/sound/Kconfig @@ -99,6 +99,8 @@ source "sound/synth/Kconfig" source "sound/xen/Kconfig" +source "sound/virtio/Kconfig" + endif # SND endif # !UML diff --git a/sound/Makefile b/sound/Makefile index 797ecdcd35e2..04ef04b1168f 100644 --- a/sound/Makefile +++ b/sound/Makefile @@ -5,7 +5,8 @@ obj-$(CONFIG_SOUND) += soundcore.o obj-$(CONFIG_DMASOUND) += oss/dmasound/ obj-$(CONFIG_SND) += core/ i2c/ drivers/ isa/ pci/ ppc/ arm/ sh/ synth/ usb/ \ - firewire/ sparc/ spi/ parisc/ pcmcia/ mips/ soc/ atmel/ hda/ x86/ xen/ + firewire/ sparc/ spi/ parisc/ pcmcia/ mips/ soc/ atmel/ hda/ x86/ xen/ \ + virtio/ obj-$(CONFIG_SND_AOA) += aoa/ # This one must be compilable even if sound is configured out diff --git a/sound/virtio/Kconfig b/sound/virtio/Kconfig new file mode 100644 index 000000000000..094cba24ee5b --- /dev/null +++ b/sound/virtio/Kconfig @@ -0,0 +1,10 @@ +# SPDX-License-Identifier: GPL-2.0+ +# Sound card driver for virtio + +config SND_VIRTIO + tristate "Virtio sound driver" + depends on VIRTIO + select SND_PCM + select SND_JACK + help + This is the virtual sound driver for virtio. Say Y or M. diff --git a/sound/virtio/Makefile b/sound/virtio/Makefile new file mode 100644 index 000000000000..8c87ebb9982b --- /dev/null +++ b/sound/virtio/Makefile @@ -0,0 +1,7 @@ +# SPDX-License-Identifier: GPL-2.0+ + +obj-$(CONFIG_SND_VIRTIO) += virtio_snd.o + +virtio_snd-objs := \ + virtio_card.o + diff --git a/sound/virtio/virtio_card.c b/sound/virtio/virtio_card.c new file mode 100644 index 000000000000..5a37056858e9 --- /dev/null +++ b/sound/virtio/virtio_card.c @@ -0,0 +1,324 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * virtio-snd: Virtio sound device + * Copyright (C) 2021 OpenSynergy GmbH + */ +#include +#include +#include +#include +#include + +#include "virtio_card.h" + +static void virtsnd_remove(struct virtio_device *vdev); + +/** + * virtsnd_event_send() - Add an event to the event queue. + * @vqueue: Underlying event virtqueue. + * @event: Event. + * @notify: Indicates whether or not to send a notification to the device. + * @gfp: Kernel flags for memory allocation. + * + * Context: Any context. + */ +static void virtsnd_event_send(struct virtqueue *vqueue, + struct virtio_snd_event *event, bool notify, + gfp_t gfp) +{ + struct scatterlist sg; + struct scatterlist *psgs[1] = { &sg }; + + /* reset event content */ + memset(event, 0, sizeof(*event)); + + sg_init_one(&sg, event, sizeof(*event)); + + if (virtqueue_add_sgs(vqueue, psgs, 0, 1, event, gfp) || !notify) + return; + + if (virtqueue_kick_prepare(vqueue)) + virtqueue_notify(vqueue); +} + +/** + * virtsnd_event_dispatch() - Dispatch an event from the device side. + * @snd: VirtIO sound device. + * @event: VirtIO sound event. + * + * Context: Any context. + */ +static void virtsnd_event_dispatch(struct virtio_snd *snd, + struct virtio_snd_event *event) +{ +} + +/** + * virtsnd_event_notify_cb() - Dispatch all reported events from the event queue. + * @vqueue: Underlying event virtqueue. + * + * This callback function is called upon a vring interrupt request from the + * device. + * + * Context: Interrupt context. + */ +static void virtsnd_event_notify_cb(struct virtqueue *vqueue) +{ + struct virtio_snd *snd = vqueue->vdev->priv; + struct virtio_snd_queue *queue = virtsnd_event_queue(snd); + struct virtio_snd_event *event; + u32 length; + unsigned long flags; + + spin_lock_irqsave(&queue->lock, flags); + do { + virtqueue_disable_cb(vqueue); + while ((event = virtqueue_get_buf(vqueue, &length))) { + virtsnd_event_dispatch(snd, event); + virtsnd_event_send(vqueue, event, true, GFP_ATOMIC); + } + if (unlikely(virtqueue_is_broken(vqueue))) + break; + } while (!virtqueue_enable_cb(vqueue)); + spin_unlock_irqrestore(&queue->lock, flags); +} + +/** + * virtsnd_find_vqs() - Enumerate and initialize all virtqueues. + * @snd: VirtIO sound device. + * + * After calling this function, the event queue is disabled. + * + * Context: Any context. + * Return: 0 on success, -errno on failure. + */ +static int virtsnd_find_vqs(struct virtio_snd *snd) +{ + struct virtio_device *vdev = snd->vdev; + static vq_callback_t *callbacks[VIRTIO_SND_VQ_MAX] = { + [VIRTIO_SND_VQ_EVENT] = virtsnd_event_notify_cb + }; + static const char *names[VIRTIO_SND_VQ_MAX] = { + [VIRTIO_SND_VQ_EVENT] = "virtsnd-event" + }; + struct virtqueue *vqs[VIRTIO_SND_VQ_MAX] = { 0 }; + unsigned int i; + unsigned int n; + int rc; + + rc = virtio_find_vqs(vdev, VIRTIO_SND_VQ_MAX, vqs, callbacks, names, + NULL); + if (rc) { + dev_err(&vdev->dev, "failed to initialize virtqueues\n"); + return rc; + } + + for (i = 0; i < VIRTIO_SND_VQ_MAX; ++i) + snd->queues[i].vqueue = vqs[i]; + + /* Allocate events and populate the event queue */ + virtqueue_disable_cb(vqs[VIRTIO_SND_VQ_EVENT]); + + n = virtqueue_get_vring_size(vqs[VIRTIO_SND_VQ_EVENT]); + + snd->event_msgs = kmalloc_array(n, sizeof(*snd->event_msgs), + GFP_KERNEL); + if (!snd->event_msgs) + return -ENOMEM; + + for (i = 0; i < n; ++i) + virtsnd_event_send(vqs[VIRTIO_SND_VQ_EVENT], + &snd->event_msgs[i], false, GFP_KERNEL); + + return 0; +} + +/** + * virtsnd_enable_event_vq() - Enable the event virtqueue. + * @snd: VirtIO sound device. + * + * Context: Any context. + */ +static void virtsnd_enable_event_vq(struct virtio_snd *snd) +{ + struct virtio_snd_queue *queue = virtsnd_event_queue(snd); + + if (!virtqueue_enable_cb(queue->vqueue)) + virtsnd_event_notify_cb(queue->vqueue); +} + +/** + * virtsnd_disable_event_vq() - Disable the event virtqueue. + * @snd: VirtIO sound device. + * + * Context: Any context. + */ +static void virtsnd_disable_event_vq(struct virtio_snd *snd) +{ + struct virtio_snd_queue *queue = virtsnd_event_queue(snd); + struct virtio_snd_event *event; + u32 length; + unsigned long flags; + + if (queue->vqueue) { + spin_lock_irqsave(&queue->lock, flags); + virtqueue_disable_cb(queue->vqueue); + while ((event = virtqueue_get_buf(queue->vqueue, &length))) + virtsnd_event_dispatch(snd, event); + spin_unlock_irqrestore(&queue->lock, flags); + } +} + +/** + * virtsnd_build_devs() - Read configuration and build ALSA devices. + * @snd: VirtIO sound device. + * + * Context: Any context that permits to sleep. + * Return: 0 on success, -errno on failure. + */ +static int virtsnd_build_devs(struct virtio_snd *snd) +{ + struct virtio_device *vdev = snd->vdev; + struct device *dev = &vdev->dev; + int rc; + + rc = snd_card_new(dev, SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1, + THIS_MODULE, 0, &snd->card); + if (rc < 0) + return rc; + + snd->card->private_data = snd; + + strscpy(snd->card->driver, VIRTIO_SND_CARD_DRIVER, + sizeof(snd->card->driver)); + strscpy(snd->card->shortname, VIRTIO_SND_CARD_NAME, + sizeof(snd->card->shortname)); + if (dev->parent->bus) + snprintf(snd->card->longname, sizeof(snd->card->longname), + VIRTIO_SND_CARD_NAME " at %s/%s/%s", + dev->parent->bus->name, dev_name(dev->parent), + dev_name(dev)); + else + snprintf(snd->card->longname, sizeof(snd->card->longname), + VIRTIO_SND_CARD_NAME " at %s/%s", + dev_name(dev->parent), dev_name(dev)); + + return snd_card_register(snd->card); +} + +/** + * virtsnd_validate() - Validate if the device can be started. + * @vdev: VirtIO parent device. + * + * Context: Any context. + * Return: 0 on success, -EINVAL on failure. + */ +static int virtsnd_validate(struct virtio_device *vdev) +{ + if (!vdev->config->get) { + dev_err(&vdev->dev, "configuration access disabled\n"); + return -EINVAL; + } + + if (!virtio_has_feature(vdev, VIRTIO_F_VERSION_1)) { + dev_err(&vdev->dev, + "device does not comply with spec version 1.x\n"); + return -EINVAL; + } + + return 0; +} + +/** + * virtsnd_probe() - Create and initialize the device. + * @vdev: VirtIO parent device. + * + * Context: Any context that permits to sleep. + * Return: 0 on success, -errno on failure. + */ +static int virtsnd_probe(struct virtio_device *vdev) +{ + struct virtio_snd *snd; + unsigned int i; + int rc; + + snd = devm_kzalloc(&vdev->dev, sizeof(*snd), GFP_KERNEL); + if (!snd) + return -ENOMEM; + + snd->vdev = vdev; + + vdev->priv = snd; + + for (i = 0; i < VIRTIO_SND_VQ_MAX; ++i) + spin_lock_init(&snd->queues[i].lock); + + rc = virtsnd_find_vqs(snd); + if (rc) + goto on_exit; + + virtio_device_ready(vdev); + + rc = virtsnd_build_devs(snd); + if (rc) + goto on_exit; + + virtsnd_enable_event_vq(snd); + +on_exit: + if (rc) + virtsnd_remove(vdev); + + return rc; +} + +/** + * virtsnd_remove() - Remove VirtIO and ALSA devices. + * @vdev: VirtIO parent device. + * + * Context: Any context that permits to sleep. + */ +static void virtsnd_remove(struct virtio_device *vdev) +{ + struct virtio_snd *snd = vdev->priv; + + virtsnd_disable_event_vq(snd); + + if (snd->card) + snd_card_free(snd->card); + + vdev->config->del_vqs(vdev); + vdev->config->reset(vdev); + + kfree(snd->event_msgs); +} + +static const struct virtio_device_id id_table[] = { + { VIRTIO_ID_SOUND, VIRTIO_DEV_ANY_ID }, + { 0 }, +}; + +static struct virtio_driver virtsnd_driver = { + .driver.name = KBUILD_MODNAME, + .driver.owner = THIS_MODULE, + .id_table = id_table, + .validate = virtsnd_validate, + .probe = virtsnd_probe, + .remove = virtsnd_remove, +}; + +static int __init init(void) +{ + return register_virtio_driver(&virtsnd_driver); +} +module_init(init); + +static void __exit fini(void) +{ + unregister_virtio_driver(&virtsnd_driver); +} +module_exit(fini); + +MODULE_DEVICE_TABLE(virtio, id_table); +MODULE_DESCRIPTION("Virtio sound card driver"); +MODULE_LICENSE("GPL"); diff --git a/sound/virtio/virtio_card.h b/sound/virtio/virtio_card.h new file mode 100644 index 000000000000..b903b1b12e90 --- /dev/null +++ b/sound/virtio/virtio_card.h @@ -0,0 +1,65 @@ +/* SPDX-License-Identifier: GPL-2.0+ */ +/* + * virtio-snd: Virtio sound device + * Copyright (C) 2021 OpenSynergy GmbH + */ +#ifndef VIRTIO_SND_CARD_H +#define VIRTIO_SND_CARD_H + +#include +#include +#include +#include + +#define VIRTIO_SND_CARD_DRIVER "virtio-snd" +#define VIRTIO_SND_CARD_NAME "VirtIO SoundCard" + +/** + * struct virtio_snd_queue - Virtqueue wrapper structure. + * @lock: Used to synchronize access to a virtqueue. + * @vqueue: Underlying virtqueue. + */ +struct virtio_snd_queue { + spinlock_t lock; + struct virtqueue *vqueue; +}; + +/** + * struct virtio_snd - VirtIO sound card device. + * @vdev: Underlying virtio device. + * @queues: Virtqueue wrappers. + * @card: ALSA sound card. + * @event_msgs: Device events. + */ +struct virtio_snd { + struct virtio_device *vdev; + struct virtio_snd_queue queues[VIRTIO_SND_VQ_MAX]; + struct snd_card *card; + struct virtio_snd_event *event_msgs; +}; + +static inline struct virtio_snd_queue * +virtsnd_control_queue(struct virtio_snd *snd) +{ + return &snd->queues[VIRTIO_SND_VQ_CONTROL]; +} + +static inline struct virtio_snd_queue * +virtsnd_event_queue(struct virtio_snd *snd) +{ + return &snd->queues[VIRTIO_SND_VQ_EVENT]; +} + +static inline struct virtio_snd_queue * +virtsnd_tx_queue(struct virtio_snd *snd) +{ + return &snd->queues[VIRTIO_SND_VQ_TX]; +} + +static inline struct virtio_snd_queue * +virtsnd_rx_queue(struct virtio_snd *snd) +{ + return &snd->queues[VIRTIO_SND_VQ_RX]; +} + +#endif /* VIRTIO_SND_CARD_H */ From 9d45e514da88ff74fc24ffb34e7d6eb92576440b Mon Sep 17 00:00:00 2001 From: Anton Yakovlev Date: Tue, 2 Mar 2021 17:47:03 +0100 Subject: [PATCH 031/587] ALSA: virtio: handling control messages The control queue can be used by different parts of the driver to send commands to the device. Control messages can be either synchronous or asynchronous. The lifetime of a message is controlled by a reference count. Introduce a module parameter to set the message completion timeout: msg_timeout_ms [=1000] Signed-off-by: Anton Yakovlev Link: https://lore.kernel.org/r/20210302164709.3142702-4-anton.yakovlev@opensynergy.com Signed-off-by: Takashi Iwai --- sound/virtio/Makefile | 3 +- sound/virtio/virtio_card.c | 13 ++ sound/virtio/virtio_card.h | 7 + sound/virtio/virtio_ctl_msg.c | 310 ++++++++++++++++++++++++++++++++++ sound/virtio/virtio_ctl_msg.h | 78 +++++++++ 5 files changed, 410 insertions(+), 1 deletion(-) create mode 100644 sound/virtio/virtio_ctl_msg.c create mode 100644 sound/virtio/virtio_ctl_msg.h diff --git a/sound/virtio/Makefile b/sound/virtio/Makefile index 8c87ebb9982b..dc551e637441 100644 --- a/sound/virtio/Makefile +++ b/sound/virtio/Makefile @@ -3,5 +3,6 @@ obj-$(CONFIG_SND_VIRTIO) += virtio_snd.o virtio_snd-objs := \ - virtio_card.o + virtio_card.o \ + virtio_ctl_msg.o diff --git a/sound/virtio/virtio_card.c b/sound/virtio/virtio_card.c index 5a37056858e9..b757b2444078 100644 --- a/sound/virtio/virtio_card.c +++ b/sound/virtio/virtio_card.c @@ -11,6 +11,10 @@ #include "virtio_card.h" +u32 virtsnd_msg_timeout_ms = MSEC_PER_SEC; +module_param_named(msg_timeout_ms, virtsnd_msg_timeout_ms, uint, 0644); +MODULE_PARM_DESC(msg_timeout_ms, "Message completion timeout in milliseconds"); + static void virtsnd_remove(struct virtio_device *vdev); /** @@ -96,9 +100,11 @@ static int virtsnd_find_vqs(struct virtio_snd *snd) { struct virtio_device *vdev = snd->vdev; static vq_callback_t *callbacks[VIRTIO_SND_VQ_MAX] = { + [VIRTIO_SND_VQ_CONTROL] = virtsnd_ctl_notify_cb, [VIRTIO_SND_VQ_EVENT] = virtsnd_event_notify_cb }; static const char *names[VIRTIO_SND_VQ_MAX] = { + [VIRTIO_SND_VQ_CONTROL] = "virtsnd-ctl", [VIRTIO_SND_VQ_EVENT] = "virtsnd-event" }; struct virtqueue *vqs[VIRTIO_SND_VQ_MAX] = { 0 }; @@ -226,6 +232,11 @@ static int virtsnd_validate(struct virtio_device *vdev) return -EINVAL; } + if (!virtsnd_msg_timeout_ms) { + dev_err(&vdev->dev, "msg_timeout_ms value cannot be zero\n"); + return -EINVAL; + } + return 0; } @@ -247,6 +258,7 @@ static int virtsnd_probe(struct virtio_device *vdev) return -ENOMEM; snd->vdev = vdev; + INIT_LIST_HEAD(&snd->ctl_msgs); vdev->priv = snd; @@ -283,6 +295,7 @@ static void virtsnd_remove(struct virtio_device *vdev) struct virtio_snd *snd = vdev->priv; virtsnd_disable_event_vq(snd); + virtsnd_ctl_msg_cancel_all(snd); if (snd->card) snd_card_free(snd->card); diff --git a/sound/virtio/virtio_card.h b/sound/virtio/virtio_card.h index b903b1b12e90..1e76eeff160f 100644 --- a/sound/virtio/virtio_card.h +++ b/sound/virtio/virtio_card.h @@ -11,6 +11,8 @@ #include #include +#include "virtio_ctl_msg.h" + #define VIRTIO_SND_CARD_DRIVER "virtio-snd" #define VIRTIO_SND_CARD_NAME "VirtIO SoundCard" @@ -29,15 +31,20 @@ struct virtio_snd_queue { * @vdev: Underlying virtio device. * @queues: Virtqueue wrappers. * @card: ALSA sound card. + * @ctl_msgs: Pending control request list. * @event_msgs: Device events. */ struct virtio_snd { struct virtio_device *vdev; struct virtio_snd_queue queues[VIRTIO_SND_VQ_MAX]; struct snd_card *card; + struct list_head ctl_msgs; struct virtio_snd_event *event_msgs; }; +/* Message completion timeout in milliseconds (module parameter). */ +extern u32 virtsnd_msg_timeout_ms; + static inline struct virtio_snd_queue * virtsnd_control_queue(struct virtio_snd *snd) { diff --git a/sound/virtio/virtio_ctl_msg.c b/sound/virtio/virtio_ctl_msg.c new file mode 100644 index 000000000000..26ff7e7cc041 --- /dev/null +++ b/sound/virtio/virtio_ctl_msg.c @@ -0,0 +1,310 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * virtio-snd: Virtio sound device + * Copyright (C) 2021 OpenSynergy GmbH + */ +#include +#include + +#include "virtio_card.h" + +/** + * struct virtio_snd_msg - Control message. + * @sg_request: Scattergather list containing a device request (header). + * @sg_response: Scattergather list containing a device response (status). + * @list: Pending message list entry. + * @notify: Request completed notification. + * @ref_count: Reference count used to manage a message lifetime. + */ +struct virtio_snd_msg { + struct scatterlist sg_request; + struct scatterlist sg_response; + struct list_head list; + struct completion notify; + refcount_t ref_count; +}; + +/** + * virtsnd_ctl_msg_ref() - Increment reference counter for the message. + * @msg: Control message. + * + * Context: Any context. + */ +void virtsnd_ctl_msg_ref(struct virtio_snd_msg *msg) +{ + refcount_inc(&msg->ref_count); +} + +/** + * virtsnd_ctl_msg_unref() - Decrement reference counter for the message. + * @msg: Control message. + * + * The message will be freed when the ref_count value is 0. + * + * Context: Any context. + */ +void virtsnd_ctl_msg_unref(struct virtio_snd_msg *msg) +{ + if (refcount_dec_and_test(&msg->ref_count)) + kfree(msg); +} + +/** + * virtsnd_ctl_msg_request() - Get a pointer to the request header. + * @msg: Control message. + * + * Context: Any context. + */ +void *virtsnd_ctl_msg_request(struct virtio_snd_msg *msg) +{ + return sg_virt(&msg->sg_request); +} + +/** + * virtsnd_ctl_msg_request() - Get a pointer to the response header. + * @msg: Control message. + * + * Context: Any context. + */ +void *virtsnd_ctl_msg_response(struct virtio_snd_msg *msg) +{ + return sg_virt(&msg->sg_response); +} + +/** + * virtsnd_ctl_msg_alloc() - Allocate and initialize a control message. + * @request_size: Size of request header. + * @response_size: Size of response header. + * @gfp: Kernel flags for memory allocation. + * + * The message will be automatically freed when the ref_count value is 0. + * + * Context: Any context. May sleep if @gfp flags permit. + * Return: Allocated message on success, NULL on failure. + */ +struct virtio_snd_msg *virtsnd_ctl_msg_alloc(size_t request_size, + size_t response_size, gfp_t gfp) +{ + struct virtio_snd_msg *msg; + + if (!request_size || !response_size) + return NULL; + + msg = kzalloc(sizeof(*msg) + request_size + response_size, gfp); + if (!msg) + return NULL; + + sg_init_one(&msg->sg_request, (u8 *)msg + sizeof(*msg), request_size); + sg_init_one(&msg->sg_response, (u8 *)msg + sizeof(*msg) + request_size, + response_size); + + INIT_LIST_HEAD(&msg->list); + init_completion(&msg->notify); + /* This reference is dropped in virtsnd_ctl_msg_complete(). */ + refcount_set(&msg->ref_count, 1); + + return msg; +} + +/** + * virtsnd_ctl_msg_send() - Send a control message. + * @snd: VirtIO sound device. + * @msg: Control message. + * @out_sgs: Additional sg-list to attach to the request header (may be NULL). + * @in_sgs: Additional sg-list to attach to the response header (may be NULL). + * @nowait: Flag indicating whether to wait for completion. + * + * Context: Any context. Takes and releases the control queue spinlock. + * May sleep if @nowait is false. + * Return: 0 on success, -errno on failure. + */ +int virtsnd_ctl_msg_send(struct virtio_snd *snd, struct virtio_snd_msg *msg, + struct scatterlist *out_sgs, + struct scatterlist *in_sgs, bool nowait) +{ + struct virtio_device *vdev = snd->vdev; + struct virtio_snd_queue *queue = virtsnd_control_queue(snd); + unsigned int js = msecs_to_jiffies(virtsnd_msg_timeout_ms); + struct virtio_snd_hdr *request = virtsnd_ctl_msg_request(msg); + struct virtio_snd_hdr *response = virtsnd_ctl_msg_response(msg); + unsigned int nouts = 0; + unsigned int nins = 0; + struct scatterlist *psgs[4]; + bool notify = false; + unsigned long flags; + int rc; + + virtsnd_ctl_msg_ref(msg); + + /* Set the default status in case the message was canceled. */ + response->code = cpu_to_le32(VIRTIO_SND_S_IO_ERR); + + psgs[nouts++] = &msg->sg_request; + if (out_sgs) + psgs[nouts++] = out_sgs; + + psgs[nouts + nins++] = &msg->sg_response; + if (in_sgs) + psgs[nouts + nins++] = in_sgs; + + spin_lock_irqsave(&queue->lock, flags); + rc = virtqueue_add_sgs(queue->vqueue, psgs, nouts, nins, msg, + GFP_ATOMIC); + if (!rc) { + notify = virtqueue_kick_prepare(queue->vqueue); + + list_add_tail(&msg->list, &snd->ctl_msgs); + } + spin_unlock_irqrestore(&queue->lock, flags); + + if (rc) { + dev_err(&vdev->dev, "failed to send control message (0x%08x)\n", + le32_to_cpu(request->code)); + + /* + * Since in this case virtsnd_ctl_msg_complete() will not be + * called, it is necessary to decrement the reference count. + */ + virtsnd_ctl_msg_unref(msg); + + goto on_exit; + } + + if (notify) + virtqueue_notify(queue->vqueue); + + if (nowait) + goto on_exit; + + rc = wait_for_completion_interruptible_timeout(&msg->notify, js); + if (rc <= 0) { + if (!rc) { + dev_err(&vdev->dev, + "control message (0x%08x) timeout\n", + le32_to_cpu(request->code)); + rc = -ETIMEDOUT; + } + + goto on_exit; + } + + switch (le32_to_cpu(response->code)) { + case VIRTIO_SND_S_OK: + rc = 0; + break; + case VIRTIO_SND_S_NOT_SUPP: + rc = -EOPNOTSUPP; + break; + case VIRTIO_SND_S_IO_ERR: + rc = -EIO; + break; + default: + rc = -EINVAL; + break; + } + +on_exit: + virtsnd_ctl_msg_unref(msg); + + return rc; +} + +/** + * virtsnd_ctl_msg_complete() - Complete a control message. + * @msg: Control message. + * + * Context: Any context. Expects the control queue spinlock to be held by + * caller. + */ +void virtsnd_ctl_msg_complete(struct virtio_snd_msg *msg) +{ + list_del(&msg->list); + complete(&msg->notify); + + virtsnd_ctl_msg_unref(msg); +} + +/** + * virtsnd_ctl_msg_cancel_all() - Cancel all pending control messages. + * @snd: VirtIO sound device. + * + * Context: Any context. + */ +void virtsnd_ctl_msg_cancel_all(struct virtio_snd *snd) +{ + struct virtio_snd_queue *queue = virtsnd_control_queue(snd); + unsigned long flags; + + spin_lock_irqsave(&queue->lock, flags); + while (!list_empty(&snd->ctl_msgs)) { + struct virtio_snd_msg *msg = + list_first_entry(&snd->ctl_msgs, struct virtio_snd_msg, + list); + + virtsnd_ctl_msg_complete(msg); + } + spin_unlock_irqrestore(&queue->lock, flags); +} + +/** + * virtsnd_ctl_query_info() - Query the item configuration from the device. + * @snd: VirtIO sound device. + * @command: Control request code (VIRTIO_SND_R_XXX_INFO). + * @start_id: Item start identifier. + * @count: Item count to query. + * @size: Item information size in bytes. + * @info: Buffer for storing item information. + * + * Context: Any context that permits to sleep. + * Return: 0 on success, -errno on failure. + */ +int virtsnd_ctl_query_info(struct virtio_snd *snd, int command, int start_id, + int count, size_t size, void *info) +{ + struct virtio_snd_msg *msg; + struct virtio_snd_query_info *query; + struct scatterlist sg; + + msg = virtsnd_ctl_msg_alloc(sizeof(*query), + sizeof(struct virtio_snd_hdr), GFP_KERNEL); + if (!msg) + return -ENOMEM; + + query = virtsnd_ctl_msg_request(msg); + query->hdr.code = cpu_to_le32(command); + query->start_id = cpu_to_le32(start_id); + query->count = cpu_to_le32(count); + query->size = cpu_to_le32(size); + + sg_init_one(&sg, info, count * size); + + return virtsnd_ctl_msg_send(snd, msg, NULL, &sg, false); +} + +/** + * virtsnd_ctl_notify_cb() - Process all completed control messages. + * @vqueue: Underlying control virtqueue. + * + * This callback function is called upon a vring interrupt request from the + * device. + * + * Context: Interrupt context. Takes and releases the control queue spinlock. + */ +void virtsnd_ctl_notify_cb(struct virtqueue *vqueue) +{ + struct virtio_snd *snd = vqueue->vdev->priv; + struct virtio_snd_queue *queue = virtsnd_control_queue(snd); + struct virtio_snd_msg *msg; + u32 length; + unsigned long flags; + + spin_lock_irqsave(&queue->lock, flags); + do { + virtqueue_disable_cb(vqueue); + while ((msg = virtqueue_get_buf(vqueue, &length))) + virtsnd_ctl_msg_complete(msg); + if (unlikely(virtqueue_is_broken(vqueue))) + break; + } while (!virtqueue_enable_cb(vqueue)); + spin_unlock_irqrestore(&queue->lock, flags); +} diff --git a/sound/virtio/virtio_ctl_msg.h b/sound/virtio/virtio_ctl_msg.h new file mode 100644 index 000000000000..7f4db044f28e --- /dev/null +++ b/sound/virtio/virtio_ctl_msg.h @@ -0,0 +1,78 @@ +/* SPDX-License-Identifier: GPL-2.0+ */ +/* + * virtio-snd: Virtio sound device + * Copyright (C) 2021 OpenSynergy GmbH + */ +#ifndef VIRTIO_SND_MSG_H +#define VIRTIO_SND_MSG_H + +#include +#include + +struct virtio_snd; +struct virtio_snd_msg; + +void virtsnd_ctl_msg_ref(struct virtio_snd_msg *msg); + +void virtsnd_ctl_msg_unref(struct virtio_snd_msg *msg); + +void *virtsnd_ctl_msg_request(struct virtio_snd_msg *msg); + +void *virtsnd_ctl_msg_response(struct virtio_snd_msg *msg); + +struct virtio_snd_msg *virtsnd_ctl_msg_alloc(size_t request_size, + size_t response_size, gfp_t gfp); + +int virtsnd_ctl_msg_send(struct virtio_snd *snd, struct virtio_snd_msg *msg, + struct scatterlist *out_sgs, + struct scatterlist *in_sgs, bool nowait); + +/** + * virtsnd_ctl_msg_send_sync() - Simplified sending of synchronous message. + * @snd: VirtIO sound device. + * @msg: Control message. + * + * After returning from this function, the message will be deleted. If message + * content is still needed, the caller must additionally to + * virtsnd_ctl_msg_ref/unref() it. + * + * The msg_timeout_ms module parameter defines the message completion timeout. + * If the message is not completed within this time, the function will return an + * error. + * + * Context: Any context that permits to sleep. + * Return: 0 on success, -errno on failure. + * + * The return value is a message status code (VIRTIO_SND_S_XXX) converted to an + * appropriate -errno value. + */ +static inline int virtsnd_ctl_msg_send_sync(struct virtio_snd *snd, + struct virtio_snd_msg *msg) +{ + return virtsnd_ctl_msg_send(snd, msg, NULL, NULL, false); +} + +/** + * virtsnd_ctl_msg_send_async() - Simplified sending of asynchronous message. + * @snd: VirtIO sound device. + * @msg: Control message. + * + * Context: Any context. + * Return: 0 on success, -errno on failure. + */ +static inline int virtsnd_ctl_msg_send_async(struct virtio_snd *snd, + struct virtio_snd_msg *msg) +{ + return virtsnd_ctl_msg_send(snd, msg, NULL, NULL, true); +} + +void virtsnd_ctl_msg_cancel_all(struct virtio_snd *snd); + +void virtsnd_ctl_msg_complete(struct virtio_snd_msg *msg); + +int virtsnd_ctl_query_info(struct virtio_snd *snd, int command, int start_id, + int count, size_t size, void *info); + +void virtsnd_ctl_notify_cb(struct virtqueue *vqueue); + +#endif /* VIRTIO_SND_MSG_H */ From 29b96bf50ba958eb5f097cdc3fbd4c1acf9547a2 Mon Sep 17 00:00:00 2001 From: Anton Yakovlev Date: Tue, 2 Mar 2021 17:47:04 +0100 Subject: [PATCH 032/587] ALSA: virtio: build PCM devices and substream hardware descriptors Like the HDA specification, the virtio sound device specification links PCM substreams, jacks and PCM channel maps into functional groups. For each discovered group, a PCM device is created, the number of which coincides with the group number. Introduce the module parameters for setting the hardware buffer parameters: pcm_buffer_ms [=160] pcm_periods_min [=2] pcm_periods_max [=16] pcm_period_ms_min [=10] pcm_period_ms_max [=80] Signed-off-by: Anton Yakovlev Link: https://lore.kernel.org/r/20210302164709.3142702-5-anton.yakovlev@opensynergy.com Signed-off-by: Takashi Iwai --- sound/virtio/Makefile | 3 +- sound/virtio/virtio_card.c | 18 ++ sound/virtio/virtio_card.h | 10 + sound/virtio/virtio_pcm.c | 479 +++++++++++++++++++++++++++++++++++++ sound/virtio/virtio_pcm.h | 72 ++++++ 5 files changed, 581 insertions(+), 1 deletion(-) create mode 100644 sound/virtio/virtio_pcm.c create mode 100644 sound/virtio/virtio_pcm.h diff --git a/sound/virtio/Makefile b/sound/virtio/Makefile index dc551e637441..69162a545a41 100644 --- a/sound/virtio/Makefile +++ b/sound/virtio/Makefile @@ -4,5 +4,6 @@ obj-$(CONFIG_SND_VIRTIO) += virtio_snd.o virtio_snd-objs := \ virtio_card.o \ - virtio_ctl_msg.o + virtio_ctl_msg.o \ + virtio_pcm.o diff --git a/sound/virtio/virtio_card.c b/sound/virtio/virtio_card.c index b757b2444078..11c76ee311b7 100644 --- a/sound/virtio/virtio_card.c +++ b/sound/virtio/virtio_card.c @@ -209,6 +209,16 @@ static int virtsnd_build_devs(struct virtio_snd *snd) VIRTIO_SND_CARD_NAME " at %s/%s", dev_name(dev->parent), dev_name(dev)); + rc = virtsnd_pcm_parse_cfg(snd); + if (rc) + return rc; + + if (snd->nsubstreams) { + rc = virtsnd_pcm_build_devs(snd); + if (rc) + return rc; + } + return snd_card_register(snd->card); } @@ -237,6 +247,9 @@ static int virtsnd_validate(struct virtio_device *vdev) return -EINVAL; } + if (virtsnd_pcm_validate(vdev)) + return -EINVAL; + return 0; } @@ -259,6 +272,7 @@ static int virtsnd_probe(struct virtio_device *vdev) snd->vdev = vdev; INIT_LIST_HEAD(&snd->ctl_msgs); + INIT_LIST_HEAD(&snd->pcm_list); vdev->priv = snd; @@ -293,6 +307,7 @@ on_exit: static void virtsnd_remove(struct virtio_device *vdev) { struct virtio_snd *snd = vdev->priv; + unsigned int i; virtsnd_disable_event_vq(snd); virtsnd_ctl_msg_cancel_all(snd); @@ -303,6 +318,9 @@ static void virtsnd_remove(struct virtio_device *vdev) vdev->config->del_vqs(vdev); vdev->config->reset(vdev); + for (i = 0; snd->substreams && i < snd->nsubstreams; ++i) + cancel_work_sync(&snd->substreams[i].elapsed_period); + kfree(snd->event_msgs); } diff --git a/sound/virtio/virtio_card.h b/sound/virtio/virtio_card.h index 1e76eeff160f..77a1b7255370 100644 --- a/sound/virtio/virtio_card.h +++ b/sound/virtio/virtio_card.h @@ -12,9 +12,13 @@ #include #include "virtio_ctl_msg.h" +#include "virtio_pcm.h" #define VIRTIO_SND_CARD_DRIVER "virtio-snd" #define VIRTIO_SND_CARD_NAME "VirtIO SoundCard" +#define VIRTIO_SND_PCM_NAME "VirtIO PCM" + +struct virtio_pcm_substream; /** * struct virtio_snd_queue - Virtqueue wrapper structure. @@ -33,6 +37,9 @@ struct virtio_snd_queue { * @card: ALSA sound card. * @ctl_msgs: Pending control request list. * @event_msgs: Device events. + * @pcm_list: VirtIO PCM device list. + * @substreams: VirtIO PCM substreams. + * @nsubstreams: Number of PCM substreams. */ struct virtio_snd { struct virtio_device *vdev; @@ -40,6 +47,9 @@ struct virtio_snd { struct snd_card *card; struct list_head ctl_msgs; struct virtio_snd_event *event_msgs; + struct list_head pcm_list; + struct virtio_pcm_substream *substreams; + u32 nsubstreams; }; /* Message completion timeout in milliseconds (module parameter). */ diff --git a/sound/virtio/virtio_pcm.c b/sound/virtio/virtio_pcm.c new file mode 100644 index 000000000000..e16567e2e214 --- /dev/null +++ b/sound/virtio/virtio_pcm.c @@ -0,0 +1,479 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * virtio-snd: Virtio sound device + * Copyright (C) 2021 OpenSynergy GmbH + */ +#include +#include + +#include "virtio_card.h" + +static u32 pcm_buffer_ms = 160; +module_param(pcm_buffer_ms, uint, 0644); +MODULE_PARM_DESC(pcm_buffer_ms, "PCM substream buffer time in milliseconds"); + +static u32 pcm_periods_min = 2; +module_param(pcm_periods_min, uint, 0644); +MODULE_PARM_DESC(pcm_periods_min, "Minimum number of PCM periods"); + +static u32 pcm_periods_max = 16; +module_param(pcm_periods_max, uint, 0644); +MODULE_PARM_DESC(pcm_periods_max, "Maximum number of PCM periods"); + +static u32 pcm_period_ms_min = 10; +module_param(pcm_period_ms_min, uint, 0644); +MODULE_PARM_DESC(pcm_period_ms_min, "Minimum PCM period time in milliseconds"); + +static u32 pcm_period_ms_max = 80; +module_param(pcm_period_ms_max, uint, 0644); +MODULE_PARM_DESC(pcm_period_ms_max, "Maximum PCM period time in milliseconds"); + +/* Map for converting VirtIO format to ALSA format. */ +static const snd_pcm_format_t g_v2a_format_map[] = { + [VIRTIO_SND_PCM_FMT_IMA_ADPCM] = SNDRV_PCM_FORMAT_IMA_ADPCM, + [VIRTIO_SND_PCM_FMT_MU_LAW] = SNDRV_PCM_FORMAT_MU_LAW, + [VIRTIO_SND_PCM_FMT_A_LAW] = SNDRV_PCM_FORMAT_A_LAW, + [VIRTIO_SND_PCM_FMT_S8] = SNDRV_PCM_FORMAT_S8, + [VIRTIO_SND_PCM_FMT_U8] = SNDRV_PCM_FORMAT_U8, + [VIRTIO_SND_PCM_FMT_S16] = SNDRV_PCM_FORMAT_S16_LE, + [VIRTIO_SND_PCM_FMT_U16] = SNDRV_PCM_FORMAT_U16_LE, + [VIRTIO_SND_PCM_FMT_S18_3] = SNDRV_PCM_FORMAT_S18_3LE, + [VIRTIO_SND_PCM_FMT_U18_3] = SNDRV_PCM_FORMAT_U18_3LE, + [VIRTIO_SND_PCM_FMT_S20_3] = SNDRV_PCM_FORMAT_S20_3LE, + [VIRTIO_SND_PCM_FMT_U20_3] = SNDRV_PCM_FORMAT_U20_3LE, + [VIRTIO_SND_PCM_FMT_S24_3] = SNDRV_PCM_FORMAT_S24_3LE, + [VIRTIO_SND_PCM_FMT_U24_3] = SNDRV_PCM_FORMAT_U24_3LE, + [VIRTIO_SND_PCM_FMT_S20] = SNDRV_PCM_FORMAT_S20_LE, + [VIRTIO_SND_PCM_FMT_U20] = SNDRV_PCM_FORMAT_U20_LE, + [VIRTIO_SND_PCM_FMT_S24] = SNDRV_PCM_FORMAT_S24_LE, + [VIRTIO_SND_PCM_FMT_U24] = SNDRV_PCM_FORMAT_U24_LE, + [VIRTIO_SND_PCM_FMT_S32] = SNDRV_PCM_FORMAT_S32_LE, + [VIRTIO_SND_PCM_FMT_U32] = SNDRV_PCM_FORMAT_U32_LE, + [VIRTIO_SND_PCM_FMT_FLOAT] = SNDRV_PCM_FORMAT_FLOAT_LE, + [VIRTIO_SND_PCM_FMT_FLOAT64] = SNDRV_PCM_FORMAT_FLOAT64_LE, + [VIRTIO_SND_PCM_FMT_DSD_U8] = SNDRV_PCM_FORMAT_DSD_U8, + [VIRTIO_SND_PCM_FMT_DSD_U16] = SNDRV_PCM_FORMAT_DSD_U16_LE, + [VIRTIO_SND_PCM_FMT_DSD_U32] = SNDRV_PCM_FORMAT_DSD_U32_LE, + [VIRTIO_SND_PCM_FMT_IEC958_SUBFRAME] = + SNDRV_PCM_FORMAT_IEC958_SUBFRAME_LE +}; + +/* Map for converting VirtIO frame rate to ALSA frame rate. */ +struct virtsnd_v2a_rate { + unsigned int alsa_bit; + unsigned int rate; +}; + +static const struct virtsnd_v2a_rate g_v2a_rate_map[] = { + [VIRTIO_SND_PCM_RATE_5512] = { SNDRV_PCM_RATE_5512, 5512 }, + [VIRTIO_SND_PCM_RATE_8000] = { SNDRV_PCM_RATE_8000, 8000 }, + [VIRTIO_SND_PCM_RATE_11025] = { SNDRV_PCM_RATE_11025, 11025 }, + [VIRTIO_SND_PCM_RATE_16000] = { SNDRV_PCM_RATE_16000, 16000 }, + [VIRTIO_SND_PCM_RATE_22050] = { SNDRV_PCM_RATE_22050, 22050 }, + [VIRTIO_SND_PCM_RATE_32000] = { SNDRV_PCM_RATE_32000, 32000 }, + [VIRTIO_SND_PCM_RATE_44100] = { SNDRV_PCM_RATE_44100, 44100 }, + [VIRTIO_SND_PCM_RATE_48000] = { SNDRV_PCM_RATE_48000, 48000 }, + [VIRTIO_SND_PCM_RATE_64000] = { SNDRV_PCM_RATE_64000, 64000 }, + [VIRTIO_SND_PCM_RATE_88200] = { SNDRV_PCM_RATE_88200, 88200 }, + [VIRTIO_SND_PCM_RATE_96000] = { SNDRV_PCM_RATE_96000, 96000 }, + [VIRTIO_SND_PCM_RATE_176400] = { SNDRV_PCM_RATE_176400, 176400 }, + [VIRTIO_SND_PCM_RATE_192000] = { SNDRV_PCM_RATE_192000, 192000 } +}; + +/** + * virtsnd_pcm_build_hw() - Parse substream config and build HW descriptor. + * @vss: VirtIO substream. + * @info: VirtIO substream information entry. + * + * Context: Any context. + * Return: 0 on success, -EINVAL if configuration is invalid. + */ +static int virtsnd_pcm_build_hw(struct virtio_pcm_substream *vss, + struct virtio_snd_pcm_info *info) +{ + struct virtio_device *vdev = vss->snd->vdev; + unsigned int i; + u64 values; + size_t sample_max = 0; + size_t sample_min = 0; + + vss->features = le32_to_cpu(info->features); + + /* + * TODO: set SNDRV_PCM_INFO_{BATCH,BLOCK_TRANSFER} if device supports + * only message-based transport. + */ + vss->hw.info = + SNDRV_PCM_INFO_MMAP | + SNDRV_PCM_INFO_MMAP_VALID | + SNDRV_PCM_INFO_BATCH | + SNDRV_PCM_INFO_BLOCK_TRANSFER | + SNDRV_PCM_INFO_INTERLEAVED | + SNDRV_PCM_INFO_PAUSE; + + if (!info->channels_min || info->channels_min > info->channels_max) { + dev_err(&vdev->dev, + "SID %u: invalid channel range [%u %u]\n", + vss->sid, info->channels_min, info->channels_max); + return -EINVAL; + } + + vss->hw.channels_min = info->channels_min; + vss->hw.channels_max = info->channels_max; + + values = le64_to_cpu(info->formats); + + vss->hw.formats = 0; + + for (i = 0; i < ARRAY_SIZE(g_v2a_format_map); ++i) + if (values & (1ULL << i)) { + snd_pcm_format_t alsa_fmt = g_v2a_format_map[i]; + int bytes = snd_pcm_format_physical_width(alsa_fmt) / 8; + + if (!sample_min || sample_min > bytes) + sample_min = bytes; + + if (sample_max < bytes) + sample_max = bytes; + + vss->hw.formats |= pcm_format_to_bits(alsa_fmt); + } + + if (!vss->hw.formats) { + dev_err(&vdev->dev, + "SID %u: no supported PCM sample formats found\n", + vss->sid); + return -EINVAL; + } + + values = le64_to_cpu(info->rates); + + vss->hw.rates = 0; + + for (i = 0; i < ARRAY_SIZE(g_v2a_rate_map); ++i) + if (values & (1ULL << i)) { + if (!vss->hw.rate_min || + vss->hw.rate_min > g_v2a_rate_map[i].rate) + vss->hw.rate_min = g_v2a_rate_map[i].rate; + + if (vss->hw.rate_max < g_v2a_rate_map[i].rate) + vss->hw.rate_max = g_v2a_rate_map[i].rate; + + vss->hw.rates |= g_v2a_rate_map[i].alsa_bit; + } + + if (!vss->hw.rates) { + dev_err(&vdev->dev, + "SID %u: no supported PCM frame rates found\n", + vss->sid); + return -EINVAL; + } + + vss->hw.periods_min = pcm_periods_min; + vss->hw.periods_max = pcm_periods_max; + + /* + * We must ensure that there is enough space in the buffer to store + * pcm_buffer_ms ms for the combination (Cmax, Smax, Rmax), where: + * Cmax = maximum supported number of channels, + * Smax = maximum supported sample size in bytes, + * Rmax = maximum supported frame rate. + */ + vss->hw.buffer_bytes_max = + PAGE_ALIGN(sample_max * vss->hw.channels_max * pcm_buffer_ms * + (vss->hw.rate_max / MSEC_PER_SEC)); + + /* + * We must ensure that the minimum period size is enough to store + * pcm_period_ms_min ms for the combination (Cmin, Smin, Rmin), where: + * Cmin = minimum supported number of channels, + * Smin = minimum supported sample size in bytes, + * Rmin = minimum supported frame rate. + */ + vss->hw.period_bytes_min = + sample_min * vss->hw.channels_min * pcm_period_ms_min * + (vss->hw.rate_min / MSEC_PER_SEC); + + /* + * We must ensure that the maximum period size is enough to store + * pcm_period_ms_max ms for the combination (Cmax, Smax, Rmax). + */ + vss->hw.period_bytes_max = + sample_max * vss->hw.channels_max * pcm_period_ms_max * + (vss->hw.rate_max / MSEC_PER_SEC); + + return 0; +} + +/** + * virtsnd_pcm_find() - Find the PCM device for the specified node ID. + * @snd: VirtIO sound device. + * @nid: Function node ID. + * + * Context: Any context. + * Return: a pointer to the PCM device or ERR_PTR(-ENOENT). + */ +struct virtio_pcm *virtsnd_pcm_find(struct virtio_snd *snd, u32 nid) +{ + struct virtio_pcm *vpcm; + + list_for_each_entry(vpcm, &snd->pcm_list, list) + if (vpcm->nid == nid) + return vpcm; + + return ERR_PTR(-ENOENT); +} + +/** + * virtsnd_pcm_find_or_create() - Find or create the PCM device for the + * specified node ID. + * @snd: VirtIO sound device. + * @nid: Function node ID. + * + * Context: Any context that permits to sleep. + * Return: a pointer to the PCM device or ERR_PTR(-errno). + */ +struct virtio_pcm *virtsnd_pcm_find_or_create(struct virtio_snd *snd, u32 nid) +{ + struct virtio_device *vdev = snd->vdev; + struct virtio_pcm *vpcm; + + vpcm = virtsnd_pcm_find(snd, nid); + if (!IS_ERR(vpcm)) + return vpcm; + + vpcm = devm_kzalloc(&vdev->dev, sizeof(*vpcm), GFP_KERNEL); + if (!vpcm) + return ERR_PTR(-ENOMEM); + + vpcm->nid = nid; + list_add_tail(&vpcm->list, &snd->pcm_list); + + return vpcm; +} + +/** + * virtsnd_pcm_validate() - Validate if the device can be started. + * @vdev: VirtIO parent device. + * + * Context: Any context. + * Return: 0 on success, -EINVAL on failure. + */ +int virtsnd_pcm_validate(struct virtio_device *vdev) +{ + if (pcm_periods_min < 2 || pcm_periods_min > pcm_periods_max) { + dev_err(&vdev->dev, + "invalid range [%u %u] of the number of PCM periods\n", + pcm_periods_min, pcm_periods_max); + return -EINVAL; + } + + if (!pcm_period_ms_min || pcm_period_ms_min > pcm_period_ms_max) { + dev_err(&vdev->dev, + "invalid range [%u %u] of the size of the PCM period\n", + pcm_period_ms_min, pcm_period_ms_max); + return -EINVAL; + } + + if (pcm_buffer_ms < pcm_periods_min * pcm_period_ms_min) { + dev_err(&vdev->dev, + "pcm_buffer_ms(=%u) value cannot be < %u ms\n", + pcm_buffer_ms, pcm_periods_min * pcm_period_ms_min); + return -EINVAL; + } + + if (pcm_period_ms_max > pcm_buffer_ms / 2) { + dev_err(&vdev->dev, + "pcm_period_ms_max(=%u) value cannot be > %u ms\n", + pcm_period_ms_max, pcm_buffer_ms / 2); + return -EINVAL; + } + + return 0; +} + +/** + * virtsnd_pcm_period_elapsed() - Kernel work function to handle the elapsed + * period state. + * @work: Elapsed period work. + * + * The main purpose of this function is to call snd_pcm_period_elapsed() in + * a process context, not in an interrupt context. This is necessary because PCM + * devices operate in non-atomic mode. + * + * Context: Process context. + */ +static void virtsnd_pcm_period_elapsed(struct work_struct *work) +{ + struct virtio_pcm_substream *vss = + container_of(work, struct virtio_pcm_substream, elapsed_period); + + snd_pcm_period_elapsed(vss->substream); +} + +/** + * virtsnd_pcm_parse_cfg() - Parse the stream configuration. + * @snd: VirtIO sound device. + * + * This function is called during initial device initialization. + * + * Context: Any context that permits to sleep. + * Return: 0 on success, -errno on failure. + */ +int virtsnd_pcm_parse_cfg(struct virtio_snd *snd) +{ + struct virtio_device *vdev = snd->vdev; + struct virtio_snd_pcm_info *info; + u32 i; + int rc; + + virtio_cread_le(vdev, struct virtio_snd_config, streams, + &snd->nsubstreams); + if (!snd->nsubstreams) + return 0; + + snd->substreams = devm_kcalloc(&vdev->dev, snd->nsubstreams, + sizeof(*snd->substreams), GFP_KERNEL); + if (!snd->substreams) + return -ENOMEM; + + info = kcalloc(snd->nsubstreams, sizeof(*info), GFP_KERNEL); + if (!info) + return -ENOMEM; + + rc = virtsnd_ctl_query_info(snd, VIRTIO_SND_R_PCM_INFO, 0, + snd->nsubstreams, sizeof(*info), info); + if (rc) + goto on_exit; + + for (i = 0; i < snd->nsubstreams; ++i) { + struct virtio_pcm_substream *vss = &snd->substreams[i]; + struct virtio_pcm *vpcm; + + vss->snd = snd; + vss->sid = i; + INIT_WORK(&vss->elapsed_period, virtsnd_pcm_period_elapsed); + + rc = virtsnd_pcm_build_hw(vss, &info[i]); + if (rc) + goto on_exit; + + vss->nid = le32_to_cpu(info[i].hdr.hda_fn_nid); + + vpcm = virtsnd_pcm_find_or_create(snd, vss->nid); + if (IS_ERR(vpcm)) { + rc = PTR_ERR(vpcm); + goto on_exit; + } + + switch (info[i].direction) { + case VIRTIO_SND_D_OUTPUT: + vss->direction = SNDRV_PCM_STREAM_PLAYBACK; + break; + case VIRTIO_SND_D_INPUT: + vss->direction = SNDRV_PCM_STREAM_CAPTURE; + break; + default: + dev_err(&vdev->dev, "SID %u: unknown direction (%u)\n", + vss->sid, info[i].direction); + rc = -EINVAL; + goto on_exit; + } + + vpcm->streams[vss->direction].nsubstreams++; + } + +on_exit: + kfree(info); + + return rc; +} + +/** + * virtsnd_pcm_build_devs() - Build ALSA PCM devices. + * @snd: VirtIO sound device. + * + * Context: Any context that permits to sleep. + * Return: 0 on success, -errno on failure. + */ +int virtsnd_pcm_build_devs(struct virtio_snd *snd) +{ + struct virtio_device *vdev = snd->vdev; + struct virtio_pcm *vpcm; + u32 i; + int rc; + + list_for_each_entry(vpcm, &snd->pcm_list, list) { + unsigned int npbs = + vpcm->streams[SNDRV_PCM_STREAM_PLAYBACK].nsubstreams; + unsigned int ncps = + vpcm->streams[SNDRV_PCM_STREAM_CAPTURE].nsubstreams; + + if (!npbs && !ncps) + continue; + + rc = snd_pcm_new(snd->card, VIRTIO_SND_CARD_DRIVER, vpcm->nid, + npbs, ncps, &vpcm->pcm); + if (rc) { + dev_err(&vdev->dev, "snd_pcm_new[%u] failed: %d\n", + vpcm->nid, rc); + return rc; + } + + vpcm->pcm->info_flags = 0; + vpcm->pcm->dev_class = SNDRV_PCM_CLASS_GENERIC; + vpcm->pcm->dev_subclass = SNDRV_PCM_SUBCLASS_GENERIC_MIX; + snprintf(vpcm->pcm->name, sizeof(vpcm->pcm->name), + VIRTIO_SND_PCM_NAME " %u", vpcm->pcm->device); + vpcm->pcm->private_data = vpcm; + vpcm->pcm->nonatomic = true; + + for (i = 0; i < ARRAY_SIZE(vpcm->streams); ++i) { + struct virtio_pcm_stream *stream = &vpcm->streams[i]; + + if (!stream->nsubstreams) + continue; + + stream->substreams = + devm_kcalloc(&vdev->dev, stream->nsubstreams, + sizeof(*stream->substreams), + GFP_KERNEL); + if (!stream->substreams) + return -ENOMEM; + + stream->nsubstreams = 0; + } + } + + for (i = 0; i < snd->nsubstreams; ++i) { + struct virtio_pcm_stream *vs; + struct virtio_pcm_substream *vss = &snd->substreams[i]; + + vpcm = virtsnd_pcm_find(snd, vss->nid); + if (IS_ERR(vpcm)) + return PTR_ERR(vpcm); + + vs = &vpcm->streams[vss->direction]; + vs->substreams[vs->nsubstreams++] = vss; + } + + list_for_each_entry(vpcm, &snd->pcm_list, list) { + for (i = 0; i < ARRAY_SIZE(vpcm->streams); ++i) { + struct virtio_pcm_stream *vs = &vpcm->streams[i]; + struct snd_pcm_str *ks = &vpcm->pcm->streams[i]; + struct snd_pcm_substream *kss; + + if (!vs->nsubstreams) + continue; + + for (kss = ks->substream; kss; kss = kss->next) + vs->substreams[kss->number]->substream = kss; + } + + snd_pcm_set_managed_buffer_all(vpcm->pcm, + SNDRV_DMA_TYPE_VMALLOC, NULL, + 0, 0); + } + + return 0; +} diff --git a/sound/virtio/virtio_pcm.h b/sound/virtio/virtio_pcm.h new file mode 100644 index 000000000000..84f2f3f14f48 --- /dev/null +++ b/sound/virtio/virtio_pcm.h @@ -0,0 +1,72 @@ +/* SPDX-License-Identifier: GPL-2.0+ */ +/* + * virtio-snd: Virtio sound device + * Copyright (C) 2021 OpenSynergy GmbH + */ +#ifndef VIRTIO_SND_PCM_H +#define VIRTIO_SND_PCM_H + +#include +#include +#include + +struct virtio_pcm; +struct virtio_pcm_msg; + +/** + * struct virtio_pcm_substream - VirtIO PCM substream. + * @snd: VirtIO sound device. + * @nid: Function group node identifier. + * @sid: Stream identifier. + * @direction: Stream data flow direction (SNDRV_PCM_STREAM_XXX). + * @features: Stream VirtIO feature bit map (1 << VIRTIO_SND_PCM_F_XXX). + * @substream: Kernel ALSA substream. + * @hw: Kernel ALSA substream hardware descriptor. + * @elapsed_period: Kernel work to handle the elapsed period state. + */ +struct virtio_pcm_substream { + struct virtio_snd *snd; + u32 nid; + u32 sid; + u32 direction; + u32 features; + struct snd_pcm_substream *substream; + struct snd_pcm_hardware hw; + struct work_struct elapsed_period; +}; + +/** + * struct virtio_pcm_stream - VirtIO PCM stream. + * @substreams: VirtIO substreams belonging to the stream. + * @nsubstreams: Number of substreams. + */ +struct virtio_pcm_stream { + struct virtio_pcm_substream **substreams; + u32 nsubstreams; +}; + +/** + * struct virtio_pcm - VirtIO PCM device. + * @list: VirtIO PCM list entry. + * @nid: Function group node identifier. + * @pcm: Kernel PCM device. + * @streams: VirtIO PCM streams (playback and capture). + */ +struct virtio_pcm { + struct list_head list; + u32 nid; + struct snd_pcm *pcm; + struct virtio_pcm_stream streams[SNDRV_PCM_STREAM_LAST + 1]; +}; + +int virtsnd_pcm_validate(struct virtio_device *vdev); + +int virtsnd_pcm_parse_cfg(struct virtio_snd *snd); + +int virtsnd_pcm_build_devs(struct virtio_snd *snd); + +struct virtio_pcm *virtsnd_pcm_find(struct virtio_snd *snd, u32 nid); + +struct virtio_pcm *virtsnd_pcm_find_or_create(struct virtio_snd *snd, u32 nid); + +#endif /* VIRTIO_SND_PCM_H */ From f40a28679e0b7cb3a9cc6627a8dbb40961990f0a Mon Sep 17 00:00:00 2001 From: Anton Yakovlev Date: Tue, 2 Mar 2021 17:47:05 +0100 Subject: [PATCH 033/587] ALSA: virtio: handling control and I/O messages for the PCM device The driver implements a message-based transport for I/O substream operations. Before the start of the substream, the hardware buffer is sliced into I/O messages, the number of which is equal to the current number of periods. The size of each message is equal to the current size of one period. I/O messages are organized in an ordered queue. The completion of the I/O message indicates an elapsed period (the only exception is the end of the stream for the capture substream). Upon completion, the message is automatically re-added to the end of the queue. Signed-off-by: Anton Yakovlev Link: https://lore.kernel.org/r/20210302164709.3142702-6-anton.yakovlev@opensynergy.com Signed-off-by: Takashi Iwai --- sound/virtio/Makefile | 3 +- sound/virtio/virtio_card.c | 22 +- sound/virtio/virtio_card.h | 9 + sound/virtio/virtio_pcm.c | 32 +++ sound/virtio/virtio_pcm.h | 40 ++++ sound/virtio/virtio_pcm_msg.c | 414 ++++++++++++++++++++++++++++++++++ 6 files changed, 515 insertions(+), 5 deletions(-) create mode 100644 sound/virtio/virtio_pcm_msg.c diff --git a/sound/virtio/Makefile b/sound/virtio/Makefile index 69162a545a41..626af3cc3ed7 100644 --- a/sound/virtio/Makefile +++ b/sound/virtio/Makefile @@ -5,5 +5,6 @@ obj-$(CONFIG_SND_VIRTIO) += virtio_snd.o virtio_snd-objs := \ virtio_card.o \ virtio_ctl_msg.o \ - virtio_pcm.o + virtio_pcm.o \ + virtio_pcm_msg.o diff --git a/sound/virtio/virtio_card.c b/sound/virtio/virtio_card.c index 11c76ee311b7..57b9b7f3a9c0 100644 --- a/sound/virtio/virtio_card.c +++ b/sound/virtio/virtio_card.c @@ -55,6 +55,12 @@ static void virtsnd_event_send(struct virtqueue *vqueue, static void virtsnd_event_dispatch(struct virtio_snd *snd, struct virtio_snd_event *event) { + switch (le32_to_cpu(event->hdr.code)) { + case VIRTIO_SND_EVT_PCM_PERIOD_ELAPSED: + case VIRTIO_SND_EVT_PCM_XRUN: + virtsnd_pcm_event(snd, event); + break; + } } /** @@ -101,11 +107,15 @@ static int virtsnd_find_vqs(struct virtio_snd *snd) struct virtio_device *vdev = snd->vdev; static vq_callback_t *callbacks[VIRTIO_SND_VQ_MAX] = { [VIRTIO_SND_VQ_CONTROL] = virtsnd_ctl_notify_cb, - [VIRTIO_SND_VQ_EVENT] = virtsnd_event_notify_cb + [VIRTIO_SND_VQ_EVENT] = virtsnd_event_notify_cb, + [VIRTIO_SND_VQ_TX] = virtsnd_pcm_tx_notify_cb, + [VIRTIO_SND_VQ_RX] = virtsnd_pcm_rx_notify_cb }; static const char *names[VIRTIO_SND_VQ_MAX] = { [VIRTIO_SND_VQ_CONTROL] = "virtsnd-ctl", - [VIRTIO_SND_VQ_EVENT] = "virtsnd-event" + [VIRTIO_SND_VQ_EVENT] = "virtsnd-event", + [VIRTIO_SND_VQ_TX] = "virtsnd-tx", + [VIRTIO_SND_VQ_RX] = "virtsnd-rx" }; struct virtqueue *vqs[VIRTIO_SND_VQ_MAX] = { 0 }; unsigned int i; @@ -318,8 +328,12 @@ static void virtsnd_remove(struct virtio_device *vdev) vdev->config->del_vqs(vdev); vdev->config->reset(vdev); - for (i = 0; snd->substreams && i < snd->nsubstreams; ++i) - cancel_work_sync(&snd->substreams[i].elapsed_period); + for (i = 0; snd->substreams && i < snd->nsubstreams; ++i) { + struct virtio_pcm_substream *vss = &snd->substreams[i]; + + cancel_work_sync(&vss->elapsed_period); + virtsnd_pcm_msg_free(vss); + } kfree(snd->event_msgs); } diff --git a/sound/virtio/virtio_card.h b/sound/virtio/virtio_card.h index 77a1b7255370..c43f9744d362 100644 --- a/sound/virtio/virtio_card.h +++ b/sound/virtio/virtio_card.h @@ -79,4 +79,13 @@ virtsnd_rx_queue(struct virtio_snd *snd) return &snd->queues[VIRTIO_SND_VQ_RX]; } +static inline struct virtio_snd_queue * +virtsnd_pcm_queue(struct virtio_pcm_substream *vss) +{ + if (vss->direction == SNDRV_PCM_STREAM_PLAYBACK) + return virtsnd_tx_queue(vss->snd); + else + return virtsnd_rx_queue(vss->snd); +} + #endif /* VIRTIO_SND_CARD_H */ diff --git a/sound/virtio/virtio_pcm.c b/sound/virtio/virtio_pcm.c index e16567e2e214..2dcd763efa29 100644 --- a/sound/virtio/virtio_pcm.c +++ b/sound/virtio/virtio_pcm.c @@ -353,6 +353,8 @@ int virtsnd_pcm_parse_cfg(struct virtio_snd *snd) vss->snd = snd; vss->sid = i; INIT_WORK(&vss->elapsed_period, virtsnd_pcm_period_elapsed); + init_waitqueue_head(&vss->msg_empty); + spin_lock_init(&vss->lock); rc = virtsnd_pcm_build_hw(vss, &info[i]); if (rc) @@ -477,3 +479,33 @@ int virtsnd_pcm_build_devs(struct virtio_snd *snd) return 0; } + +/** + * virtsnd_pcm_event() - Handle the PCM device event notification. + * @snd: VirtIO sound device. + * @event: VirtIO sound event. + * + * Context: Interrupt context. + */ +void virtsnd_pcm_event(struct virtio_snd *snd, struct virtio_snd_event *event) +{ + struct virtio_pcm_substream *vss; + u32 sid = le32_to_cpu(event->data); + + if (sid >= snd->nsubstreams) + return; + + vss = &snd->substreams[sid]; + + switch (le32_to_cpu(event->hdr.code)) { + case VIRTIO_SND_EVT_PCM_PERIOD_ELAPSED: + /* TODO: deal with shmem elapsed period */ + break; + case VIRTIO_SND_EVT_PCM_XRUN: + spin_lock(&vss->lock); + if (vss->xfer_enabled) + vss->xfer_xrun = true; + spin_unlock(&vss->lock); + break; + } +} diff --git a/sound/virtio/virtio_pcm.h b/sound/virtio/virtio_pcm.h index 84f2f3f14f48..6722f1139666 100644 --- a/sound/virtio/virtio_pcm.h +++ b/sound/virtio/virtio_pcm.h @@ -23,6 +23,17 @@ struct virtio_pcm_msg; * @substream: Kernel ALSA substream. * @hw: Kernel ALSA substream hardware descriptor. * @elapsed_period: Kernel work to handle the elapsed period state. + * @lock: Spinlock that protects fields shared by interrupt handlers and + * substream operators. + * @buffer_bytes: Current buffer size in bytes. + * @hw_ptr: Substream hardware pointer value in bytes [0 ... buffer_bytes). + * @xfer_enabled: Data transfer state (0 - off, 1 - on). + * @xfer_xrun: Data underflow/overflow state (0 - no xrun, 1 - xrun). + * @msgs: Allocated I/O messages. + * @nmsgs: Number of allocated I/O messages. + * @msg_last_enqueued: Index of the last I/O message added to the virtqueue. + * @msg_count: Number of pending I/O messages in the virtqueue. + * @msg_empty: Notify when msg_count is zero. */ struct virtio_pcm_substream { struct virtio_snd *snd; @@ -33,6 +44,16 @@ struct virtio_pcm_substream { struct snd_pcm_substream *substream; struct snd_pcm_hardware hw; struct work_struct elapsed_period; + spinlock_t lock; + size_t buffer_bytes; + size_t hw_ptr; + bool xfer_enabled; + bool xfer_xrun; + struct virtio_pcm_msg **msgs; + unsigned int nmsgs; + int msg_last_enqueued; + unsigned int msg_count; + wait_queue_head_t msg_empty; }; /** @@ -65,8 +86,27 @@ int virtsnd_pcm_parse_cfg(struct virtio_snd *snd); int virtsnd_pcm_build_devs(struct virtio_snd *snd); +void virtsnd_pcm_event(struct virtio_snd *snd, struct virtio_snd_event *event); + +void virtsnd_pcm_tx_notify_cb(struct virtqueue *vqueue); + +void virtsnd_pcm_rx_notify_cb(struct virtqueue *vqueue); + struct virtio_pcm *virtsnd_pcm_find(struct virtio_snd *snd, u32 nid); struct virtio_pcm *virtsnd_pcm_find_or_create(struct virtio_snd *snd, u32 nid); +struct virtio_snd_msg * +virtsnd_pcm_ctl_msg_alloc(struct virtio_pcm_substream *vss, + unsigned int command, gfp_t gfp); + +int virtsnd_pcm_msg_alloc(struct virtio_pcm_substream *vss, + unsigned int periods, unsigned int period_bytes); + +void virtsnd_pcm_msg_free(struct virtio_pcm_substream *vss); + +int virtsnd_pcm_msg_send(struct virtio_pcm_substream *vss); + +unsigned int virtsnd_pcm_msg_pending_num(struct virtio_pcm_substream *vss); + #endif /* VIRTIO_SND_PCM_H */ diff --git a/sound/virtio/virtio_pcm_msg.c b/sound/virtio/virtio_pcm_msg.c new file mode 100644 index 000000000000..f88c8f29cbd8 --- /dev/null +++ b/sound/virtio/virtio_pcm_msg.c @@ -0,0 +1,414 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * virtio-snd: Virtio sound device + * Copyright (C) 2021 OpenSynergy GmbH + */ +#include + +#include "virtio_card.h" + +/** + * struct virtio_pcm_msg - VirtIO I/O message. + * @substream: VirtIO PCM substream. + * @xfer: Request header payload. + * @status: Response header payload. + * @length: Data length in bytes. + * @sgs: Payload scatter-gather table. + */ +struct virtio_pcm_msg { + struct virtio_pcm_substream *substream; + struct virtio_snd_pcm_xfer xfer; + struct virtio_snd_pcm_status status; + size_t length; + struct scatterlist sgs[0]; +}; + +/** + * enum pcm_msg_sg_index - Index values for the virtio_pcm_msg->sgs field in + * an I/O message. + * @PCM_MSG_SG_XFER: Element containing a virtio_snd_pcm_xfer structure. + * @PCM_MSG_SG_STATUS: Element containing a virtio_snd_pcm_status structure. + * @PCM_MSG_SG_DATA: The first element containing a data buffer. + */ +enum pcm_msg_sg_index { + PCM_MSG_SG_XFER = 0, + PCM_MSG_SG_STATUS, + PCM_MSG_SG_DATA +}; + +/** + * virtsnd_pcm_sg_num() - Count the number of sg-elements required to represent + * vmalloc'ed buffer. + * @data: Pointer to vmalloc'ed buffer. + * @length: Buffer size. + * + * Context: Any context. + * Return: Number of physically contiguous parts in the @data. + */ +static int virtsnd_pcm_sg_num(u8 *data, unsigned int length) +{ + phys_addr_t sg_address; + unsigned int sg_length; + int num = 0; + + while (length) { + struct page *pg = vmalloc_to_page(data); + phys_addr_t pg_address = page_to_phys(pg); + size_t pg_length; + + pg_length = PAGE_SIZE - offset_in_page(data); + if (pg_length > length) + pg_length = length; + + if (!num || sg_address + sg_length != pg_address) { + sg_address = pg_address; + sg_length = pg_length; + num++; + } else { + sg_length += pg_length; + } + + data += pg_length; + length -= pg_length; + } + + return num; +} + +/** + * virtsnd_pcm_sg_from() - Build sg-list from vmalloc'ed buffer. + * @sgs: Preallocated sg-list to populate. + * @nsgs: The maximum number of elements in the @sgs. + * @data: Pointer to vmalloc'ed buffer. + * @length: Buffer size. + * + * Splits the buffer into physically contiguous parts and makes an sg-list of + * such parts. + * + * Context: Any context. + */ +static void virtsnd_pcm_sg_from(struct scatterlist *sgs, int nsgs, u8 *data, + unsigned int length) +{ + int idx = -1; + + while (length) { + struct page *pg = vmalloc_to_page(data); + size_t pg_length; + + pg_length = PAGE_SIZE - offset_in_page(data); + if (pg_length > length) + pg_length = length; + + if (idx == -1 || + sg_phys(&sgs[idx]) + sgs[idx].length != page_to_phys(pg)) { + if (idx + 1 == nsgs) + break; + sg_set_page(&sgs[++idx], pg, pg_length, + offset_in_page(data)); + } else { + sgs[idx].length += pg_length; + } + + data += pg_length; + length -= pg_length; + } + + sg_mark_end(&sgs[idx]); +} + +/** + * virtsnd_pcm_msg_alloc() - Allocate I/O messages. + * @vss: VirtIO PCM substream. + * @periods: Current number of periods. + * @period_bytes: Current period size in bytes. + * + * The function slices the buffer into @periods parts (each with the size of + * @period_bytes), and creates @periods corresponding I/O messages. + * + * Context: Any context that permits to sleep. + * Return: 0 on success, -ENOMEM on failure. + */ +int virtsnd_pcm_msg_alloc(struct virtio_pcm_substream *vss, + unsigned int periods, unsigned int period_bytes) +{ + struct snd_pcm_runtime *runtime = vss->substream->runtime; + unsigned int i; + + vss->msgs = kcalloc(periods, sizeof(*vss->msgs), GFP_KERNEL); + if (!vss->msgs) + return -ENOMEM; + + vss->nmsgs = periods; + + for (i = 0; i < periods; ++i) { + u8 *data = runtime->dma_area + period_bytes * i; + int sg_num = virtsnd_pcm_sg_num(data, period_bytes); + struct virtio_pcm_msg *msg; + + msg = kzalloc(sizeof(*msg) + sizeof(*msg->sgs) * (sg_num + 2), + GFP_KERNEL); + if (!msg) + return -ENOMEM; + + msg->substream = vss; + sg_init_one(&msg->sgs[PCM_MSG_SG_XFER], &msg->xfer, + sizeof(msg->xfer)); + sg_init_one(&msg->sgs[PCM_MSG_SG_STATUS], &msg->status, + sizeof(msg->status)); + msg->length = period_bytes; + virtsnd_pcm_sg_from(&msg->sgs[PCM_MSG_SG_DATA], sg_num, data, + period_bytes); + + vss->msgs[i] = msg; + } + + return 0; +} + +/** + * virtsnd_pcm_msg_free() - Free all allocated I/O messages. + * @vss: VirtIO PCM substream. + * + * Context: Any context. + */ +void virtsnd_pcm_msg_free(struct virtio_pcm_substream *vss) +{ + unsigned int i; + + for (i = 0; vss->msgs && i < vss->nmsgs; ++i) + kfree(vss->msgs[i]); + kfree(vss->msgs); + + vss->msgs = NULL; + vss->nmsgs = 0; +} + +/** + * virtsnd_pcm_msg_send() - Send asynchronous I/O messages. + * @vss: VirtIO PCM substream. + * + * All messages are organized in an ordered circular list. Each time the + * function is called, all currently non-enqueued messages are added to the + * virtqueue. For this, the function keeps track of two values: + * + * msg_last_enqueued = index of the last enqueued message, + * msg_count = # of pending messages in the virtqueue. + * + * Context: Any context. Expects the tx/rx queue and the VirtIO substream + * spinlocks to be held by caller. + * Return: 0 on success, -errno on failure. + */ +int virtsnd_pcm_msg_send(struct virtio_pcm_substream *vss) +{ + struct snd_pcm_runtime *runtime = vss->substream->runtime; + struct virtio_snd *snd = vss->snd; + struct virtio_device *vdev = snd->vdev; + struct virtqueue *vqueue = virtsnd_pcm_queue(vss)->vqueue; + int i; + int n; + bool notify = false; + + i = (vss->msg_last_enqueued + 1) % runtime->periods; + n = runtime->periods - vss->msg_count; + + for (; n; --n, i = (i + 1) % runtime->periods) { + struct virtio_pcm_msg *msg = vss->msgs[i]; + struct scatterlist *psgs[] = { + &msg->sgs[PCM_MSG_SG_XFER], + &msg->sgs[PCM_MSG_SG_DATA], + &msg->sgs[PCM_MSG_SG_STATUS] + }; + int rc; + + msg->xfer.stream_id = cpu_to_le32(vss->sid); + memset(&msg->status, 0, sizeof(msg->status)); + + if (vss->direction == SNDRV_PCM_STREAM_PLAYBACK) + rc = virtqueue_add_sgs(vqueue, psgs, 2, 1, msg, + GFP_ATOMIC); + else + rc = virtqueue_add_sgs(vqueue, psgs, 1, 2, msg, + GFP_ATOMIC); + + if (rc) { + dev_err(&vdev->dev, + "SID %u: failed to send I/O message\n", + vss->sid); + return rc; + } + + vss->msg_last_enqueued = i; + vss->msg_count++; + } + + if (!(vss->features & (1U << VIRTIO_SND_PCM_F_MSG_POLLING))) + notify = virtqueue_kick_prepare(vqueue); + + if (notify) + virtqueue_notify(vqueue); + + return 0; +} + +/** + * virtsnd_pcm_msg_pending_num() - Returns the number of pending I/O messages. + * @vss: VirtIO substream. + * + * Context: Any context. + * Return: Number of messages. + */ +unsigned int virtsnd_pcm_msg_pending_num(struct virtio_pcm_substream *vss) +{ + unsigned int num; + unsigned long flags; + + spin_lock_irqsave(&vss->lock, flags); + num = vss->msg_count; + spin_unlock_irqrestore(&vss->lock, flags); + + return num; +} + +/** + * virtsnd_pcm_msg_complete() - Complete an I/O message. + * @msg: I/O message. + * @written_bytes: Number of bytes written to the message. + * + * Completion of the message means the elapsed period. If transmission is + * allowed, then each completed message is immediately placed back at the end + * of the queue. + * + * For the playback substream, @written_bytes is equal to sizeof(msg->status). + * + * For the capture substream, @written_bytes is equal to sizeof(msg->status) + * plus the number of captured bytes. + * + * Context: Interrupt context. Takes and releases the VirtIO substream spinlock. + */ +static void virtsnd_pcm_msg_complete(struct virtio_pcm_msg *msg, + size_t written_bytes) +{ + struct virtio_pcm_substream *vss = msg->substream; + + /* + * hw_ptr always indicates the buffer position of the first I/O message + * in the virtqueue. Therefore, on each completion of an I/O message, + * the hw_ptr value is unconditionally advanced. + */ + spin_lock(&vss->lock); + /* + * If the capture substream returned an incorrect status, then just + * increase the hw_ptr by the message size. + */ + if (vss->direction == SNDRV_PCM_STREAM_PLAYBACK || + written_bytes <= sizeof(msg->status)) + vss->hw_ptr += msg->length; + else + vss->hw_ptr += written_bytes - sizeof(msg->status); + + if (vss->hw_ptr >= vss->buffer_bytes) + vss->hw_ptr -= vss->buffer_bytes; + + vss->xfer_xrun = false; + vss->msg_count--; + + if (vss->xfer_enabled) { + struct snd_pcm_runtime *runtime = vss->substream->runtime; + + runtime->delay = + bytes_to_frames(runtime, + le32_to_cpu(msg->status.latency_bytes)); + + schedule_work(&vss->elapsed_period); + + virtsnd_pcm_msg_send(vss); + } else if (!vss->msg_count) { + wake_up_all(&vss->msg_empty); + } + spin_unlock(&vss->lock); +} + +/** + * virtsnd_pcm_notify_cb() - Process all completed I/O messages. + * @queue: Underlying tx/rx virtqueue. + * + * Context: Interrupt context. Takes and releases the tx/rx queue spinlock. + */ +static inline void virtsnd_pcm_notify_cb(struct virtio_snd_queue *queue) +{ + struct virtio_pcm_msg *msg; + u32 written_bytes; + unsigned long flags; + + spin_lock_irqsave(&queue->lock, flags); + do { + virtqueue_disable_cb(queue->vqueue); + while ((msg = virtqueue_get_buf(queue->vqueue, &written_bytes))) + virtsnd_pcm_msg_complete(msg, written_bytes); + if (unlikely(virtqueue_is_broken(queue->vqueue))) + break; + } while (!virtqueue_enable_cb(queue->vqueue)); + spin_unlock_irqrestore(&queue->lock, flags); +} + +/** + * virtsnd_pcm_tx_notify_cb() - Process all completed TX messages. + * @vqueue: Underlying tx virtqueue. + * + * Context: Interrupt context. + */ +void virtsnd_pcm_tx_notify_cb(struct virtqueue *vqueue) +{ + struct virtio_snd *snd = vqueue->vdev->priv; + + virtsnd_pcm_notify_cb(virtsnd_tx_queue(snd)); +} + +/** + * virtsnd_pcm_rx_notify_cb() - Process all completed RX messages. + * @vqueue: Underlying rx virtqueue. + * + * Context: Interrupt context. + */ +void virtsnd_pcm_rx_notify_cb(struct virtqueue *vqueue) +{ + struct virtio_snd *snd = vqueue->vdev->priv; + + virtsnd_pcm_notify_cb(virtsnd_rx_queue(snd)); +} + +/** + * virtsnd_pcm_ctl_msg_alloc() - Allocate and initialize the PCM device control + * message for the specified substream. + * @vss: VirtIO PCM substream. + * @command: Control request code (VIRTIO_SND_R_PCM_XXX). + * @gfp: Kernel flags for memory allocation. + * + * Context: Any context. May sleep if @gfp flags permit. + * Return: Allocated message on success, NULL on failure. + */ +struct virtio_snd_msg * +virtsnd_pcm_ctl_msg_alloc(struct virtio_pcm_substream *vss, + unsigned int command, gfp_t gfp) +{ + size_t request_size = sizeof(struct virtio_snd_pcm_hdr); + size_t response_size = sizeof(struct virtio_snd_hdr); + struct virtio_snd_msg *msg; + + switch (command) { + case VIRTIO_SND_R_PCM_SET_PARAMS: + request_size = sizeof(struct virtio_snd_pcm_set_params); + break; + } + + msg = virtsnd_ctl_msg_alloc(request_size, response_size, gfp); + if (msg) { + struct virtio_snd_pcm_hdr *hdr = virtsnd_ctl_msg_request(msg); + + hdr->hdr.code = cpu_to_le32(command); + hdr->stream_id = cpu_to_le32(vss->sid); + } + + return msg; +} From da76e9f3e43a7195c69d370ee514cccae6517c76 Mon Sep 17 00:00:00 2001 From: Anton Yakovlev Date: Tue, 2 Mar 2021 17:47:06 +0100 Subject: [PATCH 034/587] ALSA: virtio: PCM substream operators Introduce the operators required for the operation of substreams. Signed-off-by: Anton Yakovlev Link: https://lore.kernel.org/r/20210302164709.3142702-7-anton.yakovlev@opensynergy.com Signed-off-by: Takashi Iwai --- sound/virtio/Makefile | 3 +- sound/virtio/virtio_pcm.c | 2 + sound/virtio/virtio_pcm.h | 5 + sound/virtio/virtio_pcm_ops.c | 445 ++++++++++++++++++++++++++++++++++ 4 files changed, 454 insertions(+), 1 deletion(-) create mode 100644 sound/virtio/virtio_pcm_ops.c diff --git a/sound/virtio/Makefile b/sound/virtio/Makefile index 626af3cc3ed7..34493226793f 100644 --- a/sound/virtio/Makefile +++ b/sound/virtio/Makefile @@ -6,5 +6,6 @@ virtio_snd-objs := \ virtio_card.o \ virtio_ctl_msg.o \ virtio_pcm.o \ - virtio_pcm_msg.o + virtio_pcm_msg.o \ + virtio_pcm_ops.o diff --git a/sound/virtio/virtio_pcm.c b/sound/virtio/virtio_pcm.c index 2dcd763efa29..c10d91fff2fb 100644 --- a/sound/virtio/virtio_pcm.c +++ b/sound/virtio/virtio_pcm.c @@ -470,6 +470,8 @@ int virtsnd_pcm_build_devs(struct virtio_snd *snd) for (kss = ks->substream; kss; kss = kss->next) vs->substreams[kss->number]->substream = kss; + + snd_pcm_set_ops(vpcm->pcm, i, &virtsnd_pcm_ops); } snd_pcm_set_managed_buffer_all(vpcm->pcm, diff --git a/sound/virtio/virtio_pcm.h b/sound/virtio/virtio_pcm.h index 6722f1139666..efd0228746cf 100644 --- a/sound/virtio/virtio_pcm.h +++ b/sound/virtio/virtio_pcm.h @@ -29,6 +29,8 @@ struct virtio_pcm_msg; * @hw_ptr: Substream hardware pointer value in bytes [0 ... buffer_bytes). * @xfer_enabled: Data transfer state (0 - off, 1 - on). * @xfer_xrun: Data underflow/overflow state (0 - no xrun, 1 - xrun). + * @stopped: True if the substream is stopped and must be released on the device + * side. * @msgs: Allocated I/O messages. * @nmsgs: Number of allocated I/O messages. * @msg_last_enqueued: Index of the last I/O message added to the virtqueue. @@ -49,6 +51,7 @@ struct virtio_pcm_substream { size_t hw_ptr; bool xfer_enabled; bool xfer_xrun; + bool stopped; struct virtio_pcm_msg **msgs; unsigned int nmsgs; int msg_last_enqueued; @@ -80,6 +83,8 @@ struct virtio_pcm { struct virtio_pcm_stream streams[SNDRV_PCM_STREAM_LAST + 1]; }; +extern const struct snd_pcm_ops virtsnd_pcm_ops; + int virtsnd_pcm_validate(struct virtio_device *vdev); int virtsnd_pcm_parse_cfg(struct virtio_snd *snd); diff --git a/sound/virtio/virtio_pcm_ops.c b/sound/virtio/virtio_pcm_ops.c new file mode 100644 index 000000000000..0682a2df6c8c --- /dev/null +++ b/sound/virtio/virtio_pcm_ops.c @@ -0,0 +1,445 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * virtio-snd: Virtio sound device + * Copyright (C) 2021 OpenSynergy GmbH + */ +#include + +#include "virtio_card.h" + +/* + * I/O messages lifetime + * --------------------- + * + * Allocation: + * Messages are initially allocated in the ops->hw_params() after the size and + * number of periods have been successfully negotiated. + * + * Freeing: + * Messages can be safely freed after the queue has been successfully flushed + * (RELEASE command in the ops->sync_stop()) and the ops->hw_free() has been + * called. + * + * When the substream stops, the ops->sync_stop() waits until the device has + * completed all pending messages. This wait can be interrupted either by a + * signal or due to a timeout. In this case, the device can still access + * messages even after calling ops->hw_free(). It can also issue an interrupt, + * and the interrupt handler will also try to access message structures. + * + * Therefore, freeing of already allocated messages occurs: + * + * - in ops->hw_params(), if this operator was called several times in a row, + * or if ops->hw_free() failed to free messages previously; + * + * - in ops->hw_free(), if the queue has been successfully flushed; + * + * - in dev->release(). + */ + +/* Map for converting ALSA format to VirtIO format. */ +struct virtsnd_a2v_format { + snd_pcm_format_t alsa_bit; + unsigned int vio_bit; +}; + +static const struct virtsnd_a2v_format g_a2v_format_map[] = { + { SNDRV_PCM_FORMAT_IMA_ADPCM, VIRTIO_SND_PCM_FMT_IMA_ADPCM }, + { SNDRV_PCM_FORMAT_MU_LAW, VIRTIO_SND_PCM_FMT_MU_LAW }, + { SNDRV_PCM_FORMAT_A_LAW, VIRTIO_SND_PCM_FMT_A_LAW }, + { SNDRV_PCM_FORMAT_S8, VIRTIO_SND_PCM_FMT_S8 }, + { SNDRV_PCM_FORMAT_U8, VIRTIO_SND_PCM_FMT_U8 }, + { SNDRV_PCM_FORMAT_S16_LE, VIRTIO_SND_PCM_FMT_S16 }, + { SNDRV_PCM_FORMAT_U16_LE, VIRTIO_SND_PCM_FMT_U16 }, + { SNDRV_PCM_FORMAT_S18_3LE, VIRTIO_SND_PCM_FMT_S18_3 }, + { SNDRV_PCM_FORMAT_U18_3LE, VIRTIO_SND_PCM_FMT_U18_3 }, + { SNDRV_PCM_FORMAT_S20_3LE, VIRTIO_SND_PCM_FMT_S20_3 }, + { SNDRV_PCM_FORMAT_U20_3LE, VIRTIO_SND_PCM_FMT_U20_3 }, + { SNDRV_PCM_FORMAT_S24_3LE, VIRTIO_SND_PCM_FMT_S24_3 }, + { SNDRV_PCM_FORMAT_U24_3LE, VIRTIO_SND_PCM_FMT_U24_3 }, + { SNDRV_PCM_FORMAT_S20_LE, VIRTIO_SND_PCM_FMT_S20 }, + { SNDRV_PCM_FORMAT_U20_LE, VIRTIO_SND_PCM_FMT_U20 }, + { SNDRV_PCM_FORMAT_S24_LE, VIRTIO_SND_PCM_FMT_S24 }, + { SNDRV_PCM_FORMAT_U24_LE, VIRTIO_SND_PCM_FMT_U24 }, + { SNDRV_PCM_FORMAT_S32_LE, VIRTIO_SND_PCM_FMT_S32 }, + { SNDRV_PCM_FORMAT_U32_LE, VIRTIO_SND_PCM_FMT_U32 }, + { SNDRV_PCM_FORMAT_FLOAT_LE, VIRTIO_SND_PCM_FMT_FLOAT }, + { SNDRV_PCM_FORMAT_FLOAT64_LE, VIRTIO_SND_PCM_FMT_FLOAT64 }, + { SNDRV_PCM_FORMAT_DSD_U8, VIRTIO_SND_PCM_FMT_DSD_U8 }, + { SNDRV_PCM_FORMAT_DSD_U16_LE, VIRTIO_SND_PCM_FMT_DSD_U16 }, + { SNDRV_PCM_FORMAT_DSD_U32_LE, VIRTIO_SND_PCM_FMT_DSD_U32 }, + { SNDRV_PCM_FORMAT_IEC958_SUBFRAME_LE, + VIRTIO_SND_PCM_FMT_IEC958_SUBFRAME } +}; + +/* Map for converting ALSA frame rate to VirtIO frame rate. */ +struct virtsnd_a2v_rate { + unsigned int rate; + unsigned int vio_bit; +}; + +static const struct virtsnd_a2v_rate g_a2v_rate_map[] = { + { 5512, VIRTIO_SND_PCM_RATE_5512 }, + { 8000, VIRTIO_SND_PCM_RATE_8000 }, + { 11025, VIRTIO_SND_PCM_RATE_11025 }, + { 16000, VIRTIO_SND_PCM_RATE_16000 }, + { 22050, VIRTIO_SND_PCM_RATE_22050 }, + { 32000, VIRTIO_SND_PCM_RATE_32000 }, + { 44100, VIRTIO_SND_PCM_RATE_44100 }, + { 48000, VIRTIO_SND_PCM_RATE_48000 }, + { 64000, VIRTIO_SND_PCM_RATE_64000 }, + { 88200, VIRTIO_SND_PCM_RATE_88200 }, + { 96000, VIRTIO_SND_PCM_RATE_96000 }, + { 176400, VIRTIO_SND_PCM_RATE_176400 }, + { 192000, VIRTIO_SND_PCM_RATE_192000 } +}; + +static int virtsnd_pcm_sync_stop(struct snd_pcm_substream *substream); + +/** + * virtsnd_pcm_open() - Open the PCM substream. + * @substream: Kernel ALSA substream. + * + * Context: Process context. + * Return: 0 on success, -errno on failure. + */ +static int virtsnd_pcm_open(struct snd_pcm_substream *substream) +{ + struct virtio_pcm *vpcm = snd_pcm_substream_chip(substream); + struct virtio_pcm_stream *vs = &vpcm->streams[substream->stream]; + struct virtio_pcm_substream *vss = vs->substreams[substream->number]; + + substream->runtime->hw = vss->hw; + substream->private_data = vss; + + snd_pcm_hw_constraint_integer(substream->runtime, + SNDRV_PCM_HW_PARAM_PERIODS); + + vss->stopped = !!virtsnd_pcm_msg_pending_num(vss); + + /* + * If the substream has already been used, then the I/O queue may be in + * an invalid state. Just in case, we do a check and try to return the + * queue to its original state, if necessary. + */ + return virtsnd_pcm_sync_stop(substream); +} + +/** + * virtsnd_pcm_close() - Close the PCM substream. + * @substream: Kernel ALSA substream. + * + * Context: Process context. + * Return: 0. + */ +static int virtsnd_pcm_close(struct snd_pcm_substream *substream) +{ + return 0; +} + +/** + * virtsnd_pcm_dev_set_params() - Set the parameters of the PCM substream on + * the device side. + * @vss: VirtIO PCM substream. + * @buffer_bytes: Size of the hardware buffer. + * @period_bytes: Size of the hardware period. + * @channels: Selected number of channels. + * @format: Selected sample format (SNDRV_PCM_FORMAT_XXX). + * @rate: Selected frame rate. + * + * Context: Any context that permits to sleep. + * Return: 0 on success, -errno on failure. + */ +static int virtsnd_pcm_dev_set_params(struct virtio_pcm_substream *vss, + unsigned int buffer_bytes, + unsigned int period_bytes, + unsigned int channels, + snd_pcm_format_t format, + unsigned int rate) +{ + struct virtio_snd_msg *msg; + struct virtio_snd_pcm_set_params *request; + unsigned int i; + int vformat = -1; + int vrate = -1; + + for (i = 0; i < ARRAY_SIZE(g_a2v_format_map); ++i) + if (g_a2v_format_map[i].alsa_bit == format) { + vformat = g_a2v_format_map[i].vio_bit; + + break; + } + + for (i = 0; i < ARRAY_SIZE(g_a2v_rate_map); ++i) + if (g_a2v_rate_map[i].rate == rate) { + vrate = g_a2v_rate_map[i].vio_bit; + + break; + } + + if (vformat == -1 || vrate == -1) + return -EINVAL; + + msg = virtsnd_pcm_ctl_msg_alloc(vss, VIRTIO_SND_R_PCM_SET_PARAMS, + GFP_KERNEL); + if (!msg) + return -ENOMEM; + + request = virtsnd_ctl_msg_request(msg); + request->buffer_bytes = cpu_to_le32(buffer_bytes); + request->period_bytes = cpu_to_le32(period_bytes); + request->channels = channels; + request->format = vformat; + request->rate = vrate; + + if (vss->features & (1U << VIRTIO_SND_PCM_F_MSG_POLLING)) + request->features |= + cpu_to_le32(1U << VIRTIO_SND_PCM_F_MSG_POLLING); + + if (vss->features & (1U << VIRTIO_SND_PCM_F_EVT_XRUNS)) + request->features |= + cpu_to_le32(1U << VIRTIO_SND_PCM_F_EVT_XRUNS); + + return virtsnd_ctl_msg_send_sync(vss->snd, msg); +} + +/** + * virtsnd_pcm_hw_params() - Set the parameters of the PCM substream. + * @substream: Kernel ALSA substream. + * @hw_params: Hardware parameters. + * + * Context: Process context. + * Return: 0 on success, -errno on failure. + */ +static int virtsnd_pcm_hw_params(struct snd_pcm_substream *substream, + struct snd_pcm_hw_params *hw_params) +{ + struct virtio_pcm_substream *vss = snd_pcm_substream_chip(substream); + struct virtio_device *vdev = vss->snd->vdev; + int rc; + + if (virtsnd_pcm_msg_pending_num(vss)) { + dev_err(&vdev->dev, "SID %u: invalid I/O queue state\n", + vss->sid); + return -EBADFD; + } + + rc = virtsnd_pcm_dev_set_params(vss, params_buffer_bytes(hw_params), + params_period_bytes(hw_params), + params_channels(hw_params), + params_format(hw_params), + params_rate(hw_params)); + if (rc) + return rc; + + /* + * Free previously allocated messages if ops->hw_params() is called + * several times in a row, or if ops->hw_free() failed to free messages. + */ + virtsnd_pcm_msg_free(vss); + + return virtsnd_pcm_msg_alloc(vss, params_periods(hw_params), + params_period_bytes(hw_params)); +} + +/** + * virtsnd_pcm_hw_free() - Reset the parameters of the PCM substream. + * @substream: Kernel ALSA substream. + * + * Context: Process context. + * Return: 0 + */ +static int virtsnd_pcm_hw_free(struct snd_pcm_substream *substream) +{ + struct virtio_pcm_substream *vss = snd_pcm_substream_chip(substream); + + /* If the queue is flushed, we can safely free the messages here. */ + if (!virtsnd_pcm_msg_pending_num(vss)) + virtsnd_pcm_msg_free(vss); + + return 0; +} + +/** + * virtsnd_pcm_prepare() - Prepare the PCM substream. + * @substream: Kernel ALSA substream. + * + * Context: Process context. + * Return: 0 on success, -errno on failure. + */ +static int virtsnd_pcm_prepare(struct snd_pcm_substream *substream) +{ + struct virtio_pcm_substream *vss = snd_pcm_substream_chip(substream); + struct virtio_device *vdev = vss->snd->vdev; + struct virtio_snd_msg *msg; + + if (virtsnd_pcm_msg_pending_num(vss)) { + dev_err(&vdev->dev, "SID %u: invalid I/O queue state\n", + vss->sid); + return -EBADFD; + } + + vss->buffer_bytes = snd_pcm_lib_buffer_bytes(substream); + vss->hw_ptr = 0; + vss->xfer_xrun = false; + vss->msg_last_enqueued = -1; + vss->msg_count = 0; + + msg = virtsnd_pcm_ctl_msg_alloc(vss, VIRTIO_SND_R_PCM_PREPARE, + GFP_KERNEL); + if (!msg) + return -ENOMEM; + + return virtsnd_ctl_msg_send_sync(vss->snd, msg); +} + +/** + * virtsnd_pcm_trigger() - Process command for the PCM substream. + * @substream: Kernel ALSA substream. + * @command: Substream command (SNDRV_PCM_TRIGGER_XXX). + * + * Context: Any context. Takes and releases the VirtIO substream spinlock. + * May take and release the tx/rx queue spinlock. + * Return: 0 on success, -errno on failure. + */ +static int virtsnd_pcm_trigger(struct snd_pcm_substream *substream, int command) +{ + struct virtio_pcm_substream *vss = snd_pcm_substream_chip(substream); + struct virtio_snd *snd = vss->snd; + struct virtio_snd_queue *queue; + struct virtio_snd_msg *msg; + unsigned long flags; + int rc; + + switch (command) { + case SNDRV_PCM_TRIGGER_START: + case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: + queue = virtsnd_pcm_queue(vss); + + spin_lock_irqsave(&queue->lock, flags); + spin_lock(&vss->lock); + rc = virtsnd_pcm_msg_send(vss); + if (!rc) + vss->xfer_enabled = true; + spin_unlock(&vss->lock); + spin_unlock_irqrestore(&queue->lock, flags); + if (rc) + return rc; + + msg = virtsnd_pcm_ctl_msg_alloc(vss, VIRTIO_SND_R_PCM_START, + GFP_KERNEL); + if (!msg) { + spin_lock_irqsave(&vss->lock, flags); + vss->xfer_enabled = false; + spin_unlock_irqrestore(&vss->lock, flags); + + return -ENOMEM; + } + + return virtsnd_ctl_msg_send_sync(snd, msg); + case SNDRV_PCM_TRIGGER_STOP: + vss->stopped = true; + fallthrough; + case SNDRV_PCM_TRIGGER_PAUSE_PUSH: + spin_lock_irqsave(&vss->lock, flags); + vss->xfer_enabled = false; + spin_unlock_irqrestore(&vss->lock, flags); + + msg = virtsnd_pcm_ctl_msg_alloc(vss, VIRTIO_SND_R_PCM_STOP, + GFP_KERNEL); + if (!msg) + return -ENOMEM; + + return virtsnd_ctl_msg_send_sync(snd, msg); + default: + return -EINVAL; + } +} + +/** + * virtsnd_pcm_sync_stop() - Synchronous PCM substream stop. + * @substream: Kernel ALSA substream. + * + * The function can be called both from the upper level or from the driver + * itself. + * + * Context: Process context. Takes and releases the VirtIO substream spinlock. + * Return: 0 on success, -errno on failure. + */ +static int virtsnd_pcm_sync_stop(struct snd_pcm_substream *substream) +{ + struct virtio_pcm_substream *vss = snd_pcm_substream_chip(substream); + struct virtio_snd *snd = vss->snd; + struct virtio_snd_msg *msg; + unsigned int js = msecs_to_jiffies(virtsnd_msg_timeout_ms); + int rc; + + cancel_work_sync(&vss->elapsed_period); + + if (!vss->stopped) + return 0; + + msg = virtsnd_pcm_ctl_msg_alloc(vss, VIRTIO_SND_R_PCM_RELEASE, + GFP_KERNEL); + if (!msg) + return -ENOMEM; + + rc = virtsnd_ctl_msg_send_sync(snd, msg); + if (rc) + return rc; + + /* + * The spec states that upon receipt of the RELEASE command "the device + * MUST complete all pending I/O messages for the specified stream ID". + * Thus, we consider the absence of I/O messages in the queue as an + * indication that the substream has been released. + */ + rc = wait_event_interruptible_timeout(vss->msg_empty, + !virtsnd_pcm_msg_pending_num(vss), + js); + if (rc <= 0) { + dev_warn(&snd->vdev->dev, "SID %u: failed to flush I/O queue\n", + vss->sid); + + return !rc ? -ETIMEDOUT : rc; + } + + vss->stopped = false; + + return 0; +} + +/** + * virtsnd_pcm_pointer() - Get the current hardware position for the PCM + * substream. + * @substream: Kernel ALSA substream. + * + * Context: Any context. Takes and releases the VirtIO substream spinlock. + * Return: Hardware position in frames inside [0 ... buffer_size) range. + */ +static snd_pcm_uframes_t +virtsnd_pcm_pointer(struct snd_pcm_substream *substream) +{ + struct virtio_pcm_substream *vss = snd_pcm_substream_chip(substream); + snd_pcm_uframes_t hw_ptr = SNDRV_PCM_POS_XRUN; + unsigned long flags; + + spin_lock_irqsave(&vss->lock, flags); + if (!vss->xfer_xrun) + hw_ptr = bytes_to_frames(substream->runtime, vss->hw_ptr); + spin_unlock_irqrestore(&vss->lock, flags); + + return hw_ptr; +} + +/* PCM substream operators map. */ +const struct snd_pcm_ops virtsnd_pcm_ops = { + .open = virtsnd_pcm_open, + .close = virtsnd_pcm_close, + .ioctl = snd_pcm_lib_ioctl, + .hw_params = virtsnd_pcm_hw_params, + .hw_free = virtsnd_pcm_hw_free, + .prepare = virtsnd_pcm_prepare, + .trigger = virtsnd_pcm_trigger, + .sync_stop = virtsnd_pcm_sync_stop, + .pointer = virtsnd_pcm_pointer, +}; From ca61a41f389c80db091db9d4ad5a651e2b4c9f70 Mon Sep 17 00:00:00 2001 From: Anton Yakovlev Date: Tue, 2 Mar 2021 17:47:07 +0100 Subject: [PATCH 035/587] ALSA: virtio: introduce jack support Enumerate all available jacks and create ALSA controls. At the moment jacks have a simple implementation and can only be used to receive notifications about a plugged in/out device. Signed-off-by: Anton Yakovlev Link: https://lore.kernel.org/r/20210302164709.3142702-8-anton.yakovlev@opensynergy.com Signed-off-by: Takashi Iwai --- sound/virtio/Makefile | 1 + sound/virtio/virtio_card.c | 14 +++ sound/virtio/virtio_card.h | 12 ++ sound/virtio/virtio_jack.c | 233 +++++++++++++++++++++++++++++++++++++ 4 files changed, 260 insertions(+) create mode 100644 sound/virtio/virtio_jack.c diff --git a/sound/virtio/Makefile b/sound/virtio/Makefile index 34493226793f..09f485291285 100644 --- a/sound/virtio/Makefile +++ b/sound/virtio/Makefile @@ -5,6 +5,7 @@ obj-$(CONFIG_SND_VIRTIO) += virtio_snd.o virtio_snd-objs := \ virtio_card.o \ virtio_ctl_msg.o \ + virtio_jack.o \ virtio_pcm.o \ virtio_pcm_msg.o \ virtio_pcm_ops.o diff --git a/sound/virtio/virtio_card.c b/sound/virtio/virtio_card.c index 57b9b7f3a9c0..89bd66c1256e 100644 --- a/sound/virtio/virtio_card.c +++ b/sound/virtio/virtio_card.c @@ -56,6 +56,10 @@ static void virtsnd_event_dispatch(struct virtio_snd *snd, struct virtio_snd_event *event) { switch (le32_to_cpu(event->hdr.code)) { + case VIRTIO_SND_EVT_JACK_CONNECTED: + case VIRTIO_SND_EVT_JACK_DISCONNECTED: + virtsnd_jack_event(snd, event); + break; case VIRTIO_SND_EVT_PCM_PERIOD_ELAPSED: case VIRTIO_SND_EVT_PCM_XRUN: virtsnd_pcm_event(snd, event); @@ -219,10 +223,20 @@ static int virtsnd_build_devs(struct virtio_snd *snd) VIRTIO_SND_CARD_NAME " at %s/%s", dev_name(dev->parent), dev_name(dev)); + rc = virtsnd_jack_parse_cfg(snd); + if (rc) + return rc; + rc = virtsnd_pcm_parse_cfg(snd); if (rc) return rc; + if (snd->njacks) { + rc = virtsnd_jack_build_devs(snd); + if (rc) + return rc; + } + if (snd->nsubstreams) { rc = virtsnd_pcm_build_devs(snd); if (rc) diff --git a/sound/virtio/virtio_card.h b/sound/virtio/virtio_card.h index c43f9744d362..f154313c79fd 100644 --- a/sound/virtio/virtio_card.h +++ b/sound/virtio/virtio_card.h @@ -18,6 +18,7 @@ #define VIRTIO_SND_CARD_NAME "VirtIO SoundCard" #define VIRTIO_SND_PCM_NAME "VirtIO PCM" +struct virtio_jack; struct virtio_pcm_substream; /** @@ -38,6 +39,8 @@ struct virtio_snd_queue { * @ctl_msgs: Pending control request list. * @event_msgs: Device events. * @pcm_list: VirtIO PCM device list. + * @jacks: VirtIO jacks. + * @njacks: Number of jacks. * @substreams: VirtIO PCM substreams. * @nsubstreams: Number of PCM substreams. */ @@ -48,6 +51,8 @@ struct virtio_snd { struct list_head ctl_msgs; struct virtio_snd_event *event_msgs; struct list_head pcm_list; + struct virtio_jack *jacks; + u32 njacks; struct virtio_pcm_substream *substreams; u32 nsubstreams; }; @@ -88,4 +93,11 @@ virtsnd_pcm_queue(struct virtio_pcm_substream *vss) return virtsnd_rx_queue(vss->snd); } +int virtsnd_jack_parse_cfg(struct virtio_snd *snd); + +int virtsnd_jack_build_devs(struct virtio_snd *snd); + +void virtsnd_jack_event(struct virtio_snd *snd, + struct virtio_snd_event *event); + #endif /* VIRTIO_SND_CARD_H */ diff --git a/sound/virtio/virtio_jack.c b/sound/virtio/virtio_jack.c new file mode 100644 index 000000000000..c69f1dcdcc84 --- /dev/null +++ b/sound/virtio/virtio_jack.c @@ -0,0 +1,233 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * virtio-snd: Virtio sound device + * Copyright (C) 2021 OpenSynergy GmbH + */ +#include +#include +#include + +#include "virtio_card.h" + +/** + * DOC: Implementation Status + * + * At the moment jacks have a simple implementation and can only be used to + * receive notifications about a plugged in/out device. + * + * VIRTIO_SND_R_JACK_REMAP + * is not supported + */ + +/** + * struct virtio_jack - VirtIO jack. + * @jack: Kernel jack control. + * @nid: Functional group node identifier. + * @features: Jack virtio feature bit map (1 << VIRTIO_SND_JACK_F_XXX). + * @defconf: Pin default configuration value. + * @caps: Pin capabilities value. + * @connected: Current jack connection status. + * @type: Kernel jack type (SND_JACK_XXX). + */ +struct virtio_jack { + struct snd_jack *jack; + u32 nid; + u32 features; + u32 defconf; + u32 caps; + bool connected; + int type; +}; + +/** + * virtsnd_jack_get_label() - Get the name string for the jack. + * @vjack: VirtIO jack. + * + * Returns the jack name based on the default pin configuration value (see HDA + * specification). + * + * Context: Any context. + * Return: Name string. + */ +static const char *virtsnd_jack_get_label(struct virtio_jack *vjack) +{ + unsigned int defconf = vjack->defconf; + unsigned int device = + (defconf & AC_DEFCFG_DEVICE) >> AC_DEFCFG_DEVICE_SHIFT; + unsigned int location = + (defconf & AC_DEFCFG_LOCATION) >> AC_DEFCFG_LOCATION_SHIFT; + + switch (device) { + case AC_JACK_LINE_OUT: + return "Line Out"; + case AC_JACK_SPEAKER: + return "Speaker"; + case AC_JACK_HP_OUT: + return "Headphone"; + case AC_JACK_CD: + return "CD"; + case AC_JACK_SPDIF_OUT: + case AC_JACK_DIG_OTHER_OUT: + if (location == AC_JACK_LOC_HDMI) + return "HDMI Out"; + else + return "SPDIF Out"; + case AC_JACK_LINE_IN: + return "Line"; + case AC_JACK_AUX: + return "Aux"; + case AC_JACK_MIC_IN: + return "Mic"; + case AC_JACK_SPDIF_IN: + return "SPDIF In"; + case AC_JACK_DIG_OTHER_IN: + return "Digital In"; + default: + return "Misc"; + } +} + +/** + * virtsnd_jack_get_type() - Get the type for the jack. + * @vjack: VirtIO jack. + * + * Returns the jack type based on the default pin configuration value (see HDA + * specification). + * + * Context: Any context. + * Return: SND_JACK_XXX value. + */ +static int virtsnd_jack_get_type(struct virtio_jack *vjack) +{ + unsigned int defconf = vjack->defconf; + unsigned int device = + (defconf & AC_DEFCFG_DEVICE) >> AC_DEFCFG_DEVICE_SHIFT; + + switch (device) { + case AC_JACK_LINE_OUT: + case AC_JACK_SPEAKER: + return SND_JACK_LINEOUT; + case AC_JACK_HP_OUT: + return SND_JACK_HEADPHONE; + case AC_JACK_SPDIF_OUT: + case AC_JACK_DIG_OTHER_OUT: + return SND_JACK_AVOUT; + case AC_JACK_MIC_IN: + return SND_JACK_MICROPHONE; + default: + return SND_JACK_LINEIN; + } +} + +/** + * virtsnd_jack_parse_cfg() - Parse the jack configuration. + * @snd: VirtIO sound device. + * + * This function is called during initial device initialization. + * + * Context: Any context that permits to sleep. + * Return: 0 on success, -errno on failure. + */ +int virtsnd_jack_parse_cfg(struct virtio_snd *snd) +{ + struct virtio_device *vdev = snd->vdev; + struct virtio_snd_jack_info *info; + u32 i; + int rc; + + virtio_cread_le(vdev, struct virtio_snd_config, jacks, &snd->njacks); + if (!snd->njacks) + return 0; + + snd->jacks = devm_kcalloc(&vdev->dev, snd->njacks, sizeof(*snd->jacks), + GFP_KERNEL); + if (!snd->jacks) + return -ENOMEM; + + info = kcalloc(snd->njacks, sizeof(*info), GFP_KERNEL); + if (!info) + return -ENOMEM; + + rc = virtsnd_ctl_query_info(snd, VIRTIO_SND_R_JACK_INFO, 0, snd->njacks, + sizeof(*info), info); + if (rc) + goto on_exit; + + for (i = 0; i < snd->njacks; ++i) { + struct virtio_jack *vjack = &snd->jacks[i]; + + vjack->nid = le32_to_cpu(info[i].hdr.hda_fn_nid); + vjack->features = le32_to_cpu(info[i].features); + vjack->defconf = le32_to_cpu(info[i].hda_reg_defconf); + vjack->caps = le32_to_cpu(info[i].hda_reg_caps); + vjack->connected = info[i].connected; + } + +on_exit: + kfree(info); + + return rc; +} + +/** + * virtsnd_jack_build_devs() - Build ALSA controls for jacks. + * @snd: VirtIO sound device. + * + * Context: Any context that permits to sleep. + * Return: 0 on success, -errno on failure. + */ +int virtsnd_jack_build_devs(struct virtio_snd *snd) +{ + u32 i; + int rc; + + for (i = 0; i < snd->njacks; ++i) { + struct virtio_jack *vjack = &snd->jacks[i]; + + vjack->type = virtsnd_jack_get_type(vjack); + + rc = snd_jack_new(snd->card, virtsnd_jack_get_label(vjack), + vjack->type, &vjack->jack, true, true); + if (rc) + return rc; + + if (vjack->jack) + vjack->jack->private_data = vjack; + + snd_jack_report(vjack->jack, + vjack->connected ? vjack->type : 0); + } + + return 0; +} + +/** + * virtsnd_jack_event() - Handle the jack event notification. + * @snd: VirtIO sound device. + * @event: VirtIO sound event. + * + * Context: Interrupt context. + */ +void virtsnd_jack_event(struct virtio_snd *snd, struct virtio_snd_event *event) +{ + u32 jack_id = le32_to_cpu(event->data); + struct virtio_jack *vjack; + + if (jack_id >= snd->njacks) + return; + + vjack = &snd->jacks[jack_id]; + + switch (le32_to_cpu(event->hdr.code)) { + case VIRTIO_SND_EVT_JACK_CONNECTED: + vjack->connected = true; + break; + case VIRTIO_SND_EVT_JACK_DISCONNECTED: + vjack->connected = false; + break; + default: + return; + } + + snd_jack_report(vjack->jack, vjack->connected ? vjack->type : 0); +} From 19325fedf245ca932c58a629d3888a9a393534ab Mon Sep 17 00:00:00 2001 From: Anton Yakovlev Date: Tue, 2 Mar 2021 17:47:08 +0100 Subject: [PATCH 036/587] ALSA: virtio: introduce PCM channel map support Enumerate all available PCM channel maps and create ALSA controls. Signed-off-by: Anton Yakovlev Link: https://lore.kernel.org/r/20210302164709.3142702-9-anton.yakovlev@opensynergy.com Signed-off-by: Takashi Iwai --- sound/virtio/Makefile | 1 + sound/virtio/virtio_card.c | 10 ++ sound/virtio/virtio_card.h | 8 ++ sound/virtio/virtio_chmap.c | 219 ++++++++++++++++++++++++++++++++++++ sound/virtio/virtio_pcm.h | 4 + 5 files changed, 242 insertions(+) create mode 100644 sound/virtio/virtio_chmap.c diff --git a/sound/virtio/Makefile b/sound/virtio/Makefile index 09f485291285..2742bddb8874 100644 --- a/sound/virtio/Makefile +++ b/sound/virtio/Makefile @@ -4,6 +4,7 @@ obj-$(CONFIG_SND_VIRTIO) += virtio_snd.o virtio_snd-objs := \ virtio_card.o \ + virtio_chmap.o \ virtio_ctl_msg.o \ virtio_jack.o \ virtio_pcm.o \ diff --git a/sound/virtio/virtio_card.c b/sound/virtio/virtio_card.c index 89bd66c1256e..1c03fcc41c3b 100644 --- a/sound/virtio/virtio_card.c +++ b/sound/virtio/virtio_card.c @@ -231,6 +231,10 @@ static int virtsnd_build_devs(struct virtio_snd *snd) if (rc) return rc; + rc = virtsnd_chmap_parse_cfg(snd); + if (rc) + return rc; + if (snd->njacks) { rc = virtsnd_jack_build_devs(snd); if (rc) @@ -243,6 +247,12 @@ static int virtsnd_build_devs(struct virtio_snd *snd) return rc; } + if (snd->nchmaps) { + rc = virtsnd_chmap_build_devs(snd); + if (rc) + return rc; + } + return snd_card_register(snd->card); } diff --git a/sound/virtio/virtio_card.h b/sound/virtio/virtio_card.h index f154313c79fd..86ef3941895e 100644 --- a/sound/virtio/virtio_card.h +++ b/sound/virtio/virtio_card.h @@ -43,6 +43,8 @@ struct virtio_snd_queue { * @njacks: Number of jacks. * @substreams: VirtIO PCM substreams. * @nsubstreams: Number of PCM substreams. + * @chmaps: VirtIO channel maps. + * @nchmaps: Number of channel maps. */ struct virtio_snd { struct virtio_device *vdev; @@ -55,6 +57,8 @@ struct virtio_snd { u32 njacks; struct virtio_pcm_substream *substreams; u32 nsubstreams; + struct virtio_snd_chmap_info *chmaps; + u32 nchmaps; }; /* Message completion timeout in milliseconds (module parameter). */ @@ -100,4 +104,8 @@ int virtsnd_jack_build_devs(struct virtio_snd *snd); void virtsnd_jack_event(struct virtio_snd *snd, struct virtio_snd_event *event); +int virtsnd_chmap_parse_cfg(struct virtio_snd *snd); + +int virtsnd_chmap_build_devs(struct virtio_snd *snd); + #endif /* VIRTIO_SND_CARD_H */ diff --git a/sound/virtio/virtio_chmap.c b/sound/virtio/virtio_chmap.c new file mode 100644 index 000000000000..5bc924933a59 --- /dev/null +++ b/sound/virtio/virtio_chmap.c @@ -0,0 +1,219 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * virtio-snd: Virtio sound device + * Copyright (C) 2021 OpenSynergy GmbH + */ +#include + +#include "virtio_card.h" + +/* VirtIO->ALSA channel position map */ +static const u8 g_v2a_position_map[] = { + [VIRTIO_SND_CHMAP_NONE] = SNDRV_CHMAP_UNKNOWN, + [VIRTIO_SND_CHMAP_NA] = SNDRV_CHMAP_NA, + [VIRTIO_SND_CHMAP_MONO] = SNDRV_CHMAP_MONO, + [VIRTIO_SND_CHMAP_FL] = SNDRV_CHMAP_FL, + [VIRTIO_SND_CHMAP_FR] = SNDRV_CHMAP_FR, + [VIRTIO_SND_CHMAP_RL] = SNDRV_CHMAP_RL, + [VIRTIO_SND_CHMAP_RR] = SNDRV_CHMAP_RR, + [VIRTIO_SND_CHMAP_FC] = SNDRV_CHMAP_FC, + [VIRTIO_SND_CHMAP_LFE] = SNDRV_CHMAP_LFE, + [VIRTIO_SND_CHMAP_SL] = SNDRV_CHMAP_SL, + [VIRTIO_SND_CHMAP_SR] = SNDRV_CHMAP_SR, + [VIRTIO_SND_CHMAP_RC] = SNDRV_CHMAP_RC, + [VIRTIO_SND_CHMAP_FLC] = SNDRV_CHMAP_FLC, + [VIRTIO_SND_CHMAP_FRC] = SNDRV_CHMAP_FRC, + [VIRTIO_SND_CHMAP_RLC] = SNDRV_CHMAP_RLC, + [VIRTIO_SND_CHMAP_RRC] = SNDRV_CHMAP_RRC, + [VIRTIO_SND_CHMAP_FLW] = SNDRV_CHMAP_FLW, + [VIRTIO_SND_CHMAP_FRW] = SNDRV_CHMAP_FRW, + [VIRTIO_SND_CHMAP_FLH] = SNDRV_CHMAP_FLH, + [VIRTIO_SND_CHMAP_FCH] = SNDRV_CHMAP_FCH, + [VIRTIO_SND_CHMAP_FRH] = SNDRV_CHMAP_FRH, + [VIRTIO_SND_CHMAP_TC] = SNDRV_CHMAP_TC, + [VIRTIO_SND_CHMAP_TFL] = SNDRV_CHMAP_TFL, + [VIRTIO_SND_CHMAP_TFR] = SNDRV_CHMAP_TFR, + [VIRTIO_SND_CHMAP_TFC] = SNDRV_CHMAP_TFC, + [VIRTIO_SND_CHMAP_TRL] = SNDRV_CHMAP_TRL, + [VIRTIO_SND_CHMAP_TRR] = SNDRV_CHMAP_TRR, + [VIRTIO_SND_CHMAP_TRC] = SNDRV_CHMAP_TRC, + [VIRTIO_SND_CHMAP_TFLC] = SNDRV_CHMAP_TFLC, + [VIRTIO_SND_CHMAP_TFRC] = SNDRV_CHMAP_TFRC, + [VIRTIO_SND_CHMAP_TSL] = SNDRV_CHMAP_TSL, + [VIRTIO_SND_CHMAP_TSR] = SNDRV_CHMAP_TSR, + [VIRTIO_SND_CHMAP_LLFE] = SNDRV_CHMAP_LLFE, + [VIRTIO_SND_CHMAP_RLFE] = SNDRV_CHMAP_RLFE, + [VIRTIO_SND_CHMAP_BC] = SNDRV_CHMAP_BC, + [VIRTIO_SND_CHMAP_BLC] = SNDRV_CHMAP_BLC, + [VIRTIO_SND_CHMAP_BRC] = SNDRV_CHMAP_BRC +}; + +/** + * virtsnd_chmap_parse_cfg() - Parse the channel map configuration. + * @snd: VirtIO sound device. + * + * This function is called during initial device initialization. + * + * Context: Any context that permits to sleep. + * Return: 0 on success, -errno on failure. + */ +int virtsnd_chmap_parse_cfg(struct virtio_snd *snd) +{ + struct virtio_device *vdev = snd->vdev; + u32 i; + int rc; + + virtio_cread_le(vdev, struct virtio_snd_config, chmaps, &snd->nchmaps); + if (!snd->nchmaps) + return 0; + + snd->chmaps = devm_kcalloc(&vdev->dev, snd->nchmaps, + sizeof(*snd->chmaps), GFP_KERNEL); + if (!snd->chmaps) + return -ENOMEM; + + rc = virtsnd_ctl_query_info(snd, VIRTIO_SND_R_CHMAP_INFO, 0, + snd->nchmaps, sizeof(*snd->chmaps), + snd->chmaps); + if (rc) + return rc; + + /* Count the number of channel maps per each PCM device/stream. */ + for (i = 0; i < snd->nchmaps; ++i) { + struct virtio_snd_chmap_info *info = &snd->chmaps[i]; + u32 nid = le32_to_cpu(info->hdr.hda_fn_nid); + struct virtio_pcm *vpcm; + struct virtio_pcm_stream *vs; + + vpcm = virtsnd_pcm_find_or_create(snd, nid); + if (IS_ERR(vpcm)) + return PTR_ERR(vpcm); + + switch (info->direction) { + case VIRTIO_SND_D_OUTPUT: + vs = &vpcm->streams[SNDRV_PCM_STREAM_PLAYBACK]; + break; + case VIRTIO_SND_D_INPUT: + vs = &vpcm->streams[SNDRV_PCM_STREAM_CAPTURE]; + break; + default: + dev_err(&vdev->dev, + "chmap #%u: unknown direction (%u)\n", i, + info->direction); + return -EINVAL; + } + + vs->nchmaps++; + } + + return 0; +} + +/** + * virtsnd_chmap_add_ctls() - Create an ALSA control for channel maps. + * @pcm: ALSA PCM device. + * @direction: PCM stream direction (SNDRV_PCM_STREAM_XXX). + * @vs: VirtIO PCM stream. + * + * Context: Any context. + * Return: 0 on success, -errno on failure. + */ +static int virtsnd_chmap_add_ctls(struct snd_pcm *pcm, int direction, + struct virtio_pcm_stream *vs) +{ + u32 i; + int max_channels = 0; + + for (i = 0; i < vs->nchmaps; i++) + if (max_channels < vs->chmaps[i].channels) + max_channels = vs->chmaps[i].channels; + + return snd_pcm_add_chmap_ctls(pcm, direction, vs->chmaps, max_channels, + 0, NULL); +} + +/** + * virtsnd_chmap_build_devs() - Build ALSA controls for channel maps. + * @snd: VirtIO sound device. + * + * Context: Any context. + * Return: 0 on success, -errno on failure. + */ +int virtsnd_chmap_build_devs(struct virtio_snd *snd) +{ + struct virtio_device *vdev = snd->vdev; + struct virtio_pcm *vpcm; + struct virtio_pcm_stream *vs; + u32 i; + int rc; + + /* Allocate channel map elements per each PCM device/stream. */ + list_for_each_entry(vpcm, &snd->pcm_list, list) { + for (i = 0; i < ARRAY_SIZE(vpcm->streams); ++i) { + vs = &vpcm->streams[i]; + + if (!vs->nchmaps) + continue; + + vs->chmaps = devm_kcalloc(&vdev->dev, vs->nchmaps + 1, + sizeof(*vs->chmaps), + GFP_KERNEL); + if (!vs->chmaps) + return -ENOMEM; + + vs->nchmaps = 0; + } + } + + /* Initialize channel maps per each PCM device/stream. */ + for (i = 0; i < snd->nchmaps; ++i) { + struct virtio_snd_chmap_info *info = &snd->chmaps[i]; + unsigned int channels = info->channels; + unsigned int ch; + struct snd_pcm_chmap_elem *chmap; + + vpcm = virtsnd_pcm_find(snd, le32_to_cpu(info->hdr.hda_fn_nid)); + if (IS_ERR(vpcm)) + return PTR_ERR(vpcm); + + if (info->direction == VIRTIO_SND_D_OUTPUT) + vs = &vpcm->streams[SNDRV_PCM_STREAM_PLAYBACK]; + else + vs = &vpcm->streams[SNDRV_PCM_STREAM_CAPTURE]; + + chmap = &vs->chmaps[vs->nchmaps++]; + + if (channels > ARRAY_SIZE(chmap->map)) + channels = ARRAY_SIZE(chmap->map); + + chmap->channels = channels; + + for (ch = 0; ch < channels; ++ch) { + u8 position = info->positions[ch]; + + if (position >= ARRAY_SIZE(g_v2a_position_map)) + return -EINVAL; + + chmap->map[ch] = g_v2a_position_map[position]; + } + } + + /* Create an ALSA control per each PCM device/stream. */ + list_for_each_entry(vpcm, &snd->pcm_list, list) { + if (!vpcm->pcm) + continue; + + for (i = 0; i < ARRAY_SIZE(vpcm->streams); ++i) { + vs = &vpcm->streams[i]; + + if (!vs->nchmaps) + continue; + + rc = virtsnd_chmap_add_ctls(vpcm->pcm, i, vs); + if (rc) + return rc; + } + } + + return 0; +} diff --git a/sound/virtio/virtio_pcm.h b/sound/virtio/virtio_pcm.h index efd0228746cf..1353fdc9bd69 100644 --- a/sound/virtio/virtio_pcm.h +++ b/sound/virtio/virtio_pcm.h @@ -63,10 +63,14 @@ struct virtio_pcm_substream { * struct virtio_pcm_stream - VirtIO PCM stream. * @substreams: VirtIO substreams belonging to the stream. * @nsubstreams: Number of substreams. + * @chmaps: Kernel channel maps belonging to the stream. + * @nchmaps: Number of channel maps. */ struct virtio_pcm_stream { struct virtio_pcm_substream **substreams; u32 nsubstreams; + struct snd_pcm_chmap_elem *chmaps; + u32 nchmaps; }; /** From 575483e90a3292c2afceb7161732046e411d6fdd Mon Sep 17 00:00:00 2001 From: Anton Yakovlev Date: Tue, 2 Mar 2021 17:47:09 +0100 Subject: [PATCH 037/587] ALSA: virtio: introduce device suspend/resume support All running PCM substreams are stopped on device suspend and restarted on device resume. Signed-off-by: Anton Yakovlev Link: https://lore.kernel.org/r/20210302164709.3142702-10-anton.yakovlev@opensynergy.com Signed-off-by: Takashi Iwai --- sound/virtio/virtio_card.c | 56 +++++++++++++++++++++++++++++++++++ sound/virtio/virtio_pcm.h | 3 ++ sound/virtio/virtio_pcm_ops.c | 33 ++++++++++++++++----- 3 files changed, 85 insertions(+), 7 deletions(-) diff --git a/sound/virtio/virtio_card.c b/sound/virtio/virtio_card.c index 1c03fcc41c3b..ae9128063917 100644 --- a/sound/virtio/virtio_card.c +++ b/sound/virtio/virtio_card.c @@ -362,6 +362,58 @@ static void virtsnd_remove(struct virtio_device *vdev) kfree(snd->event_msgs); } +#ifdef CONFIG_PM_SLEEP +/** + * virtsnd_freeze() - Suspend device. + * @vdev: VirtIO parent device. + * + * Context: Any context. + * Return: 0 on success, -errno on failure. + */ +static int virtsnd_freeze(struct virtio_device *vdev) +{ + struct virtio_snd *snd = vdev->priv; + unsigned int i; + + virtsnd_disable_event_vq(snd); + virtsnd_ctl_msg_cancel_all(snd); + + vdev->config->del_vqs(vdev); + vdev->config->reset(vdev); + + for (i = 0; i < snd->nsubstreams; ++i) + cancel_work_sync(&snd->substreams[i].elapsed_period); + + kfree(snd->event_msgs); + snd->event_msgs = NULL; + + return 0; +} + +/** + * virtsnd_restore() - Resume device. + * @vdev: VirtIO parent device. + * + * Context: Any context. + * Return: 0 on success, -errno on failure. + */ +static int virtsnd_restore(struct virtio_device *vdev) +{ + struct virtio_snd *snd = vdev->priv; + int rc; + + rc = virtsnd_find_vqs(snd); + if (rc) + return rc; + + virtio_device_ready(vdev); + + virtsnd_enable_event_vq(snd); + + return 0; +} +#endif /* CONFIG_PM_SLEEP */ + static const struct virtio_device_id id_table[] = { { VIRTIO_ID_SOUND, VIRTIO_DEV_ANY_ID }, { 0 }, @@ -374,6 +426,10 @@ static struct virtio_driver virtsnd_driver = { .validate = virtsnd_validate, .probe = virtsnd_probe, .remove = virtsnd_remove, +#ifdef CONFIG_PM_SLEEP + .freeze = virtsnd_freeze, + .restore = virtsnd_restore, +#endif }; static int __init init(void) diff --git a/sound/virtio/virtio_pcm.h b/sound/virtio/virtio_pcm.h index 1353fdc9bd69..062eb8e8f2cf 100644 --- a/sound/virtio/virtio_pcm.h +++ b/sound/virtio/virtio_pcm.h @@ -31,6 +31,8 @@ struct virtio_pcm_msg; * @xfer_xrun: Data underflow/overflow state (0 - no xrun, 1 - xrun). * @stopped: True if the substream is stopped and must be released on the device * side. + * @suspended: True if the substream is suspended and must be reconfigured on + * the device side at resume. * @msgs: Allocated I/O messages. * @nmsgs: Number of allocated I/O messages. * @msg_last_enqueued: Index of the last I/O message added to the virtqueue. @@ -52,6 +54,7 @@ struct virtio_pcm_substream { bool xfer_enabled; bool xfer_xrun; bool stopped; + bool suspended; struct virtio_pcm_msg **msgs; unsigned int nmsgs; int msg_last_enqueued; diff --git a/sound/virtio/virtio_pcm_ops.c b/sound/virtio/virtio_pcm_ops.c index 0682a2df6c8c..f8bfb87624be 100644 --- a/sound/virtio/virtio_pcm_ops.c +++ b/sound/virtio/virtio_pcm_ops.c @@ -115,6 +115,7 @@ static int virtsnd_pcm_open(struct snd_pcm_substream *substream) SNDRV_PCM_HW_PARAM_PERIODS); vss->stopped = !!virtsnd_pcm_msg_pending_num(vss); + vss->suspended = false; /* * If the substream has already been used, then the I/O queue may be in @@ -272,16 +273,31 @@ static int virtsnd_pcm_prepare(struct snd_pcm_substream *substream) struct virtio_device *vdev = vss->snd->vdev; struct virtio_snd_msg *msg; - if (virtsnd_pcm_msg_pending_num(vss)) { - dev_err(&vdev->dev, "SID %u: invalid I/O queue state\n", - vss->sid); - return -EBADFD; + if (!vss->suspended) { + if (virtsnd_pcm_msg_pending_num(vss)) { + dev_err(&vdev->dev, "SID %u: invalid I/O queue state\n", + vss->sid); + return -EBADFD; + } + + vss->buffer_bytes = snd_pcm_lib_buffer_bytes(substream); + vss->hw_ptr = 0; + vss->msg_last_enqueued = -1; + } else { + struct snd_pcm_runtime *runtime = substream->runtime; + unsigned int buffer_bytes = snd_pcm_lib_buffer_bytes(substream); + unsigned int period_bytes = snd_pcm_lib_period_bytes(substream); + int rc; + + rc = virtsnd_pcm_dev_set_params(vss, buffer_bytes, period_bytes, + runtime->channels, + runtime->format, runtime->rate); + if (rc) + return rc; } - vss->buffer_bytes = snd_pcm_lib_buffer_bytes(substream); - vss->hw_ptr = 0; vss->xfer_xrun = false; - vss->msg_last_enqueued = -1; + vss->suspended = false; vss->msg_count = 0; msg = virtsnd_pcm_ctl_msg_alloc(vss, VIRTIO_SND_R_PCM_PREPARE, @@ -336,6 +352,9 @@ static int virtsnd_pcm_trigger(struct snd_pcm_substream *substream, int command) } return virtsnd_ctl_msg_send_sync(snd, msg); + case SNDRV_PCM_TRIGGER_SUSPEND: + vss->suspended = true; + fallthrough; case SNDRV_PCM_TRIGGER_STOP: vss->stopped = true; fallthrough; From b95a913cb368edcb606d844a6dc6240093d87020 Mon Sep 17 00:00:00 2001 From: Vitaly Rodionov Date: Sat, 6 Mar 2021 11:19:31 +0000 Subject: [PATCH 038/587] ALSA: hda/cirrus: Increase AUTO_CFG_MAX_INS from 8 to 18 In preparation to support Cirrus Logic CS8409 HDA bridge on new Dell platforms it is nessasary to increase AUTO_CFG_MAX_INS and AUTO_CFG_NUM_INPUTS values. Currently AUTO_CFG_MAX_INS is limited to 8, but Cirrus Logic HDA bridge CS8409 has 18 input pins, 16 ASP receivers and 2 DMIC inputs. We have to increase this value to 18, so generic code can handle this correctly. Tested on DELL Inspiron-3505, DELL Inspiron-3501, DELL Inspiron-3500 Signed-off-by: Vitaly Rodionov Link: https://lore.kernel.org/r/20210306111934.4832-2-vitalyr@opensource.cirrus.com Signed-off-by: Takashi Iwai --- sound/pci/hda/hda_auto_parser.h | 2 +- sound/pci/hda/hda_local.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/sound/pci/hda/hda_auto_parser.h b/sound/pci/hda/hda_auto_parser.h index a22ca0e17a08..df63d66af1ab 100644 --- a/sound/pci/hda/hda_auto_parser.h +++ b/sound/pci/hda/hda_auto_parser.h @@ -27,7 +27,7 @@ enum { }; #define AUTO_CFG_MAX_OUTS HDA_MAX_OUTS -#define AUTO_CFG_MAX_INS 8 +#define AUTO_CFG_MAX_INS 18 struct auto_pin_cfg_item { hda_nid_t pin; diff --git a/sound/pci/hda/hda_local.h b/sound/pci/hda/hda_local.h index 5beb8aa44ecd..317245a5585d 100644 --- a/sound/pci/hda/hda_local.h +++ b/sound/pci/hda/hda_local.h @@ -180,7 +180,7 @@ int snd_hda_create_spdif_in_ctls(struct hda_codec *codec, hda_nid_t nid); /* * input MUX helper */ -#define HDA_MAX_NUM_INPUTS 16 +#define HDA_MAX_NUM_INPUTS 36 struct hda_input_mux_item { char label[32]; unsigned int index; From 6cc7e93f46a5ce9f65ad3c6c6f645f1d831a8fa4 Mon Sep 17 00:00:00 2001 From: Vitaly Rodionov Date: Sat, 6 Mar 2021 11:19:32 +0000 Subject: [PATCH 039/587] ALSA: hda/cirrus: Add support for CS8409 HDA bridge and CS42L42 companion codec. Dell's laptops Inspiron 3500, Inspiron 3501, Inspiron 3505 are using Cirrus Logic CS8409 HDA bridge with CS42L42 companion codec. The CS8409 is a multichannel HD audio routing controller. CS8409 includes support for four channels of digital microphone data and two bidirectional ASPs for up to 32 channels of TDM data or 4 channels of I2S data. The CS8409 is intended to be used with a remote companion codec that implements high performance analog functions in close physical proximity to the end-equipment audio port or speaker driver. The CS42L42 is a low-power audio codec with integrated MIPI SoundWire interface or I2C/I2S/TDM interfaces designed for portable applications. It provides a high-dynamic range, stereo DAC for audio playback and a mono high-dynamic-range ADC for audio capture CS42L42 is connected to CS8409 HDA bridge via I2C and I2S. CS8409 CS42L42 ------- -------- ASP1.A TX --> ASP_SDIN ASP1.A RX <-- ASP_SDOUT GPIO5 --> RST# GPIO4 <-- INT# GPIO3 <-- WAKE# GPIO7 <-> I2C SDA GPIO6 --> I2C CLK Tested on DELL Inspiron-3500, DELL Inspiron-3501, DELL Inspiron-3505 This patch will register CS8409 with sound card and create input/output paths and two input devices, initialise CS42L42 companion codec and configure it for ASP TX/RX TDM mode, 24bit, 48kHz. cat /proc/asound/pcm 00-00: CS8409 Analog : CS8409 Analog : playback 1 : capture 1 00-03: HDMI 0 : HDMI 0 : playback 1 dmesg snd_hda_codec_cirrus hdaudioC0D0: autoconfig for CS8409: line_outs=1 (0x2c/0x0/0x0/0x0/0x0) type:speaker snd_hda_codec_cirrus hdaudioC0D0: speaker_outs=0 (0x0/0x0/0x0/0x0/0x0) snd_hda_codec_cirrus hdaudioC0D0: hp_outs=1 (0x24/0x0/0x0/0x0/0x0) snd_hda_codec_cirrus hdaudioC0D0: mono: mono_out=0x0 snd_hda_codec_cirrus hdaudioC0D0: inputs: snd_hda_codec_cirrus hdaudioC0D0: Internal Mic=0x44 snd_hda_codec_cirrus hdaudioC0D0: Mic=0x34 input: HDA Intel PCH Headphone as /devices/pci0000:00/0000:00:1f.3/sound/card0/input8 input: HDA Intel PCH Headset Mic as /devices/pci0000:00/0000:00:1f.3/sound/card0/input9 Signed-off-by: Vitaly Rodionov Link: https://lore.kernel.org/r/20210306111934.4832-3-vitalyr@opensource.cirrus.com Signed-off-by: Takashi Iwai --- sound/pci/hda/patch_cirrus.c | 576 +++++++++++++++++++++++++++++++++++ 1 file changed, 576 insertions(+) diff --git a/sound/pci/hda/patch_cirrus.c b/sound/pci/hda/patch_cirrus.c index f46204ab0b90..d664eed5c3cf 100644 --- a/sound/pci/hda/patch_cirrus.c +++ b/sound/pci/hda/patch_cirrus.c @@ -9,6 +9,7 @@ #include #include #include +#include #include #include #include "hda_local.h" @@ -1219,6 +1220,580 @@ static int patch_cs4213(struct hda_codec *codec) return err; } +/* Cirrus Logic CS8409 HDA bridge with + * companion codec CS42L42 + */ +#define CS8409_VENDOR_NID 0x47 + +#define CS8409_CS42L42_HP_PIN_NID 0x24 +#define CS8409_CS42L42_SPK_PIN_NID 0x2c +#define CS8409_CS42L42_AMIC_PIN_NID 0x34 +#define CS8409_CS42L42_DMIC_PIN_NID 0x44 + +#define GPIO3_INT (1 << 3) +#define GPIO4_INT (1 << 4) +#define GPIO5_INT (1 << 5) + +#define CS42L42_I2C_ADDR (0x48 << 1) + +#define CIR_I2C_ADDR 0x0059 +#define CIR_I2C_DATA 0x005A +#define CIR_I2C_CTRL 0x005B +#define CIR_I2C_STATUS 0x005C +#define CIR_I2C_QWRITE 0x005D +#define CIR_I2C_QREAD 0x005E + +struct cs8409_i2c_param { + unsigned int addr; + unsigned int reg; +}; + +struct cs8409_cir_param { + unsigned int nid; + unsigned int cir; + unsigned int coeff; +}; + +enum { + CS8409_BULLSEYE, + CS8409_WARLOCK, + CS8409_CYBORG, + CS8409_VERBS, +}; + +/* Dell Inspiron models with cs8409/cs42l42 */ +static const struct hda_model_fixup cs8409_models[] = { + { .id = CS8409_BULLSEYE, .name = "bullseye" }, + { .id = CS8409_WARLOCK, .name = "warlock" }, + { .id = CS8409_CYBORG, .name = "cyborg" }, + {} +}; + +/* Dell Inspiron platforms + * with cs8409 bridge and cs42l42 codec + */ +static const struct snd_pci_quirk cs8409_fixup_tbl[] = { + SND_PCI_QUIRK(0x1028, 0x0A11, "Bullseye", CS8409_BULLSEYE), + SND_PCI_QUIRK(0x1028, 0x0A12, "Bullseye", CS8409_BULLSEYE), + SND_PCI_QUIRK(0x1028, 0x0A23, "Bullseye", CS8409_BULLSEYE), + SND_PCI_QUIRK(0x1028, 0x0A24, "Bullseye", CS8409_BULLSEYE), + SND_PCI_QUIRK(0x1028, 0x0A25, "Bullseye", CS8409_BULLSEYE), + SND_PCI_QUIRK(0x1028, 0x0A29, "Bullseye", CS8409_BULLSEYE), + SND_PCI_QUIRK(0x1028, 0x0A2A, "Bullseye", CS8409_BULLSEYE), + SND_PCI_QUIRK(0x1028, 0x0A2B, "Bullseye", CS8409_BULLSEYE), + SND_PCI_QUIRK(0x1028, 0x0AB0, "Warlock", CS8409_WARLOCK), + SND_PCI_QUIRK(0x1028, 0x0AB2, "Warlock", CS8409_WARLOCK), + SND_PCI_QUIRK(0x1028, 0x0AB1, "Warlock", CS8409_WARLOCK), + SND_PCI_QUIRK(0x1028, 0x0AB3, "Warlock", CS8409_WARLOCK), + SND_PCI_QUIRK(0x1028, 0x0AB4, "Warlock", CS8409_WARLOCK), + SND_PCI_QUIRK(0x1028, 0x0AB5, "Warlock", CS8409_WARLOCK), + SND_PCI_QUIRK(0x1028, 0x0AD9, "Warlock", CS8409_WARLOCK), + SND_PCI_QUIRK(0x1028, 0x0ADA, "Warlock", CS8409_WARLOCK), + SND_PCI_QUIRK(0x1028, 0x0ADB, "Warlock", CS8409_WARLOCK), + SND_PCI_QUIRK(0x1028, 0x0ADC, "Warlock", CS8409_WARLOCK), + SND_PCI_QUIRK(0x1028, 0x0AF4, "Warlock", CS8409_WARLOCK), + SND_PCI_QUIRK(0x1028, 0x0AF5, "Warlock", CS8409_WARLOCK), + SND_PCI_QUIRK(0x1028, 0x0A77, "Cyborg", CS8409_CYBORG), + SND_PCI_QUIRK(0x1028, 0x0A78, "Cyborg", CS8409_CYBORG), + SND_PCI_QUIRK(0x1028, 0x0A79, "Cyborg", CS8409_CYBORG), + SND_PCI_QUIRK(0x1028, 0x0A7A, "Cyborg", CS8409_CYBORG), + SND_PCI_QUIRK(0x1028, 0x0A7D, "Cyborg", CS8409_CYBORG), + SND_PCI_QUIRK(0x1028, 0x0A7E, "Cyborg", CS8409_CYBORG), + SND_PCI_QUIRK(0x1028, 0x0A7F, "Cyborg", CS8409_CYBORG), + SND_PCI_QUIRK(0x1028, 0x0A80, "Cyborg", CS8409_CYBORG), + SND_PCI_QUIRK(0x1028, 0x0ADF, "Cyborg", CS8409_CYBORG), + SND_PCI_QUIRK(0x1028, 0x0AE0, "Cyborg", CS8409_CYBORG), + SND_PCI_QUIRK(0x1028, 0x0AE1, "Cyborg", CS8409_CYBORG), + SND_PCI_QUIRK(0x1028, 0x0AE2, "Cyborg", CS8409_CYBORG), + SND_PCI_QUIRK(0x1028, 0x0AE9, "Cyborg", CS8409_CYBORG), + SND_PCI_QUIRK(0x1028, 0x0AEA, "Cyborg", CS8409_CYBORG), + SND_PCI_QUIRK(0x1028, 0x0AEB, "Cyborg", CS8409_CYBORG), + SND_PCI_QUIRK(0x1028, 0x0AEC, "Cyborg", CS8409_CYBORG), + SND_PCI_QUIRK(0x1028, 0x0AED, "Cyborg", CS8409_CYBORG), + SND_PCI_QUIRK(0x1028, 0x0AEE, "Cyborg", CS8409_CYBORG), + SND_PCI_QUIRK(0x1028, 0x0AEF, "Cyborg", CS8409_CYBORG), + SND_PCI_QUIRK(0x1028, 0x0AF0, "Cyborg", CS8409_CYBORG), + {} /* terminator */ +}; + +static const struct hda_verb cs8409_cs42l42_init_verbs[] = { + { 0x01, AC_VERB_SET_GPIO_WAKE_MASK, 0x0018 }, /* WAKE from GPIO 3,4 */ + { 0x47, AC_VERB_SET_PROC_STATE, 0x0001 }, /* Enable VPW processing */ + { 0x47, AC_VERB_SET_COEF_INDEX, 0x0002 }, /* Configure GPIO 6,7 */ + { 0x47, AC_VERB_SET_PROC_COEF, 0x0080 }, /* I2C mode */ + { 0x47, AC_VERB_SET_COEF_INDEX, 0x005b }, /* Set I2C bus speed */ + { 0x47, AC_VERB_SET_PROC_COEF, 0x0200 }, /* 100kHz I2C_STO = 2 */ + {} /* terminator */ +}; + +static const struct hda_pintbl cs8409_cs42l42_pincfgs[] = { + { 0x24, 0x042120f0 }, /* ASP-1-TX */ + { 0x34, 0x04a12050 }, /* ASP-1-RX */ + { 0x2c, 0x901000f0 }, /* ASP-2-TX */ + { 0x44, 0x90a00090 }, /* DMIC-1 */ + {} /* terminator */ +}; + +static const struct hda_verb cs8409_cs42l42_add_verbs[] = { + { 0x24, 0x71c, 0xF0 }, /* Widget node ASP-1-TX */ + { 0x24, 0x71d, 0x20 }, + { 0x24, 0x71e, 0x21 }, + { 0x24, 0x71f, 0x04 }, + { 0x34, 0x71c, 0x50 }, /* Widget node ASP-1-RX0 */ + { 0x34, 0x71d, 0x20 }, + { 0x34, 0x71e, 0xa1 }, + { 0x34, 0x71f, 0x04 }, + { 0x2C, 0x71c, 0xF0 }, /* Widget node ASP-2-TX */ + { 0x2C, 0x71d, 0x00 }, + { 0x2C, 0x71e, 0x10 }, + { 0x2C, 0x71f, 0x90 }, + { 0x44, 0x71c, 0x90 }, /* Widget node DMIC-1 */ + { 0x44, 0x71d, 0x00 }, + { 0x44, 0x71e, 0xA0 }, + { 0x44, 0x71f, 0x90 }, + {} /* terminator */ +}; + +static const struct hda_fixup cs8409_fixups[] = { + [CS8409_BULLSEYE] = { + .type = HDA_FIXUP_PINS, + .v.pins = cs8409_cs42l42_pincfgs, + .chained = true, + .chain_id = CS8409_VERBS, + }, + [CS8409_WARLOCK] = { + .type = HDA_FIXUP_PINS, + .v.pins = cs8409_cs42l42_pincfgs, + .chained = true, + .chain_id = CS8409_VERBS, + }, + [CS8409_CYBORG] = { + .type = HDA_FIXUP_PINS, + .v.pins = cs8409_cs42l42_pincfgs, + .chained = true, + .chain_id = CS8409_VERBS, + }, + [CS8409_VERBS] = { + .type = HDA_FIXUP_VERBS, + .v.verbs = cs8409_cs42l42_add_verbs, + }, +}; + +/* Vendor specific HW configuration for CS42L42 */ +static const struct cs8409_i2c_param cs42l42_init_reg_seq[] = { + { 0x1010, 0xB0 }, + { 0x1D01, 0x00 }, + { 0x1D02, 0x06 }, + { 0x1D03, 0x00 }, + { 0x1107, 0x01 }, + { 0x1009, 0x02 }, + { 0x1007, 0x03 }, + { 0x1201, 0x00 }, + { 0x1208, 0x13 }, + { 0x1205, 0xFF }, + { 0x1206, 0x00 }, + { 0x1207, 0x20 }, + { 0x1202, 0x0D }, + { 0x2A02, 0x02 }, + { 0x2A03, 0x00 }, + { 0x2A04, 0x00 }, + { 0x2A05, 0x02 }, + { 0x2A06, 0x00 }, + { 0x2A07, 0x20 }, + { 0x2A08, 0x02 }, + { 0x2A09, 0x00 }, + { 0x2A0A, 0x80 }, + { 0x2A0B, 0x02 }, + { 0x2A0C, 0x00 }, + { 0x2A0D, 0xA0 }, + { 0x2A01, 0x0C }, + { 0x2902, 0x01 }, + { 0x2903, 0x02 }, + { 0x2904, 0x00 }, + { 0x2905, 0x00 }, + { 0x2901, 0x01 }, + { 0x1101, 0x0A }, + { 0x1102, 0x84 }, + { 0x2301, 0x00 }, + { 0x2303, 0x00 }, + { 0x2302, 0x3f }, + { 0x2001, 0x03 }, + { 0x1B75, 0xB6 }, + { 0x1B73, 0xC2 }, + { 0x1129, 0x01 }, + { 0x1121, 0xF3 }, + { 0x1103, 0x20 }, + { 0x1105, 0x00 }, + { 0x1112, 0xC0 }, + { 0x1113, 0x80 }, + { 0x1C03, 0xC0 }, + { 0x1105, 0x00 }, + { 0x1112, 0xC0 }, + {} /* Terminator */ +}; + +/* Vendor specific hw configuration for CS8409 */ +static const struct cs8409_cir_param cs8409_cs42l42_hw_cfg[] = { + { 0x47, 0x00, 0xb008 }, /* +PLL1/2_EN, +I2C_EN */ + { 0x47, 0x01, 0x0002 }, /* ASP1/2_EN=0, ASP1_STP=1 */ + { 0x47, 0x02, 0x0a80 }, /* ASP1/2_BUS_IDLE=10, +GPIO_I2C */ + { 0x47, 0x19, 0x0800 }, /* ASP1.A: TX.LAP=0, TX.LSZ=24 bits, TX.LCS=0 */ + { 0x47, 0x1a, 0x0820 }, /* ASP1.A: TX.RAP=0, TX.RSZ=24 bits, TX.RCS=32 */ + { 0x47, 0x29, 0x0800 }, /* ASP2.A: TX.LAP=0, TX.LSZ=24 bits, TX.LCS=0 */ + { 0x47, 0x2a, 0x2800 }, /* ASP2.A: TX.RAP=1, TX.RSZ=24 bits, TX.RCS=0 */ + { 0x47, 0x39, 0x0800 }, /* ASP1.A: RX.LAP=0, RX.LSZ=24 bits, RX.LCS=0 */ + { 0x47, 0x3a, 0x0800 }, /* ASP1.A: RX.RAP=0, RX.RSZ=24 bits, RX.RCS=0 */ + { 0x47, 0x03, 0x8000 }, /* ASP1: LCHI = 00h */ + { 0x47, 0x04, 0x28ff }, /* ASP1: MC/SC_SRCSEL=PLL1, LCPR=FFh */ + { 0x47, 0x05, 0x0062 }, /* ASP1: MCEN=0, FSD=011, SCPOL_IN/OUT=0, SCDIV=1:4 */ + { 0x47, 0x06, 0x801f }, /* ASP2: LCHI=1Fh */ + { 0x47, 0x07, 0x283f }, /* ASP2: MC/SC_SRCSEL=PLL1, LCPR=3Fh */ + { 0x47, 0x08, 0x805c }, /* ASP2: 5050=1, MCEN=0, FSD=010, SCPOL_IN/OUT=1, SCDIV=1:16 */ + { 0x47, 0x09, 0x0023 }, /* DMIC1_MO=10b, DMIC1/2_SR=1 */ + { 0x47, 0x0a, 0x0000 }, /* ASP1/2_BEEP=0 */ + { 0x47, 0x01, 0x0062 }, /* ASP1/2_EN=1, ASP1_STP=1 */ + { 0x47, 0x00, 0x9008 }, /* -PLL2_EN */ + { 0x47, 0x68, 0x0000 }, /* TX2.A: pre-scale att.=0 dB */ + { 0x47, 0x82, 0xfc03 }, /* ASP1/2_xxx_EN=1, ASP1/2_MCLK_EN=0, DMIC1_SCL_EN=1 */ + { 0x47, 0xc0, 0x9999 }, /* test mode on */ + { 0x47, 0xc5, 0x0000 }, /* GPIO hysteresis = 30 us */ + { 0x47, 0xc0, 0x0000 }, /* test mode off */ + {} /* Terminator */ +}; + +/* Enable I2C clocks */ +static void cs8409_enable_i2c_clock(struct hda_codec *codec, unsigned int flag) +{ + unsigned int retval = 0; + unsigned int newval = 0; + + retval = cs_vendor_coef_get(codec, 0x0); + newval = (flag) ? (retval | 0x8) : (retval & 0xfffffff7); + cs_vendor_coef_set(codec, 0x0, newval); +} + +/* Wait I2C transaction */ +static int cs8409_i2c_wait_complete(struct hda_codec *codec) +{ + int repeat = 5; + unsigned int retval = 0; + + do { + retval = cs_vendor_coef_get(codec, CIR_I2C_STATUS); + if ((retval & 0x18) != 0x18) { + usleep_range(2000, 4000); + --repeat; + } else + break; + + } while (repeat); + + return repeat > 0 ? 0 : -1; +} + +/* CS8409 slave i2cRead */ +static unsigned int cs8409_i2c_read(struct hda_codec *codec, + unsigned int i2c_address, + unsigned int i2c_reg, + unsigned int paged) +{ + unsigned int i2c_reg_data; + unsigned int retval = 0; + + cs8409_enable_i2c_clock(codec, 1); + cs_vendor_coef_set(codec, CIR_I2C_ADDR, i2c_address); + + if (paged) { + cs_vendor_coef_set(codec, CIR_I2C_QWRITE, i2c_reg >> 8); + if (cs8409_i2c_wait_complete(codec) == -1) { + codec_err(codec, + "%s() Paged Transaction Failed 0x%02x : 0x%04x = 0x%02x\n", + __func__, i2c_address, i2c_reg, retval); + } + } + + i2c_reg_data = (i2c_reg << 8) & 0x0ffff; + cs_vendor_coef_set(codec, CIR_I2C_QREAD, i2c_reg_data); + if (cs8409_i2c_wait_complete(codec) == -1) { + codec_err(codec, "%s() Transaction Failed 0x%02x : 0x%04x = 0x%02x\n", + __func__, i2c_address, i2c_reg, retval); + } + + /* Register in bits 15-8 and the data in 7-0 */ + retval = cs_vendor_coef_get(codec, CIR_I2C_QREAD); + retval &= 0x0ff; + + cs8409_enable_i2c_clock(codec, 0); + + return retval; +} + +/* CS8409 slave i2cWrite */ +static unsigned int cs8409_i2c_write(struct hda_codec *codec, + unsigned int i2c_address, unsigned int i2c_reg, + unsigned int i2c_data, + unsigned int paged) +{ + unsigned int retval = 0; + unsigned int i2c_reg_data = 0; + + cs8409_enable_i2c_clock(codec, 1); + cs_vendor_coef_set(codec, CIR_I2C_ADDR, i2c_address); + + if (paged) { + cs_vendor_coef_set(codec, CIR_I2C_QWRITE, i2c_reg >> 8); + if (cs8409_i2c_wait_complete(codec) == -1) { + codec_err(codec, + "%s() Paged Transaction Failed 0x%02x : 0x%04x = 0x%02x\n", + __func__, i2c_address, i2c_reg, retval); + } + } + + i2c_reg_data = ((i2c_reg << 8) & 0x0ff00) | (i2c_data & 0x0ff); + cs_vendor_coef_set(codec, CIR_I2C_QWRITE, i2c_reg_data); + + if (cs8409_i2c_wait_complete(codec) == -1) { + codec_err(codec, "%s() Transaction Failed 0x%02x : 0x%04x = 0x%02x\n", + __func__, i2c_address, i2c_reg, retval); + } + + cs8409_enable_i2c_clock(codec, 0); + + return retval; +} + +/* Assert/release RTS# line to CS42L42 */ +static void cs8409_cs42l42_reset(struct hda_codec *codec) +{ + /* Assert RTS# line */ + snd_hda_codec_write(codec, + codec->core.afg, 0, AC_VERB_SET_GPIO_DATA, 0); + /* wait ~10ms */ + usleep_range(10000, 15000); + /* Release RTS# line */ + snd_hda_codec_write(codec, + codec->core.afg, 0, AC_VERB_SET_GPIO_DATA, GPIO5_INT); + /* wait ~10ms */ + usleep_range(10000, 15000); + + /* Clear interrupts status */ + cs8409_i2c_read(codec, CS42L42_I2C_ADDR, 0x1308, 1); + cs8409_i2c_read(codec, CS42L42_I2C_ADDR, 0x1309, 1); + cs8409_i2c_read(codec, CS42L42_I2C_ADDR, 0x130A, 1); + cs8409_i2c_read(codec, CS42L42_I2C_ADDR, 0x130F, 1); + +} + +static void cs8409_cs42l42_reg_setup(struct hda_codec *codec) +{ + const struct cs8409_i2c_param *seq = cs42l42_init_reg_seq; + + for (; seq->addr; seq++) + cs8409_i2c_write(codec, CS42L42_I2C_ADDR, seq->addr, seq->reg, 1); + +} + +static int cs8409_cs42l42_build_controls(struct hda_codec *codec) +{ + int err; + + err = snd_hda_gen_build_controls(codec); + if (err < 0) + return err; + + snd_hda_apply_fixup(codec, HDA_FIXUP_ACT_BUILD); + + return 0; +} + +#ifdef CONFIG_PM +/* Manage PDREF, when transition to D3hot */ +static int cs8409_suspend(struct hda_codec *codec) +{ + /* Assert CS42L42 RTS# line */ + snd_hda_codec_write(codec, + codec->core.afg, 0, AC_VERB_SET_GPIO_DATA, 0); + snd_hda_shutup_pins(codec); + return 0; +} +#endif + +/* Vendor specific HW configuration + * PLL, ASP, I2C, SPI, GPIOs, DMIC etc... + */ +static int cs8409_cs42l42_hw_init(struct hda_codec *codec) +{ + const struct cs8409_cir_param *seq = cs8409_cs42l42_hw_cfg; + struct cs_spec *spec = codec->spec; + + if (spec->gpio_mask) { + snd_hda_codec_write(codec, 0x01, 0, AC_VERB_SET_GPIO_MASK, + spec->gpio_mask); + snd_hda_codec_write(codec, 0x01, 0, AC_VERB_SET_GPIO_DIRECTION, + spec->gpio_dir); + snd_hda_codec_write(codec, 0x01, 0, AC_VERB_SET_GPIO_DATA, + spec->gpio_data); + } + + for (; seq->nid; seq++) + cs_vendor_coef_set(codec, seq->cir, seq->coeff); + + /* Reset CS42L42 */ + cs8409_cs42l42_reset(codec); + + /* Initialise CS42L42 companion codec */ + cs8409_cs42l42_reg_setup(codec); + + if (codec->fixup_id == CS8409_WARLOCK || + codec->fixup_id == CS8409_CYBORG) { + /* FULL_SCALE_VOL = 0 for Warlock / Cyborg */ + cs8409_i2c_write(codec, CS42L42_I2C_ADDR, 0x2001, 0x01, 1); + /* DMIC1_MO=00b, DMIC1/2_SR=1 */ + cs_vendor_coef_set(codec, 0x09, 0x0003); + } + + return 1; +} + +static int cs8409_cs42l42_init(struct hda_codec *codec) +{ + int ret = 0; + + ret = snd_hda_gen_init(codec); + + if (!ret) { + /* On Dell platforms with suspend D3 mode support we + * have to re-initialise cs8409 bridge and companion + * cs42l42 codec + */ + snd_hda_sequence_write(codec, cs8409_cs42l42_init_verbs); + snd_hda_sequence_write(codec, cs8409_cs42l42_add_verbs); + + cs8409_cs42l42_hw_init(codec); + + } + + return ret; +} + +static const struct hda_codec_ops cs8409_cs42l42_patch_ops = { + .build_controls = cs8409_cs42l42_build_controls, + .build_pcms = snd_hda_gen_build_pcms, + .init = cs8409_cs42l42_init, + .free = cs_free, + .unsol_event = snd_hda_jack_unsol_event, +#ifdef CONFIG_PM + .suspend = cs8409_suspend, +#endif +}; + +static int cs8409_cs42l42_fixup(struct hda_codec *codec) +{ + int err = 0; + struct cs_spec *spec = codec->spec; + unsigned int pincap = 0; + + /* Basic initial sequence for specific hw configuration */ + snd_hda_sequence_write(codec, cs8409_cs42l42_init_verbs); + + /* CS8409 is simple HDA bridge and intended to be used with a remote + * companion codec. Most of input/output PIN(s) have only basic + * capabilities. NID(s) 0x24 and 0x34 have only OUTC and INC + * capabilities and no presence detect capable (PDC) and call to + * snd_hda_gen_build_controls() will mark them as non detectable + * phantom jacks. However, in this configuration companion codec + * CS42L42 is connected to these pins and it has jack detect + * capabilities. We have to override pin capabilities, + * otherwise they will not be created as input devices. + */ + _snd_hdac_read_parm(&codec->core, + CS8409_CS42L42_HP_PIN_NID, AC_PAR_PIN_CAP, &pincap); + + snd_hdac_override_parm(&codec->core, + CS8409_CS42L42_HP_PIN_NID, AC_PAR_PIN_CAP, + (pincap | (AC_PINCAP_IMP_SENSE | AC_PINCAP_PRES_DETECT))); + + _snd_hdac_read_parm(&codec->core, CS8409_CS42L42_AMIC_PIN_NID, + AC_PAR_PIN_CAP, &pincap); + + snd_hdac_override_parm(&codec->core, + CS8409_CS42L42_AMIC_PIN_NID, AC_PAR_PIN_CAP, + (pincap | (AC_PINCAP_IMP_SENSE | AC_PINCAP_PRES_DETECT))); + + snd_hda_override_wcaps(codec, CS8409_CS42L42_HP_PIN_NID, + (get_wcaps(codec, CS8409_CS42L42_HP_PIN_NID) | AC_WCAP_UNSOL_CAP)); + + snd_hda_override_wcaps(codec, CS8409_CS42L42_AMIC_PIN_NID, + (get_wcaps(codec, CS8409_CS42L42_AMIC_PIN_NID) | AC_WCAP_UNSOL_CAP)); + + snd_hda_apply_fixup(codec, HDA_FIXUP_ACT_PRE_PROBE); + + err = snd_hda_parse_pin_defcfg(codec, &spec->gen.autocfg, 0, 0); + if (err < 0) + return err; + + err = snd_hda_gen_parse_auto_config(codec, &spec->gen.autocfg); + if (err < 0) + return err; + + snd_hda_apply_fixup(codec, HDA_FIXUP_ACT_PROBE); + + return err; +} + +static int patch_cs8409(struct hda_codec *codec) +{ + struct cs_spec *spec; + int err = -EINVAL; + + spec = cs_alloc_spec(codec, CS8409_VENDOR_NID); + if (!spec) + return -ENOMEM; + + snd_hda_pick_fixup(codec, + cs8409_models, cs8409_fixup_tbl, cs8409_fixups); + + codec_dbg(codec, "Picked ID=%d, VID=%08x, DEV=%08x\n", + codec->fixup_id, + codec->bus->pci->subsystem_vendor, + codec->bus->pci->subsystem_device); + + switch (codec->fixup_id) { + /* Dell platforms with CS42L42 companion codec */ + case CS8409_BULLSEYE: + case CS8409_WARLOCK: + case CS8409_CYBORG: + + snd_hda_add_verbs(codec, cs8409_cs42l42_add_verbs); + + codec->patch_ops = cs8409_cs42l42_patch_ops; + + spec->gen.suppress_auto_mute = 1; + spec->gen.no_primary_hp = 1; + /* GPIO 5 out, 3,4 in */ + spec->gpio_dir = GPIO5_INT; + spec->gpio_data = 0; + spec->gpio_mask = 0x03f; + + err = cs8409_cs42l42_fixup(codec); + + if (err > 0) + err = cs8409_cs42l42_hw_init(codec); + break; + + default: + codec_err(codec, "VID=%08x, DEV=%08x not supported\n", + codec->bus->pci->subsystem_vendor, + codec->bus->pci->subsystem_device); + break; + } + if (err < 0) + cs_free(codec); + else + snd_hda_codec_set_name(codec, "CS8409/CS42L42"); + + return err; +} /* * patch entries @@ -1229,6 +1804,7 @@ static const struct hda_device_id snd_hda_id_cirrus[] = { HDA_CODEC_ENTRY(0x10134208, "CS4208", patch_cs4208), HDA_CODEC_ENTRY(0x10134210, "CS4210", patch_cs4210), HDA_CODEC_ENTRY(0x10134213, "CS4213", patch_cs4213), + HDA_CODEC_ENTRY(0x10138409, "CS8409", patch_cs8409), {} /* terminator */ }; MODULE_DEVICE_TABLE(hdaudio, snd_hda_id_cirrus); From b73df04187ebb52edf3f7e502bb245c5ccab2763 Mon Sep 17 00:00:00 2001 From: Vitaly Rodionov Date: Sat, 6 Mar 2021 11:19:33 +0000 Subject: [PATCH 040/587] ALSA: hda/cirrus: Add jack detect interrupt support from CS42L42 companion codec. In the case of CS8409 we do not have unsol events from NID's 0x24 and 0x34 where hs mic and hp are connected. Companion codec CS42L42 will generate interrupt via gpio 4 to notify jack events. We have to overwrite standard snd_hda_jack_unsol_event(), read CS42L42 jack detect status registers and then notify status via generic snd_hda_jack_unsol_event() call. Tested on DELL Inspiron-3500, DELL Inspiron-3501, DELL Inspiron-3505. Signed-off-by: Vitaly Rodionov Link: https://lore.kernel.org/r/20210306111934.4832-4-vitalyr@opensource.cirrus.com Signed-off-by: Takashi Iwai --- sound/pci/hda/patch_cirrus.c | 309 ++++++++++++++++++++++++++++++++++- 1 file changed, 307 insertions(+), 2 deletions(-) diff --git a/sound/pci/hda/patch_cirrus.c b/sound/pci/hda/patch_cirrus.c index d664eed5c3cf..1d2f6a1224e6 100644 --- a/sound/pci/hda/patch_cirrus.c +++ b/sound/pci/hda/patch_cirrus.c @@ -9,6 +9,7 @@ #include #include #include +#include #include #include #include @@ -38,6 +39,15 @@ struct cs_spec { /* for MBP SPDIF control */ int (*spdif_sw_put)(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol); + + unsigned int cs42l42_hp_jack_in:1; + unsigned int cs42l42_mic_jack_in:1; + + struct mutex cs8409_i2c_mux; + + /* verb exec op override */ + int (*exec_verb)(struct hdac_device *dev, unsigned int cmd, + unsigned int flags, unsigned int *res); }; /* available models with CS420x */ @@ -1229,6 +1239,13 @@ static int patch_cs4213(struct hda_codec *codec) #define CS8409_CS42L42_SPK_PIN_NID 0x2c #define CS8409_CS42L42_AMIC_PIN_NID 0x34 #define CS8409_CS42L42_DMIC_PIN_NID 0x44 +#define CS8409_CS42L42_DMIC_ADC_PIN_NID 0x22 + +#define CS42L42_HSDET_AUTO_DONE 0x02 +#define CS42L42_HSTYPE_MASK 0x03 + +#define CS42L42_JACK_INSERTED 0x0C +#define CS42L42_JACK_REMOVED 0x00 #define GPIO3_INT (1 << 3) #define GPIO4_INT (1 << 4) @@ -1429,6 +1446,7 @@ static const struct cs8409_i2c_param cs42l42_init_reg_seq[] = { { 0x1C03, 0xC0 }, { 0x1105, 0x00 }, { 0x1112, 0xC0 }, + { 0x1101, 0x02 }, {} /* Terminator */ }; @@ -1565,6 +1583,8 @@ static unsigned int cs8409_i2c_write(struct hda_codec *codec, /* Assert/release RTS# line to CS42L42 */ static void cs8409_cs42l42_reset(struct hda_codec *codec) { + struct cs_spec *spec = codec->spec; + /* Assert RTS# line */ snd_hda_codec_write(codec, codec->core.afg, 0, AC_VERB_SET_GPIO_DATA, 0); @@ -1576,21 +1596,190 @@ static void cs8409_cs42l42_reset(struct hda_codec *codec) /* wait ~10ms */ usleep_range(10000, 15000); - /* Clear interrupts status */ + mutex_lock(&spec->cs8409_i2c_mux); + + /* Clear interrupts, by reading interrupt status registers */ cs8409_i2c_read(codec, CS42L42_I2C_ADDR, 0x1308, 1); cs8409_i2c_read(codec, CS42L42_I2C_ADDR, 0x1309, 1); cs8409_i2c_read(codec, CS42L42_I2C_ADDR, 0x130A, 1); cs8409_i2c_read(codec, CS42L42_I2C_ADDR, 0x130F, 1); + mutex_unlock(&spec->cs8409_i2c_mux); + +} + +/* Configure CS42L42 slave codec for jack autodetect */ +static int cs8409_cs42l42_enable_jack_detect(struct hda_codec *codec) +{ + struct cs_spec *spec = codec->spec; + + mutex_lock(&spec->cs8409_i2c_mux); + + /* Set TIP_SENSE_EN for analog front-end of tip sense. */ + cs8409_i2c_write(codec, CS42L42_I2C_ADDR, 0x1b70, 0x0020, 1); + /* Clear WAKE# */ + cs8409_i2c_write(codec, CS42L42_I2C_ADDR, 0x1b71, 0x0001, 1); + /* Wait ~2.5ms */ + usleep_range(2500, 3000); + /* Set mode WAKE# output follows the combination logic directly */ + cs8409_i2c_write(codec, CS42L42_I2C_ADDR, 0x1b71, 0x0020, 1); + /* Clear interrupts status */ + cs8409_i2c_read(codec, CS42L42_I2C_ADDR, 0x130f, 1); + cs8409_i2c_read(codec, CS42L42_I2C_ADDR, 0x1b7b, 1); + /* Enable interrupt */ + cs8409_i2c_write(codec, CS42L42_I2C_ADDR, 0x1320, 0x03, 1); + cs8409_i2c_write(codec, CS42L42_I2C_ADDR, 0x1b79, 0x00, 1); + + mutex_unlock(&spec->cs8409_i2c_mux); + + return 0; +} + +/* Enable and run CS42L42 slave codec jack auto detect */ +static void cs8409_cs42l42_run_jack_detect(struct hda_codec *codec) +{ + struct cs_spec *spec = codec->spec; + + mutex_lock(&spec->cs8409_i2c_mux); + + /* Clear interrupts */ + cs8409_i2c_read(codec, CS42L42_I2C_ADDR, 0x1308, 1); + cs8409_i2c_read(codec, CS42L42_I2C_ADDR, 0x1b77, 1); + + cs8409_i2c_write(codec, CS42L42_I2C_ADDR, 0x1102, 0x87, 1); + cs8409_i2c_write(codec, CS42L42_I2C_ADDR, 0x1f06, 0x86, 1); + cs8409_i2c_write(codec, CS42L42_I2C_ADDR, 0x1b74, 0x07, 1); + cs8409_i2c_write(codec, CS42L42_I2C_ADDR, 0x131b, 0x01, 1); + cs8409_i2c_write(codec, CS42L42_I2C_ADDR, 0x1120, 0x80, 1); + /* Wait ~110ms*/ + usleep_range(110000, 200000); + cs8409_i2c_write(codec, CS42L42_I2C_ADDR, 0x111f, 0x77, 1); + cs8409_i2c_write(codec, CS42L42_I2C_ADDR, 0x1120, 0xc0, 1); + /* Wait ~10ms */ + usleep_range(10000, 25000); + + mutex_unlock(&spec->cs8409_i2c_mux); + } static void cs8409_cs42l42_reg_setup(struct hda_codec *codec) { const struct cs8409_i2c_param *seq = cs42l42_init_reg_seq; + struct cs_spec *spec = codec->spec; + + mutex_lock(&spec->cs8409_i2c_mux); for (; seq->addr; seq++) cs8409_i2c_write(codec, CS42L42_I2C_ADDR, seq->addr, seq->reg, 1); + mutex_unlock(&spec->cs8409_i2c_mux); + +} + +/* + * In the case of CS8409 we do not have unsolicited events from NID's 0x24 + * and 0x34 where hs mic and hp are connected. Companion codec CS42L42 will + * generate interrupt via gpio 4 to notify jack events. We have to overwrite + * generic snd_hda_jack_unsol_event(), read CS42L42 jack detect status registers + * and then notify status via generic snd_hda_jack_unsol_event() call. + */ +static void cs8409_jack_unsol_event(struct hda_codec *codec, unsigned int res) +{ + struct cs_spec *spec = codec->spec; + int status_changed = 0; + unsigned int reg_cdc_status = 0; + unsigned int reg_hs_status = 0; + unsigned int reg_ts_status = 0; + int type = 0; + struct hda_jack_tbl *jk; + + /* jack_unsol_event() will be called every time gpio line changing state. + * In this case gpio4 line goes up as a result of reading interrupt status + * registers in previous cs8409_jack_unsol_event() call. + * We don't need to handle this event, ignoring... + */ + if ((res & (1 << 4))) + return; + + mutex_lock(&spec->cs8409_i2c_mux); + + /* Read jack detect status registers */ + reg_cdc_status = cs8409_i2c_read(codec, CS42L42_I2C_ADDR, 0x1308, 1); + reg_hs_status = cs8409_i2c_read(codec, CS42L42_I2C_ADDR, 0x1124, 1); + reg_ts_status = cs8409_i2c_read(codec, CS42L42_I2C_ADDR, 0x130f, 1); + + /* Clear interrupts */ + cs8409_i2c_read(codec, CS42L42_I2C_ADDR, 0x1b7b, 1); + cs8409_i2c_read(codec, CS42L42_I2C_ADDR, 0x1308, 1); + cs8409_i2c_read(codec, CS42L42_I2C_ADDR, 0x130f, 1); + + mutex_unlock(&spec->cs8409_i2c_mux); + + /* HSDET_AUTO_DONE */ + if (reg_cdc_status & CS42L42_HSDET_AUTO_DONE) { + + type = ((reg_hs_status & CS42L42_HSTYPE_MASK) + 1); + /* CS42L42 reports optical jack as type 4 + * We don't handle optical jack + */ + if (type != 4) { + if (!spec->cs42l42_hp_jack_in) { + status_changed = 1; + spec->cs42l42_hp_jack_in = 1; + } + /* type = 3 has no mic */ + if ((!spec->cs42l42_mic_jack_in) && (type != 3)) { + status_changed = 1; + spec->cs42l42_mic_jack_in = 1; + } + } else { + if (spec->cs42l42_hp_jack_in || spec->cs42l42_mic_jack_in) { + status_changed = 1; + spec->cs42l42_hp_jack_in = 0; + spec->cs42l42_mic_jack_in = 0; + } + } + + } else { + /* TIP_SENSE INSERT/REMOVE */ + switch (reg_ts_status) { + case CS42L42_JACK_INSERTED: + cs8409_cs42l42_run_jack_detect(codec); + break; + + case CS42L42_JACK_REMOVED: + if (spec->cs42l42_hp_jack_in || spec->cs42l42_mic_jack_in) { + status_changed = 1; + spec->cs42l42_hp_jack_in = 0; + spec->cs42l42_mic_jack_in = 0; + } + break; + + default: + /* jack in transition */ + status_changed = 0; + break; + } + } + + if (status_changed) { + + snd_hda_set_pin_ctl(codec, CS8409_CS42L42_SPK_PIN_NID, + (spec->cs42l42_hp_jack_in)?0 : PIN_OUT); + + /* Report jack*/ + jk = snd_hda_jack_tbl_get_mst(codec, CS8409_CS42L42_HP_PIN_NID, 0); + if (jk) { + snd_hda_jack_unsol_event(codec, + (jk->tag << AC_UNSOL_RES_TAG_SHIFT) & AC_UNSOL_RES_TAG); + } + /* Report jack*/ + jk = snd_hda_jack_tbl_get_mst(codec, CS8409_CS42L42_AMIC_PIN_NID, 0); + if (jk) { + snd_hda_jack_unsol_event(codec, + (jk->tag << AC_UNSOL_RES_TAG_SHIFT) & AC_UNSOL_RES_TAG); + } + } } static int cs8409_cs42l42_build_controls(struct hda_codec *codec) @@ -1603,6 +1792,13 @@ static int cs8409_cs42l42_build_controls(struct hda_codec *codec) snd_hda_apply_fixup(codec, HDA_FIXUP_ACT_BUILD); + /* Run jack auto detect first time on boot + * after controls have been added, to check if jack has + * been already plugged in + */ + cs8409_cs42l42_run_jack_detect(codec); + usleep_range(100000, 150000); + return 0; } @@ -1610,14 +1806,61 @@ static int cs8409_cs42l42_build_controls(struct hda_codec *codec) /* Manage PDREF, when transition to D3hot */ static int cs8409_suspend(struct hda_codec *codec) { + struct cs_spec *spec = codec->spec; + + mutex_lock(&spec->cs8409_i2c_mux); + /* Power down CS42L42 ASP/EQ/MIX/HP */ + cs8409_i2c_write(codec, CS42L42_I2C_ADDR, 0x1101, 0xfe, 1); + mutex_unlock(&spec->cs8409_i2c_mux); /* Assert CS42L42 RTS# line */ snd_hda_codec_write(codec, codec->core.afg, 0, AC_VERB_SET_GPIO_DATA, 0); + snd_hda_shutup_pins(codec); + return 0; } #endif +static void cs8409_cs42l42_cap_sync_hook(struct hda_codec *codec, + struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct cs_spec *spec = codec->spec; + unsigned int curval, expval; + /* CS8409 DMIC Pin only allows the setting of the Stream Parameters in + * Power State D0. When a headset is unplugged, and the path is switched to + * the DMIC, the Stream is restarted with the new ADC, but this is done in + * Power State D3. Restart the Stream now DMIC is in D0. + */ + if (spec->gen.cur_adc == CS8409_CS42L42_DMIC_ADC_PIN_NID) { + curval = snd_hda_codec_read(codec, spec->gen.cur_adc, + 0, AC_VERB_GET_CONV, 0); + expval = (spec->gen.cur_adc_stream_tag << 4) | 0; + if (curval != expval) { + codec_dbg(codec, "%s Restarting Stream after DMIC switch\n", __func__); + __snd_hda_codec_cleanup_stream(codec, spec->gen.cur_adc, 1); + snd_hda_codec_setup_stream(codec, spec->gen.cur_adc, + spec->gen.cur_adc_stream_tag, 0, + spec->gen.cur_adc_format); + } + } +} + +/* Enable/Disable Unsolicited Response for gpio(s) 3,4 */ +static void cs8409_enable_ur(struct hda_codec *codec, int flag) +{ + /* GPIO4 INT# and GPIO3 WAKE# */ + snd_hda_codec_write(codec, codec->core.afg, + 0, AC_VERB_SET_GPIO_UNSOLICITED_RSP_MASK, + flag?(GPIO3_INT | GPIO4_INT) : 0); + + snd_hda_codec_write(codec, codec->core.afg, + 0, AC_VERB_SET_UNSOLICITED_ENABLE, + flag?AC_UNSOL_ENABLED : 0); + +} + /* Vendor specific HW configuration * PLL, ASP, I2C, SPI, GPIOs, DMIC etc... */ @@ -1638,6 +1881,9 @@ static int cs8409_cs42l42_hw_init(struct hda_codec *codec) for (; seq->nid; seq++) cs_vendor_coef_set(codec, seq->cir, seq->coeff); + /* Disable Unsolicited Response during boot */ + cs8409_enable_ur(codec, 0); + /* Reset CS42L42 */ cs8409_cs42l42_reset(codec); @@ -1647,11 +1893,18 @@ static int cs8409_cs42l42_hw_init(struct hda_codec *codec) if (codec->fixup_id == CS8409_WARLOCK || codec->fixup_id == CS8409_CYBORG) { /* FULL_SCALE_VOL = 0 for Warlock / Cyborg */ + mutex_lock(&spec->cs8409_i2c_mux); cs8409_i2c_write(codec, CS42L42_I2C_ADDR, 0x2001, 0x01, 1); + mutex_unlock(&spec->cs8409_i2c_mux); /* DMIC1_MO=00b, DMIC1/2_SR=1 */ cs_vendor_coef_set(codec, 0x09, 0x0003); } + cs8409_cs42l42_enable_jack_detect(codec); + + /* Enable Unsolicited Response */ + cs8409_enable_ur(codec, 1); + return 1; } @@ -1671,6 +1924,8 @@ static int cs8409_cs42l42_init(struct hda_codec *codec) cs8409_cs42l42_hw_init(codec); + cs8409_cs42l42_run_jack_detect(codec); + usleep_range(100000, 150000); } return ret; @@ -1681,7 +1936,7 @@ static const struct hda_codec_ops cs8409_cs42l42_patch_ops = { .build_pcms = snd_hda_gen_build_pcms, .init = cs8409_cs42l42_init, .free = cs_free, - .unsol_event = snd_hda_jack_unsol_event, + .unsol_event = cs8409_jack_unsol_event, #ifdef CONFIG_PM .suspend = cs8409_suspend, #endif @@ -1741,6 +1996,45 @@ static int cs8409_cs42l42_fixup(struct hda_codec *codec) return err; } +static int cs8409_cs42l42_exec_verb(struct hdac_device *dev, + unsigned int cmd, unsigned int flags, unsigned int *res) +{ + struct hda_codec *codec = container_of(dev, struct hda_codec, core); + struct cs_spec *spec = codec->spec; + + unsigned int nid = 0; + unsigned int verb = 0; + + nid = ((cmd >> 20) & 0x07f); + verb = ((cmd >> 8) & 0x0fff); + + /* CS8409 pins have no AC_PINSENSE_PRESENCE + * capabilities. We have to intercept 2 calls for pins 0x24 and 0x34 + * and return correct pin sense values for read_pin_sense() call from + * hda_jack based on CS42L42 jack detect status. + */ + switch (nid) { + case CS8409_CS42L42_HP_PIN_NID: + if (verb == AC_VERB_GET_PIN_SENSE) { + *res = (spec->cs42l42_hp_jack_in) ? AC_PINSENSE_PRESENCE : 0; + return 0; + } + break; + + case CS8409_CS42L42_AMIC_PIN_NID: + if (verb == AC_VERB_GET_PIN_SENSE) { + *res = (spec->cs42l42_mic_jack_in) ? AC_PINSENSE_PRESENCE : 0; + return 0; + } + break; + + default: + break; + } + + return spec->exec_verb(dev, cmd, flags, res); +} + static int patch_cs8409(struct hda_codec *codec) { struct cs_spec *spec; @@ -1766,8 +2060,16 @@ static int patch_cs8409(struct hda_codec *codec) snd_hda_add_verbs(codec, cs8409_cs42l42_add_verbs); + /* verb exec op override */ + spec->exec_verb = codec->core.exec_verb; + codec->core.exec_verb = cs8409_cs42l42_exec_verb; + + mutex_init(&spec->cs8409_i2c_mux); + codec->patch_ops = cs8409_cs42l42_patch_ops; + spec->gen.cap_sync_hook = cs8409_cs42l42_cap_sync_hook; + spec->gen.suppress_auto_mute = 1; spec->gen.no_primary_hp = 1; /* GPIO 5 out, 3,4 in */ @@ -1775,6 +2077,9 @@ static int patch_cs8409(struct hda_codec *codec) spec->gpio_data = 0; spec->gpio_mask = 0x03f; + spec->cs42l42_hp_jack_in = 0; + spec->cs42l42_mic_jack_in = 0; + err = cs8409_cs42l42_fixup(codec); if (err > 0) From b9dd23bb03fe241ccb774c59b05d5cbac07895dc Mon Sep 17 00:00:00 2001 From: Stefan Binding Date: Sat, 6 Mar 2021 11:19:34 +0000 Subject: [PATCH 041/587] ALSA: hda/cirrus: Add Headphone and Headset MIC Volume Control CS8409 does not support Volume Control for NIDs 0x24 (the Headphones), or 0x34 (The Headset Mic). However, CS42L42 codec does support gain control for both. We can add support for Volume Controls, by writing the the CS42L42 regmap via i2c commands, using custom info, get and put volume functions, saved in the control. Tested on DELL Inspiron-3500, DELL Inspiron-3501, DELL Inspiron-3500 Signed-off-by: Stefan Binding Signed-off-by: Vitaly Rodionov Link: https://lore.kernel.org/r/20210306111934.4832-5-vitalyr@opensource.cirrus.com Signed-off-by: Takashi Iwai --- sound/pci/hda/patch_cirrus.c | 200 +++++++++++++++++++++++++++++++++++ 1 file changed, 200 insertions(+) diff --git a/sound/pci/hda/patch_cirrus.c b/sound/pci/hda/patch_cirrus.c index 1d2f6a1224e6..6a9e5c803977 100644 --- a/sound/pci/hda/patch_cirrus.c +++ b/sound/pci/hda/patch_cirrus.c @@ -21,6 +21,9 @@ /* */ +#define CS42L42_HP_CH (2U) +#define CS42L42_HS_MIC_CH (1U) + struct cs_spec { struct hda_gen_spec gen; @@ -42,6 +45,9 @@ struct cs_spec { unsigned int cs42l42_hp_jack_in:1; unsigned int cs42l42_mic_jack_in:1; + unsigned int cs42l42_volume_init:1; + char cs42l42_hp_volume[CS42L42_HP_CH]; + char cs42l42_hs_mic_volume[CS42L42_HS_MIC_CH]; struct mutex cs8409_i2c_mux; @@ -1260,6 +1266,14 @@ static int patch_cs4213(struct hda_codec *codec) #define CIR_I2C_QWRITE 0x005D #define CIR_I2C_QREAD 0x005E +#define CS8409_CS42L42_HP_VOL_REAL_MIN (-63) +#define CS8409_CS42L42_HP_VOL_REAL_MAX (0) +#define CS8409_CS42L42_AMIC_VOL_REAL_MIN (-97) +#define CS8409_CS42L42_AMIC_VOL_REAL_MAX (12) +#define CS8409_CS42L42_REG_HS_VOLUME_CHA (0x2301) +#define CS8409_CS42L42_REG_HS_VOLUME_CHB (0x2303) +#define CS8409_CS42L42_REG_AMIC_VOLUME (0x1D03) + struct cs8409_i2c_param { unsigned int addr; unsigned int reg; @@ -1580,6 +1594,165 @@ static unsigned int cs8409_i2c_write(struct hda_codec *codec, return retval; } +static int cs8409_cs42l42_volume_info(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_info *uinfo) +{ + struct hda_codec *codec = snd_kcontrol_chip(kcontrol); + u16 nid = get_amp_nid(kcontrol); + u8 chs = get_amp_channels(kcontrol); + + codec_dbg(codec, "%s() nid: %d\n", __func__, nid); + switch (nid) { + case CS8409_CS42L42_HP_PIN_NID: + uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER; + uinfo->count = chs == 3 ? 2 : 1; + uinfo->value.integer.min = CS8409_CS42L42_HP_VOL_REAL_MIN; + uinfo->value.integer.max = CS8409_CS42L42_HP_VOL_REAL_MAX; + break; + case CS8409_CS42L42_AMIC_PIN_NID: + uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER; + uinfo->count = chs == 3 ? 2 : 1; + uinfo->value.integer.min = CS8409_CS42L42_AMIC_VOL_REAL_MIN; + uinfo->value.integer.max = CS8409_CS42L42_AMIC_VOL_REAL_MAX; + break; + default: + break; + } + return 0; +} + +static void cs8409_cs42l42_update_volume(struct hda_codec *codec) +{ + struct cs_spec *spec = codec->spec; + + mutex_lock(&spec->cs8409_i2c_mux); + spec->cs42l42_hp_volume[0] = -(cs8409_i2c_read(codec, CS42L42_I2C_ADDR, + CS8409_CS42L42_REG_HS_VOLUME_CHA, 1)); + spec->cs42l42_hp_volume[1] = -(cs8409_i2c_read(codec, CS42L42_I2C_ADDR, + CS8409_CS42L42_REG_HS_VOLUME_CHB, 1)); + spec->cs42l42_hs_mic_volume[0] = -(cs8409_i2c_read(codec, CS42L42_I2C_ADDR, + CS8409_CS42L42_REG_AMIC_VOLUME, 1)); + mutex_unlock(&spec->cs8409_i2c_mux); + spec->cs42l42_volume_init = 1; +} + +static int cs8409_cs42l42_volume_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct hda_codec *codec = snd_kcontrol_chip(kcontrol); + struct cs_spec *spec = codec->spec; + hda_nid_t nid = get_amp_nid(kcontrol); + int chs = get_amp_channels(kcontrol); + long *valp = ucontrol->value.integer.value; + + if (!spec->cs42l42_volume_init) { + snd_hda_power_up(codec); + cs8409_cs42l42_update_volume(codec); + snd_hda_power_down(codec); + } + switch (nid) { + case CS8409_CS42L42_HP_PIN_NID: + if (chs & 1) + *valp++ = spec->cs42l42_hp_volume[0]; + if (chs & 2) + *valp++ = spec->cs42l42_hp_volume[1]; + break; + case CS8409_CS42L42_AMIC_PIN_NID: + if (chs & 1) + *valp++ = spec->cs42l42_hs_mic_volume[0]; + break; + default: + break; + } + return 0; +} + +static int cs8409_cs42l42_volume_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct hda_codec *codec = snd_kcontrol_chip(kcontrol); + struct cs_spec *spec = codec->spec; + hda_nid_t nid = get_amp_nid(kcontrol); + int chs = get_amp_channels(kcontrol); + long *valp = ucontrol->value.integer.value; + int change = 0; + char vol = 0; + + snd_hda_power_up(codec); + switch (nid) { + case CS8409_CS42L42_HP_PIN_NID: + mutex_lock(&spec->cs8409_i2c_mux); + if (chs & 1) { + vol = -(*valp); + change = cs8409_i2c_write(codec, CS42L42_I2C_ADDR, + CS8409_CS42L42_REG_HS_VOLUME_CHA, vol, 1); + valp++; + } + if (chs & 2) { + vol = -(*valp); + change |= cs8409_i2c_write(codec, CS42L42_I2C_ADDR, + CS8409_CS42L42_REG_HS_VOLUME_CHB, vol, 1); + } + mutex_unlock(&spec->cs8409_i2c_mux); + break; + case CS8409_CS42L42_AMIC_PIN_NID: + mutex_lock(&spec->cs8409_i2c_mux); + if (chs & 1) { + change = cs8409_i2c_write( + codec, CS42L42_I2C_ADDR, + CS8409_CS42L42_REG_AMIC_VOLUME, (char)*valp, 1); + valp++; + } + mutex_unlock(&spec->cs8409_i2c_mux); + break; + default: + break; + } + cs8409_cs42l42_update_volume(codec); + snd_hda_power_down(codec); + return change; +} + +static const DECLARE_TLV_DB_SCALE( + cs8409_cs42l42_hp_db_scale, + CS8409_CS42L42_HP_VOL_REAL_MIN * 100, 100, 1); + +static const DECLARE_TLV_DB_SCALE( + cs8409_cs42l42_amic_db_scale, + CS8409_CS42L42_AMIC_VOL_REAL_MIN * 100, 100, 1); + +static const struct snd_kcontrol_new cs8409_cs42l42_hp_volume_mixer = { + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, + .index = 0, + .name = "Headphone Playback Volume", + .subdevice = (HDA_SUBDEV_AMP_FLAG | HDA_SUBDEV_NID_FLAG), + .access = (SNDRV_CTL_ELEM_ACCESS_READWRITE + | SNDRV_CTL_ELEM_ACCESS_TLV_READ), + .info = cs8409_cs42l42_volume_info, + .get = cs8409_cs42l42_volume_get, + .put = cs8409_cs42l42_volume_put, + .tlv = { .p = cs8409_cs42l42_hp_db_scale }, + .private_value = HDA_COMPOSE_AMP_VAL( + CS8409_CS42L42_HP_PIN_NID, 3, 0, HDA_OUTPUT) + | HDA_AMP_VAL_MIN_MUTE +}; + +static const struct snd_kcontrol_new cs8409_cs42l42_amic_volume_mixer = { + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, + .index = 0, + .name = "Headset Mic Capture Volume", + .subdevice = (HDA_SUBDEV_AMP_FLAG | HDA_SUBDEV_NID_FLAG), + .access = (SNDRV_CTL_ELEM_ACCESS_READWRITE + | SNDRV_CTL_ELEM_ACCESS_TLV_READ), + .info = cs8409_cs42l42_volume_info, + .get = cs8409_cs42l42_volume_get, + .put = cs8409_cs42l42_volume_put, + .tlv = { .p = cs8409_cs42l42_amic_db_scale }, + .private_value = HDA_COMPOSE_AMP_VAL( + CS8409_CS42L42_AMIC_PIN_NID, 1, 0, HDA_INPUT) + | HDA_AMP_VAL_MIN_MUTE +}; + /* Assert/release RTS# line to CS42L42 */ static void cs8409_cs42l42_reset(struct hda_codec *codec) { @@ -1900,6 +2073,24 @@ static int cs8409_cs42l42_hw_init(struct hda_codec *codec) cs_vendor_coef_set(codec, 0x09, 0x0003); } + /* Restore Volumes after Resume */ + if (spec->cs42l42_volume_init) { + mutex_lock(&spec->cs8409_i2c_mux); + cs8409_i2c_write(codec, CS42L42_I2C_ADDR, + CS8409_CS42L42_REG_HS_VOLUME_CHA, -spec->cs42l42_hp_volume[0], + 1); + cs8409_i2c_write(codec, CS42L42_I2C_ADDR, + CS8409_CS42L42_REG_HS_VOLUME_CHB, -spec->cs42l42_hp_volume[1], + 1); + cs8409_i2c_write( + codec, CS42L42_I2C_ADDR, + CS8409_CS42L42_REG_AMIC_VOLUME, spec->cs42l42_hs_mic_volume[0], + 1); + mutex_unlock(&spec->cs8409_i2c_mux); + } + + cs8409_cs42l42_update_volume(codec); + cs8409_cs42l42_enable_jack_detect(codec); /* Enable Unsolicited Response */ @@ -1991,6 +2182,14 @@ static int cs8409_cs42l42_fixup(struct hda_codec *codec) if (err < 0) return err; + if (!snd_hda_gen_add_kctl( + &spec->gen, NULL, &cs8409_cs42l42_hp_volume_mixer)) + return -1; + + if (!snd_hda_gen_add_kctl( + &spec->gen, NULL, &cs8409_cs42l42_amic_volume_mixer)) + return -1; + snd_hda_apply_fixup(codec, HDA_FIXUP_ACT_PROBE); return err; @@ -2072,6 +2271,7 @@ static int patch_cs8409(struct hda_codec *codec) spec->gen.suppress_auto_mute = 1; spec->gen.no_primary_hp = 1; + spec->gen.suppress_vmaster = 1; /* GPIO 5 out, 3,4 in */ spec->gpio_dir = GPIO5_INT; spec->gpio_data = 0; From 97e2b5e5dcd543cd4d85ecb1bfa2a9721a08f411 Mon Sep 17 00:00:00 2001 From: Lucas Tanure Date: Fri, 5 Mar 2021 17:34:28 +0000 Subject: [PATCH 042/587] ASoC: cs42l42: Fix Bitclock polarity inversion The driver was setting bit clock polarity opposite to intended polarity. Also simplify the code by grouping ADC and DAC clock configurations into a single field. Signed-off-by: Lucas Tanure Link: https://lore.kernel.org/r/20210305173442.195740-2-tanureal@opensource.cirrus.com Signed-off-by: Mark Brown --- sound/soc/codecs/cs42l42.c | 20 ++++++++------------ sound/soc/codecs/cs42l42.h | 11 ++++++----- 2 files changed, 14 insertions(+), 17 deletions(-) diff --git a/sound/soc/codecs/cs42l42.c b/sound/soc/codecs/cs42l42.c index 210fcbedf241..df0d5fec0287 100644 --- a/sound/soc/codecs/cs42l42.c +++ b/sound/soc/codecs/cs42l42.c @@ -797,27 +797,23 @@ static int cs42l42_set_dai_fmt(struct snd_soc_dai *codec_dai, unsigned int fmt) /* Bitclock/frame inversion */ switch (fmt & SND_SOC_DAIFMT_INV_MASK) { case SND_SOC_DAIFMT_NB_NF: + asp_cfg_val |= CS42L42_ASP_SCPOL_NOR << CS42L42_ASP_SCPOL_SHIFT; break; case SND_SOC_DAIFMT_NB_IF: - asp_cfg_val |= CS42L42_ASP_POL_INV << - CS42L42_ASP_LCPOL_IN_SHIFT; + asp_cfg_val |= CS42L42_ASP_SCPOL_NOR << CS42L42_ASP_SCPOL_SHIFT; + asp_cfg_val |= CS42L42_ASP_LCPOL_INV << CS42L42_ASP_LCPOL_SHIFT; break; case SND_SOC_DAIFMT_IB_NF: - asp_cfg_val |= CS42L42_ASP_POL_INV << - CS42L42_ASP_SCPOL_IN_DAC_SHIFT; break; case SND_SOC_DAIFMT_IB_IF: - asp_cfg_val |= CS42L42_ASP_POL_INV << - CS42L42_ASP_LCPOL_IN_SHIFT; - asp_cfg_val |= CS42L42_ASP_POL_INV << - CS42L42_ASP_SCPOL_IN_DAC_SHIFT; + asp_cfg_val |= CS42L42_ASP_LCPOL_INV << CS42L42_ASP_LCPOL_SHIFT; break; } - snd_soc_component_update_bits(component, CS42L42_ASP_CLK_CFG, - CS42L42_ASP_MODE_MASK | - CS42L42_ASP_SCPOL_IN_DAC_MASK | - CS42L42_ASP_LCPOL_IN_MASK, asp_cfg_val); + snd_soc_component_update_bits(component, CS42L42_ASP_CLK_CFG, CS42L42_ASP_MODE_MASK | + CS42L42_ASP_SCPOL_MASK | + CS42L42_ASP_LCPOL_MASK, + asp_cfg_val); return 0; } diff --git a/sound/soc/codecs/cs42l42.h b/sound/soc/codecs/cs42l42.h index 9e3cc528dcff..1f0d67c95a9a 100644 --- a/sound/soc/codecs/cs42l42.h +++ b/sound/soc/codecs/cs42l42.h @@ -258,11 +258,12 @@ #define CS42L42_ASP_SLAVE_MODE 0x00 #define CS42L42_ASP_MODE_SHIFT 4 #define CS42L42_ASP_MODE_MASK (1 << CS42L42_ASP_MODE_SHIFT) -#define CS42L42_ASP_SCPOL_IN_DAC_SHIFT 2 -#define CS42L42_ASP_SCPOL_IN_DAC_MASK (1 << CS42L42_ASP_SCPOL_IN_DAC_SHIFT) -#define CS42L42_ASP_LCPOL_IN_SHIFT 0 -#define CS42L42_ASP_LCPOL_IN_MASK (1 << CS42L42_ASP_LCPOL_IN_SHIFT) -#define CS42L42_ASP_POL_INV 1 +#define CS42L42_ASP_SCPOL_SHIFT 2 +#define CS42L42_ASP_SCPOL_MASK (3 << CS42L42_ASP_SCPOL_SHIFT) +#define CS42L42_ASP_SCPOL_NOR 3 +#define CS42L42_ASP_LCPOL_SHIFT 0 +#define CS42L42_ASP_LCPOL_MASK (3 << CS42L42_ASP_LCPOL_SHIFT) +#define CS42L42_ASP_LCPOL_INV 3 #define CS42L42_ASP_FRM_CFG (CS42L42_PAGE_12 + 0x08) #define CS42L42_ASP_STP_SHIFT 4 From 3656667e66858fef45017c8e7c73e9918ed23915 Mon Sep 17 00:00:00 2001 From: Lucas Tanure Date: Fri, 5 Mar 2021 17:34:29 +0000 Subject: [PATCH 043/587] ASoC: cs42l42: Fix channel width support Remove the hard coded 32 bits width and replace with the correct width calculated by params_width. Signed-off-by: Lucas Tanure Link: https://lore.kernel.org/r/20210305173442.195740-3-tanureal@opensource.cirrus.com Signed-off-by: Mark Brown --- sound/soc/codecs/cs42l42.c | 47 ++++++++++++++++++-------------------- sound/soc/codecs/cs42l42.h | 1 - 2 files changed, 22 insertions(+), 26 deletions(-) diff --git a/sound/soc/codecs/cs42l42.c b/sound/soc/codecs/cs42l42.c index df0d5fec0287..4f9ad9547929 100644 --- a/sound/soc/codecs/cs42l42.c +++ b/sound/soc/codecs/cs42l42.c @@ -691,24 +691,6 @@ static int cs42l42_pll_config(struct snd_soc_component *component) CS42L42_CLK_OASRC_SEL_MASK, CS42L42_CLK_OASRC_SEL_12 << CS42L42_CLK_OASRC_SEL_SHIFT); - /* channel 1 on low LRCLK, 32 bit */ - snd_soc_component_update_bits(component, - CS42L42_ASP_RX_DAI0_CH1_AP_RES, - CS42L42_ASP_RX_CH_AP_MASK | - CS42L42_ASP_RX_CH_RES_MASK, - (CS42L42_ASP_RX_CH_AP_LOW << - CS42L42_ASP_RX_CH_AP_SHIFT) | - (CS42L42_ASP_RX_CH_RES_32 << - CS42L42_ASP_RX_CH_RES_SHIFT)); - /* Channel 2 on high LRCLK, 32 bit */ - snd_soc_component_update_bits(component, - CS42L42_ASP_RX_DAI0_CH2_AP_RES, - CS42L42_ASP_RX_CH_AP_MASK | - CS42L42_ASP_RX_CH_RES_MASK, - (CS42L42_ASP_RX_CH_AP_HI << - CS42L42_ASP_RX_CH_AP_SHIFT) | - (CS42L42_ASP_RX_CH_RES_32 << - CS42L42_ASP_RX_CH_RES_SHIFT)); if (pll_ratio_table[i].mclk_src_sel == 0) { /* Pass the clock straight through */ snd_soc_component_update_bits(component, @@ -824,14 +806,29 @@ static int cs42l42_pcm_hw_params(struct snd_pcm_substream *substream, { struct snd_soc_component *component = dai->component; struct cs42l42_private *cs42l42 = snd_soc_component_get_drvdata(component); - int retval; + unsigned int width = (params_width(params) / 8) - 1; + unsigned int val = 0; cs42l42->srate = params_rate(params); - cs42l42->swidth = params_width(params); - retval = cs42l42_pll_config(component); + switch(substream->stream) { + case SNDRV_PCM_STREAM_PLAYBACK: + val |= width << CS42L42_ASP_RX_CH_RES_SHIFT; + /* channel 1 on low LRCLK */ + snd_soc_component_update_bits(component, CS42L42_ASP_RX_DAI0_CH1_AP_RES, + CS42L42_ASP_RX_CH_AP_MASK | + CS42L42_ASP_RX_CH_RES_MASK, val); + /* Channel 2 on high LRCLK */ + val |= CS42L42_ASP_RX_CH_AP_HI << CS42L42_ASP_RX_CH_AP_SHIFT; + snd_soc_component_update_bits(component, CS42L42_ASP_RX_DAI0_CH2_AP_RES, + CS42L42_ASP_RX_CH_AP_MASK | + CS42L42_ASP_RX_CH_RES_MASK, val); + break; + default: + break; + } - return retval; + return cs42l42_pll_config(component); } static int cs42l42_set_sysclk(struct snd_soc_dai *dai, @@ -896,9 +893,9 @@ static int cs42l42_mute(struct snd_soc_dai *dai, int mute, int direction) return 0; } -#define CS42L42_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S18_3LE | \ - SNDRV_PCM_FMTBIT_S20_3LE | SNDRV_PCM_FMTBIT_S24_LE | \ - SNDRV_PCM_FMTBIT_S32_LE) +#define CS42L42_FORMATS (SNDRV_PCM_FMTBIT_S16_LE |\ + SNDRV_PCM_FMTBIT_S24_LE |\ + SNDRV_PCM_FMTBIT_S32_LE ) static const struct snd_soc_dai_ops cs42l42_ops = { diff --git a/sound/soc/codecs/cs42l42.h b/sound/soc/codecs/cs42l42.h index 1f0d67c95a9a..9b017b76828a 100644 --- a/sound/soc/codecs/cs42l42.h +++ b/sound/soc/codecs/cs42l42.h @@ -757,7 +757,6 @@ struct cs42l42_private { struct completion pdn_done; u32 sclk; u32 srate; - u32 swidth; u8 plug_state; u8 hs_type; u8 ts_inv; From a2ddc577ee4641889bf105d4d6e05be415bd4462 Mon Sep 17 00:00:00 2001 From: Lucas Tanure Date: Fri, 5 Mar 2021 17:34:30 +0000 Subject: [PATCH 044/587] ASoC: cs42l42: Fix mixer volume control The minimum value is 0x3f (-63dB), which also is mute Signed-off-by: Lucas Tanure Link: https://lore.kernel.org/r/20210305173442.195740-4-tanureal@opensource.cirrus.com Signed-off-by: Mark Brown --- sound/soc/codecs/cs42l42.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/sound/soc/codecs/cs42l42.c b/sound/soc/codecs/cs42l42.c index 4f9ad9547929..d5078ce79fad 100644 --- a/sound/soc/codecs/cs42l42.c +++ b/sound/soc/codecs/cs42l42.c @@ -401,7 +401,7 @@ static const struct regmap_config cs42l42_regmap = { }; static DECLARE_TLV_DB_SCALE(adc_tlv, -9600, 100, false); -static DECLARE_TLV_DB_SCALE(mixer_tlv, -6200, 100, false); +static DECLARE_TLV_DB_SCALE(mixer_tlv, -6300, 100, true); static const char * const cs42l42_hpf_freq_text[] = { "1.86Hz", "120Hz", "235Hz", "466Hz" @@ -458,7 +458,7 @@ static const struct snd_kcontrol_new cs42l42_snd_controls[] = { CS42L42_DAC_HPF_EN_SHIFT, true, false), SOC_DOUBLE_R_TLV("Mixer Volume", CS42L42_MIXER_CHA_VOL, CS42L42_MIXER_CHB_VOL, CS42L42_MIXER_CH_VOL_SHIFT, - 0x3e, 1, mixer_tlv) + 0x3f, 1, mixer_tlv) }; static int cs42l42_hpdrv_evt(struct snd_soc_dapm_widget *w, From 9ad4f9ea976e05d4eba62ea58c7c7c45705b80a1 Mon Sep 17 00:00:00 2001 From: Lucas Tanure Date: Fri, 5 Mar 2021 17:34:31 +0000 Subject: [PATCH 045/587] ASoC: cs42l42: Don't enable/disable regulator at Bias Level dev_pm_ops already enable/disable the codec if not in use Signed-off-by: Lucas Tanure Link: https://lore.kernel.org/r/20210305173442.195740-5-tanureal@opensource.cirrus.com Signed-off-by: Mark Brown --- sound/soc/codecs/cs42l42.c | 38 -------------------------------------- 1 file changed, 38 deletions(-) diff --git a/sound/soc/codecs/cs42l42.c b/sound/soc/codecs/cs42l42.c index d5078ce79fad..eee3fc320030 100644 --- a/sound/soc/codecs/cs42l42.c +++ b/sound/soc/codecs/cs42l42.c @@ -511,43 +511,6 @@ static const struct snd_soc_dapm_route cs42l42_audio_map[] = { {"HP", NULL, "HPDRV"} }; -static int cs42l42_set_bias_level(struct snd_soc_component *component, - enum snd_soc_bias_level level) -{ - struct cs42l42_private *cs42l42 = snd_soc_component_get_drvdata(component); - int ret; - - switch (level) { - case SND_SOC_BIAS_ON: - break; - case SND_SOC_BIAS_PREPARE: - break; - case SND_SOC_BIAS_STANDBY: - if (snd_soc_component_get_bias_level(component) == SND_SOC_BIAS_OFF) { - regcache_cache_only(cs42l42->regmap, false); - regcache_sync(cs42l42->regmap); - ret = regulator_bulk_enable( - ARRAY_SIZE(cs42l42->supplies), - cs42l42->supplies); - if (ret != 0) { - dev_err(component->dev, - "Failed to enable regulators: %d\n", - ret); - return ret; - } - } - break; - case SND_SOC_BIAS_OFF: - - regcache_cache_only(cs42l42->regmap, true); - regulator_bulk_disable(ARRAY_SIZE(cs42l42->supplies), - cs42l42->supplies); - break; - } - - return 0; -} - static int cs42l42_component_probe(struct snd_soc_component *component) { struct cs42l42_private *cs42l42 = @@ -560,7 +523,6 @@ static int cs42l42_component_probe(struct snd_soc_component *component) static const struct snd_soc_component_driver soc_component_dev_cs42l42 = { .probe = cs42l42_component_probe, - .set_bias_level = cs42l42_set_bias_level, .dapm_widgets = cs42l42_dapm_widgets, .num_dapm_widgets = ARRAY_SIZE(cs42l42_dapm_widgets), .dapm_routes = cs42l42_audio_map, From ddaa9bea4ffaba50f814585f294a5d98641b41ad Mon Sep 17 00:00:00 2001 From: Lucas Tanure Date: Fri, 5 Mar 2021 17:34:32 +0000 Subject: [PATCH 046/587] ASoC: cs42l42: Always wait at least 3ms after reset This delay is part of the power-up sequence defined in the datasheet. A runtime_resume is a power-up so must also include the delay. Signed-off-by: Lucas Tanure Link: https://lore.kernel.org/r/20210305173442.195740-6-tanureal@opensource.cirrus.com Signed-off-by: Mark Brown --- sound/soc/codecs/cs42l42.c | 3 ++- sound/soc/codecs/cs42l42.h | 1 + 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/sound/soc/codecs/cs42l42.c b/sound/soc/codecs/cs42l42.c index eee3fc320030..811b7b1c9732 100644 --- a/sound/soc/codecs/cs42l42.c +++ b/sound/soc/codecs/cs42l42.c @@ -1756,7 +1756,7 @@ static int cs42l42_i2c_probe(struct i2c_client *i2c_client, dev_dbg(&i2c_client->dev, "Found reset GPIO\n"); gpiod_set_value_cansleep(cs42l42->reset_gpio, 1); } - mdelay(3); + usleep_range(CS42L42_BOOT_TIME_US, CS42L42_BOOT_TIME_US * 2); /* Request IRQ */ ret = devm_request_threaded_irq(&i2c_client->dev, @@ -1881,6 +1881,7 @@ static int cs42l42_runtime_resume(struct device *dev) } gpiod_set_value_cansleep(cs42l42->reset_gpio, 1); + usleep_range(CS42L42_BOOT_TIME_US, CS42L42_BOOT_TIME_US * 2); regcache_cache_only(cs42l42->regmap, false); regcache_sync(cs42l42->regmap); diff --git a/sound/soc/codecs/cs42l42.h b/sound/soc/codecs/cs42l42.h index 9b017b76828a..866d7c873e3c 100644 --- a/sound/soc/codecs/cs42l42.h +++ b/sound/soc/codecs/cs42l42.h @@ -740,6 +740,7 @@ #define CS42L42_FRAC2_VAL(val) (((val) & 0xff0000) >> 16) #define CS42L42_NUM_SUPPLIES 5 +#define CS42L42_BOOT_TIME_US 3000 static const char *const cs42l42_supply_names[CS42L42_NUM_SUPPLIES] = { "VA", From 8106efdce03673d5ba963ced2db47d669d2dec82 Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Thu, 18 Feb 2021 16:29:07 -0600 Subject: [PATCH 047/587] ASoC: qcom: lpass-hdmi: remove useless return cppcheck warning: sound/soc/qcom/lpass-hdmi.c:189:9: warning: Identical condition and return expression 'ret', return value is always 0 [identicalConditionAfterEarlyExit] return ret; ^ sound/soc/qcom/lpass-hdmi.c:186:6: note: If condition 'ret' is true, the function will return/exit if (ret) ^ sound/soc/qcom/lpass-hdmi.c:189:9: note: Returning identical expression 'ret' return ret; ^ sound/soc/qcom/lpass-hdmi.c:206:9: warning: Identical condition and return expression 'ret', return value is always 0 [identicalConditionAfterEarlyExit] return ret; ^ sound/soc/qcom/lpass-hdmi.c:203:6: note: If condition 'ret' is true, the function will return/exit if (ret) ^ sound/soc/qcom/lpass-hdmi.c:206:9: note: Returning identical expression 'ret' return ret; ^ Signed-off-by: Pierre-Louis Bossart Reviewed-by: Srinivas Kandagatla Link: https://lore.kernel.org/r/20210218222916.89809-2-pierre-louis.bossart@linux.intel.com Signed-off-by: Mark Brown --- sound/soc/qcom/lpass-hdmi.c | 4 ---- 1 file changed, 4 deletions(-) diff --git a/sound/soc/qcom/lpass-hdmi.c b/sound/soc/qcom/lpass-hdmi.c index abfb8737a89f..24b1a7523adb 100644 --- a/sound/soc/qcom/lpass-hdmi.c +++ b/sound/soc/qcom/lpass-hdmi.c @@ -183,8 +183,6 @@ static int lpass_hdmi_daiops_hw_params(struct snd_pcm_substream *substream, return ret; ret = regmap_field_write(sstream_ctl->dp_staffing_en, LPASS_SSTREAM_DEFAULT_ENABLE); - if (ret) - return ret; return ret; } @@ -200,8 +198,6 @@ static int lpass_hdmi_daiops_prepare(struct snd_pcm_substream *substream, return ret; ret = regmap_field_write(drvdata->meta_ctl->mute, LPASS_MUTE_DISABLE); - if (ret) - return ret; return ret; } From 64298706dcc99d1d1fe0882f1ddeb9a3ab5526da Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Thu, 18 Feb 2021 16:29:08 -0600 Subject: [PATCH 048/587] ASoC: qcom: lpass-platform: remove useless assignment cppcheck warning: sound/soc/qcom/lpass-platform.c:791:10: style: Variable 'ret' is assigned a value that is never used. [unreadVariable] int ret = -EINVAL; ^ Signed-off-by: Pierre-Louis Bossart Reviewed-by: Srinivas Kandagatla Link: https://lore.kernel.org/r/20210218222916.89809-3-pierre-louis.bossart@linux.intel.com Signed-off-by: Mark Brown --- sound/soc/qcom/lpass-platform.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sound/soc/qcom/lpass-platform.c b/sound/soc/qcom/lpass-platform.c index 0074b7f2dbc1..0df9481ea4c6 100644 --- a/sound/soc/qcom/lpass-platform.c +++ b/sound/soc/qcom/lpass-platform.c @@ -788,7 +788,7 @@ static int lpass_platform_pcm_new(struct snd_soc_component *component, { struct snd_pcm *pcm = soc_runtime->pcm; struct snd_pcm_substream *psubstream, *csubstream; - int ret = -EINVAL; + int ret; size_t size = lpass_platform_pcm_hardware.buffer_bytes_max; psubstream = pcm->streams[SNDRV_PCM_STREAM_PLAYBACK].substream; From 18bcac6ed7464844bc18eaa362b0920f6d48bef6 Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Thu, 18 Feb 2021 16:29:09 -0600 Subject: [PATCH 049/587] ASoC: qcom: q6dsp-dai: clarify expression cppcheck warning: sound/soc/qcom/qdsp6/q6afe-dai.c:264:35: style: Clarify calculation precedence for '&' and '?'. [clarifyCalculation] tdm->slot_mask = (dai->id & 0x1 ? tx_mask : rx_mask) & cap_mask; ^ Signed-off-by: Pierre-Louis Bossart Reviewed-by: Srinivas Kandagatla Link: https://lore.kernel.org/r/20210218222916.89809-4-pierre-louis.bossart@linux.intel.com Signed-off-by: Mark Brown --- sound/soc/qcom/qdsp6/q6afe-dai.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sound/soc/qcom/qdsp6/q6afe-dai.c b/sound/soc/qcom/qdsp6/q6afe-dai.c index 4e1f101281e7..3b52abec6a93 100644 --- a/sound/soc/qcom/qdsp6/q6afe-dai.c +++ b/sound/soc/qcom/qdsp6/q6afe-dai.c @@ -261,7 +261,7 @@ static int q6tdm_set_tdm_slot(struct snd_soc_dai *dai, tdm->nslots_per_frame = slots; tdm->slot_width = slot_width; /* TDM RX dais ids are even and tx are odd */ - tdm->slot_mask = (dai->id & 0x1 ? tx_mask : rx_mask) & cap_mask; + tdm->slot_mask = ((dai->id & 0x1) ? tx_mask : rx_mask) & cap_mask; break; default: dev_err(dai->dev, "%s: invalid dai id 0x%x\n", From 12900bacb4f358f8921e4dcf7e3f28aac3a37d8b Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Thu, 18 Feb 2021 16:29:10 -0600 Subject: [PATCH 050/587] ASoC: qcom: q6afe: remove useless assignments cppcheck warnings: sound/soc/qcom/qdsp6/q6afe.c:848:25: note: Assignment 'p=NULL', assigned value is 0 struct q6afe_port *p = NULL; ^ sound/soc/qcom/qdsp6/q6afe.c:854:7: note: Null pointer dereference if (p->token == token) { ^ sound/soc/qcom/qdsp6/q6afe.c:939:8: style: Redundant initialization for 'wait'. The initialized value is overwritten before it is read. [redundantInitialization] wait = &port->wait; ^ sound/soc/qcom/qdsp6/q6afe.c:933:26: note: wait is initialized wait_queue_head_t *wait = &port->wait; ^ sound/soc/qcom/qdsp6/q6afe.c:939:8: note: wait is overwritten wait = &port->wait; ^ sound/soc/qcom/qdsp6/q6afe.c:1191:10: style: Redundant initialization for 'port_id'. The initialized value is overwritten before it is read. [redundantInitialization] port_id = port->id; ^ sound/soc/qcom/qdsp6/q6afe.c:1186:14: note: port_id is initialized int port_id = port->id; ^ sound/soc/qcom/qdsp6/q6afe.c:1191:10: note: port_id is overwritten port_id = port->id; ^ Signed-off-by: Pierre-Louis Bossart Reviewed-by: Srinivas Kandagatla Link: https://lore.kernel.org/r/20210218222916.89809-5-pierre-louis.bossart@linux.intel.com Signed-off-by: Mark Brown --- sound/soc/qcom/qdsp6/q6afe.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/sound/soc/qcom/qdsp6/q6afe.c b/sound/soc/qcom/qdsp6/q6afe.c index cad1cd1bfdf0..6f700c311337 100644 --- a/sound/soc/qcom/qdsp6/q6afe.c +++ b/sound/soc/qcom/qdsp6/q6afe.c @@ -845,7 +845,7 @@ static void q6afe_port_free(struct kref *ref) static struct q6afe_port *q6afe_find_port(struct q6afe *afe, int token) { - struct q6afe_port *p = NULL; + struct q6afe_port *p; struct q6afe_port *ret = NULL; unsigned long flags; @@ -930,7 +930,7 @@ EXPORT_SYMBOL_GPL(q6afe_get_port_id); static int afe_apr_send_pkt(struct q6afe *afe, struct apr_pkt *pkt, struct q6afe_port *port, uint32_t rsp_opcode) { - wait_queue_head_t *wait = &port->wait; + wait_queue_head_t *wait; struct aprv2_ibasic_rsp_result_t *result; int ret; @@ -1188,7 +1188,6 @@ int q6afe_port_stop(struct q6afe_port *port) int index, pkt_size; void *p; - port_id = port->id; index = port->token; if (index < 0 || index >= AFE_PORT_MAX) { dev_err(afe->dev, "AFE port index[%d] invalid!\n", index); From 32d4e59cb39de508698ae4db5707af23c3835e4c Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Thu, 18 Feb 2021 16:29:11 -0600 Subject: [PATCH 051/587] ASoC: qcom: q6afe: align function prototype cppcheck warning: sound/soc/qcom/qdsp6/q6afe.c:1101:63: style:inconclusive: Function 'q6afe_set_lpass_clock' argument 3 names different: declaration 'clk_src' definition 'attri'. [funcArgNamesDifferent] int q6afe_set_lpass_clock(struct device *dev, int clk_id, int attri, ^ sound/soc/qcom/qdsp6/q6afe.h:236:63: note: Function 'q6afe_set_lpass_clock' argument 3 names different: declaration 'clk_src' definition 'attri'. int q6afe_set_lpass_clock(struct device *dev, int clk_id, int clk_src, ^ sound/soc/qcom/qdsp6/q6afe.c:1101:63: note: Function 'q6afe_set_lpass_clock' argument 3 names different: declaration 'clk_src' definition 'attri'. int q6afe_set_lpass_clock(struct device *dev, int clk_id, int attri, ^ Signed-off-by: Pierre-Louis Bossart Reviewed-by: Srinivas Kandagatla Link: https://lore.kernel.org/r/20210218222916.89809-6-pierre-louis.bossart@linux.intel.com Signed-off-by: Mark Brown --- sound/soc/qcom/qdsp6/q6afe.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sound/soc/qcom/qdsp6/q6afe.h b/sound/soc/qcom/qdsp6/q6afe.h index 22e10269aa10..41133f8797c9 100644 --- a/sound/soc/qcom/qdsp6/q6afe.h +++ b/sound/soc/qcom/qdsp6/q6afe.h @@ -233,7 +233,7 @@ void q6afe_cdc_dma_port_prepare(struct q6afe_port *port, int q6afe_port_set_sysclk(struct q6afe_port *port, int clk_id, int clk_src, int clk_root, unsigned int freq, int dir); -int q6afe_set_lpass_clock(struct device *dev, int clk_id, int clk_src, +int q6afe_set_lpass_clock(struct device *dev, int clk_id, int attri, int clk_root, unsigned int freq); int q6afe_vote_lpass_core_hw(struct device *dev, uint32_t hw_block_id, char *client_name, uint32_t *client_handle); From be79e73e3adbcb8912b005c6485ed0e1590480e4 Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Thu, 18 Feb 2021 16:29:12 -0600 Subject: [PATCH 052/587] ASoC: qcom: q6asm: align function prototypes cppcheck warnings: sound/soc/qcom/qdsp6/q6asm.c:502:16: style:inconclusive: Function 'q6asm_map_memory_regions' argument 4 names different: declaration 'bufsz' definition 'period_sz'. [funcArgNamesDifferent] size_t period_sz, unsigned int periods) ^ sound/soc/qcom/qdsp6/q6asm.h:150:16: note: Function 'q6asm_map_memory_regions' argument 4 names different: declaration 'bufsz' definition 'period_sz'. size_t bufsz, unsigned int bufcnt); ^ sound/soc/qcom/qdsp6/q6asm.c:502:16: note: Function 'q6asm_map_memory_regions' argument 4 names different: declaration 'bufsz' definition 'period_sz'. size_t period_sz, unsigned int periods) ^ sound/soc/qcom/qdsp6/q6asm.c:502:40: style:inconclusive: Function 'q6asm_map_memory_regions' argument 5 names different: declaration 'bufcnt' definition 'periods'. [funcArgNamesDifferent] size_t period_sz, unsigned int periods) ^ sound/soc/qcom/qdsp6/q6asm.h:150:36: note: Function 'q6asm_map_memory_regions' argument 5 names different: declaration 'bufcnt' definition 'periods'. size_t bufsz, unsigned int bufcnt); ^ sound/soc/qcom/qdsp6/q6asm.c:502:40: note: Function 'q6asm_map_memory_regions' argument 5 names different: declaration 'bufcnt' definition 'periods'. size_t period_sz, unsigned int periods) ^ sound/soc/qcom/qdsp6/q6asm.c:823:47: style:inconclusive: Function 'q6asm_get_session_id' argument 1 names different: declaration 'ac' definition 'c'. [funcArgNamesDifferent] int q6asm_get_session_id(struct audio_client *c) ^ sound/soc/qcom/qdsp6/q6asm.h:146:47: note: Function 'q6asm_get_session_id' argument 1 names different: declaration 'ac' definition 'c'. int q6asm_get_session_id(struct audio_client *ac); ^ sound/soc/qcom/qdsp6/q6asm.c:823:47: note: Function 'q6asm_get_session_id' argument 1 names different: declaration 'ac' definition 'c'. int q6asm_get_session_id(struct audio_client *c) ^ sound/soc/qcom/qdsp6/q6asm.c:1573:52: style:inconclusive: Function 'q6asm_write_async' argument 6 names different: declaration 'flags' definition 'wflags'. [funcArgNamesDifferent] uint32_t msw_ts, uint32_t lsw_ts, uint32_t wflags) ^ sound/soc/qcom/qdsp6/q6asm.h:100:52: note: Function 'q6asm_write_async' argument 6 names different: declaration 'flags' definition 'wflags'. uint32_t msw_ts, uint32_t lsw_ts, uint32_t flags); ^ sound/soc/qcom/qdsp6/q6asm.c:1573:52: note: Function 'q6asm_write_async' argument 6 names different: declaration 'flags' definition 'wflags'. uint32_t msw_ts, uint32_t lsw_ts, uint32_t wflags) ^ Signed-off-by: Pierre-Louis Bossart Reviewed-by: Srinivas Kandagatla Link: https://lore.kernel.org/r/20210218222916.89809-7-pierre-louis.bossart@linux.intel.com Signed-off-by: Mark Brown --- sound/soc/qcom/qdsp6/q6asm.h | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/sound/soc/qcom/qdsp6/q6asm.h b/sound/soc/qcom/qdsp6/q6asm.h index 82e584aa534f..394604c34943 100644 --- a/sound/soc/qcom/qdsp6/q6asm.h +++ b/sound/soc/qcom/qdsp6/q6asm.h @@ -97,7 +97,7 @@ struct audio_client *q6asm_audio_client_alloc(struct device *dev, int session_id, int perf_mode); void q6asm_audio_client_free(struct audio_client *ac); int q6asm_write_async(struct audio_client *ac, uint32_t stream_id, uint32_t len, - uint32_t msw_ts, uint32_t lsw_ts, uint32_t flags); + uint32_t msw_ts, uint32_t lsw_ts, uint32_t wflags); int q6asm_open_write(struct audio_client *ac, uint32_t stream_id, uint32_t format, u32 codec_profile, uint16_t bits_per_sample, bool is_gapless); @@ -143,10 +143,10 @@ int q6asm_stream_remove_trailing_silence(struct audio_client *ac, uint32_t trailing_samples); int q6asm_cmd(struct audio_client *ac, uint32_t stream_id, int cmd); int q6asm_cmd_nowait(struct audio_client *ac, uint32_t stream_id, int cmd); -int q6asm_get_session_id(struct audio_client *ac); +int q6asm_get_session_id(struct audio_client *c); int q6asm_map_memory_regions(unsigned int dir, struct audio_client *ac, phys_addr_t phys, - size_t bufsz, unsigned int bufcnt); + size_t period_sz, unsigned int periods); int q6asm_unmap_memory_regions(unsigned int dir, struct audio_client *ac); #endif /* __Q6_ASM_H__ */ From 77af06de30139fbddae67dd9db70d7ccc53b1955 Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Thu, 18 Feb 2021 16:29:13 -0600 Subject: [PATCH 053/587] ASoC: wcd-clsh-v2: align function prototypes cppcheck warnings: sound/soc/codecs/wcd-clsh-v2.c:523:28: style:inconclusive: Function 'wcd_clsh_ctrl_set_state' argument 2 names different: declaration 'event' definition 'clsh_event'. [funcArgNamesDifferent] enum wcd_clsh_event clsh_event, ^ sound/soc/codecs/wcd-clsh-v2.h:45:28: note: Function 'wcd_clsh_ctrl_set_state' argument 2 names different: declaration 'event' definition 'clsh_event'. enum wcd_clsh_event event, ^ sound/soc/codecs/wcd-clsh-v2.c:523:28: note: Function 'wcd_clsh_ctrl_set_state' argument 2 names different: declaration 'event' definition 'clsh_event'. enum wcd_clsh_event clsh_event, ^ sound/soc/codecs/wcd-clsh-v2.c:524:12: style:inconclusive: Function 'wcd_clsh_ctrl_set_state' argument 3 names different: declaration 'state' definition 'nstate'. [funcArgNamesDifferent] int nstate, ^ sound/soc/codecs/wcd-clsh-v2.h:46:12: note: Function 'wcd_clsh_ctrl_set_state' argument 3 names different: declaration 'state' definition 'nstate'. int state, ^ sound/soc/codecs/wcd-clsh-v2.c:524:12: note: Function 'wcd_clsh_ctrl_set_state' argument 3 names different: declaration 'state' definition 'nstate'. int nstate, ^ sound/soc/codecs/wcd-clsh-v2.c:557:69: style:inconclusive: Function 'wcd_clsh_ctrl_alloc' argument 1 names different: declaration 'component' definition 'comp'. [funcArgNamesDifferent] struct wcd_clsh_ctrl *wcd_clsh_ctrl_alloc(struct snd_soc_component *comp, ^ sound/soc/codecs/wcd-clsh-v2.h:40:31: note: Function 'wcd_clsh_ctrl_alloc' argument 1 names different: declaration 'component' definition 'comp'. struct snd_soc_component *component, ^ sound/soc/codecs/wcd-clsh-v2.c:557:69: note: Function 'wcd_clsh_ctrl_alloc' argument 1 names different: declaration 'component' definition 'comp'. struct wcd_clsh_ctrl *wcd_clsh_ctrl_alloc(struct snd_soc_component *comp, ^ Signed-off-by: Pierre-Louis Bossart Reviewed-by: Srinivas Kandagatla Link: https://lore.kernel.org/r/20210218222916.89809-8-pierre-louis.bossart@linux.intel.com Signed-off-by: Mark Brown --- sound/soc/codecs/wcd-clsh-v2.h | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/sound/soc/codecs/wcd-clsh-v2.h b/sound/soc/codecs/wcd-clsh-v2.h index a902f9893467..a6d0f2d0e9e3 100644 --- a/sound/soc/codecs/wcd-clsh-v2.h +++ b/sound/soc/codecs/wcd-clsh-v2.h @@ -37,13 +37,13 @@ enum wcd_clsh_mode { struct wcd_clsh_ctrl; extern struct wcd_clsh_ctrl *wcd_clsh_ctrl_alloc( - struct snd_soc_component *component, + struct snd_soc_component *comp, int version); extern void wcd_clsh_ctrl_free(struct wcd_clsh_ctrl *ctrl); extern int wcd_clsh_ctrl_get_state(struct wcd_clsh_ctrl *ctrl); extern int wcd_clsh_ctrl_set_state(struct wcd_clsh_ctrl *ctrl, - enum wcd_clsh_event event, - int state, + enum wcd_clsh_event clsh_event, + int nstate, enum wcd_clsh_mode mode); #endif /* _WCD_CLSH_V2_H_ */ From 8d2f2d7ff3c69e1b7a2d1424e4d2dc8a6fe77849 Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Thu, 18 Feb 2021 16:29:14 -0600 Subject: [PATCH 054/587] ASoC: wcd9335: clarify return value cppcheck warning: sound/soc/codecs/wcd9335.c:5216:9: warning: Identical condition and return expression 'ret', return value is always 0 [identicalConditionAfterEarlyExit] return ret; ^ sound/soc/codecs/wcd9335.c:5211:6: note: If condition 'ret' is true, the function will return/exit if (ret) ^ sound/soc/codecs/wcd9335.c:5216:9: note: Returning identical expression 'ret' return ret; ^ Signed-off-by: Pierre-Louis Bossart Reviewed-by: Srinivas Kandagatla Link: https://lore.kernel.org/r/20210218222916.89809-9-pierre-louis.bossart@linux.intel.com Signed-off-by: Mark Brown --- sound/soc/codecs/wcd9335.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sound/soc/codecs/wcd9335.c b/sound/soc/codecs/wcd9335.c index 9ddfed797b7e..adb325fac930 100644 --- a/sound/soc/codecs/wcd9335.c +++ b/sound/soc/codecs/wcd9335.c @@ -5213,7 +5213,7 @@ static int wcd9335_slim_status(struct slim_device *sdev, wcd9335_probe(wcd); - return ret; + return 0; } static const struct slim_device_id wcd9335_slim_id[] = { From 7faaea14feeeb88177ecf8a640a203c319960d43 Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Thu, 18 Feb 2021 16:29:15 -0600 Subject: [PATCH 055/587] ASoC: wcd934x: remove useless return cppcheck warning: sound/soc/codecs/wcd934x.c:1571:9: warning: Identical condition and return expression 'ret', return value is always 0 [identicalConditionAfterEarlyExit] return ret; ^ sound/soc/codecs/wcd934x.c:1568:6: note: If condition 'ret' is true, the function will return/exit if (ret) ^ sound/soc/codecs/wcd934x.c:1571:9: note: Returning identical expression 'ret' return ret; ^ Signed-off-by: Pierre-Louis Bossart Reviewed-by: Srinivas Kandagatla Link: https://lore.kernel.org/r/20210218222916.89809-10-pierre-louis.bossart@linux.intel.com Signed-off-by: Mark Brown --- sound/soc/codecs/wcd934x.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/sound/soc/codecs/wcd934x.c b/sound/soc/codecs/wcd934x.c index d18ae5e3ee80..2c4818dc2e6d 100644 --- a/sound/soc/codecs/wcd934x.c +++ b/sound/soc/codecs/wcd934x.c @@ -1565,8 +1565,6 @@ static int wcd934x_set_interpolator_rate(struct snd_soc_dai *dai, return ret; ret = wcd934x_set_mix_interpolator_rate(dai, (u8)rate_val, sample_rate); - if (ret) - return ret; return ret; } From 4b4f2119f98518c86c5651771ad9db9070c76de4 Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Thu, 18 Feb 2021 16:29:16 -0600 Subject: [PATCH 056/587] ASoC: lpass-wsa-macro: add missing test cppcheck warning: sound/soc/codecs/lpass-wsa-macro.c:958:6: style: Variable 'ret' is reassigned a value before the old one has been used. [redundantAssignment] ret = wsa_macro_set_prim_interpolator_rate(dai, (u8) rate_val, sample_rate); ^ sound/soc/codecs/lpass-wsa-macro.c:946:6: note: ret is assigned ret = wsa_macro_set_mix_interpolator_rate(dai, (u8) rate_val, sample_rate); ^ sound/soc/codecs/lpass-wsa-macro.c:958:6: note: ret is overwritten ret = wsa_macro_set_prim_interpolator_rate(dai, (u8) rate_val, sample_rate); ^ set_mix_interpolator_rate can return -EINVAL, add a test and bail on error. Signed-off-by: Pierre-Louis Bossart Reviewed-by: Srinivas Kandagatla Link: https://lore.kernel.org/r/20210218222916.89809-11-pierre-louis.bossart@linux.intel.com Signed-off-by: Mark Brown --- sound/soc/codecs/lpass-wsa-macro.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/sound/soc/codecs/lpass-wsa-macro.c b/sound/soc/codecs/lpass-wsa-macro.c index 9ca49a165f69..e37c8148c0de 100644 --- a/sound/soc/codecs/lpass-wsa-macro.c +++ b/sound/soc/codecs/lpass-wsa-macro.c @@ -944,6 +944,8 @@ static int wsa_macro_set_interpolator_rate(struct snd_soc_dai *dai, goto prim_rate; ret = wsa_macro_set_mix_interpolator_rate(dai, (u8) rate_val, sample_rate); + if (ret < 0) + return ret; prim_rate: /* set primary path sample rate */ for (i = 0; i < ARRAY_SIZE(int_prim_sample_rate_val); i++) { From 628fc9d9a0e6e52fd3116b5591cb4e90473db9ad Mon Sep 17 00:00:00 2001 From: Rikard Falkeborn Date: Wed, 24 Feb 2021 22:19:15 +0100 Subject: [PATCH 057/587] ASoC: rt*: Constify static struct sdw_slave_ops The only usage of these is to assign their address to the ops field in the sdw_driver struct, which is a pointer to const. Make them const to allow the compiler to put them in read-only memory. Signed-off-by: Rikard Falkeborn Link: https://lore.kernel.org/r/20210224211918.39109-2-rikard.falkeborn@gmail.com Signed-off-by: Mark Brown --- sound/soc/codecs/rt1308-sdw.c | 2 +- sound/soc/codecs/rt5682-sdw.c | 2 +- sound/soc/codecs/rt700-sdw.c | 2 +- sound/soc/codecs/rt711-sdw.c | 2 +- sound/soc/codecs/rt715-sdw.c | 2 +- 5 files changed, 5 insertions(+), 5 deletions(-) diff --git a/sound/soc/codecs/rt1308-sdw.c b/sound/soc/codecs/rt1308-sdw.c index afd2c3b687cc..1c226994aebd 100644 --- a/sound/soc/codecs/rt1308-sdw.c +++ b/sound/soc/codecs/rt1308-sdw.c @@ -594,7 +594,7 @@ static int rt1308_sdw_pcm_hw_free(struct snd_pcm_substream *substream, * slave_ops: callbacks for get_clock_stop_mode, clock_stop and * port_prep are not defined for now */ -static struct sdw_slave_ops rt1308_slave_ops = { +static const struct sdw_slave_ops rt1308_slave_ops = { .read_prop = rt1308_read_prop, .interrupt_callback = rt1308_interrupt_callback, .update_status = rt1308_update_status, diff --git a/sound/soc/codecs/rt5682-sdw.c b/sound/soc/codecs/rt5682-sdw.c index b49f1e16125d..0b7ac74e671d 100644 --- a/sound/soc/codecs/rt5682-sdw.c +++ b/sound/soc/codecs/rt5682-sdw.c @@ -683,7 +683,7 @@ static int rt5682_interrupt_callback(struct sdw_slave *slave, return 0; } -static struct sdw_slave_ops rt5682_slave_ops = { +static const struct sdw_slave_ops rt5682_slave_ops = { .read_prop = rt5682_read_prop, .interrupt_callback = rt5682_interrupt_callback, .update_status = rt5682_update_status, diff --git a/sound/soc/codecs/rt700-sdw.c b/sound/soc/codecs/rt700-sdw.c index 4001612dfd73..ff9c081fd52a 100644 --- a/sound/soc/codecs/rt700-sdw.c +++ b/sound/soc/codecs/rt700-sdw.c @@ -430,7 +430,7 @@ static int rt700_interrupt_callback(struct sdw_slave *slave, * slave_ops: callbacks for get_clock_stop_mode, clock_stop and * port_prep are not defined for now */ -static struct sdw_slave_ops rt700_slave_ops = { +static const struct sdw_slave_ops rt700_slave_ops = { .read_prop = rt700_read_prop, .interrupt_callback = rt700_interrupt_callback, .update_status = rt700_update_status, diff --git a/sound/soc/codecs/rt711-sdw.c b/sound/soc/codecs/rt711-sdw.c index 2beb4286d997..8f5ebe92d407 100644 --- a/sound/soc/codecs/rt711-sdw.c +++ b/sound/soc/codecs/rt711-sdw.c @@ -431,7 +431,7 @@ static int rt711_interrupt_callback(struct sdw_slave *slave, return 0; } -static struct sdw_slave_ops rt711_slave_ops = { +static const struct sdw_slave_ops rt711_slave_ops = { .read_prop = rt711_read_prop, .interrupt_callback = rt711_interrupt_callback, .update_status = rt711_update_status, diff --git a/sound/soc/codecs/rt715-sdw.c b/sound/soc/codecs/rt715-sdw.c index 71dd3b97a459..81a1dd77b6f6 100644 --- a/sound/soc/codecs/rt715-sdw.c +++ b/sound/soc/codecs/rt715-sdw.c @@ -488,7 +488,7 @@ static int rt715_bus_config(struct sdw_slave *slave, return 0; } -static struct sdw_slave_ops rt715_slave_ops = { +static const struct sdw_slave_ops rt715_slave_ops = { .read_prop = rt715_read_prop, .update_status = rt715_update_status, .bus_config = rt715_bus_config, From f9e56a34cda2189a1d1611bdff1f6d1d0fb460e5 Mon Sep 17 00:00:00 2001 From: Rikard Falkeborn Date: Wed, 24 Feb 2021 22:19:16 +0100 Subject: [PATCH 058/587] ASoC: rt*: Constify static struct snd_soc_dai_ops The only usage of them is to assign their address to the ops field in the snd_soc_dai_driver struct, which is a pointer to const. Make them const to allow the compiler to put them in read-only memory. Signed-off-by: Rikard Falkeborn Link: https://lore.kernel.org/r/20210224211918.39109-3-rikard.falkeborn@gmail.com Signed-off-by: Mark Brown --- sound/soc/codecs/rt1015.c | 2 +- sound/soc/codecs/rt1016.c | 2 +- sound/soc/codecs/rt5682-sdw.c | 2 +- sound/soc/codecs/rt700.c | 2 +- sound/soc/codecs/rt711.c | 2 +- sound/soc/codecs/rt715.c | 2 +- 6 files changed, 6 insertions(+), 6 deletions(-) diff --git a/sound/soc/codecs/rt1015.c b/sound/soc/codecs/rt1015.c index 844e4079d176..501cc45240b4 100644 --- a/sound/soc/codecs/rt1015.c +++ b/sound/soc/codecs/rt1015.c @@ -1028,7 +1028,7 @@ static void rt1015_remove(struct snd_soc_component *component) #define RT1015_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S20_3LE | \ SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S8) -static struct snd_soc_dai_ops rt1015_aif_dai_ops = { +static const struct snd_soc_dai_ops rt1015_aif_dai_ops = { .hw_params = rt1015_hw_params, .set_fmt = rt1015_set_dai_fmt, .set_tdm_slot = rt1015_set_tdm_slot, diff --git a/sound/soc/codecs/rt1016.c b/sound/soc/codecs/rt1016.c index a23d368ab4da..483375fc16ca 100644 --- a/sound/soc/codecs/rt1016.c +++ b/sound/soc/codecs/rt1016.c @@ -534,7 +534,7 @@ static void rt1016_remove(struct snd_soc_component *component) #define RT1016_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S20_3LE | \ SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S8) -static struct snd_soc_dai_ops rt1016_aif_dai_ops = { +static const struct snd_soc_dai_ops rt1016_aif_dai_ops = { .hw_params = rt1016_hw_params, .set_fmt = rt1016_set_dai_fmt, }; diff --git a/sound/soc/codecs/rt5682-sdw.c b/sound/soc/codecs/rt5682-sdw.c index 0b7ac74e671d..5e097f776561 100644 --- a/sound/soc/codecs/rt5682-sdw.c +++ b/sound/soc/codecs/rt5682-sdw.c @@ -269,7 +269,7 @@ static int rt5682_sdw_hw_free(struct snd_pcm_substream *substream, return 0; } -static struct snd_soc_dai_ops rt5682_sdw_ops = { +static const struct snd_soc_dai_ops rt5682_sdw_ops = { .hw_params = rt5682_sdw_hw_params, .hw_free = rt5682_sdw_hw_free, .set_sdw_stream = rt5682_set_sdw_stream, diff --git a/sound/soc/codecs/rt700.c b/sound/soc/codecs/rt700.c index 66ec395dbbcd..01af9d9dd3ca 100644 --- a/sound/soc/codecs/rt700.c +++ b/sound/soc/codecs/rt700.c @@ -1002,7 +1002,7 @@ static int rt700_pcm_hw_free(struct snd_pcm_substream *substream, #define RT700_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S20_3LE | \ SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S8) -static struct snd_soc_dai_ops rt700_ops = { +static const struct snd_soc_dai_ops rt700_ops = { .hw_params = rt700_pcm_hw_params, .hw_free = rt700_pcm_hw_free, .set_sdw_stream = rt700_set_sdw_stream, diff --git a/sound/soc/codecs/rt711.c b/sound/soc/codecs/rt711.c index 85f744184a60..202bf6fbc5be 100644 --- a/sound/soc/codecs/rt711.c +++ b/sound/soc/codecs/rt711.c @@ -1048,7 +1048,7 @@ static int rt711_pcm_hw_free(struct snd_pcm_substream *substream, #define RT711_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S20_3LE | \ SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S8) -static struct snd_soc_dai_ops rt711_ops = { +static const struct snd_soc_dai_ops rt711_ops = { .hw_params = rt711_pcm_hw_params, .hw_free = rt711_pcm_hw_free, .set_sdw_stream = rt711_set_sdw_stream, diff --git a/sound/soc/codecs/rt715.c b/sound/soc/codecs/rt715.c index 9a7d393d424a..f419d001a3fb 100644 --- a/sound/soc/codecs/rt715.c +++ b/sound/soc/codecs/rt715.c @@ -683,7 +683,7 @@ static int rt715_pcm_hw_free(struct snd_pcm_substream *substream, #define RT715_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S20_3LE | \ SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S8) -static struct snd_soc_dai_ops rt715_ops = { +static const struct snd_soc_dai_ops rt715_ops = { .hw_params = rt715_pcm_hw_params, .hw_free = rt715_pcm_hw_free, .set_sdw_stream = rt715_set_sdw_stream, From 3084e5f7f75339451d8bb39dede700c37e588b8c Mon Sep 17 00:00:00 2001 From: Rikard Falkeborn Date: Wed, 24 Feb 2021 22:19:17 +0100 Subject: [PATCH 059/587] ASoC: rt*: Constify static struct acpi_device_id These are never modified, so make them const to allow the compiler to put them in read-only memory. Signed-off-by: Rikard Falkeborn Link: https://lore.kernel.org/r/20210224211918.39109-4-rikard.falkeborn@gmail.com Signed-off-by: Mark Brown --- sound/soc/codecs/rt1011.c | 2 +- sound/soc/codecs/rt1015.c | 2 +- sound/soc/codecs/rt1016.c | 2 +- sound/soc/codecs/rt1305.c | 2 +- sound/soc/codecs/rt1308.c | 2 +- 5 files changed, 5 insertions(+), 5 deletions(-) diff --git a/sound/soc/codecs/rt1011.c b/sound/soc/codecs/rt1011.c index 098ecf13814d..6877be5f36b9 100644 --- a/sound/soc/codecs/rt1011.c +++ b/sound/soc/codecs/rt1011.c @@ -2151,7 +2151,7 @@ MODULE_DEVICE_TABLE(of, rt1011_of_match); #endif #ifdef CONFIG_ACPI -static struct acpi_device_id rt1011_acpi_match[] = { +static const struct acpi_device_id rt1011_acpi_match[] = { {"10EC1011", 0,}, {}, }; diff --git a/sound/soc/codecs/rt1015.c b/sound/soc/codecs/rt1015.c index 501cc45240b4..3cd967ae999d 100644 --- a/sound/soc/codecs/rt1015.c +++ b/sound/soc/codecs/rt1015.c @@ -1121,7 +1121,7 @@ MODULE_DEVICE_TABLE(of, rt1015_of_match); #endif #ifdef CONFIG_ACPI -static struct acpi_device_id rt1015_acpi_match[] = { +static const struct acpi_device_id rt1015_acpi_match[] = { {"10EC1015", 0,}, {}, }; diff --git a/sound/soc/codecs/rt1016.c b/sound/soc/codecs/rt1016.c index 483375fc16ca..c14a809da52b 100644 --- a/sound/soc/codecs/rt1016.c +++ b/sound/soc/codecs/rt1016.c @@ -623,7 +623,7 @@ MODULE_DEVICE_TABLE(of, rt1016_of_match); #endif #ifdef CONFIG_ACPI -static struct acpi_device_id rt1016_acpi_match[] = { +static const struct acpi_device_id rt1016_acpi_match[] = { {"10EC1016", 0,}, {}, }; diff --git a/sound/soc/codecs/rt1305.c b/sound/soc/codecs/rt1305.c index 4e9dfd235e59..16aa405fb8f0 100644 --- a/sound/soc/codecs/rt1305.c +++ b/sound/soc/codecs/rt1305.c @@ -975,7 +975,7 @@ MODULE_DEVICE_TABLE(of, rt1305_of_match); #endif #ifdef CONFIG_ACPI -static struct acpi_device_id rt1305_acpi_match[] = { +static const struct acpi_device_id rt1305_acpi_match[] = { {"10EC1305", 0,}, {"10EC1306", 0,}, {}, diff --git a/sound/soc/codecs/rt1308.c b/sound/soc/codecs/rt1308.c index b75931a69a1c..76e65844543d 100644 --- a/sound/soc/codecs/rt1308.c +++ b/sound/soc/codecs/rt1308.c @@ -790,7 +790,7 @@ MODULE_DEVICE_TABLE(of, rt1308_of_match); #endif #ifdef CONFIG_ACPI -static struct acpi_device_id rt1308_acpi_match[] = { +static const struct acpi_device_id rt1308_acpi_match[] = { { "10EC1308", 0, }, { }, }; From c4fd082e466277b82fe2c0480b19f9398652302b Mon Sep 17 00:00:00 2001 From: Rikard Falkeborn Date: Wed, 24 Feb 2021 22:19:18 +0100 Subject: [PATCH 060/587] ASoc: rt5631: Constify static struct coeff_clk_div coeff_div is only read from, so make it const to show the intent. Signed-off-by: Rikard Falkeborn Link: https://lore.kernel.org/r/20210224211918.39109-5-rikard.falkeborn@gmail.com Signed-off-by: Mark Brown --- sound/soc/codecs/rt5631.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sound/soc/codecs/rt5631.c b/sound/soc/codecs/rt5631.c index 653da3eaf355..afc1305a7fa5 100644 --- a/sound/soc/codecs/rt5631.c +++ b/sound/soc/codecs/rt5631.c @@ -1283,7 +1283,7 @@ static const struct pll_div codec_slave_pll_div[] = { {3072000, 12288000, 0x0a90}, }; -static struct coeff_clk_div coeff_div[] = { +static const struct coeff_clk_div coeff_div[] = { /* sysclk is 256fs */ {2048000, 8000 * 32, 8000, 0x1000}, {2048000, 8000 * 64, 8000, 0x0000}, From b296743576220b745938fde62e4f8ad25a195985 Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Fri, 19 Feb 2021 17:29:29 -0600 Subject: [PATCH 061/587] ASoC: fsl: fsl_asrc: remove useless assignment cppcheck warning: sound/soc/fsl/fsl_asrc.c:613:8: style: Variable 'i' is assigned a value that is never used. [unreadVariable] int i = 0, j = 0; ^ The same issue occurs for the 'j' variable. Signed-off-by: Pierre-Louis Bossart Link: https://lore.kernel.org/r/20210219232937.6440-2-pierre-louis.bossart@linux.intel.com Signed-off-by: Mark Brown --- sound/soc/fsl/fsl_asrc.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sound/soc/fsl/fsl_asrc.c b/sound/soc/fsl/fsl_asrc.c index c325c984d165..63d236ef5c4d 100644 --- a/sound/soc/fsl/fsl_asrc.c +++ b/sound/soc/fsl/fsl_asrc.c @@ -610,7 +610,7 @@ static void fsl_asrc_select_clk(struct fsl_asrc_priv *asrc_priv, struct asrc_config *config = pair_priv->config; int rate[2], select_clk[2]; /* Array size 2 means IN and OUT */ int clk_rate, clk_index; - int i = 0, j = 0; + int i, j; rate[IN] = in_rate; rate[OUT] = out_rate; From b035a9efda2889c4d6064b67100bba6eff17af32 Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Fri, 19 Feb 2021 17:29:30 -0600 Subject: [PATCH 062/587] ASoC: fsl: fsl_dma: remove unused variable cppcheck warning: sound/soc/fsl/fsl_dma.c:411:10: style: Variable 'channel' is assigned a value that is never used. [unreadVariable] channel = substream->stream == SNDRV_PCM_STREAM_PLAYBACK ? 0 : 1; ^ Removing this line shows the variable isn't needed any longer so remove declaration as well. Signed-off-by: Pierre-Louis Bossart Link: https://lore.kernel.org/r/20210219232937.6440-3-pierre-louis.bossart@linux.intel.com Signed-off-by: Mark Brown --- sound/soc/fsl/fsl_dma.c | 3 --- 1 file changed, 3 deletions(-) diff --git a/sound/soc/fsl/fsl_dma.c b/sound/soc/fsl/fsl_dma.c index e0c39c5f4854..84bd8a5356eb 100644 --- a/sound/soc/fsl/fsl_dma.c +++ b/sound/soc/fsl/fsl_dma.c @@ -392,7 +392,6 @@ static int fsl_dma_open(struct snd_soc_component *component, dma_addr_t ld_buf_phys; u64 temp_link; /* Pointer to next link descriptor */ u32 mr; - unsigned int channel; int ret = 0; unsigned int i; @@ -408,8 +407,6 @@ static int fsl_dma_open(struct snd_soc_component *component, return ret; } - channel = substream->stream == SNDRV_PCM_STREAM_PLAYBACK ? 0 : 1; - if (dma->assigned) { dev_err(dev, "dma channel already assigned\n"); return -EBUSY; From 062b85216886bbb5e318705c479838563bfdd9d2 Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Fri, 19 Feb 2021 17:29:31 -0600 Subject: [PATCH 063/587] ASoC: fsl: fsl_easrc: remove useless assignments cppcheck warnings: sound/soc/fsl/fsl_easrc.c:751:53: style: Variable 'st2_mem_alloc' is assigned a value that is never used. [unreadVariable] int st1_chanxexp, st1_mem_alloc = 0, st2_mem_alloc = 0; ^ sound/soc/fsl/fsl_easrc.c:1331:11: style: Variable 'size' is assigned a value that is never used. [unreadVariable] int size = 0; ^ Signed-off-by: Pierre-Louis Bossart Link: https://lore.kernel.org/r/20210219232937.6440-4-pierre-louis.bossart@linux.intel.com Signed-off-by: Mark Brown --- sound/soc/fsl/fsl_easrc.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/sound/soc/fsl/fsl_easrc.c b/sound/soc/fsl/fsl_easrc.c index 636a702f37a6..725a5d3aaa02 100644 --- a/sound/soc/fsl/fsl_easrc.c +++ b/sound/soc/fsl/fsl_easrc.c @@ -710,7 +710,7 @@ static int fsl_easrc_max_ch_for_slot(struct fsl_asrc_pair *ctx, struct fsl_easrc_slot *slot) { struct fsl_easrc_ctx_priv *ctx_priv = ctx->private; - int st1_mem_alloc = 0, st2_mem_alloc = 0; + int st1_mem_alloc = 0, st2_mem_alloc; int pf_mem_alloc = 0; int max_channels = 8 - slot->num_channel; int channels = 0; @@ -748,7 +748,7 @@ static int fsl_easrc_config_one_slot(struct fsl_asrc_pair *ctx, { struct fsl_asrc *easrc = ctx->asrc; struct fsl_easrc_ctx_priv *ctx_priv = ctx->private; - int st1_chanxexp, st1_mem_alloc = 0, st2_mem_alloc = 0; + int st1_chanxexp, st1_mem_alloc = 0, st2_mem_alloc; unsigned int reg0, reg1, reg2, reg3; unsigned int addr; @@ -1328,7 +1328,7 @@ static int fsl_easrc_stop_context(struct fsl_asrc_pair *ctx) { struct fsl_asrc *easrc = ctx->asrc; int val, i; - int size = 0; + int size; int retry = 200; regmap_read(easrc->regmap, REG_EASRC_CC(ctx->index), &val); From 8f6fef01a5ba48b416d1dc7e910268e03d270a10 Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Fri, 19 Feb 2021 17:29:32 -0600 Subject: [PATCH 064/587] ASoC: fsl: fsl_esai: clarify expression cppcheck warning: sound/soc/fsl/fsl_esai.c:307:16: style: Clarify calculation precedence for '%' and '?'. [clarifyCalculation] clk_id % 2 ? "extal" : "fsys"); ^ Signed-off-by: Pierre-Louis Bossart Link: https://lore.kernel.org/r/20210219232937.6440-5-pierre-louis.bossart@linux.intel.com Signed-off-by: Mark Brown --- sound/soc/fsl/fsl_esai.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sound/soc/fsl/fsl_esai.c b/sound/soc/fsl/fsl_esai.c index 08056fa0a0fa..41b154417b92 100644 --- a/sound/soc/fsl/fsl_esai.c +++ b/sound/soc/fsl/fsl_esai.c @@ -304,7 +304,7 @@ static int fsl_esai_set_dai_sysclk(struct snd_soc_dai *dai, int clk_id, if (IS_ERR(clksrc)) { dev_err(dai->dev, "no assigned %s clock\n", - clk_id % 2 ? "extal" : "fsys"); + (clk_id % 2) ? "extal" : "fsys"); return PTR_ERR(clksrc); } clk_rate = clk_get_rate(clksrc); From 2fb563567bc425b9a7371f1432c62e25627e1754 Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Fri, 19 Feb 2021 17:29:33 -0600 Subject: [PATCH 065/587] ASoC: fsl: fsl_ssi: remove unnecessary tests cppcheck warnings: sound/soc/fsl/fsl_ssi.c:767:34: style: Condition 'div2' is always false [knownConditionTrueFalse] stccr = SSI_SxCCR_PM(pm + 1) | (div2 ? SSI_SxCCR_DIV2 : 0) | ^ sound/soc/fsl/fsl_ssi.c:722:9: note: Assignment 'div2=0', assigned value is 0 div2 = 0; ^ sound/soc/fsl/fsl_ssi.c:767:34: note: Condition 'div2' is always false stccr = SSI_SxCCR_PM(pm + 1) | (div2 ? SSI_SxCCR_DIV2 : 0) | ^ sound/soc/fsl/fsl_ssi.c:768:4: style: Condition 'psr' is always false [knownConditionTrueFalse] (psr ? SSI_SxCCR_PSR : 0); ^ sound/soc/fsl/fsl_ssi.c:721:8: note: Assignment 'psr=0', assigned value is 0 psr = 0; ^ sound/soc/fsl/fsl_ssi.c:768:4: note: Condition 'psr' is always false (psr ? SSI_SxCCR_PSR : 0); ^ Upon further analysis, the variables 'div2' and 'psr' are set to zero and never modified. All the tests can be removed. Signed-off-by: Pierre-Louis Bossart Link: https://lore.kernel.org/r/20210219232937.6440-6-pierre-louis.bossart@linux.intel.com Signed-off-by: Mark Brown --- sound/soc/fsl/fsl_ssi.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/sound/soc/fsl/fsl_ssi.c b/sound/soc/fsl/fsl_ssi.c index ad8af3f450e2..4e2ce47a7c6e 100644 --- a/sound/soc/fsl/fsl_ssi.c +++ b/sound/soc/fsl/fsl_ssi.c @@ -747,7 +747,7 @@ static int fsl_ssi_set_bclk(struct snd_pcm_substream *substream, sub *= 100000; do_div(sub, freq); - if (sub < savesub && !(i == 0 && psr == 0 && div2 == 0)) { + if (sub < savesub && !(i == 0)) { baudrate = tmprate; savesub = sub; pm = i; @@ -764,8 +764,7 @@ static int fsl_ssi_set_bclk(struct snd_pcm_substream *substream, return -EINVAL; } - stccr = SSI_SxCCR_PM(pm + 1) | (div2 ? SSI_SxCCR_DIV2 : 0) | - (psr ? SSI_SxCCR_PSR : 0); + stccr = SSI_SxCCR_PM(pm + 1); mask = SSI_SxCCR_PM_MASK | SSI_SxCCR_DIV2 | SSI_SxCCR_PSR; /* STCCR is used for RX in synchronous mode */ From 4a6202f0cef51714bcc46728cdf8153da49d2785 Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Fri, 19 Feb 2021 17:29:34 -0600 Subject: [PATCH 066/587] ASoC: fsl: imx-hdmi: remove unused structure members cppcheck warning: sound/soc/fsl/imx-hdmi.c:21:16: style: struct member 'cpu_priv::sysclk_freq' is never used. [unusedStructMember] unsigned long sysclk_freq[2]; ^ Additional checks show the sysclk_dir member is also not used. Signed-off-by: Pierre-Louis Bossart Link: https://lore.kernel.org/r/20210219232937.6440-7-pierre-louis.bossart@linux.intel.com Signed-off-by: Mark Brown --- sound/soc/fsl/imx-hdmi.c | 4 ---- 1 file changed, 4 deletions(-) diff --git a/sound/soc/fsl/imx-hdmi.c b/sound/soc/fsl/imx-hdmi.c index dbbb7618351c..1ebcb9a2336b 100644 --- a/sound/soc/fsl/imx-hdmi.c +++ b/sound/soc/fsl/imx-hdmi.c @@ -10,16 +10,12 @@ /** * struct cpu_priv - CPU private data - * @sysclk_freq: SYSCLK rates for set_sysclk() - * @sysclk_dir: SYSCLK directions for set_sysclk() * @sysclk_id: SYSCLK ids for set_sysclk() * @slot_width: Slot width of each frame * * Note: [1] for tx and [0] for rx */ struct cpu_priv { - unsigned long sysclk_freq[2]; - u32 sysclk_dir[2]; u32 sysclk_id[2]; u32 slot_width; }; From 91ab7743112bf2414cd6264dbadb94deef51855a Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Fri, 19 Feb 2021 17:29:35 -0600 Subject: [PATCH 067/587] ASoC: fsl: mpc5200: signed parameter in snprintf format cppcheck warning: sound/soc/fsl/mpc5200_dma.c:414:2: warning: %u in format string (no. 1) requires 'unsigned int' but the argument type is 'signed int'. [invalidPrintfArgType_uint] snprintf(psc_dma->name, sizeof psc_dma->name, "PSC%u", psc_dma->id); ^ Also fix sizeof use, missing parentheses reported by checkpatch.pl Signed-off-by: Pierre-Louis Bossart Link: https://lore.kernel.org/r/20210219232937.6440-8-pierre-louis.bossart@linux.intel.com Signed-off-by: Mark Brown --- sound/soc/fsl/mpc5200_dma.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sound/soc/fsl/mpc5200_dma.c b/sound/soc/fsl/mpc5200_dma.c index 231984882176..6c65cd858b0b 100644 --- a/sound/soc/fsl/mpc5200_dma.c +++ b/sound/soc/fsl/mpc5200_dma.c @@ -411,7 +411,7 @@ int mpc5200_audio_dma_create(struct platform_device *op) psc_dma->dev = &op->dev; psc_dma->playback.psc_dma = psc_dma; psc_dma->capture.psc_dma = psc_dma; - snprintf(psc_dma->name, sizeof psc_dma->name, "PSC%u", psc_dma->id); + snprintf(psc_dma->name, sizeof(psc_dma->name), "PSC%d", psc_dma->id); /* Find the address of the fifo data registers and setup the * DMA tasks */ From f5036db354d9cc0d2261758e3dada3894d378dbb Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Fri, 19 Feb 2021 17:29:36 -0600 Subject: [PATCH 068/587] ASoC: fsl: mpc8610: remove useless assignment cppcheck warning: sound/soc/fsl/mpc8610_hpcd.c:333:6: style: Redundant initialization for 'ret'. The initialized value is overwritten before it is read. [redundantInitialization] ret = fsl_asoc_get_dma_channel(np, "fsl,playback-dma", ^ sound/soc/fsl/mpc8610_hpcd.c:193:10: note: ret is initialized int ret = -ENODEV; ^ sound/soc/fsl/mpc8610_hpcd.c:333:6: note: ret is overwritten ret = fsl_asoc_get_dma_channel(np, "fsl,playback-dma", ^ Signed-off-by: Pierre-Louis Bossart Link: https://lore.kernel.org/r/20210219232937.6440-9-pierre-louis.bossart@linux.intel.com Signed-off-by: Mark Brown --- sound/soc/fsl/mpc8610_hpcd.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sound/soc/fsl/mpc8610_hpcd.c b/sound/soc/fsl/mpc8610_hpcd.c index eccc833390d4..58b9ca3c4da0 100644 --- a/sound/soc/fsl/mpc8610_hpcd.c +++ b/sound/soc/fsl/mpc8610_hpcd.c @@ -190,7 +190,7 @@ static int mpc8610_hpcd_probe(struct platform_device *pdev) struct device_node *codec_np = NULL; struct mpc8610_hpcd_data *machine_data; struct snd_soc_dai_link_component *comp; - int ret = -ENODEV; + int ret; const char *sprop; const u32 *iprop; From b86fe83448b45254cf39bc4f7db739b29488d72a Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Fri, 19 Feb 2021 17:29:37 -0600 Subject: [PATCH 069/587] ASoC: fsl: p1022_ds: remove useless assignment cppcheck warning: sound/soc/fsl/p1022_ds.c:344:6: style: Redundant initialization for 'ret'. The initialized value is overwritten before it is read. [redundantInitialization] ret = fsl_asoc_get_dma_channel(np, "fsl,playback-dma", &mdata->dai[0], ^ sound/soc/fsl/p1022_ds.c:203:10: note: ret is initialized int ret = -ENODEV; ^ sound/soc/fsl/p1022_ds.c:344:6: note: ret is overwritten ret = fsl_asoc_get_dma_channel(np, "fsl,playback-dma", &mdata->dai[0], ^ Signed-off-by: Pierre-Louis Bossart Link: https://lore.kernel.org/r/20210219232937.6440-10-pierre-louis.bossart@linux.intel.com Signed-off-by: Mark Brown --- sound/soc/fsl/p1022_ds.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sound/soc/fsl/p1022_ds.c b/sound/soc/fsl/p1022_ds.c index ac68d2238045..317c767b0099 100644 --- a/sound/soc/fsl/p1022_ds.c +++ b/sound/soc/fsl/p1022_ds.c @@ -200,7 +200,7 @@ static int p1022_ds_probe(struct platform_device *pdev) struct device_node *codec_np = NULL; struct machine_data *mdata; struct snd_soc_dai_link_component *comp; - int ret = -ENODEV; + int ret; const char *sprop; const u32 *iprop; From 6053a840f711fbb4e36fad06880be11db37d3cdc Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Mon, 22 Feb 2021 09:46:57 +0900 Subject: [PATCH 070/587] ASoC: soc-pcm: remove strange format storing dpcm_init_runtime_hw() (= A) is used from dpcm_set_fe_runtime() (= B) with for_each_rtd_cpu_dais() loop (= C), and it checks formats (= D). (A) static void dpcm_init_runtime_hw(...) { ... ^ if (runtime->hw.formats) | (D1) runtime->hw.formats &= stream->formats; (D) else | (D2) runtime->hw.formats = stream->formats; v } (B) static void dpcm_set_fe_runtime(...) { ... (C) for_each_rtd_cpu_dais(rtd, i, cpu_dai) { ... (A) dpcm_init_runtime_hw(...); } } If this for_each_rtd_cpu_dais() loop (= C) calls dpcm_init_runtime_hw() (= A) multiple times, this means it is Multi-CPU. If we focus to format operation at (D), using mask (= D1) is understandable because it restricts unsupported format. But, enabling format when zero format case (= D2) is very strange, because it might enables unsupported format. This runtime->hw.formats is initialized by ULLONG_MAX at soc_pcm_hw_init(), thus becoming zero format means it can't use such format. And doing this strange format operation is only here. This patch removes strange format operation (= D2), and use standard soc_pcm_hw_update_format() for it. Signed-off-by: Kuninori Morimoto Link: https://lore.kernel.org/r/87sg5pvshq.wl-kuninori.morimoto.gx@renesas.com Signed-off-by: Mark Brown --- sound/soc/soc-pcm.c | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/sound/soc/soc-pcm.c b/sound/soc/soc-pcm.c index 14d85ca1e435..bb912a94e895 100644 --- a/sound/soc/soc-pcm.c +++ b/sound/soc/soc-pcm.c @@ -1533,10 +1533,7 @@ static void dpcm_init_runtime_hw(struct snd_pcm_runtime *runtime, soc_pcm_hw_update_rate(hw, stream); soc_pcm_hw_update_chan(hw, stream); - if (runtime->hw.formats) - runtime->hw.formats &= stream->formats; - else - runtime->hw.formats = stream->formats; + soc_pcm_hw_update_format(hw, stream); } static void dpcm_runtime_merge_format(struct snd_pcm_substream *substream, From 7f4a763642cc8d5f49e64a3611de8f62102c9d31 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Mon, 22 Feb 2021 09:47:19 +0900 Subject: [PATCH 071/587] ASoC: soc-pcm: unpack dpcm_init_runtime_hw() dpcm_init_runtime_hw() is now just verbose function. This patch unpacks it. Signed-off-by: Kuninori Morimoto Link: https://lore.kernel.org/r/87r1l9vsh4.wl-kuninori.morimoto.gx@renesas.com Signed-off-by: Mark Brown --- sound/soc/soc-pcm.c | 20 +++++++------------- 1 file changed, 7 insertions(+), 13 deletions(-) diff --git a/sound/soc/soc-pcm.c b/sound/soc/soc-pcm.c index bb912a94e895..fd279fb28533 100644 --- a/sound/soc/soc-pcm.c +++ b/sound/soc/soc-pcm.c @@ -1526,16 +1526,6 @@ unwind: return err; } -static void dpcm_init_runtime_hw(struct snd_pcm_runtime *runtime, - struct snd_soc_pcm_stream *stream) -{ - struct snd_pcm_hardware *hw = &runtime->hw; - - soc_pcm_hw_update_rate(hw, stream); - soc_pcm_hw_update_chan(hw, stream); - soc_pcm_hw_update_format(hw, stream); -} - static void dpcm_runtime_merge_format(struct snd_pcm_substream *substream, struct snd_pcm_runtime *runtime) { @@ -1669,6 +1659,8 @@ static void dpcm_set_fe_runtime(struct snd_pcm_substream *substream) soc_pcm_hw_init(hw); for_each_rtd_cpu_dais(rtd, i, cpu_dai) { + struct snd_soc_pcm_stream *stream; + /* * Skip CPUs which don't support the current stream * type. See soc_pcm_init_runtime_hw() for more details @@ -1676,9 +1668,11 @@ static void dpcm_set_fe_runtime(struct snd_pcm_substream *substream) if (!snd_soc_dai_stream_valid(cpu_dai, substream->stream)) continue; - dpcm_init_runtime_hw(runtime, - snd_soc_dai_get_pcm_stream(cpu_dai, - substream->stream)); + stream = snd_soc_dai_get_pcm_stream(cpu_dai, substream->stream); + + soc_pcm_hw_update_rate(hw, stream); + soc_pcm_hw_update_chan(hw, stream); + soc_pcm_hw_update_format(hw, stream); } dpcm_runtime_merge_format(substream, runtime); From 5f53898af1a2bf753f111ec1c7ed668fe6557b76 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Mon, 22 Feb 2021 09:47:26 +0900 Subject: [PATCH 072/587] ASoC: soc-pcm: add dpcm_runtime_setup_fe() dpcm_fe_dai_startup() (= A) calls dpcm_set_fe_runtime() (= B) to setup DPCM runtime. From *naming point of view*, it sounds like setup function for FE. (A) static int dpcm_fe_dai_startup(...) { ... (B) dpcm_set_fe_runtime(...); ... } But in dpcm_set_fe_runtime() (= B), It setups FE by for_each loop (= X), and setups BE by dpcm_runtime_merge_xxx() (= Y). (B) static void dpcm_set_fe_runtime(...) { ... ^ for_each_rtd_cpu_dais(...) { | ... (X) soc_pcm_hw_update_rate(...); | soc_pcm_hw_update_chan(...); | soc_pcm_hw_update_format(...); v } ^ dpcm_runtime_merge_format(...); (Y) dpcm_runtime_merge_chan(...); v dpcm_runtime_merge_rate(...); } These means that the function which is called as xxx_fe_xxx() is setups both FE and BE. This is confusable and can be hot bed for bug. To tidyup it, as 1st step, this patch adds new dpcm_runtime_setup_fe() for (X). Signed-off-by: Kuninori Morimoto Link: https://lore.kernel.org/r/87pn0tvsgx.wl-kuninori.morimoto.gx@renesas.com Signed-off-by: Mark Brown --- sound/soc/soc-pcm.c | 53 ++++++++++++++++++++++++++------------------- 1 file changed, 31 insertions(+), 22 deletions(-) diff --git a/sound/soc/soc-pcm.c b/sound/soc/soc-pcm.c index fd279fb28533..066218f1f075 100644 --- a/sound/soc/soc-pcm.c +++ b/sound/soc/soc-pcm.c @@ -1526,6 +1526,36 @@ unwind: return err; } +static void dpcm_runtime_setup_fe(struct snd_pcm_substream *substream) +{ + struct snd_soc_pcm_runtime *fe = asoc_substream_to_rtd(substream); + struct snd_pcm_runtime *runtime = substream->runtime; + struct snd_pcm_hardware *hw = &runtime->hw; + struct snd_soc_dai *dai; + int stream = substream->stream; + int i; + + soc_pcm_hw_init(hw); + + for_each_rtd_cpu_dais(fe, i, dai) { + struct snd_soc_pcm_stream *cpu_stream; + + /* + * Skip CPUs which don't support the current stream + * type. See soc_pcm_init_runtime_hw() for more details + */ + if (!snd_soc_dai_stream_valid(dai, stream)) + continue; + + cpu_stream = snd_soc_dai_get_pcm_stream(dai, stream); + + soc_pcm_hw_update_rate(hw, cpu_stream); + soc_pcm_hw_update_chan(hw, cpu_stream); + soc_pcm_hw_update_format(hw, cpu_stream); + } + +} + static void dpcm_runtime_merge_format(struct snd_pcm_substream *substream, struct snd_pcm_runtime *runtime) { @@ -1651,29 +1681,8 @@ static void dpcm_runtime_merge_rate(struct snd_pcm_substream *substream, static void dpcm_set_fe_runtime(struct snd_pcm_substream *substream) { struct snd_pcm_runtime *runtime = substream->runtime; - struct snd_pcm_hardware *hw = &runtime->hw; - struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream); - struct snd_soc_dai *cpu_dai; - int i; - soc_pcm_hw_init(hw); - - for_each_rtd_cpu_dais(rtd, i, cpu_dai) { - struct snd_soc_pcm_stream *stream; - - /* - * Skip CPUs which don't support the current stream - * type. See soc_pcm_init_runtime_hw() for more details - */ - if (!snd_soc_dai_stream_valid(cpu_dai, substream->stream)) - continue; - - stream = snd_soc_dai_get_pcm_stream(cpu_dai, substream->stream); - - soc_pcm_hw_update_rate(hw, stream); - soc_pcm_hw_update_chan(hw, stream); - soc_pcm_hw_update_format(hw, stream); - } + dpcm_runtime_setup_fe(substream); dpcm_runtime_merge_format(substream, runtime); dpcm_runtime_merge_chan(substream, runtime); From 1b8cb123f3dd6f205541299e2a573237452a6ffe Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Mon, 22 Feb 2021 09:47:34 +0900 Subject: [PATCH 073/587] ASoC: soc-pcm: add dpcm_runtime_setup() dpcm_fe_dai_startup() (= A) calls dpcm_set_fe_runtime() (= B) to setup DPCM runtime. From *naming point of view*, it sounds like setup function for FE. (A) static int dpcm_fe_dai_startup(...) { ... (B) dpcm_set_fe_runtime(...); ... } But in dpcm_set_fe_runtime() (= B), It setups FE by dpcm_runtime_setup_fe() (= X), and setups BE by dpcm_runtime_merge_xxx() (= Y). (B) static void dpcm_set_fe_runtime(...) { ... (X) dpcm_runtime_setup_fe(...); ^ dpcm_runtime_merge_format(...); (Y) dpcm_runtime_merge_chan(...); v dpcm_runtime_merge_rate(...); } These means that the function which is called as xxx_fe_xxx() is setups both FE and BE. This is confusable and can be hot bed for bug. This patch renames unclear dpcm_runtime_merge_xxx() (= Y) to more clear dpcm_runtime_setup_be_xxx(). Signed-off-by: Kuninori Morimoto Link: https://lore.kernel.org/r/87o8gdvsgr.wl-kuninori.morimoto.gx@renesas.com Signed-off-by: Mark Brown --- sound/soc/soc-pcm.c | 20 +++++++++----------- 1 file changed, 9 insertions(+), 11 deletions(-) diff --git a/sound/soc/soc-pcm.c b/sound/soc/soc-pcm.c index 066218f1f075..7fc7e3e24444 100644 --- a/sound/soc/soc-pcm.c +++ b/sound/soc/soc-pcm.c @@ -1556,10 +1556,10 @@ static void dpcm_runtime_setup_fe(struct snd_pcm_substream *substream) } -static void dpcm_runtime_merge_format(struct snd_pcm_substream *substream, - struct snd_pcm_runtime *runtime) +static void dpcm_runtime_setup_be_format(struct snd_pcm_substream *substream) { struct snd_soc_pcm_runtime *fe = asoc_substream_to_rtd(substream); + struct snd_pcm_runtime *runtime = substream->runtime; struct snd_pcm_hardware *hw = &runtime->hw; struct snd_soc_dpcm *dpcm; struct snd_soc_dai *dai; @@ -1593,10 +1593,10 @@ static void dpcm_runtime_merge_format(struct snd_pcm_substream *substream, } } -static void dpcm_runtime_merge_chan(struct snd_pcm_substream *substream, - struct snd_pcm_runtime *runtime) +static void dpcm_runtime_setup_be_chan(struct snd_pcm_substream *substream) { struct snd_soc_pcm_runtime *fe = asoc_substream_to_rtd(substream); + struct snd_pcm_runtime *runtime = substream->runtime; struct snd_pcm_hardware *hw = &runtime->hw; struct snd_soc_dpcm *dpcm; int stream = substream->stream; @@ -1641,10 +1641,10 @@ static void dpcm_runtime_merge_chan(struct snd_pcm_substream *substream, } } -static void dpcm_runtime_merge_rate(struct snd_pcm_substream *substream, - struct snd_pcm_runtime *runtime) +static void dpcm_runtime_setup_be_rate(struct snd_pcm_substream *substream) { struct snd_soc_pcm_runtime *fe = asoc_substream_to_rtd(substream); + struct snd_pcm_runtime *runtime = substream->runtime; struct snd_pcm_hardware *hw = &runtime->hw; struct snd_soc_dpcm *dpcm; int stream = substream->stream; @@ -1680,13 +1680,11 @@ static void dpcm_runtime_merge_rate(struct snd_pcm_substream *substream, static void dpcm_set_fe_runtime(struct snd_pcm_substream *substream) { - struct snd_pcm_runtime *runtime = substream->runtime; - dpcm_runtime_setup_fe(substream); - dpcm_runtime_merge_format(substream, runtime); - dpcm_runtime_merge_chan(substream, runtime); - dpcm_runtime_merge_rate(substream, runtime); + dpcm_runtime_setup_be_format(substream); + dpcm_runtime_setup_be_chan(substream); + dpcm_runtime_setup_be_rate(substream); } static int dpcm_apply_symmetry(struct snd_pcm_substream *fe_substream, From 4fe28461e289e7209dc969d5878997069f5be157 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Mon, 22 Feb 2021 09:47:36 +0900 Subject: [PATCH 074/587] ASoC: soc-pcm: unpack dpcm_set_fe_runtime() dpcm_fe_dai_startup() (= A) calls dpcm_set_fe_runtime() (= B) to setup DPCM runtime. From *naming point of view*, it sounds like setup function for FE. (A) static int dpcm_fe_dai_startup(...) { ... (B) dpcm_set_fe_runtime(...); ... } But in dpcm_set_fe_runtime() (= B), It setups FE by dpcm_runtime_setup_fe() (= X), and setups BE by dpcm_runtime_merge_xxx() (= Y). (B) static void dpcm_set_fe_runtime(...) { ... (X) dpcm_runtime_setup_fe(...); ^ dpcm_runtime_setup_be_format(...); (Y) dpcm_runtime_setup_be_chan(...); v dpcm_runtime_setup_be_rate(...); } These means that the function which is called as xxx_fe_xxx() is setups both FE and BE. This is confusable and can be hot bed for bug. Now dpcm_set_fe_runtime() (= B) is simple enough and confusable naming, let's unpack it at dpcm_fe_dai_startup(). Signed-off-by: Kuninori Morimoto Link: https://lore.kernel.org/r/87mtvxvsgn.wl-kuninori.morimoto.gx@renesas.com Signed-off-by: Mark Brown --- sound/soc/soc-pcm.c | 15 +++++---------- 1 file changed, 5 insertions(+), 10 deletions(-) diff --git a/sound/soc/soc-pcm.c b/sound/soc/soc-pcm.c index 7fc7e3e24444..511c9218308a 100644 --- a/sound/soc/soc-pcm.c +++ b/sound/soc/soc-pcm.c @@ -1678,15 +1678,6 @@ static void dpcm_runtime_setup_be_rate(struct snd_pcm_substream *substream) } } -static void dpcm_set_fe_runtime(struct snd_pcm_substream *substream) -{ - dpcm_runtime_setup_fe(substream); - - dpcm_runtime_setup_be_format(substream); - dpcm_runtime_setup_be_chan(substream); - dpcm_runtime_setup_be_rate(substream); -} - static int dpcm_apply_symmetry(struct snd_pcm_substream *fe_substream, int stream) { @@ -1766,7 +1757,11 @@ static int dpcm_fe_dai_startup(struct snd_pcm_substream *fe_substream) fe->dpcm[stream].state = SND_SOC_DPCM_STATE_OPEN; - dpcm_set_fe_runtime(fe_substream); + dpcm_runtime_setup_fe(fe_substream); + + dpcm_runtime_setup_be_format(fe_substream); + dpcm_runtime_setup_be_chan(fe_substream); + dpcm_runtime_setup_be_rate(fe_substream); ret = dpcm_apply_symmetry(fe_substream, stream); if (ret < 0) From 5a81abc2ea3d7cc094b3bef16b0fb0157b8ced0f Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Fri, 19 Feb 2021 17:09:13 -0600 Subject: [PATCH 075/587] ASoC: samsung: i2s: remove unassigned variable cppcheck warning: sound/soc/samsung/i2s.c:1159:18: style: Variable 'dai' is not assigned a value. [unassignedVariable] struct i2s_dai *dai; ^ This variable is only used for a sizeof(*dai). Signed-off-by: Pierre-Louis Bossart Reviewed-by: Krzysztof Kozlowski Link: https://lore.kernel.org/r/20210219230918.5058-2-pierre-louis.bossart@linux.intel.com Signed-off-by: Mark Brown --- sound/soc/samsung/i2s.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/sound/soc/samsung/i2s.c b/sound/soc/samsung/i2s.c index b043183174b2..c632842d42eb 100644 --- a/sound/soc/samsung/i2s.c +++ b/sound/soc/samsung/i2s.c @@ -1156,11 +1156,10 @@ static int i2s_alloc_dais(struct samsung_i2s_priv *priv, static const char *stream_names[] = { "Primary Playback", "Secondary Playback" }; struct snd_soc_dai_driver *dai_drv; - struct i2s_dai *dai; int i; priv->dai = devm_kcalloc(&priv->pdev->dev, num_dais, - sizeof(*dai), GFP_KERNEL); + sizeof(struct i2s_dai), GFP_KERNEL); if (!priv->dai) return -ENOMEM; From 0587e83c5d8bc09af005bd736234b480a8fd66f2 Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Fri, 19 Feb 2021 17:09:14 -0600 Subject: [PATCH 076/587] ASoC: samsung: s3c24xx_simtec: add missing error check cppcheck warning: sound/soc/samsung/s3c24xx_simtec.c:191:7: style: Variable 'ret' is assigned a value that is never used. [unreadVariable] ret = snd_soc_dai_set_clkdiv(cpu_dai, S3C24XX_DIV_PRESCALER, ^ Looking at the code, it's not clear why the return value is checked in the two other cases but not here, so mirror the behavior and add a check. Signed-off-by: Pierre-Louis Bossart Reviewed-by: Krzysztof Kozlowski Link: https://lore.kernel.org/r/20210219230918.5058-3-pierre-louis.bossart@linux.intel.com Signed-off-by: Mark Brown --- sound/soc/samsung/s3c24xx_simtec.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/sound/soc/samsung/s3c24xx_simtec.c b/sound/soc/samsung/s3c24xx_simtec.c index 3cddd11344ac..81a29d12c57d 100644 --- a/sound/soc/samsung/s3c24xx_simtec.c +++ b/sound/soc/samsung/s3c24xx_simtec.c @@ -190,6 +190,11 @@ static int simtec_hw_params(struct snd_pcm_substream *substream, ret = snd_soc_dai_set_clkdiv(cpu_dai, S3C24XX_DIV_PRESCALER, cdclk_scale); + if (ret) { + pr_err("%s: failed to set clock div\n", + __func__); + return ret; + } } return 0; From fbb123e248c127f9bccdd6181487bcad1275c137 Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Fri, 19 Feb 2021 17:09:15 -0600 Subject: [PATCH 077/587] ASoC: samsung: smdk_wm8994: add missing return cppcheck warning: sound/soc/samsung/smdk_wm8994.c:179:6: style: Variable 'ret' is reassigned a value before the old one has been used. [redundantAssignment] ret = devm_snd_soc_register_card(&pdev->dev, card); ^ sound/soc/samsung/smdk_wm8994.c:166:8: note: ret is assigned ret = -EINVAL; ^ sound/soc/samsung/smdk_wm8994.c:179:6: note: ret is overwritten ret = devm_snd_soc_register_card(&pdev->dev, card); ^ The initial authors bothered to set ret to -EINVAL and throw a dev_err() message, so it looks like there is a missing return to avoid continuing if the property is missing. Signed-off-by: Pierre-Louis Bossart Reviewed-by: Krzysztof Kozlowski Link: https://lore.kernel.org/r/20210219230918.5058-4-pierre-louis.bossart@linux.intel.com Signed-off-by: Mark Brown --- sound/soc/samsung/smdk_wm8994.c | 1 + 1 file changed, 1 insertion(+) diff --git a/sound/soc/samsung/smdk_wm8994.c b/sound/soc/samsung/smdk_wm8994.c index 681b244d5312..39a7a449f554 100644 --- a/sound/soc/samsung/smdk_wm8994.c +++ b/sound/soc/samsung/smdk_wm8994.c @@ -164,6 +164,7 @@ static int smdk_audio_probe(struct platform_device *pdev) dev_err(&pdev->dev, "Property 'samsung,i2s-controller' missing or invalid\n"); ret = -EINVAL; + return ret; } smdk_dai[0].platforms->name = NULL; From c856cef731ddfde68ec21a827919aef68e37fb27 Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Fri, 19 Feb 2021 17:09:16 -0600 Subject: [PATCH 078/587] ASoC: samsung: snow: remove useless test cppcheck warning: sound/soc/samsung/snow.c:112:2: style:inconclusive: Found duplicate branches for 'if' and 'else'. [duplicateBranch] if (rtd->num_codecs > 1) ^ sound/soc/samsung/snow.c:114:2: note: Found duplicate branches for 'if' and 'else'. else ^ sound/soc/samsung/snow.c:112:2: note: Found duplicate branches for 'if' and 'else'. if (rtd->num_codecs > 1) ^ Signed-off-by: Pierre-Louis Bossart Fixes: 7de6b6bc1a58 ("ASoC: samsung: use asoc_rtd_to_cpu() / asoc_rtd_to_codec() macro for DAI pointer") Reviewed-by: Krzysztof Kozlowski Link: https://lore.kernel.org/r/20210219230918.5058-5-pierre-louis.bossart@linux.intel.com Signed-off-by: Mark Brown --- sound/soc/samsung/snow.c | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/sound/soc/samsung/snow.c b/sound/soc/samsung/snow.c index 989af624dd11..6da674e901ca 100644 --- a/sound/soc/samsung/snow.c +++ b/sound/soc/samsung/snow.c @@ -109,10 +109,7 @@ static int snow_late_probe(struct snd_soc_card *card) rtd = snd_soc_get_pcm_runtime(card, &card->dai_link[0]); /* In the multi-codec case codec_dais 0 is MAX98095 and 1 is HDMI. */ - if (rtd->num_codecs > 1) - codec_dai = asoc_rtd_to_codec(rtd, 0); - else - codec_dai = asoc_rtd_to_codec(rtd, 0); + codec_dai = asoc_rtd_to_codec(rtd, 0); /* Set the MCLK rate for the codec */ return snd_soc_dai_set_sysclk(codec_dai, 0, From 7ca5f04946176ae9611bb80e3ec3d3fa300b7cff Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Thu, 18 Feb 2021 16:19:16 -0600 Subject: [PATCH 079/587] ASoC: soc-ops: remove useless assignment cppcheck warning: sound/soc/soc-ops.c:410:35: style: Variable 'val2' is assigned a value that is never used. [unreadVariable] unsigned int val, val_mask, val2 = 0; ^ Signed-off-by: Pierre-Louis Bossart Link: https://lore.kernel.org/r/20210218221921.88991-2-pierre-louis.bossart@linux.intel.com Signed-off-by: Mark Brown --- sound/soc/soc-ops.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sound/soc/soc-ops.c b/sound/soc/soc-ops.c index 10f48827bb0e..58527247df83 100644 --- a/sound/soc/soc-ops.c +++ b/sound/soc/soc-ops.c @@ -407,7 +407,7 @@ int snd_soc_put_volsw_sx(struct snd_kcontrol *kcontrol, int min = mc->min; unsigned int mask = (1U << (fls(min + max) - 1)) - 1; int err = 0; - unsigned int val, val_mask, val2 = 0; + unsigned int val, val_mask, val2; val_mask = mask << shift; val = (ucontrol->value.integer.value[0] + min) & mask; From 9dbe774091b0e473509221f7dcef0795b5380298 Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Thu, 18 Feb 2021 16:19:17 -0600 Subject: [PATCH 080/587] ASoC: soc-pcm: remove redundant assignment cppcheck warning: sound/soc/soc-pcm.c:2398:7: style: Variable 'ret' is reassigned a value before the old one has been used. [redundantAssignment] ret = -EINVAL; ^ sound/soc/soc-pcm.c:2395:7: note: ret is assigned ret = -EINVAL; ^ sound/soc/soc-pcm.c:2398:7: note: ret is overwritten ret = -EINVAL; ^ This looks like a copy/paste or git merge issue. Signed-off-by: Pierre-Louis Bossart Link: https://lore.kernel.org/r/20210218221921.88991-3-pierre-louis.bossart@linux.intel.com Signed-off-by: Mark Brown --- sound/soc/soc-pcm.c | 1 - 1 file changed, 1 deletion(-) diff --git a/sound/soc/soc-pcm.c b/sound/soc/soc-pcm.c index 14d85ca1e435..12fd10a6c190 100644 --- a/sound/soc/soc-pcm.c +++ b/sound/soc/soc-pcm.c @@ -2395,7 +2395,6 @@ static int dpcm_run_update_startup(struct snd_soc_pcm_runtime *fe, int stream) /* Only start the BE if the FE is ready */ if (fe->dpcm[stream].state == SND_SOC_DPCM_STATE_HW_FREE || fe->dpcm[stream].state == SND_SOC_DPCM_STATE_CLOSE) { - ret = -EINVAL; dev_err(fe->dev, "ASoC: FE %s is not ready %d\n", fe->dai_link->name, fe->dpcm[stream].state); ret = -EINVAL; From 61b9eedd93b1f55e922dfd3ac3cb844e2b69b808 Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Thu, 18 Feb 2021 16:19:18 -0600 Subject: [PATCH 081/587] ASoC: soc-pcm: remove shadowing variable cppcheck warning: sound/soc/soc-pcm.c:1718:7: style: Local variable 'i' shadows outer variable [shadowVariable] int i; ^ sound/soc/soc-pcm.c:1696:6: note: Shadowed declaration int i; ^ sound/soc/soc-pcm.c:1718:7: note: Shadow variable int i; ^ the second variable seems totally unnecessary. Signed-off-by: Pierre-Louis Bossart Link: https://lore.kernel.org/r/20210218221921.88991-4-pierre-louis.bossart@linux.intel.com Signed-off-by: Mark Brown --- sound/soc/soc-pcm.c | 1 - 1 file changed, 1 deletion(-) diff --git a/sound/soc/soc-pcm.c b/sound/soc/soc-pcm.c index 12fd10a6c190..705fb2d548a9 100644 --- a/sound/soc/soc-pcm.c +++ b/sound/soc/soc-pcm.c @@ -1718,7 +1718,6 @@ static int dpcm_apply_symmetry(struct snd_pcm_substream *fe_substream, snd_soc_dpcm_get_substream(be, stream); struct snd_soc_pcm_runtime *rtd; struct snd_soc_dai *dai; - int i; /* A backend may not have the requested substream */ if (!be_substream) From 61456212e80ee274828d2d14fcc7b9364dfc0744 Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Thu, 18 Feb 2021 16:19:19 -0600 Subject: [PATCH 082/587] ASoC: soc-pcm: add error log cppcheck warning: sound/soc/soc-pcm.c:1907:6: style: Variable 'err' is assigned a value that is never used. [unreadVariable] err = dpcm_be_dai_hw_free(fe, stream); ^ it's not clear why dpcm_be_dai_hw_free() is sometimes called without testing the error status, and sometimes an error message is provided. When in doubt, add an error message for consistency. This may have to be revisited. Signed-off-by: Pierre-Louis Bossart Link: https://lore.kernel.org/r/20210218221921.88991-5-pierre-louis.bossart@linux.intel.com Signed-off-by: Mark Brown --- sound/soc/soc-pcm.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/sound/soc/soc-pcm.c b/sound/soc/soc-pcm.c index 705fb2d548a9..2de69dc240bd 100644 --- a/sound/soc/soc-pcm.c +++ b/sound/soc/soc-pcm.c @@ -1907,6 +1907,8 @@ static int dpcm_fe_dai_hw_free(struct snd_pcm_substream *substream) /* only hw_params backends that are either sinks or sources * to this frontend DAI */ err = dpcm_be_dai_hw_free(fe, stream); + if (err < 0) + dev_err(fe->dev, "ASoC: hw_free BE failed %d\n", err); fe->dpcm[stream].state = SND_SOC_DPCM_STATE_HW_FREE; dpcm_set_fe_update_state(fe, stream, SND_SOC_DPCM_UPDATE_NO); From 47108a61b2f7f5a9eb13f88691f03147c4f9fc40 Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Thu, 18 Feb 2021 16:19:20 -0600 Subject: [PATCH 083/587] ASoC: soc-topology: clarify expression cppcheck warning: sound/soc/soc-topology.c:1676:52: style: Clarify calculation precedence for '&' and '?'. [clarifyCalculation] flags & SND_SOC_TPLG_DAI_FLGBIT_SYMMETRIC_RATES ? 1 : 0; ^ sound/soc/soc-topology.c:1680:55: style: Clarify calculation precedence for '&' and '?'. [clarifyCalculation] flags & SND_SOC_TPLG_DAI_FLGBIT_SYMMETRIC_CHANNELS ? ^ sound/soc/soc-topology.c:1685:57: style: Clarify calculation precedence for '&' and '?'. [clarifyCalculation] flags & SND_SOC_TPLG_DAI_FLGBIT_SYMMETRIC_SAMPLEBITS ? ^ sound/soc/soc-topology.c:1768:52: style: Clarify calculation precedence for '&' and '?'. [clarifyCalculation] flags & SND_SOC_TPLG_LNK_FLGBIT_SYMMETRIC_RATES ? 1 : 0; ^ sound/soc/soc-topology.c:1772:55: style: Clarify calculation precedence for '&' and '?'. [clarifyCalculation] flags & SND_SOC_TPLG_LNK_FLGBIT_SYMMETRIC_CHANNELS ? ^ sound/soc/soc-topology.c:1777:57: style: Clarify calculation precedence for '&' and '?'. [clarifyCalculation] flags & SND_SOC_TPLG_LNK_FLGBIT_SYMMETRIC_SAMPLEBITS ? ^ sound/soc/soc-topology.c:1782:48: style: Clarify calculation precedence for '&' and '?'. [clarifyCalculation] flags & SND_SOC_TPLG_LNK_FLGBIT_VOICE_WAKEUP ? ^ Signed-off-by: Pierre-Louis Bossart Link: https://lore.kernel.org/r/20210218221921.88991-6-pierre-louis.bossart@linux.intel.com Signed-off-by: Mark Brown --- sound/soc/soc-topology.c | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/sound/soc/soc-topology.c b/sound/soc/soc-topology.c index 1b0cd33a1348..73076d425efb 100644 --- a/sound/soc/soc-topology.c +++ b/sound/soc/soc-topology.c @@ -1673,16 +1673,16 @@ static void set_dai_flags(struct snd_soc_dai_driver *dai_drv, { if (flag_mask & SND_SOC_TPLG_DAI_FLGBIT_SYMMETRIC_RATES) dai_drv->symmetric_rate = - flags & SND_SOC_TPLG_DAI_FLGBIT_SYMMETRIC_RATES ? 1 : 0; + (flags & SND_SOC_TPLG_DAI_FLGBIT_SYMMETRIC_RATES) ? 1 : 0; if (flag_mask & SND_SOC_TPLG_DAI_FLGBIT_SYMMETRIC_CHANNELS) dai_drv->symmetric_channels = - flags & SND_SOC_TPLG_DAI_FLGBIT_SYMMETRIC_CHANNELS ? + (flags & SND_SOC_TPLG_DAI_FLGBIT_SYMMETRIC_CHANNELS) ? 1 : 0; if (flag_mask & SND_SOC_TPLG_DAI_FLGBIT_SYMMETRIC_SAMPLEBITS) dai_drv->symmetric_sample_bits = - flags & SND_SOC_TPLG_DAI_FLGBIT_SYMMETRIC_SAMPLEBITS ? + (flags & SND_SOC_TPLG_DAI_FLGBIT_SYMMETRIC_SAMPLEBITS) ? 1 : 0; } @@ -1765,22 +1765,22 @@ static void set_link_flags(struct snd_soc_dai_link *link, { if (flag_mask & SND_SOC_TPLG_LNK_FLGBIT_SYMMETRIC_RATES) link->symmetric_rate = - flags & SND_SOC_TPLG_LNK_FLGBIT_SYMMETRIC_RATES ? 1 : 0; + (flags & SND_SOC_TPLG_LNK_FLGBIT_SYMMETRIC_RATES) ? 1 : 0; if (flag_mask & SND_SOC_TPLG_LNK_FLGBIT_SYMMETRIC_CHANNELS) link->symmetric_channels = - flags & SND_SOC_TPLG_LNK_FLGBIT_SYMMETRIC_CHANNELS ? + (flags & SND_SOC_TPLG_LNK_FLGBIT_SYMMETRIC_CHANNELS) ? 1 : 0; if (flag_mask & SND_SOC_TPLG_LNK_FLGBIT_SYMMETRIC_SAMPLEBITS) link->symmetric_sample_bits = - flags & SND_SOC_TPLG_LNK_FLGBIT_SYMMETRIC_SAMPLEBITS ? + (flags & SND_SOC_TPLG_LNK_FLGBIT_SYMMETRIC_SAMPLEBITS) ? 1 : 0; if (flag_mask & SND_SOC_TPLG_LNK_FLGBIT_VOICE_WAKEUP) link->ignore_suspend = - flags & SND_SOC_TPLG_LNK_FLGBIT_VOICE_WAKEUP ? - 1 : 0; + (flags & SND_SOC_TPLG_LNK_FLGBIT_VOICE_WAKEUP) ? + 1 : 0; } /* create the FE DAI link */ From bd029fc86834760276171bd2301d6c43e45a65b0 Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Thu, 18 Feb 2021 16:19:21 -0600 Subject: [PATCH 084/587] ASoC: generic: simple-card-utils: remove useless assignment cppcheck warning: sound/soc/generic/simple-card-utils.c:258:10: style: Variable 'ret' is assigned a value that is never used. [unreadVariable] int ret = 0; ^ Signed-off-by: Pierre-Louis Bossart Link: https://lore.kernel.org/r/20210218221921.88991-7-pierre-louis.bossart@linux.intel.com Signed-off-by: Mark Brown --- sound/soc/generic/simple-card-utils.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sound/soc/generic/simple-card-utils.c b/sound/soc/generic/simple-card-utils.c index ab31045cfc95..06c2512b6f2d 100644 --- a/sound/soc/generic/simple-card-utils.c +++ b/sound/soc/generic/simple-card-utils.c @@ -254,7 +254,7 @@ int asoc_simple_hw_params(struct snd_pcm_substream *substream, struct simple_dai_props *dai_props = simple_priv_to_props(priv, rtd->num); unsigned int mclk, mclk_fs = 0; - int ret = 0; + int ret; if (dai_props->mclk_fs) mclk_fs = dai_props->mclk_fs; From 77150b5a5a473ec35c0bf6f1a8b966329ad9439d Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Fri, 19 Feb 2021 17:16:28 -0600 Subject: [PATCH 085/587] ASoC: sh: dma-sh7760: remove unused variable cppcheck warning: sound/soc/sh/dma-sh7760.c:180:6: style: Unused variable: ret [unusedVariable] int ret; ^ Signed-off-by: Pierre-Louis Bossart Link: https://lore.kernel.org/r/20210219231635.5749-2-pierre-louis.bossart@linux.intel.com Signed-off-by: Mark Brown --- sound/soc/sh/dma-sh7760.c | 1 - 1 file changed, 1 deletion(-) diff --git a/sound/soc/sh/dma-sh7760.c b/sound/soc/sh/dma-sh7760.c index b70068dd5a06..121e48f984c5 100644 --- a/sound/soc/sh/dma-sh7760.c +++ b/sound/soc/sh/dma-sh7760.c @@ -177,7 +177,6 @@ static int camelot_hw_params(struct snd_soc_component *component, struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream); struct camelot_pcm *cam = &cam_pcm_data[asoc_rtd_to_cpu(rtd, 0)->id]; int recv = substream->stream == SNDRV_PCM_STREAM_PLAYBACK ? 0:1; - int ret; if (recv) { cam->rx_period_size = params_period_bytes(hw_params); From d29a60604fe6cb8d4dc1782dbfe893dacb7f57e2 Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Fri, 19 Feb 2021 17:16:29 -0600 Subject: [PATCH 086/587] ASoC: sh: rcar: align function prototypes cppcheck warnings: sound/soc/sh/rcar/adg.c:208:51: style:inconclusive: Function 'rsnd_adg_set_cmd_timsel_gen2' argument 1 names different: declaration 'mod' definition 'cmd_mod'. [funcArgNamesDifferent] int rsnd_adg_set_cmd_timsel_gen2(struct rsnd_mod *cmd_mod, ^ sound/soc/sh/rcar/rsnd.h:608:51: note: Function 'rsnd_adg_set_cmd_timsel_gen2' argument 1 names different: declaration 'mod' definition 'cmd_mod'. int rsnd_adg_set_cmd_timsel_gen2(struct rsnd_mod *mod, ^ sound/soc/sh/rcar/adg.c:208:51: note: Function 'rsnd_adg_set_cmd_timsel_gen2' argument 1 names different: declaration 'mod' definition 'cmd_mod'. int rsnd_adg_set_cmd_timsel_gen2(struct rsnd_mod *cmd_mod, ^ sound/soc/sh/rcar/adg.c:322:44: style:inconclusive: Function 'rsnd_adg_ssi_clk_stop' argument 1 names different: declaration 'mod' definition 'ssi_mod'. [funcArgNamesDifferent] int rsnd_adg_ssi_clk_stop(struct rsnd_mod *ssi_mod) ^ sound/soc/sh/rcar/rsnd.h:600:44: note: Function 'rsnd_adg_ssi_clk_stop' argument 1 names different: declaration 'mod' definition 'ssi_mod'. int rsnd_adg_ssi_clk_stop(struct rsnd_mod *mod); ^ sound/soc/sh/rcar/adg.c:322:44: note: Function 'rsnd_adg_ssi_clk_stop' argument 1 names different: declaration 'mod' definition 'ssi_mod'. int rsnd_adg_ssi_clk_stop(struct rsnd_mod *ssi_mod) ^ sound/soc/sh/rcar/adg.c:329:49: style:inconclusive: Function 'rsnd_adg_ssi_clk_try_start' argument 1 names different: declaration 'mod' definition 'ssi_mod'. [funcArgNamesDifferent] int rsnd_adg_ssi_clk_try_start(struct rsnd_mod *ssi_mod, unsigned int rate) ^ sound/soc/sh/rcar/rsnd.h:601:49: note: Function 'rsnd_adg_ssi_clk_try_start' argument 1 names different: declaration 'mod' definition 'ssi_mod'. int rsnd_adg_ssi_clk_try_start(struct rsnd_mod *mod, unsigned int rate); ^ sound/soc/sh/rcar/adg.c:329:49: note: Function 'rsnd_adg_ssi_clk_try_start' argument 1 names different: declaration 'mod' definition 'ssi_mod'. int rsnd_adg_ssi_clk_try_start(struct rsnd_mod *ssi_mod, unsigned int rate) ^ Signed-off-by: Pierre-Louis Bossart Link: https://lore.kernel.org/r/20210219231635.5749-3-pierre-louis.bossart@linux.intel.com Signed-off-by: Mark Brown --- sound/soc/sh/rcar/rsnd.h | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/sound/soc/sh/rcar/rsnd.h b/sound/soc/sh/rcar/rsnd.h index 6b519370fd64..1255a85151db 100644 --- a/sound/soc/sh/rcar/rsnd.h +++ b/sound/soc/sh/rcar/rsnd.h @@ -597,15 +597,15 @@ phys_addr_t rsnd_gen_get_phy_addr(struct rsnd_priv *priv, int reg_id); * R-Car ADG */ int rsnd_adg_clk_query(struct rsnd_priv *priv, unsigned int rate); -int rsnd_adg_ssi_clk_stop(struct rsnd_mod *mod); -int rsnd_adg_ssi_clk_try_start(struct rsnd_mod *mod, unsigned int rate); +int rsnd_adg_ssi_clk_stop(struct rsnd_mod *ssi_mod); +int rsnd_adg_ssi_clk_try_start(struct rsnd_mod *ssi_mod, unsigned int rate); int rsnd_adg_probe(struct rsnd_priv *priv); void rsnd_adg_remove(struct rsnd_priv *priv); int rsnd_adg_set_src_timesel_gen2(struct rsnd_mod *src_mod, struct rsnd_dai_stream *io, unsigned int in_rate, unsigned int out_rate); -int rsnd_adg_set_cmd_timsel_gen2(struct rsnd_mod *mod, +int rsnd_adg_set_cmd_timsel_gen2(struct rsnd_mod *cmd_mod, struct rsnd_dai_stream *io); #define rsnd_adg_clk_enable(priv) rsnd_adg_clk_control(priv, 1) #define rsnd_adg_clk_disable(priv) rsnd_adg_clk_control(priv, 0) From 652fc90f9de4ab0ba023cbdf5b0853f9447d7966 Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Fri, 19 Feb 2021 17:16:30 -0600 Subject: [PATCH 087/587] ASoC: sh: rcar: simplify return cppcheck warning: sound/soc/sh/rcar/core.c:219:9: warning: Identical condition and return expression 'ret', return value is always 0 [identicalConditionAfterEarlyExit] return ret; ^ sound/soc/sh/rcar/core.c:210:6: note: If condition 'ret' is true, the function will return/exit if (ret) ^ sound/soc/sh/rcar/core.c:219:9: note: Returning identical expression 'ret' return ret; ^ Signed-off-by: Pierre-Louis Bossart Link: https://lore.kernel.org/r/20210219231635.5749-4-pierre-louis.bossart@linux.intel.com Signed-off-by: Mark Brown --- sound/soc/sh/rcar/core.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sound/soc/sh/rcar/core.c b/sound/soc/sh/rcar/core.c index 1029d8d9d800..a07c77dd5250 100644 --- a/sound/soc/sh/rcar/core.c +++ b/sound/soc/sh/rcar/core.c @@ -216,7 +216,7 @@ int rsnd_mod_init(struct rsnd_priv *priv, mod->clk = clk; mod->priv = priv; - return ret; + return 0; } void rsnd_mod_quit(struct rsnd_mod *mod) From 4862811f87350c3656e86dfc3ce310d0390d48ab Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Fri, 19 Feb 2021 17:16:32 -0600 Subject: [PATCH 088/587] ASoC: sh: rcar: ctu: add missing error check cppcheck warning: sound/soc/sh/rcar/ctu.c:212:6: style: Variable 'ret' is reassigned a value before the old one has been used. [redundantAssignment] ret = rsnd_kctrl_new_m(mod, io, rtd, "CTU SV0", ^ sound/soc/sh/rcar/ctu.c:205:6: note: ret is assigned ret = rsnd_kctrl_new_m(mod, io, rtd, "CTU Pass", ^ sound/soc/sh/rcar/ctu.c:212:6: note: ret is overwritten ret = rsnd_kctrl_new_m(mod, io, rtd, "CTU SV0", ^ All the kcontrol creations are checked for errors, except for one. Add the missing error check. Signed-off-by: Pierre-Louis Bossart Link: https://lore.kernel.org/r/20210219231635.5749-6-pierre-louis.bossart@linux.intel.com Signed-off-by: Mark Brown --- sound/soc/sh/rcar/ctu.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/sound/soc/sh/rcar/ctu.c b/sound/soc/sh/rcar/ctu.c index 7647b3d4c0ba..20eecd088d13 100644 --- a/sound/soc/sh/rcar/ctu.c +++ b/sound/soc/sh/rcar/ctu.c @@ -207,6 +207,8 @@ static int rsnd_ctu_pcm_new(struct rsnd_mod *mod, NULL, &ctu->pass, RSND_MAX_CHANNELS, 0xC); + if (ret < 0) + return ret; /* ROW0 */ ret = rsnd_kctrl_new_m(mod, io, rtd, "CTU SV0", From 9946871c608739b76c95d62aed70f9ee4f2d6747 Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Fri, 19 Feb 2021 17:16:33 -0600 Subject: [PATCH 089/587] ASoC: sh: rcar: ssi: remove redundant assignment cppcheck warning: sound/soc/sh/rcar/ssi.c:403:6: style: Redundant initialization for 'wsr'. The initialized value is overwritten before it is read. [redundantInitialization] wsr = ssi->wsr; ^ sound/soc/sh/rcar/ssi.c:372:11: note: wsr is initialized u32 wsr = ssi->wsr; ^ sound/soc/sh/rcar/ssi.c:403:6: note: wsr is overwritten wsr = ssi->wsr; ^ Signed-off-by: Pierre-Louis Bossart Link: https://lore.kernel.org/r/20210219231635.5749-7-pierre-louis.bossart@linux.intel.com Signed-off-by: Mark Brown --- sound/soc/sh/rcar/ssi.c | 1 - 1 file changed, 1 deletion(-) diff --git a/sound/soc/sh/rcar/ssi.c b/sound/soc/sh/rcar/ssi.c index d0ded427a836..659b25992ff2 100644 --- a/sound/soc/sh/rcar/ssi.c +++ b/sound/soc/sh/rcar/ssi.c @@ -400,7 +400,6 @@ static void rsnd_ssi_config_init(struct rsnd_mod *mod, * see * rsnd_ssiu_init_gen2() */ - wsr = ssi->wsr; if (is_tdm || is_tdm_split) { wsr |= WS_MODE; cr_own |= CHNL_8; From eeff1df1fa13126f6024eb6dd0075b3182a3e011 Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Fri, 19 Feb 2021 17:16:34 -0600 Subject: [PATCH 090/587] ASoC: sh: siu_pcm: remove useless assignment cppcheck warning: sound/soc/sh/siu_pcm.c:375:5: style: Redundant initialization for 'rt'. The initialized value is overwritten before it is read. [redundantInitialization] rt = siu_stream->substream->runtime; ^ sound/soc/sh/siu_pcm.c:366:30: note: rt is initialized struct snd_pcm_runtime *rt = ss->runtime; ^ sound/soc/sh/siu_pcm.c:375:5: note: rt is overwritten rt = siu_stream->substream->runtime; ^ Signed-off-by: Pierre-Louis Bossart Link: https://lore.kernel.org/r/20210219231635.5749-8-pierre-louis.bossart@linux.intel.com Signed-off-by: Mark Brown --- sound/soc/sh/siu_pcm.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sound/soc/sh/siu_pcm.c b/sound/soc/sh/siu_pcm.c index 4785886df4f0..6496300f73a9 100644 --- a/sound/soc/sh/siu_pcm.c +++ b/sound/soc/sh/siu_pcm.c @@ -363,7 +363,7 @@ static int siu_pcm_prepare(struct snd_soc_component *component, struct siu_info *info = siu_i2s_data; struct siu_port *port_info = siu_port_info(ss); struct device *dev = ss->pcm->card->dev; - struct snd_pcm_runtime *rt = ss->runtime; + struct snd_pcm_runtime *rt; struct siu_stream *siu_stream; snd_pcm_sframes_t xfer_cnt; From b7e41867a4c9e3613494fbda1c5995f9ed39f3f1 Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Fri, 19 Feb 2021 17:16:35 -0600 Subject: [PATCH 091/587] ASoC: sh: siu_pcm: remove unused variable cppcheck warning: sound/soc/sh/siu_pcm.c:225:8: style: Variable 'virt' is assigned a value that is never used. [unreadVariable] virt = PERIOD_OFFSET(rt->dma_area, ^ It's not clear what this variable was needed for, remove it. Signed-off-by: Pierre-Louis Bossart Link: https://lore.kernel.org/r/20210219231635.5749-9-pierre-louis.bossart@linux.intel.com Signed-off-by: Mark Brown --- sound/soc/sh/siu_pcm.c | 4 ---- 1 file changed, 4 deletions(-) diff --git a/sound/soc/sh/siu_pcm.c b/sound/soc/sh/siu_pcm.c index 6496300f73a9..0a8a3c314a73 100644 --- a/sound/soc/sh/siu_pcm.c +++ b/sound/soc/sh/siu_pcm.c @@ -217,14 +217,10 @@ static void siu_io_work(struct work_struct *work) if (substream->stream == SNDRV_PCM_STREAM_CAPTURE) { dma_addr_t buff; size_t count; - u8 *virt; buff = (dma_addr_t)PERIOD_OFFSET(rt->dma_addr, siu_stream->cur_period, siu_stream->period_bytes); - virt = PERIOD_OFFSET(rt->dma_area, - siu_stream->cur_period, - siu_stream->period_bytes); count = siu_stream->period_bytes; /* DMA transfer start */ From 64ca77d9f55afbbe5e63b1d290cade4acfb8e4fa Mon Sep 17 00:00:00 2001 From: Julia Lawall Date: Sat, 13 Feb 2021 11:19:04 +0100 Subject: [PATCH 092/587] ASoC: mmp-sspa: drop unneeded snd_soc_dai_set_drvdata snd_soc_dai_set_drvdata is not needed when the set data comes from snd_soc_dai_get_drvdata or dev_get_drvdata. The problem was fixed usingthe following semantic patch: (http://coccinelle.lip6.fr/) // @@ expression x,y,e; @@ x = dev_get_drvdata(y->dev) ... when != x = e - snd_soc_dai_set_drvdata(y,x); @@ expression x,y,e; @@ x = snd_soc_dai_get_drvdata(y) ... when != x = e - snd_soc_dai_set_drvdata(y,x); // Signed-off-by: Julia Lawall Link: https://lore.kernel.org/r/20210213101907.1318496-2-Julia.Lawall@inria.fr Signed-off-by: Mark Brown --- sound/soc/pxa/mmp-sspa.c | 1 - 1 file changed, 1 deletion(-) diff --git a/sound/soc/pxa/mmp-sspa.c b/sound/soc/pxa/mmp-sspa.c index 4803972ee655..7e39210a0b38 100644 --- a/sound/soc/pxa/mmp-sspa.c +++ b/sound/soc/pxa/mmp-sspa.c @@ -330,7 +330,6 @@ static int mmp_sspa_probe(struct snd_soc_dai *dai) &sspa->playback_dma_data, &sspa->capture_dma_data); - snd_soc_dai_set_drvdata(dai, sspa); return 0; } From b8fdf60931440296912e35bfe08b351fd3c37d11 Mon Sep 17 00:00:00 2001 From: Julia Lawall Date: Sat, 13 Feb 2021 11:19:05 +0100 Subject: [PATCH 093/587] ASoC: mxs-saif: drop unneeded snd_soc_dai_set_drvdata snd_soc_dai_set_drvdata is not needed when the set data comes from snd_soc_dai_get_drvdata or dev_get_drvdata. The problem was fixed usingthe following semantic patch: (http://coccinelle.lip6.fr/) // @@ expression x,y,e; @@ x = dev_get_drvdata(y->dev) ... when != x = e - snd_soc_dai_set_drvdata(y,x); @@ expression x,y,e; @@ x = snd_soc_dai_get_drvdata(y) ... when != x = e - snd_soc_dai_set_drvdata(y,x); // In this case, the whole probe function then does nothing, so drop it. Signed-off-by: Julia Lawall Link: https://lore.kernel.org/r/20210213101907.1318496-3-Julia.Lawall@inria.fr Signed-off-by: Mark Brown --- sound/soc/mxs/mxs-saif.c | 10 ---------- 1 file changed, 10 deletions(-) diff --git a/sound/soc/mxs/mxs-saif.c b/sound/soc/mxs/mxs-saif.c index 07f8cf9980e3..6a2d24d48964 100644 --- a/sound/soc/mxs/mxs-saif.c +++ b/sound/soc/mxs/mxs-saif.c @@ -642,18 +642,8 @@ static const struct snd_soc_dai_ops mxs_saif_dai_ops = { .set_fmt = mxs_saif_set_dai_fmt, }; -static int mxs_saif_dai_probe(struct snd_soc_dai *dai) -{ - struct mxs_saif *saif = dev_get_drvdata(dai->dev); - - snd_soc_dai_set_drvdata(dai, saif); - - return 0; -} - static struct snd_soc_dai_driver mxs_saif_dai = { .name = "mxs-saif", - .probe = mxs_saif_dai_probe, .playback = { .channels_min = 2, .channels_max = 2, From 36785fec16bed809f622bd523c4cabdfefa9e836 Mon Sep 17 00:00:00 2001 From: Julia Lawall Date: Sat, 13 Feb 2021 11:19:06 +0100 Subject: [PATCH 094/587] ASoC: sun4i-i2s: drop unneeded snd_soc_dai_set_drvdata snd_soc_dai_set_drvdata is not needed when the set data comes from snd_soc_dai_get_drvdata or dev_get_drvdata. The problem was fixed usingthe following semantic patch: (http://coccinelle.lip6.fr/) // @@ expression x,y,e; @@ x = dev_get_drvdata(y->dev) ... when != x = e - snd_soc_dai_set_drvdata(y,x); @@ expression x,y,e; @@ x = snd_soc_dai_get_drvdata(y) ... when != x = e - snd_soc_dai_set_drvdata(y,x); // Signed-off-by: Julia Lawall Link: https://lore.kernel.org/r/20210213101907.1318496-4-Julia.Lawall@inria.fr Signed-off-by: Mark Brown --- sound/soc/sunxi/sun4i-i2s.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/sound/soc/sunxi/sun4i-i2s.c b/sound/soc/sunxi/sun4i-i2s.c index 78506c3811dc..c57feae3396e 100644 --- a/sound/soc/sunxi/sun4i-i2s.c +++ b/sound/soc/sunxi/sun4i-i2s.c @@ -1079,8 +1079,6 @@ static int sun4i_i2s_dai_probe(struct snd_soc_dai *dai) &i2s->playback_dma_data, &i2s->capture_dma_data); - snd_soc_dai_set_drvdata(dai, i2s); - return 0; } From eb0d22d793e82c126ce922fda387c29fe26a2bff Mon Sep 17 00:00:00 2001 From: Julia Lawall Date: Sat, 13 Feb 2021 11:19:07 +0100 Subject: [PATCH 095/587] ASoC: fsl: drop unneeded snd_soc_dai_set_drvdata snd_soc_dai_set_drvdata is not needed when the set data comes from snd_soc_dai_get_drvdata or dev_get_drvdata. The problem was fixed usingthe following semantic patch: (http://coccinelle.lip6.fr/) // @@ expression x,y,e; @@ x = dev_get_drvdata(y->dev) ... when != x = e - snd_soc_dai_set_drvdata(y,x); @@ expression x,y,e; @@ x = snd_soc_dai_get_drvdata(y) ... when != x = e - snd_soc_dai_set_drvdata(y,x); // Signed-off-by: Julia Lawall Acked-by: Nicolin Chen Link: https://lore.kernel.org/r/20210213101907.1318496-5-Julia.Lawall@inria.fr Signed-off-by: Mark Brown --- sound/soc/fsl/fsl_micfil.c | 2 -- sound/soc/fsl/fsl_sai.c | 2 -- sound/soc/fsl/fsl_xcvr.c | 1 - 3 files changed, 5 deletions(-) diff --git a/sound/soc/fsl/fsl_micfil.c b/sound/soc/fsl/fsl_micfil.c index 5935af2e5ff4..2b9edd4bb94d 100644 --- a/sound/soc/fsl/fsl_micfil.c +++ b/sound/soc/fsl/fsl_micfil.c @@ -423,8 +423,6 @@ static int fsl_micfil_dai_probe(struct snd_soc_dai *cpu_dai) return ret; } - snd_soc_dai_set_drvdata(cpu_dai, micfil); - return 0; } diff --git a/sound/soc/fsl/fsl_sai.c b/sound/soc/fsl/fsl_sai.c index 5e65b456d3e2..8876d0ed37d9 100644 --- a/sound/soc/fsl/fsl_sai.c +++ b/sound/soc/fsl/fsl_sai.c @@ -727,8 +727,6 @@ static int fsl_sai_dai_probe(struct snd_soc_dai *cpu_dai) snd_soc_dai_init_dma_data(cpu_dai, &sai->dma_params_tx, &sai->dma_params_rx); - snd_soc_dai_set_drvdata(cpu_dai, sai); - return 0; } diff --git a/sound/soc/fsl/fsl_xcvr.c b/sound/soc/fsl/fsl_xcvr.c index 6dd0a5fcd455..4f33dbe29c78 100644 --- a/sound/soc/fsl/fsl_xcvr.c +++ b/sound/soc/fsl/fsl_xcvr.c @@ -869,7 +869,6 @@ static int fsl_xcvr_dai_probe(struct snd_soc_dai *dai) struct fsl_xcvr *xcvr = snd_soc_dai_get_drvdata(dai); snd_soc_dai_init_dma_data(dai, &xcvr->dma_prms_tx, &xcvr->dma_prms_rx); - snd_soc_dai_set_drvdata(dai, xcvr); snd_soc_add_dai_controls(dai, &fsl_xcvr_mode_kctl, 1); snd_soc_add_dai_controls(dai, &fsl_xcvr_arc_mode_kctl, 1); From 929cc78260550e82fc481c8c9428ec2aa589d88c Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Thu, 25 Feb 2021 09:25:02 +0900 Subject: [PATCH 096/587] ASoC: rsnd: cleanup ppcheck warning for ssiu.c This patch cleanups below ppcheck warning. sound/soc/sh/rcar/ssiu.c:212:10: style: The scope of the variable 'shift' can be reduced. [variableScope] int i, shift; ^ sound/soc/sh/rcar/ssiu.c:337:19: style: The scope of the variable 'mod' can be reduced. [variableScope] struct rsnd_mod *mod; ^ sound/soc/sh/rcar/ssiu.c:362:22: style: The scope of the variable 'np' can be reduced. [variableScope] struct device_node *np; ^ sound/soc/sh/rcar/ssiu.c:363:19: style: The scope of the variable 'mod' can be reduced. [variableScope] struct rsnd_mod *mod; ^ sound/soc/sh/rcar/ssiu.c:366:6: style: The scope of the variable 'i' can be reduced. [variableScope] int i; ^ sound/soc/sh/rcar/ssiu.c:397:13: style: The scope of the variable 'ret' can be reduced. [variableScope] int i, nr, ret; ^ Signed-off-by: Kuninori Morimoto Link: https://lore.kernel.org/r/87lfbdro2p.wl-kuninori.morimoto.gx@renesas.com Signed-off-by: Mark Brown --- sound/soc/sh/rcar/ssiu.c | 22 ++++++++++++---------- 1 file changed, 12 insertions(+), 10 deletions(-) diff --git a/sound/soc/sh/rcar/ssiu.c b/sound/soc/sh/rcar/ssiu.c index f29bd72f3a26..852cdeedf7e9 100644 --- a/sound/soc/sh/rcar/ssiu.c +++ b/sound/soc/sh/rcar/ssiu.c @@ -209,7 +209,7 @@ static int rsnd_ssiu_init_gen2(struct rsnd_mod *mod, struct rsnd_mod *ssi_mod = rsnd_io_to_mod_ssi(io); struct rsnd_mod *pos; u32 val; - int i, shift; + int i; i = rsnd_mod_id(ssi_mod); @@ -221,7 +221,8 @@ static int rsnd_ssiu_init_gen2(struct rsnd_mod *mod, i; for_each_rsnd_mod_array(i, pos, io, rsnd_ssi_array) { - shift = (i * 4) + 20; + int shift = (i * 4) + 20; + val = (val & ~(0xF << shift)) | rsnd_mod_id(pos) << shift; } @@ -334,7 +335,6 @@ static void rsnd_parse_connect_ssiu_compatible(struct rsnd_priv *priv, struct rsnd_dai_stream *io) { struct rsnd_mod *ssi_mod = rsnd_io_to_mod_ssi(io); - struct rsnd_mod *mod; struct rsnd_ssiu *ssiu; int i; @@ -343,7 +343,7 @@ static void rsnd_parse_connect_ssiu_compatible(struct rsnd_priv *priv, /* select BUSIF0 */ for_each_rsnd_ssiu(ssiu, priv, i) { - mod = rsnd_mod_get(ssiu); + struct rsnd_mod *mod = rsnd_mod_get(ssiu); if ((rsnd_mod_id(ssi_mod) == rsnd_mod_id(mod)) && (rsnd_mod_id_sub(mod) == 0)) { @@ -359,17 +359,17 @@ void rsnd_parse_connect_ssiu(struct rsnd_dai *rdai, { struct rsnd_priv *priv = rsnd_rdai_to_priv(rdai); struct device_node *node = rsnd_ssiu_of_node(priv); - struct device_node *np; - struct rsnd_mod *mod; struct rsnd_dai_stream *io_p = &rdai->playback; struct rsnd_dai_stream *io_c = &rdai->capture; - int i; /* use rcar_sound,ssiu if exist */ if (node) { - i = 0; + struct device_node *np; + int i = 0; + for_each_child_of_node(node, np) { - mod = rsnd_ssiu_mod_get(priv, i); + struct rsnd_mod *mod = rsnd_ssiu_mod_get(priv, i); + if (np == playback) rsnd_dai_connect(mod, io_p, mod->type); if (np == capture) @@ -394,7 +394,7 @@ int rsnd_ssiu_probe(struct rsnd_priv *priv) struct rsnd_ssiu *ssiu; struct rsnd_mod_ops *ops; const int *list = NULL; - int i, nr, ret; + int i, nr; /* * Keep DT compatibility. @@ -441,6 +441,8 @@ int rsnd_ssiu_probe(struct rsnd_priv *priv) } for_each_rsnd_ssiu(ssiu, priv, i) { + int ret; + if (node) { int j; From 0779baa812cf27325ad1d43a917144f50ffd2142 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Thu, 25 Feb 2021 09:25:08 +0900 Subject: [PATCH 097/587] ASoC: rsnd: cleanup ppcheck warning for ssi.c This patch cleanups below ppcheck warning. sound/soc/sh/rcar/ssi.c:170:19: style: The scope of the variable 'mod' can be reduced. [variableScope] struct rsnd_mod *mod; ^ sound/soc/sh/rcar/ssi.c:535:6: style: The scope of the variable 'i' can be reduced. [variableScope] int i; ^ sound/soc/sh/rcar/ssi.c:1212:19: style: The scope of the variable 'mod' can be reduced. [variableScope] struct rsnd_mod *mod; ^ sound/soc/sh/rcar/ssi.c:328:16: portability: Shifting signed 32-bit value by 31 bits is implementation-defined behaviour [shiftTooManyBitsSigned] ssi->cr_clk = FORCE | rsnd_rdai_width_to_swl(rdai) | ^ sound/soc/sh/rcar/ssi.c:387:12: portability: Shifting signed 32-bit value by 31 bits is implementation-defined behaviour [shiftTooManyBitsSigned] cr_own |= FORCE | rsnd_rdai_width_to_swl(rdai); ^ Signed-off-by: Kuninori Morimoto Link: https://lore.kernel.org/r/87k0qxro2j.wl-kuninori.morimoto.gx@renesas.com Signed-off-by: Mark Brown --- sound/soc/sh/rcar/ssi.c | 45 +++++++++++++++++++++-------------------- 1 file changed, 23 insertions(+), 22 deletions(-) diff --git a/sound/soc/sh/rcar/ssi.c b/sound/soc/sh/rcar/ssi.c index d0ded427a836..49aa81ff9361 100644 --- a/sound/soc/sh/rcar/ssi.c +++ b/sound/soc/sh/rcar/ssi.c @@ -24,23 +24,23 @@ /* * SSICR */ -#define FORCE (1 << 31) /* Fixed */ -#define DMEN (1 << 28) /* DMA Enable */ -#define UIEN (1 << 27) /* Underflow Interrupt Enable */ -#define OIEN (1 << 26) /* Overflow Interrupt Enable */ -#define IIEN (1 << 25) /* Idle Mode Interrupt Enable */ -#define DIEN (1 << 24) /* Data Interrupt Enable */ -#define CHNL_4 (1 << 22) /* Channels */ -#define CHNL_6 (2 << 22) /* Channels */ -#define CHNL_8 (3 << 22) /* Channels */ -#define DWL_MASK (7 << 19) /* Data Word Length mask */ -#define DWL_8 (0 << 19) /* Data Word Length */ -#define DWL_16 (1 << 19) /* Data Word Length */ -#define DWL_18 (2 << 19) /* Data Word Length */ -#define DWL_20 (3 << 19) /* Data Word Length */ -#define DWL_22 (4 << 19) /* Data Word Length */ -#define DWL_24 (5 << 19) /* Data Word Length */ -#define DWL_32 (6 << 19) /* Data Word Length */ +#define FORCE (1u << 31) /* Fixed */ +#define DMEN (1u << 28) /* DMA Enable */ +#define UIEN (1u << 27) /* Underflow Interrupt Enable */ +#define OIEN (1u << 26) /* Overflow Interrupt Enable */ +#define IIEN (1u << 25) /* Idle Mode Interrupt Enable */ +#define DIEN (1u << 24) /* Data Interrupt Enable */ +#define CHNL_4 (1u << 22) /* Channels */ +#define CHNL_6 (2u << 22) /* Channels */ +#define CHNL_8 (3u << 22) /* Channels */ +#define DWL_MASK (7u << 19) /* Data Word Length mask */ +#define DWL_8 (0u << 19) /* Data Word Length */ +#define DWL_16 (1u << 19) /* Data Word Length */ +#define DWL_18 (2u << 19) /* Data Word Length */ +#define DWL_20 (3u << 19) /* Data Word Length */ +#define DWL_22 (4u << 19) /* Data Word Length */ +#define DWL_24 (5u << 19) /* Data Word Length */ +#define DWL_32 (6u << 19) /* Data Word Length */ /* * System word length @@ -167,7 +167,6 @@ static void rsnd_ssi_status_check(struct rsnd_mod *mod, static u32 rsnd_ssi_multi_secondaries(struct rsnd_dai_stream *io) { - struct rsnd_mod *mod; enum rsnd_mod_type types[] = { RSND_MOD_SSIM1, RSND_MOD_SSIM2, @@ -177,7 +176,8 @@ static u32 rsnd_ssi_multi_secondaries(struct rsnd_dai_stream *io) mask = 0; for (i = 0; i < ARRAY_SIZE(types); i++) { - mod = rsnd_io_to_mod(io, types[i]); + struct rsnd_mod *mod = rsnd_io_to_mod(io, types[i]); + if (!mod) continue; @@ -533,7 +533,6 @@ static int rsnd_ssi_quit(struct rsnd_mod *mod, struct device *dev = rsnd_priv_to_dev(priv); int is_tdm, is_tdm_split; int id = rsnd_mod_id(mod); - int i; u32 sys_int_enable = 0; is_tdm = rsnd_runtime_is_tdm(io); @@ -561,6 +560,8 @@ static int rsnd_ssi_quit(struct rsnd_mod *mod, /* disable busif buffer over/under run interrupt. */ if (is_tdm || is_tdm_split) { + int i; + switch (id) { case 0: case 1: @@ -1210,7 +1211,6 @@ void rsnd_parse_connect_ssi(struct rsnd_dai *rdai, struct rsnd_priv *priv = rsnd_rdai_to_priv(rdai); struct device_node *node; struct device_node *np; - struct rsnd_mod *mod; int i; node = rsnd_ssi_of_node(priv); @@ -1219,7 +1219,8 @@ void rsnd_parse_connect_ssi(struct rsnd_dai *rdai, i = 0; for_each_child_of_node(node, np) { - mod = rsnd_ssi_mod_get(priv, i); + struct rsnd_mod *mod = rsnd_ssi_mod_get(priv, i); + if (np == playback) rsnd_ssi_connect(mod, &rdai->playback); if (np == capture) From e539943c664e58a7005959f2c902d1fbda464b59 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Thu, 25 Feb 2021 09:25:14 +0900 Subject: [PATCH 098/587] ASoC: rsnd: cleanup ppcheck warning for core.c This patch cleanups below ppcheck warning. sound/soc/sh/rcar/core.c:233:26: style: The scope of the variable 'io' can be reduced. [variableScope] struct rsnd_dai_stream *io; ^ sound/soc/sh/rcar/core.c:489:19: style: The scope of the variable 'mod' can be reduced. [variableScope] struct rsnd_mod *mod; ^ sound/soc/sh/rcar/core.c:1064:9: style: The scope of the variable 'j' can be reduced. [variableScope] int i, j; ^ sound/soc/sh/rcar/core.c:1143:19: style: The scope of the variable 'mod' can be reduced. [variableScope] struct rsnd_mod *mod; ^ sound/soc/sh/rcar/core.c:1261:22: style: The scope of the variable 'playback' can be reduced. [variableScope] struct device_node *playback, *capture; ^ sound/soc/sh/rcar/core.c:1261:33: style: The scope of the variable 'capture' can be reduced. [variableScope] struct device_node *playback, *capture; ^ sound/soc/sh/rcar/core.c:1419:29: style: The scope of the variable 'be_params' can be reduced. [variableScope] struct snd_pcm_hw_params *be_params; ^ sound/soc/sh/rcar/core.c:1369:22: style: Local variable 'rdai' shadows outer variable [shadowVariable] struct rsnd_dai *rdai = rsnd_rdai_get(priv, dai_i); ^ sound/soc/sh/rcar/core.c:1338:19: note: Shadowed declaration struct rsnd_dai *rdai; ^ sound/soc/sh/rcar/core.c:1369:22: note: Shadow variable struct rsnd_dai *rdai = rsnd_rdai_get(priv, dai_i); ^ sound/soc/sh/rcar/core.c:1380:22: style: Local variable 'rdai' shadows outer variable [shadowVariable] struct rsnd_dai *rdai = rsnd_rdai_get(priv, dai_i); ^ Reported-by: Pierre-Louis Bossart Signed-off-by: Kuninori Morimoto Link: https://lore.kernel.org/r/87im6hro2d.wl-kuninori.morimoto.gx@renesas.com Signed-off-by: Mark Brown --- sound/soc/sh/rcar/core.c | 32 ++++++++++++++------------------ 1 file changed, 14 insertions(+), 18 deletions(-) diff --git a/sound/soc/sh/rcar/core.c b/sound/soc/sh/rcar/core.c index 1029d8d9d800..ee1f320935db 100644 --- a/sound/soc/sh/rcar/core.c +++ b/sound/soc/sh/rcar/core.c @@ -230,12 +230,12 @@ void rsnd_mod_interrupt(struct rsnd_mod *mod, struct rsnd_dai_stream *io)) { struct rsnd_priv *priv = rsnd_mod_to_priv(mod); - struct rsnd_dai_stream *io; struct rsnd_dai *rdai; int i; for_each_rsnd_dai(rdai, priv, i) { - io = &rdai->playback; + struct rsnd_dai_stream *io = &rdai->playback; + if (mod == io->mod[mod->type]) callback(mod, io); @@ -486,13 +486,12 @@ struct rsnd_mod *rsnd_mod_next(int *iterator, enum rsnd_mod_type *array, int array_size) { - struct rsnd_mod *mod; - enum rsnd_mod_type type; int max = array ? array_size : RSND_MOD_MAX; for (; *iterator < max; (*iterator)++) { - type = (array) ? array[*iterator] : *iterator; - mod = rsnd_io_to_mod(io, type); + enum rsnd_mod_type type = (array) ? array[*iterator] : *iterator; + struct rsnd_mod *mod = rsnd_io_to_mod(io, type); + if (mod) return mod; } @@ -1061,7 +1060,7 @@ static void rsnd_parse_tdm_split_mode(struct rsnd_priv *priv, struct device_node *ssiu_np = rsnd_ssiu_of_node(priv); struct device_node *np; int is_play = rsnd_io_is_play(io); - int i, j; + int i; if (!ssiu_np) return; @@ -1078,13 +1077,11 @@ static void rsnd_parse_tdm_split_mode(struct rsnd_priv *priv, if (!node) break; - j = 0; for_each_child_of_node(ssiu_np, np) { if (np == node) { rsnd_flags_set(io, RSND_STREAM_TDM_SPLIT); dev_dbg(dev, "%s is part of TDM Split\n", io->name); } - j++; } of_node_put(node); @@ -1140,7 +1137,6 @@ void rsnd_parse_connect_common(struct rsnd_dai *rdai, { struct rsnd_priv *priv = rsnd_rdai_to_priv(rdai); struct device_node *np; - struct rsnd_mod *mod; int i; if (!node) @@ -1148,7 +1144,8 @@ void rsnd_parse_connect_common(struct rsnd_dai *rdai, i = 0; for_each_child_of_node(node, np) { - mod = mod_get(priv, i); + struct rsnd_mod *mod = mod_get(priv, i); + if (np == playback) rsnd_dai_connect(mod, &rdai->playback, mod->type); if (np == capture) @@ -1258,7 +1255,6 @@ static void __rsnd_dai_probe(struct rsnd_priv *priv, struct device_node *dai_np, int dai_i) { - struct device_node *playback, *capture; struct rsnd_dai_stream *io_playback; struct rsnd_dai_stream *io_capture; struct snd_soc_dai_driver *drv; @@ -1301,8 +1297,8 @@ static void __rsnd_dai_probe(struct rsnd_priv *priv, rsnd_rdai_width_set(rdai, 32); /* default 32bit width */ for (io_i = 0;; io_i++) { - playback = of_parse_phandle(dai_np, "playback", io_i); - capture = of_parse_phandle(dai_np, "capture", io_i); + struct device_node *playback = of_parse_phandle(dai_np, "playback", io_i); + struct device_node *capture = of_parse_phandle(dai_np, "capture", io_i); if (!playback && !capture) break; @@ -1366,7 +1362,7 @@ static int rsnd_dai_probe(struct rsnd_priv *priv) for_each_endpoint_of_node(dai_node, dai_np) { __rsnd_dai_probe(priv, dai_np, dai_i); if (rsnd_is_gen3(priv)) { - struct rsnd_dai *rdai = rsnd_rdai_get(priv, dai_i); + rdai = rsnd_rdai_get(priv, dai_i); rsnd_parse_connect_graph(priv, &rdai->playback, dai_np); rsnd_parse_connect_graph(priv, &rdai->capture, dai_np); @@ -1377,7 +1373,7 @@ static int rsnd_dai_probe(struct rsnd_priv *priv) for_each_child_of_node(dai_node, dai_np) { __rsnd_dai_probe(priv, dai_np, dai_i); if (rsnd_is_gen3(priv)) { - struct rsnd_dai *rdai = rsnd_rdai_get(priv, dai_i); + rdai = rsnd_rdai_get(priv, dai_i); rsnd_parse_connect_simple(priv, &rdai->playback, dai_np); rsnd_parse_connect_simple(priv, &rdai->capture, dai_np); @@ -1416,11 +1412,11 @@ static int rsnd_hw_params(struct snd_soc_component *component, struct rsnd_priv *priv = rsnd_io_to_priv(io); struct device *dev = rsnd_priv_to_dev(priv); struct snd_soc_dpcm *dpcm; - struct snd_pcm_hw_params *be_params; int stream = substream->stream; for_each_dpcm_be(fe, stream, dpcm) { - be_params = &dpcm->hw_params; + struct snd_pcm_hw_params *be_params = &dpcm->hw_params; + if (params_channels(hw_params) != params_channels(be_params)) io->converted_chan = params_channels(be_params); if (params_rate(hw_params) != params_rate(be_params)) From 31dbf7acc6a3abf84c2cb3c2312283ed8691de5b Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Thu, 25 Feb 2021 09:25:19 +0900 Subject: [PATCH 099/587] ASoC: rsnd: cleanup ppcheck warning for cmd.c This patch cleanups below ppcheck warning. sound/soc/sh/rcar/cmd.c:46:20: style: The scope of the variable 'src' can be reduced. [variableScope] struct rsnd_mod *src; ^ sound/soc/sh/rcar/cmd.c:47:27: style: The scope of the variable 'tio' can be reduced. [variableScope] struct rsnd_dai_stream *tio; ^ sound/soc/sh/rcar/cmd.c:145:13: style: The scope of the variable 'ret' can be reduced. [variableScope] int i, nr, ret; ^ Signed-off-by: Kuninori Morimoto Link: https://lore.kernel.org/r/87h7m1ro28.wl-kuninori.morimoto.gx@renesas.com Signed-off-by: Mark Brown --- sound/soc/sh/rcar/cmd.c | 15 +++++++-------- 1 file changed, 7 insertions(+), 8 deletions(-) diff --git a/sound/soc/sh/rcar/cmd.c b/sound/soc/sh/rcar/cmd.c index e6bb6a9a0684..9fdb37c2cbc2 100644 --- a/sound/soc/sh/rcar/cmd.c +++ b/sound/soc/sh/rcar/cmd.c @@ -43,8 +43,6 @@ static int rsnd_cmd_init(struct rsnd_mod *mod, if (mix) { struct rsnd_dai *rdai; - struct rsnd_mod *src; - struct rsnd_dai_stream *tio; int i; /* @@ -54,8 +52,9 @@ static int rsnd_cmd_init(struct rsnd_mod *mod, */ data = 0; for_each_rsnd_dai(rdai, priv, i) { - tio = &rdai->playback; - src = rsnd_io_to_mod_src(tio); + struct rsnd_dai_stream *tio = &rdai->playback; + struct rsnd_mod *src = rsnd_io_to_mod_src(tio); + if (mix == rsnd_io_to_mod_mix(tio)) data |= path[rsnd_mod_id(src)]; @@ -142,7 +141,7 @@ int rsnd_cmd_probe(struct rsnd_priv *priv) { struct device *dev = rsnd_priv_to_dev(priv); struct rsnd_cmd *cmd; - int i, nr, ret; + int i, nr; /* This driver doesn't support Gen1 at this point */ if (rsnd_is_gen1(priv)) @@ -161,9 +160,9 @@ int rsnd_cmd_probe(struct rsnd_priv *priv) priv->cmd = cmd; for_each_rsnd_cmd(cmd, priv, i) { - ret = rsnd_mod_init(priv, rsnd_mod_get(cmd), - &rsnd_cmd_ops, NULL, - RSND_MOD_CMD, i); + int ret = rsnd_mod_init(priv, rsnd_mod_get(cmd), + &rsnd_cmd_ops, NULL, + RSND_MOD_CMD, i); if (ret) return ret; } From b6e499bcb32f07364cf62e7022032f1c0632f76c Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Thu, 25 Feb 2021 09:25:23 +0900 Subject: [PATCH 100/587] ASoC: rsnd: cleanup ppcheck warning for adg.c This patch cleanups below ppcheck warning. sound/soc/sh/rcar/adg.c:67:9: style: The scope of the variable 'ratio' can be reduced. [variableScope] int i, ratio; ^ sound/soc/sh/rcar/adg.c:114:6: style: The scope of the variable 'idx' can be reduced. [variableScope] int idx, sel, div, step; ^ sound/soc/sh/rcar/adg.c:114:21: style: The scope of the variable 'step' can be reduced. [variableScope] int idx, sel, div, step; ^ sound/soc/sh/rcar/adg.c:397:14: style: The scope of the variable 'clk' can be reduced. [variableScope] struct clk *clk; ^ Signed-off-by: Kuninori Morimoto Link: https://lore.kernel.org/r/87ft1lro24.wl-kuninori.morimoto.gx@renesas.com Signed-off-by: Mark Brown --- sound/soc/sh/rcar/adg.c | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/sound/soc/sh/rcar/adg.c b/sound/soc/sh/rcar/adg.c index abdfd9cf91e2..0b8ae3eee148 100644 --- a/sound/soc/sh/rcar/adg.c +++ b/sound/soc/sh/rcar/adg.c @@ -64,13 +64,13 @@ static const char * const clk_name[] = { static u32 rsnd_adg_calculate_rbgx(unsigned long div) { - int i, ratio; + int i; if (!div) return 0; for (i = 3; i >= 0; i--) { - ratio = 2 << (i * 2); + int ratio = 2 << (i * 2); if (0 == (div % ratio)) return (u32)((i << 8) | ((div / ratio) - 1)); } @@ -111,7 +111,7 @@ static void __rsnd_adg_get_timesel_ratio(struct rsnd_priv *priv, { struct rsnd_adg *adg = rsnd_priv_to_adg(priv); struct device *dev = rsnd_priv_to_dev(priv); - int idx, sel, div, step; + int sel; unsigned int val, en; unsigned int min, diff; unsigned int sel_rate[] = { @@ -126,8 +126,9 @@ static void __rsnd_adg_get_timesel_ratio(struct rsnd_priv *priv, val = 0; en = 0; for (sel = 0; sel < ARRAY_SIZE(sel_rate); sel++) { - idx = 0; - step = 2; + int idx = 0; + int step = 2; + int div; if (!sel_rate[sel]) continue; @@ -394,11 +395,11 @@ static void rsnd_adg_get_clkin(struct rsnd_priv *priv, struct rsnd_adg *adg) { struct device *dev = rsnd_priv_to_dev(priv); - struct clk *clk; int i; for (i = 0; i < CLKMAX; i++) { - clk = devm_clk_get(dev, clk_name[i]); + struct clk *clk = devm_clk_get(dev, clk_name[i]); + adg->clk[i] = IS_ERR(clk) ? NULL : clk; } } From 933f98be60a7b9c287acb081fb5d6659dd5e0441 Mon Sep 17 00:00:00 2001 From: Krzysztof Kozlowski Date: Sun, 21 Feb 2021 16:30:24 +0100 Subject: [PATCH 101/587] ASoC: constify of_phandle_args in snd_soc_get_dai_name() The pointer to of_phandle_args passed to snd_soc_get_dai_name() and of_xlate_dai_name() implementations is not modified. Since it is being used only to translate passed OF node to a DAI name, it should not be modified, so mark it as const for correctness and safer code. Signed-off-by: Krzysztof Kozlowski Link: https://lore.kernel.org/r/20210221153024.453583-1-krzk@kernel.org Signed-off-by: Mark Brown --- include/sound/soc-component.h | 4 ++-- include/sound/soc.h | 2 +- sound/soc/meson/aiu-acodec-ctrl.c | 2 +- sound/soc/meson/aiu-codec-ctrl.c | 2 +- sound/soc/meson/aiu.c | 4 ++-- sound/soc/meson/aiu.h | 2 +- sound/soc/qcom/lpass-cpu.c | 2 +- sound/soc/qcom/qdsp6/q6afe-dai.c | 2 +- sound/soc/soc-component.c | 2 +- sound/soc/soc-core.c | 2 +- 10 files changed, 12 insertions(+), 12 deletions(-) diff --git a/include/sound/soc-component.h b/include/sound/soc-component.h index 5b47768222b7..7dc75b39287f 100644 --- a/include/sound/soc-component.h +++ b/include/sound/soc-component.h @@ -101,7 +101,7 @@ struct snd_soc_component_driver { /* DT */ int (*of_xlate_dai_name)(struct snd_soc_component *component, - struct of_phandle_args *args, + const struct of_phandle_args *args, const char **dai_name); int (*of_xlate_dai_id)(struct snd_soc_component *comment, struct device_node *endpoint); @@ -450,7 +450,7 @@ void snd_soc_component_remove(struct snd_soc_component *component); int snd_soc_component_of_xlate_dai_id(struct snd_soc_component *component, struct device_node *ep); int snd_soc_component_of_xlate_dai_name(struct snd_soc_component *component, - struct of_phandle_args *args, + const struct of_phandle_args *args, const char **dai_name); int snd_soc_component_compr_open(struct snd_compr_stream *cstream); void snd_soc_component_compr_free(struct snd_compr_stream *cstream, diff --git a/include/sound/soc.h b/include/sound/soc.h index bd38015d6c6d..78609ab331c8 100644 --- a/include/sound/soc.h +++ b/include/sound/soc.h @@ -1219,7 +1219,7 @@ unsigned int snd_soc_of_parse_daifmt(struct device_node *np, struct device_node **bitclkmaster, struct device_node **framemaster); int snd_soc_get_dai_id(struct device_node *ep); -int snd_soc_get_dai_name(struct of_phandle_args *args, +int snd_soc_get_dai_name(const struct of_phandle_args *args, const char **dai_name); int snd_soc_of_get_dai_name(struct device_node *of_node, const char **dai_name); diff --git a/sound/soc/meson/aiu-acodec-ctrl.c b/sound/soc/meson/aiu-acodec-ctrl.c index 7078197e0cc5..27a6d3259c50 100644 --- a/sound/soc/meson/aiu-acodec-ctrl.c +++ b/sound/soc/meson/aiu-acodec-ctrl.c @@ -159,7 +159,7 @@ static const struct snd_kcontrol_new aiu_acodec_ctrl_controls[] = { }; static int aiu_acodec_of_xlate_dai_name(struct snd_soc_component *component, - struct of_phandle_args *args, + const struct of_phandle_args *args, const char **dai_name) { return aiu_of_xlate_dai_name(component, args, dai_name, AIU_ACODEC); diff --git a/sound/soc/meson/aiu-codec-ctrl.c b/sound/soc/meson/aiu-codec-ctrl.c index 4b773d3e8b07..c3ea733fce91 100644 --- a/sound/soc/meson/aiu-codec-ctrl.c +++ b/sound/soc/meson/aiu-codec-ctrl.c @@ -125,7 +125,7 @@ static const struct snd_soc_dapm_route aiu_hdmi_ctrl_routes[] = { }; static int aiu_hdmi_of_xlate_dai_name(struct snd_soc_component *component, - struct of_phandle_args *args, + const struct of_phandle_args *args, const char **dai_name) { return aiu_of_xlate_dai_name(component, args, dai_name, AIU_HDMI); diff --git a/sound/soc/meson/aiu.c b/sound/soc/meson/aiu.c index dc35ca79021c..ba15d5762b0b 100644 --- a/sound/soc/meson/aiu.c +++ b/sound/soc/meson/aiu.c @@ -42,7 +42,7 @@ static const struct snd_soc_dapm_route aiu_cpu_dapm_routes[] = { }; int aiu_of_xlate_dai_name(struct snd_soc_component *component, - struct of_phandle_args *args, + const struct of_phandle_args *args, const char **dai_name, unsigned int component_id) { @@ -72,7 +72,7 @@ int aiu_of_xlate_dai_name(struct snd_soc_component *component, } static int aiu_cpu_of_xlate_dai_name(struct snd_soc_component *component, - struct of_phandle_args *args, + const struct of_phandle_args *args, const char **dai_name) { return aiu_of_xlate_dai_name(component, args, dai_name, AIU_CPU); diff --git a/sound/soc/meson/aiu.h b/sound/soc/meson/aiu.h index 87aa19ac4af3..393b6c2307e4 100644 --- a/sound/soc/meson/aiu.h +++ b/sound/soc/meson/aiu.h @@ -45,7 +45,7 @@ struct aiu { SNDRV_PCM_FMTBIT_S24_LE) int aiu_of_xlate_dai_name(struct snd_soc_component *component, - struct of_phandle_args *args, + const struct of_phandle_args *args, const char **dai_name, unsigned int component_id); diff --git a/sound/soc/qcom/lpass-cpu.c b/sound/soc/qcom/lpass-cpu.c index c642e5f8f28c..4762286b33fe 100644 --- a/sound/soc/qcom/lpass-cpu.c +++ b/sound/soc/qcom/lpass-cpu.c @@ -340,7 +340,7 @@ int asoc_qcom_lpass_cpu_dai_probe(struct snd_soc_dai *dai) EXPORT_SYMBOL_GPL(asoc_qcom_lpass_cpu_dai_probe); static int asoc_qcom_of_xlate_dai_name(struct snd_soc_component *component, - struct of_phandle_args *args, + const struct of_phandle_args *args, const char **dai_name) { struct lpass_data *drvdata = snd_soc_component_get_drvdata(component); diff --git a/sound/soc/qcom/qdsp6/q6afe-dai.c b/sound/soc/qcom/qdsp6/q6afe-dai.c index 4e1f101281e7..e8915519f427 100644 --- a/sound/soc/qcom/qdsp6/q6afe-dai.c +++ b/sound/soc/qcom/qdsp6/q6afe-dai.c @@ -1315,7 +1315,7 @@ static struct snd_soc_dai_driver q6afe_dais[] = { }; static int q6afe_of_xlate_dai_name(struct snd_soc_component *component, - struct of_phandle_args *args, + const struct of_phandle_args *args, const char **dai_name) { int id = args->args[0]; diff --git a/sound/soc/soc-component.c b/sound/soc/soc-component.c index 159bf88b9f8c..8415e9bd2932 100644 --- a/sound/soc/soc-component.c +++ b/sound/soc/soc-component.c @@ -370,7 +370,7 @@ int snd_soc_component_of_xlate_dai_id(struct snd_soc_component *component, } int snd_soc_component_of_xlate_dai_name(struct snd_soc_component *component, - struct of_phandle_args *args, + const struct of_phandle_args *args, const char **dai_name) { if (component->driver->of_xlate_dai_name) diff --git a/sound/soc/soc-core.c b/sound/soc/soc-core.c index 0cffc9527e28..16ba54eb8164 100644 --- a/sound/soc/soc-core.c +++ b/sound/soc/soc-core.c @@ -2998,7 +2998,7 @@ int snd_soc_get_dai_id(struct device_node *ep) } EXPORT_SYMBOL_GPL(snd_soc_get_dai_id); -int snd_soc_get_dai_name(struct of_phandle_args *args, +int snd_soc_get_dai_name(const struct of_phandle_args *args, const char **dai_name) { struct snd_soc_component *pos; From 13fba3e873b1f21ed3de6596568ef02d31050b6f Mon Sep 17 00:00:00 2001 From: dingsenjie Date: Wed, 24 Feb 2021 16:54:07 +0800 Subject: [PATCH 102/587] ASoC: uniphier: Simplify the return expression of uniphier_aio_startup Simplify the return expression in the aio-cpu.c. Signed-off-by: dingsenjie Link: https://lore.kernel.org/r/20210224085407.22120-1-dingsenjie@163.com Signed-off-by: Mark Brown --- sound/soc/uniphier/aio-cpu.c | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/sound/soc/uniphier/aio-cpu.c b/sound/soc/uniphier/aio-cpu.c index 25c40c28eba4..cf9814130067 100644 --- a/sound/soc/uniphier/aio-cpu.c +++ b/sound/soc/uniphier/aio-cpu.c @@ -256,17 +256,12 @@ static int uniphier_aio_startup(struct snd_pcm_substream *substream, { struct uniphier_aio *aio = uniphier_priv(dai); struct uniphier_aio_sub *sub = &aio->sub[substream->stream]; - int ret; sub->substream = substream; sub->pass_through = 0; sub->use_mmap = true; - ret = aio_init(sub); - if (ret) - return ret; - - return 0; + return aio_init(sub); } static void uniphier_aio_shutdown(struct snd_pcm_substream *substream, From 907e0cdebc1f36623ca8ce6a6376abb1ad56e93d Mon Sep 17 00:00:00 2001 From: Shengjiu Wang Date: Mon, 22 Feb 2021 16:40:20 +0800 Subject: [PATCH 103/587] ASoC: fsl_sai: Add pm qos cpu latency support On SoCs such as i.MX7ULP, cpuidle has some levels which may disable system/bus clocks, so need to add pm_qos to prevent cpuidle from entering low level idles and make sure system/bus clocks are enabled when sai is active. Signed-off-by: Shengjiu Wang Link: https://lore.kernel.org/r/1613983220-5373-1-git-send-email-shengjiu.wang@nxp.com Signed-off-by: Mark Brown --- sound/soc/fsl/fsl_sai.c | 12 ++++++++++++ sound/soc/fsl/fsl_sai.h | 4 ++++ 2 files changed, 16 insertions(+) diff --git a/sound/soc/fsl/fsl_sai.c b/sound/soc/fsl/fsl_sai.c index 5e65b456d3e2..a22679dea578 100644 --- a/sound/soc/fsl/fsl_sai.c +++ b/sound/soc/fsl/fsl_sai.c @@ -10,6 +10,7 @@ #include #include #include +#include #include #include #include @@ -1177,6 +1178,7 @@ static const struct fsl_sai_soc_data fsl_sai_vf610_data = { .fifo_depth = 32, .reg_offset = 0, .mclk0_is_mclk1 = false, + .flags = 0, }; static const struct fsl_sai_soc_data fsl_sai_imx6sx_data = { @@ -1185,6 +1187,7 @@ static const struct fsl_sai_soc_data fsl_sai_imx6sx_data = { .fifo_depth = 32, .reg_offset = 0, .mclk0_is_mclk1 = true, + .flags = 0, }; static const struct fsl_sai_soc_data fsl_sai_imx7ulp_data = { @@ -1193,6 +1196,7 @@ static const struct fsl_sai_soc_data fsl_sai_imx7ulp_data = { .fifo_depth = 16, .reg_offset = 8, .mclk0_is_mclk1 = false, + .flags = PMQOS_CPU_LATENCY, }; static const struct fsl_sai_soc_data fsl_sai_imx8mq_data = { @@ -1201,6 +1205,7 @@ static const struct fsl_sai_soc_data fsl_sai_imx8mq_data = { .fifo_depth = 128, .reg_offset = 8, .mclk0_is_mclk1 = false, + .flags = 0, }; static const struct fsl_sai_soc_data fsl_sai_imx8qm_data = { @@ -1209,6 +1214,7 @@ static const struct fsl_sai_soc_data fsl_sai_imx8qm_data = { .fifo_depth = 64, .reg_offset = 0, .mclk0_is_mclk1 = false, + .flags = 0, }; static const struct of_device_id fsl_sai_ids[] = { @@ -1235,6 +1241,9 @@ static int fsl_sai_runtime_suspend(struct device *dev) clk_disable_unprepare(sai->bus_clk); + if (sai->soc_data->flags & PMQOS_CPU_LATENCY) + cpu_latency_qos_remove_request(&sai->pm_qos_req); + regcache_cache_only(sai->regmap, true); return 0; @@ -1264,6 +1273,9 @@ static int fsl_sai_runtime_resume(struct device *dev) goto disable_tx_clk; } + if (sai->soc_data->flags & PMQOS_CPU_LATENCY) + cpu_latency_qos_add_request(&sai->pm_qos_req, 0); + regcache_cache_only(sai->regmap, false); regcache_mark_dirty(sai->regmap); regmap_write(sai->regmap, FSL_SAI_TCSR(ofs), FSL_SAI_CSR_SR); diff --git a/sound/soc/fsl/fsl_sai.h b/sound/soc/fsl/fsl_sai.h index ff2619f1b214..bc60030967dd 100644 --- a/sound/soc/fsl/fsl_sai.h +++ b/sound/soc/fsl/fsl_sai.h @@ -216,12 +216,15 @@ #define FSL_SAI_MAXBURST_TX 6 #define FSL_SAI_MAXBURST_RX 6 +#define PMQOS_CPU_LATENCY BIT(0) + struct fsl_sai_soc_data { bool use_imx_pcm; bool use_edma; bool mclk0_is_mclk1; unsigned int fifo_depth; unsigned int reg_offset; + unsigned int flags; }; /** @@ -273,6 +276,7 @@ struct fsl_sai { struct snd_dmaengine_dai_dma_data dma_params_tx; struct fsl_sai_verid verid; struct fsl_sai_param param; + struct pm_qos_request pm_qos_req; }; #define TX 1 From ff5687854323533668ec06dd38808bae9a984f68 Mon Sep 17 00:00:00 2001 From: Colin Ian King Date: Mon, 15 Feb 2021 20:05:01 +0000 Subject: [PATCH 104/587] ASoC: codecs: lpass-rx-macro: remove redundant initialization of variable hph_pwr_mode The variable hph_pwr_mode is being initialized with a value that is never read and it is being updated later with a new value. The initialization is redundant and can be removed. Signed-off-by: Colin Ian King Reviewed-by: Srinivas Kandagatla Link: https://lore.kernel.org/r/20210215200501.90697-1-colin.king@canonical.com Signed-off-by: Mark Brown --- sound/soc/codecs/lpass-rx-macro.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sound/soc/codecs/lpass-rx-macro.c b/sound/soc/codecs/lpass-rx-macro.c index 8c04b3b2c907..76909c50d7b9 100644 --- a/sound/soc/codecs/lpass-rx-macro.c +++ b/sound/soc/codecs/lpass-rx-macro.c @@ -2038,7 +2038,7 @@ static int rx_macro_load_compander_coeff(struct snd_soc_component *component, { u16 comp_coeff_lsb_reg, comp_coeff_msb_reg; int i; - int hph_pwr_mode = HPH_LOHIFI; + int hph_pwr_mode; if (!rx->comp_enabled[comp]) return 0; From 1730ef62874dbdc53dc2abfa430f09f0b304bafc Mon Sep 17 00:00:00 2001 From: Colin Ian King Date: Fri, 26 Feb 2021 18:56:53 +0000 Subject: [PATCH 105/587] ASoC: Intel: boards: sof-wm8804: add check for PLL setting Currently the return from snd_soc_dai_set_pll is not checking for failure, this is the only driver in the kernel that ignores this, so it probably should be added for sake of completeness. Fix this by adding an error return check. Addresses-Coverity: ("Unchecked return value") Fixes: f139546fb7d4 ("ASoC: Intel: boards: sof-wm8804: support for Hifiberry Digiplus boards") Signed-off-by: Colin Ian King Acked-by: Pierre-Louis Bossart Link: https://lore.kernel.org/r/20210226185653.1071321-1-colin.king@canonical.com Signed-off-by: Mark Brown --- sound/soc/intel/boards/sof_wm8804.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/sound/soc/intel/boards/sof_wm8804.c b/sound/soc/intel/boards/sof_wm8804.c index a46ba13e8eb0..6a181e45143d 100644 --- a/sound/soc/intel/boards/sof_wm8804.c +++ b/sound/soc/intel/boards/sof_wm8804.c @@ -124,7 +124,11 @@ static int sof_wm8804_hw_params(struct snd_pcm_substream *substream, } snd_soc_dai_set_clkdiv(codec_dai, WM8804_MCLK_DIV, mclk_div); - snd_soc_dai_set_pll(codec_dai, 0, 0, sysclk, mclk_freq); + ret = snd_soc_dai_set_pll(codec_dai, 0, 0, sysclk, mclk_freq); + if (ret < 0) { + dev_err(rtd->card->dev, "Failed to set WM8804 PLL\n"); + return ret; + } ret = snd_soc_dai_set_sysclk(codec_dai, WM8804_TX_CLKSRC_PLL, sysclk, SND_SOC_CLOCK_OUT); From 1372c76802bed271ddcfdd71b6fe3ea9254e6277 Mon Sep 17 00:00:00 2001 From: Kai Vehmanen Date: Wed, 24 Feb 2021 16:15:41 +0200 Subject: [PATCH 106/587] ASoC: SOF: Intel: hda: turn off display power in resume Turn off display power at the end of controller resume flow. This is now possible with the changes done in commit 87fc20e4a0cb ("ASoC: SOF: Intel: hda: use hdac_ext fine-grained link management"). As codec driver is able to request the HDA link to be brought back up, the controller no longer needs to blindly keep display power enabled. Co-developed-by: Sathyanarayana Nujella Signed-off-by: Sathyanarayana Nujella Signed-off-by: Kai Vehmanen Reviewed-by: Ranjani Sridharan Reviewed-by: Keyon Jie Link: https://lore.kernel.org/r/20210224141541.3331254-1-kai.vehmanen@linux.intel.com Signed-off-by: Mark Brown --- sound/soc/sof/intel/hda-dsp.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/sound/soc/sof/intel/hda-dsp.c b/sound/soc/sof/intel/hda-dsp.c index c3b757cf01a0..6e24e1cb13f9 100644 --- a/sound/soc/sof/intel/hda-dsp.c +++ b/sound/soc/sof/intel/hda-dsp.c @@ -678,7 +678,7 @@ static int hda_resume(struct snd_sof_dev *sdev, bool runtime_resume) if (ret < 0) { dev_err(sdev->dev, "error: failed to start controller after resume\n"); - return ret; + goto cleanup; } #if IS_ENABLED(CONFIG_SND_SOC_SOF_HDA) @@ -704,6 +704,10 @@ static int hda_resume(struct snd_sof_dev *sdev, bool runtime_resume) hda_dsp_ctrl_ppcap_enable(sdev, true); hda_dsp_ctrl_ppcap_int_enable(sdev, true); +cleanup: + /* display codec can powered off after controller init */ + hda_codec_i915_display_power(sdev, false); + return 0; } From 5f160cbe76bfdb097ebf5514a4562e8dc658d5d2 Mon Sep 17 00:00:00 2001 From: Viorel Suman Date: Mon, 22 Feb 2021 17:09:50 +0800 Subject: [PATCH 107/587] ASoC: fsl_xcvr: move reset assert into runtime_resume Move reset assert into runtime_resume since we cannot rely on reset assert state when the device is put out from suspend. Signed-off-by: Viorel Suman Signed-off-by: Shengjiu Wang Link: https://lore.kernel.org/r/1613984990-5534-1-git-send-email-shengjiu.wang@nxp.com Signed-off-by: Mark Brown --- sound/soc/fsl/fsl_xcvr.c | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/sound/soc/fsl/fsl_xcvr.c b/sound/soc/fsl/fsl_xcvr.c index 6dd0a5fcd455..c01eb213ea56 100644 --- a/sound/soc/fsl/fsl_xcvr.c +++ b/sound/soc/fsl/fsl_xcvr.c @@ -1243,10 +1243,6 @@ static __maybe_unused int fsl_xcvr_runtime_suspend(struct device *dev) if (ret < 0) dev_err(dev, "Failed to assert M0+ core: %d\n", ret); - ret = reset_control_assert(xcvr->reset); - if (ret < 0) - dev_err(dev, "Failed to assert M0+ reset: %d\n", ret); - regcache_cache_only(xcvr->regmap, true); clk_disable_unprepare(xcvr->spba_clk); @@ -1262,6 +1258,12 @@ static __maybe_unused int fsl_xcvr_runtime_resume(struct device *dev) struct fsl_xcvr *xcvr = dev_get_drvdata(dev); int ret; + ret = reset_control_assert(xcvr->reset); + if (ret < 0) { + dev_err(dev, "Failed to assert M0+ reset: %d\n", ret); + return ret; + } + ret = clk_prepare_enable(xcvr->ipg_clk); if (ret) { dev_err(dev, "failed to start IPG clock.\n"); From 1b99d50b9709a2cddaba4a7faf1862b4f7bec865 Mon Sep 17 00:00:00 2001 From: Cezary Rojewski Date: Mon, 25 Jan 2021 12:54:41 +0100 Subject: [PATCH 108/587] ASoC: Intel: Skylake: Compile when any configuration is selected MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Skylake is dependent on SND_SOC_INTEL_SKYLAKE (aka "all SST platforms") whereas selecting specific configuration such as KBL-only will not cause driver code to compile. Switch to SND_SOC_INTEL_SKYLAKE_COMMON dependency so selecting any configuration causes the driver to be built. Reported-by: Kai-Heng Feng Suggested-by: Amadeusz SÅ‚awiÅ„ski Fixes: 35bc99aaa1a3 ("ASoC: Intel: Skylake: Add more platform granularity") Signed-off-by: Cezary Rojewski Link: https://lore.kernel.org/r/20210125115441.10383-1-cezary.rojewski@intel.com Signed-off-by: Mark Brown --- sound/soc/intel/Makefile | 2 +- sound/soc/intel/skylake/Makefile | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/sound/soc/intel/Makefile b/sound/soc/intel/Makefile index 4e0248d2accc..7c5038803be7 100644 --- a/sound/soc/intel/Makefile +++ b/sound/soc/intel/Makefile @@ -5,7 +5,7 @@ obj-$(CONFIG_SND_SOC) += common/ # Platform Support obj-$(CONFIG_SND_SST_ATOM_HIFI2_PLATFORM) += atom/ obj-$(CONFIG_SND_SOC_INTEL_CATPT) += catpt/ -obj-$(CONFIG_SND_SOC_INTEL_SKYLAKE) += skylake/ +obj-$(CONFIG_SND_SOC_INTEL_SKYLAKE_COMMON) += skylake/ obj-$(CONFIG_SND_SOC_INTEL_KEEMBAY) += keembay/ # Machine support diff --git a/sound/soc/intel/skylake/Makefile b/sound/soc/intel/skylake/Makefile index dd39149b89b1..1c4649bccec5 100644 --- a/sound/soc/intel/skylake/Makefile +++ b/sound/soc/intel/skylake/Makefile @@ -7,7 +7,7 @@ ifdef CONFIG_DEBUG_FS snd-soc-skl-objs += skl-debug.o endif -obj-$(CONFIG_SND_SOC_INTEL_SKYLAKE) += snd-soc-skl.o +obj-$(CONFIG_SND_SOC_INTEL_SKYLAKE_COMMON) += snd-soc-skl.o #Skylake Clock device support snd-soc-skl-ssp-clk-objs := skl-ssp-clk.o From 2b719fd20f327f81270b0ab99159f61da3bbac34 Mon Sep 17 00:00:00 2001 From: Shuming Fan Date: Tue, 23 Feb 2021 17:07:59 +0800 Subject: [PATCH 109/587] ASoC: rt1316: Add RT1316 SDCA vendor-specific driver This is the initial amplifier driver for rt1316 SDCA version. Signed-off-by: Shuming Fan Link: https://lore.kernel.org/r/20210223090759.15323-1-shumingf@realtek.com Signed-off-by: Mark Brown --- sound/soc/codecs/Kconfig | 6 + sound/soc/codecs/Makefile | 2 + sound/soc/codecs/rt1316-sdw.c | 744 ++++++++++++++++++++++++++++++++++ sound/soc/codecs/rt1316-sdw.h | 55 +++ 4 files changed, 807 insertions(+) create mode 100644 sound/soc/codecs/rt1316-sdw.c create mode 100644 sound/soc/codecs/rt1316-sdw.h diff --git a/sound/soc/codecs/Kconfig b/sound/soc/codecs/Kconfig index 1c87b42606c9..0eb9f06660e7 100644 --- a/sound/soc/codecs/Kconfig +++ b/sound/soc/codecs/Kconfig @@ -182,6 +182,7 @@ config SND_SOC_ALL_CODECS imply SND_SOC_RT711_SDW imply SND_SOC_RT715_SDW imply SND_SOC_RT1308_SDW + imply SND_SOC_RT1316_SDW imply SND_SOC_SGTL5000 imply SND_SOC_SI476X imply SND_SOC_SIMPLE_AMPLIFIER @@ -1143,6 +1144,11 @@ config SND_SOC_RT1308_SDW depends on I2C && SOUNDWIRE select REGMAP_SOUNDWIRE +config SND_SOC_RT1316_SDW + tristate "Realtek RT1316 Codec - SDW" + depends on SOUNDWIRE + select REGMAP_SOUNDWIRE + config SND_SOC_RT5514 tristate depends on I2C diff --git a/sound/soc/codecs/Makefile b/sound/soc/codecs/Makefile index 81357dc62ea0..1585bc1d9a25 100644 --- a/sound/soc/codecs/Makefile +++ b/sound/soc/codecs/Makefile @@ -173,6 +173,7 @@ snd-soc-rt1015p-objs := rt1015p.o snd-soc-rt1305-objs := rt1305.o snd-soc-rt1308-objs := rt1308.o snd-soc-rt1308-sdw-objs := rt1308-sdw.o +snd-soc-rt1316-sdw-objs := rt1316-sdw.o snd-soc-rt274-objs := rt274.o snd-soc-rt286-objs := rt286.o snd-soc-rt298-objs := rt298.o @@ -487,6 +488,7 @@ obj-$(CONFIG_SND_SOC_RT1015P) += snd-soc-rt1015p.o obj-$(CONFIG_SND_SOC_RT1305) += snd-soc-rt1305.o obj-$(CONFIG_SND_SOC_RT1308) += snd-soc-rt1308.o obj-$(CONFIG_SND_SOC_RT1308_SDW) += snd-soc-rt1308-sdw.o +obj-$(CONFIG_SND_SOC_RT1316_SDW) += snd-soc-rt1316-sdw.o obj-$(CONFIG_SND_SOC_RT274) += snd-soc-rt274.o obj-$(CONFIG_SND_SOC_RT286) += snd-soc-rt286.o obj-$(CONFIG_SND_SOC_RT298) += snd-soc-rt298.o diff --git a/sound/soc/codecs/rt1316-sdw.c b/sound/soc/codecs/rt1316-sdw.c new file mode 100644 index 000000000000..a6fb34a48f33 --- /dev/null +++ b/sound/soc/codecs/rt1316-sdw.c @@ -0,0 +1,744 @@ +// SPDX-License-Identifier: GPL-2.0-only +// +// rt1316-sdw.c -- rt1316 SDCA ALSA SoC amplifier audio driver +// +// Copyright(c) 2021 Realtek Semiconductor Corp. +// +// +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "rt1316-sdw.h" + +static const struct reg_default rt1316_reg_defaults[] = { + { 0x3004, 0x00 }, + { 0x3005, 0x00 }, + { 0x3206, 0x00 }, + { 0xc001, 0x00 }, + { 0xc002, 0x00 }, + { 0xc003, 0x00 }, + { 0xc004, 0x00 }, + { 0xc005, 0x00 }, + { 0xc006, 0x00 }, + { 0xc007, 0x00 }, + { 0xc008, 0x00 }, + { 0xc009, 0x00 }, + { 0xc00a, 0x00 }, + { 0xc00b, 0x00 }, + { 0xc00c, 0x00 }, + { 0xc00d, 0x00 }, + { 0xc00e, 0x00 }, + { 0xc00f, 0x00 }, + { 0xc010, 0xa5 }, + { 0xc011, 0x00 }, + { 0xc012, 0xff }, + { 0xc013, 0xff }, + { 0xc014, 0x40 }, + { 0xc015, 0x00 }, + { 0xc016, 0x00 }, + { 0xc017, 0x00 }, + { 0xc605, 0x30 }, + { 0xc700, 0x0a }, + { 0xc701, 0xaa }, + { 0xc702, 0x1a }, + { 0xc703, 0x0a }, + { 0xc710, 0x80 }, + { 0xc711, 0x00 }, + { 0xc712, 0x3e }, + { 0xc713, 0x80 }, + { 0xc714, 0x80 }, + { 0xc715, 0x06 }, + { 0xd101, 0x00 }, + { 0xd102, 0x30 }, + { 0xd103, 0x00 }, + { SDW_SDCA_CTL(FUNC_NUM_SMART_AMP, RT1316_SDCA_ENT_UDMPU21, RT1316_SDCA_CTL_UDMPU_CLUSTER, 0), 0x00 }, + { SDW_SDCA_CTL(FUNC_NUM_SMART_AMP, RT1316_SDCA_ENT_FU21, RT1316_SDCA_CTL_FU_MUTE, CH_L), 0x01 }, + { SDW_SDCA_CTL(FUNC_NUM_SMART_AMP, RT1316_SDCA_ENT_FU21, RT1316_SDCA_CTL_FU_MUTE, CH_R), 0x01 }, + { SDW_SDCA_CTL(FUNC_NUM_SMART_AMP, RT1316_SDCA_ENT_XU24, RT1316_SDCA_CTL_BYPASS, 0), 0x01 }, + { SDW_SDCA_CTL(FUNC_NUM_SMART_AMP, RT1316_SDCA_ENT_PDE23, RT1316_SDCA_CTL_REQ_POWER_STATE, 0), 0x03 }, + { SDW_SDCA_CTL(FUNC_NUM_SMART_AMP, RT1316_SDCA_ENT_PDE22, RT1316_SDCA_CTL_REQ_POWER_STATE, 0), 0x03 }, + { SDW_SDCA_CTL(FUNC_NUM_SMART_AMP, RT1316_SDCA_ENT_PDE24, RT1316_SDCA_CTL_REQ_POWER_STATE, 0), 0x03 }, +}; + +static const struct reg_sequence rt1316_blind_write[] = { + { 0xc710, 0x17 }, + { 0xc711, 0x80 }, + { 0xc712, 0x26 }, + { 0xc713, 0x06 }, + { 0xc714, 0x80 }, + { 0xc715, 0x06 }, + { 0xc702, 0x0a }, + { 0xc703, 0x0a }, + { 0xc001, 0x45 }, + { 0xc003, 0x00 }, + { 0xc004, 0x11 }, + { 0xc005, 0x00 }, + { 0xc006, 0x00 }, + { 0xc106, 0x00 }, + { 0xc007, 0x11 }, + { 0xc008, 0x11 }, + { 0xc009, 0x00 }, + + { 0x2f0a, 0x00 }, + { 0xd101, 0xf0 }, + { 0xd103, 0x9b }, + { 0x2f36, 0x8e }, + { 0x3206, 0x80 }, + { 0x3211, 0x0b }, + { 0x3216, 0x06 }, + { 0xc614, 0x20 }, + { 0xc615, 0x0a }, + { 0xc616, 0x02 }, + { 0xc617, 0x00 }, + { 0xc60b, 0x10 }, + { 0xc60e, 0x05 }, + { 0xc102, 0x00 }, + { 0xc090, 0xb0 }, + { 0xc00f, 0x01 }, + { 0xc09c, 0x7b }, + + { 0xc602, 0x07 }, + { 0xc603, 0x07 }, + { 0xc0a3, 0x71 }, + { 0xc00b, 0x30 }, + { 0xc093, 0x80 }, + { 0xc09d, 0x80 }, + { 0xc0b0, 0x77 }, + { 0xc010, 0xa5 }, + { 0xc050, 0x83 }, + { 0x2f55, 0x03 }, + { 0x3217, 0xb5 }, + { 0x3202, 0x02 }, + + { SDW_SDCA_CTL(FUNC_NUM_SMART_AMP, RT1316_SDCA_ENT_XU24, RT1316_SDCA_CTL_BYPASS, 0), 0x00 }, + + /* for IV sense */ + { 0x2232, 0x80 }, + { 0xc0b0, 0x77 }, + { 0xc011, 0x00 }, + { 0xc020, 0x00 }, + { 0xc023, 0x00 }, + { 0x3101, 0x00 }, + { 0x3004, 0xa0 }, + { 0x3005, 0xb1 }, + { 0xc007, 0x11 }, + { 0xc008, 0x11 }, + { 0xc009, 0x00 }, + { 0xc022, 0xd6 }, + { 0xc025, 0xd6 }, + + { 0xd001, 0x03 }, + { 0xd002, 0xbf }, + { 0xd003, 0x03 }, + { 0xd004, 0xbf }, +}; + +static bool rt1316_readable_register(struct device *dev, unsigned int reg) +{ + switch (reg) { + case 0x2f0a: + case 0x2f36: + case 0x3203 ... 0x320e: + case 0xc000 ... 0xc7b4: + case 0xcf00 ... 0xcf03: + case 0xd101 ... 0xd103: + case SDW_SDCA_CTL(FUNC_NUM_SMART_AMP, RT1316_SDCA_ENT_UDMPU21, RT1316_SDCA_CTL_UDMPU_CLUSTER, 0): + case SDW_SDCA_CTL(FUNC_NUM_SMART_AMP, RT1316_SDCA_ENT_FU21, RT1316_SDCA_CTL_FU_MUTE, CH_L): + case SDW_SDCA_CTL(FUNC_NUM_SMART_AMP, RT1316_SDCA_ENT_FU21, RT1316_SDCA_CTL_FU_MUTE, CH_R): + case SDW_SDCA_CTL(FUNC_NUM_SMART_AMP, RT1316_SDCA_ENT_PDE23, RT1316_SDCA_CTL_REQ_POWER_STATE, 0): + case SDW_SDCA_CTL(FUNC_NUM_SMART_AMP, RT1316_SDCA_ENT_PDE27, RT1316_SDCA_CTL_REQ_POWER_STATE, 0): + case SDW_SDCA_CTL(FUNC_NUM_SMART_AMP, RT1316_SDCA_ENT_PDE22, RT1316_SDCA_CTL_REQ_POWER_STATE, 0): + case SDW_SDCA_CTL(FUNC_NUM_SMART_AMP, RT1316_SDCA_ENT_PDE24, RT1316_SDCA_CTL_REQ_POWER_STATE, 0): + return true; + default: + return false; + } +} + +static bool rt1316_volatile_register(struct device *dev, unsigned int reg) +{ + switch (reg) { + case 0xc000: + case 0xc093: + case 0xc09d: + case 0xc0a3: + case 0xc201: + case 0xc427 ... 0xc428: + case 0xd102: + return true; + default: + return false; + } +} + +static const struct regmap_config rt1316_sdw_regmap = { + .reg_bits = 32, + .val_bits = 8, + .readable_reg = rt1316_readable_register, + .volatile_reg = rt1316_volatile_register, + .max_register = 0x4108ffff, + .reg_defaults = rt1316_reg_defaults, + .num_reg_defaults = ARRAY_SIZE(rt1316_reg_defaults), + .cache_type = REGCACHE_RBTREE, + .use_single_read = true, + .use_single_write = true, +}; + +static int rt1316_read_prop(struct sdw_slave *slave) +{ + struct sdw_slave_prop *prop = &slave->prop; + int nval; + int i, j; + u32 bit; + unsigned long addr; + struct sdw_dpn_prop *dpn; + + prop->scp_int1_mask = SDW_SCP_INT1_BUS_CLASH | SDW_SCP_INT1_PARITY; + prop->quirks = SDW_SLAVE_QUIRKS_INVALID_INITIAL_PARITY; + prop->is_sdca = true; + + prop->paging_support = true; + + /* first we need to allocate memory for set bits in port lists */ + prop->source_ports = 0x04; /* BITMAP: 00000100 */ + prop->sink_ports = 0x2; /* BITMAP: 00000010 */ + + nval = hweight32(prop->source_ports); + prop->src_dpn_prop = devm_kcalloc(&slave->dev, nval, + sizeof(*prop->src_dpn_prop), GFP_KERNEL); + if (!prop->src_dpn_prop) + return -ENOMEM; + + i = 0; + dpn = prop->src_dpn_prop; + addr = prop->source_ports; + for_each_set_bit(bit, &addr, 32) { + dpn[i].num = bit; + dpn[i].type = SDW_DPN_FULL; + dpn[i].simple_ch_prep_sm = true; + dpn[i].ch_prep_timeout = 10; + i++; + } + + /* do this again for sink now */ + nval = hweight32(prop->sink_ports); + prop->sink_dpn_prop = devm_kcalloc(&slave->dev, nval, + sizeof(*prop->sink_dpn_prop), GFP_KERNEL); + if (!prop->sink_dpn_prop) + return -ENOMEM; + + j = 0; + dpn = prop->sink_dpn_prop; + addr = prop->sink_ports; + for_each_set_bit(bit, &addr, 32) { + dpn[j].num = bit; + dpn[j].type = SDW_DPN_FULL; + dpn[j].simple_ch_prep_sm = true; + dpn[j].ch_prep_timeout = 10; + j++; + } + + /* set the timeout values */ + prop->clk_stop_timeout = 20; + + dev_dbg(&slave->dev, "%s\n", __func__); + + return 0; +} + +static int rt1316_io_init(struct device *dev, struct sdw_slave *slave) +{ + struct rt1316_sdw_priv *rt1316 = dev_get_drvdata(dev); + + if (rt1316->hw_init) + return 0; + + if (rt1316->first_hw_init) { + regcache_cache_only(rt1316->regmap, false); + regcache_cache_bypass(rt1316->regmap, true); + } else { + /* + * PM runtime is only enabled when a Slave reports as Attached + */ + + /* set autosuspend parameters */ + pm_runtime_set_autosuspend_delay(&slave->dev, 3000); + pm_runtime_use_autosuspend(&slave->dev); + + /* update count of parent 'active' children */ + pm_runtime_set_active(&slave->dev); + + /* make sure the device does not suspend immediately */ + pm_runtime_mark_last_busy(&slave->dev); + + pm_runtime_enable(&slave->dev); + } + + pm_runtime_get_noresume(&slave->dev); + + /* sw reset */ + regmap_write(rt1316->regmap, 0xc000, 0x02); + + /* initial settings - blind write */ + regmap_multi_reg_write(rt1316->regmap, rt1316_blind_write, + ARRAY_SIZE(rt1316_blind_write)); + + if (rt1316->first_hw_init) { + regcache_cache_bypass(rt1316->regmap, false); + regcache_mark_dirty(rt1316->regmap); + } else + rt1316->first_hw_init = true; + + /* Mark Slave initialization complete */ + rt1316->hw_init = true; + + pm_runtime_mark_last_busy(&slave->dev); + pm_runtime_put_autosuspend(&slave->dev); + + dev_dbg(&slave->dev, "%s hw_init complete\n", __func__); + return 0; +} + +static int rt1316_update_status(struct sdw_slave *slave, + enum sdw_slave_status status) +{ + struct rt1316_sdw_priv *rt1316 = dev_get_drvdata(&slave->dev); + + /* Update the status */ + rt1316->status = status; + + if (status == SDW_SLAVE_UNATTACHED) + rt1316->hw_init = false; + + /* + * Perform initialization only if slave status is present and + * hw_init flag is false + */ + if (rt1316->hw_init || rt1316->status != SDW_SLAVE_ATTACHED) + return 0; + + /* perform I/O transfers required for Slave initialization */ + return rt1316_io_init(&slave->dev, slave); +} + +static int rt1316_classd_event(struct snd_soc_dapm_widget *w, + struct snd_kcontrol *kcontrol, int event) +{ + struct snd_soc_component *component = + snd_soc_dapm_to_component(w->dapm); + struct rt1316_sdw_priv *rt1316 = snd_soc_component_get_drvdata(component); + unsigned char ps0 = 0x0, ps3 = 0x3; + + switch (event) { + case SND_SOC_DAPM_POST_PMU: + regmap_write(rt1316->regmap, + SDW_SDCA_CTL(FUNC_NUM_SMART_AMP, RT1316_SDCA_ENT_PDE23, + RT1316_SDCA_CTL_REQ_POWER_STATE, 0), + ps0); + regmap_write(rt1316->regmap, + SDW_SDCA_CTL(FUNC_NUM_SMART_AMP, RT1316_SDCA_ENT_PDE27, + RT1316_SDCA_CTL_REQ_POWER_STATE, 0), + ps0); + regmap_write(rt1316->regmap, + SDW_SDCA_CTL(FUNC_NUM_SMART_AMP, RT1316_SDCA_ENT_PDE22, + RT1316_SDCA_CTL_REQ_POWER_STATE, 0), + ps0); + break; + case SND_SOC_DAPM_PRE_PMD: + regmap_write(rt1316->regmap, + SDW_SDCA_CTL(FUNC_NUM_SMART_AMP, RT1316_SDCA_ENT_PDE23, + RT1316_SDCA_CTL_REQ_POWER_STATE, 0), + ps3); + regmap_write(rt1316->regmap, + SDW_SDCA_CTL(FUNC_NUM_SMART_AMP, RT1316_SDCA_ENT_PDE27, + RT1316_SDCA_CTL_REQ_POWER_STATE, 0), + ps3); + regmap_write(rt1316->regmap, + SDW_SDCA_CTL(FUNC_NUM_SMART_AMP, RT1316_SDCA_ENT_PDE22, + RT1316_SDCA_CTL_REQ_POWER_STATE, 0), + ps3); + break; + + default: + break; + } + + return 0; +} + +static int rt1316_pde24_event(struct snd_soc_dapm_widget *w, + struct snd_kcontrol *kcontrol, int event) +{ + struct snd_soc_component *component = + snd_soc_dapm_to_component(w->dapm); + struct rt1316_sdw_priv *rt1316 = snd_soc_component_get_drvdata(component); + unsigned char ps0 = 0x0, ps3 = 0x3; + + switch (event) { + case SND_SOC_DAPM_POST_PMU: + regmap_write(rt1316->regmap, + SDW_SDCA_CTL(FUNC_NUM_SMART_AMP, RT1316_SDCA_ENT_PDE24, + RT1316_SDCA_CTL_REQ_POWER_STATE, 0), + ps0); + break; + case SND_SOC_DAPM_PRE_PMD: + regmap_write(rt1316->regmap, + SDW_SDCA_CTL(FUNC_NUM_SMART_AMP, RT1316_SDCA_ENT_PDE24, + RT1316_SDCA_CTL_REQ_POWER_STATE, 0), + ps3); + break; + } + return 0; +} + +static const char * const rt1316_rx_data_ch_select[] = { + "L,R", + "L,L", + "L,R", + "L,L+R", + "R,L", + "R,R", + "R,L+R", + "L+R,L", + "L+R,R", + "L+R,L+R", +}; + +static SOC_ENUM_SINGLE_DECL(rt1316_rx_data_ch_enum, + SDW_SDCA_CTL(FUNC_NUM_SMART_AMP, RT1316_SDCA_ENT_UDMPU21, RT1316_SDCA_CTL_UDMPU_CLUSTER, 0), 0, + rt1316_rx_data_ch_select); + +static const struct snd_kcontrol_new rt1316_snd_controls[] = { + + /* I2S Data Channel Selection */ + SOC_ENUM("RX Channel Select", rt1316_rx_data_ch_enum), + + /* XU24 Bypass Control */ + SOC_SINGLE("XU24 Bypass Switch", + SDW_SDCA_CTL(FUNC_NUM_SMART_AMP, RT1316_SDCA_ENT_XU24, RT1316_SDCA_CTL_BYPASS, 0), 0, 1, 0), + + /* Left/Right IV tag */ + SOC_SINGLE("Left V Tag Select", 0x3004, 0, 7, 0), + SOC_SINGLE("Left I Tag Select", 0x3004, 4, 7, 0), + SOC_SINGLE("Right V Tag Select", 0x3005, 0, 7, 0), + SOC_SINGLE("Right I Tag Select", 0x3005, 4, 7, 0), + + /* IV mixer Control */ + SOC_DOUBLE("Isense Mixer Switch", 0xc605, 2, 0, 1, 1), + SOC_DOUBLE("Vsense Mixer Switch", 0xc605, 3, 1, 1, 1), +}; + +static const struct snd_kcontrol_new rt1316_sto_dac = + SOC_DAPM_DOUBLE_R("Switch", + SDW_SDCA_CTL(FUNC_NUM_SMART_AMP, RT1316_SDCA_ENT_FU21, RT1316_SDCA_CTL_FU_MUTE, CH_L), + SDW_SDCA_CTL(FUNC_NUM_SMART_AMP, RT1316_SDCA_ENT_FU21, RT1316_SDCA_CTL_FU_MUTE, CH_R), + 0, 1, 1); + +static const struct snd_soc_dapm_widget rt1316_dapm_widgets[] = { + /* Audio Interface */ + SND_SOC_DAPM_AIF_IN("DP1RX", "DP1 Playback", 0, SND_SOC_NOPM, 0, 0), + SND_SOC_DAPM_AIF_OUT("DP2TX", "DP2 Capture", 0, SND_SOC_NOPM, 0, 0), + + /* Digital Interface */ + SND_SOC_DAPM_SWITCH("DAC", SND_SOC_NOPM, 0, 0, &rt1316_sto_dac), + + /* Output Lines */ + SND_SOC_DAPM_PGA_E("CLASS D", SND_SOC_NOPM, 0, 0, NULL, 0, + rt1316_classd_event, + SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMU), + SND_SOC_DAPM_OUTPUT("SPOL"), + SND_SOC_DAPM_OUTPUT("SPOR"), + + SND_SOC_DAPM_SUPPLY("PDE 24", SND_SOC_NOPM, 0, 0, + rt1316_pde24_event, + SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD), + SND_SOC_DAPM_PGA("I Sense", SND_SOC_NOPM, 0, 0, NULL, 0), + SND_SOC_DAPM_PGA("V Sense", SND_SOC_NOPM, 0, 0, NULL, 0), + SND_SOC_DAPM_SIGGEN("I Gen"), + SND_SOC_DAPM_SIGGEN("V Gen"), +}; + +static const struct snd_soc_dapm_route rt1316_dapm_routes[] = { + { "DAC", "Switch", "DP1RX" }, + { "CLASS D", NULL, "DAC" }, + { "SPOL", NULL, "CLASS D" }, + { "SPOR", NULL, "CLASS D" }, + + { "I Sense", NULL, "I Gen" }, + { "V Sense", NULL, "V Gen" }, + { "I Sense", NULL, "PDE 24" }, + { "V Sense", NULL, "PDE 24" }, + { "DP2TX", NULL, "I Sense" }, + { "DP2TX", NULL, "V Sense" }, +}; + +static int rt1316_set_sdw_stream(struct snd_soc_dai *dai, void *sdw_stream, + int direction) +{ + struct sdw_stream_data *stream; + + if (!sdw_stream) + return 0; + + stream = kzalloc(sizeof(*stream), GFP_KERNEL); + if (!stream) + return -ENOMEM; + + stream->sdw_stream = sdw_stream; + + /* Use tx_mask or rx_mask to configure stream tag and set dma_data */ + if (direction == SNDRV_PCM_STREAM_PLAYBACK) + dai->playback_dma_data = stream; + else + dai->capture_dma_data = stream; + + return 0; +} + +static void rt1316_sdw_shutdown(struct snd_pcm_substream *substream, + struct snd_soc_dai *dai) +{ + struct sdw_stream_data *stream; + + stream = snd_soc_dai_get_dma_data(dai, substream); + snd_soc_dai_set_dma_data(dai, substream, NULL); + kfree(stream); +} + +static int rt1316_sdw_hw_params(struct snd_pcm_substream *substream, + struct snd_pcm_hw_params *params, struct snd_soc_dai *dai) +{ + struct snd_soc_component *component = dai->component; + struct rt1316_sdw_priv *rt1316 = + snd_soc_component_get_drvdata(component); + struct sdw_stream_config stream_config; + struct sdw_port_config port_config; + enum sdw_data_direction direction; + struct sdw_stream_data *stream; + int retval, port, num_channels, ch_mask; + + dev_dbg(dai->dev, "%s %s", __func__, dai->name); + stream = snd_soc_dai_get_dma_data(dai, substream); + + if (!stream) + return -EINVAL; + + if (!rt1316->sdw_slave) + return -EINVAL; + + /* SoundWire specific configuration */ + /* port 1 for playback */ + if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { + direction = SDW_DATA_DIR_RX; + port = 1; + } else { + direction = SDW_DATA_DIR_TX; + port = 2; + } + + num_channels = params_channels(params); + ch_mask = (1 << num_channels) - 1; + + stream_config.frame_rate = params_rate(params); + stream_config.ch_count = num_channels; + stream_config.bps = snd_pcm_format_width(params_format(params)); + stream_config.direction = direction; + + port_config.ch_mask = ch_mask; + port_config.num = port; + + retval = sdw_stream_add_slave(rt1316->sdw_slave, &stream_config, + &port_config, 1, stream->sdw_stream); + if (retval) { + dev_err(dai->dev, "Unable to configure port\n"); + return retval; + } + + return 0; +} + +static int rt1316_sdw_pcm_hw_free(struct snd_pcm_substream *substream, + struct snd_soc_dai *dai) +{ + struct snd_soc_component *component = dai->component; + struct rt1316_sdw_priv *rt1316 = + snd_soc_component_get_drvdata(component); + struct sdw_stream_data *stream = + snd_soc_dai_get_dma_data(dai, substream); + + if (!rt1316->sdw_slave) + return -EINVAL; + + sdw_stream_remove_slave(rt1316->sdw_slave, stream->sdw_stream); + return 0; +} + +/* + * slave_ops: callbacks for get_clock_stop_mode, clock_stop and + * port_prep are not defined for now + */ +static struct sdw_slave_ops rt1316_slave_ops = { + .read_prop = rt1316_read_prop, + .update_status = rt1316_update_status, +}; + +static const struct snd_soc_component_driver soc_component_sdw_rt1316 = { + .controls = rt1316_snd_controls, + .num_controls = ARRAY_SIZE(rt1316_snd_controls), + .dapm_widgets = rt1316_dapm_widgets, + .num_dapm_widgets = ARRAY_SIZE(rt1316_dapm_widgets), + .dapm_routes = rt1316_dapm_routes, + .num_dapm_routes = ARRAY_SIZE(rt1316_dapm_routes), +}; + +static const struct snd_soc_dai_ops rt1316_aif_dai_ops = { + .hw_params = rt1316_sdw_hw_params, + .hw_free = rt1316_sdw_pcm_hw_free, + .set_sdw_stream = rt1316_set_sdw_stream, + .shutdown = rt1316_sdw_shutdown, +}; + +#define RT1316_STEREO_RATES SNDRV_PCM_RATE_48000 +#define RT1316_FORMATS (SNDRV_PCM_FMTBIT_S20_3LE | SNDRV_PCM_FMTBIT_S16_LE | \ + SNDRV_PCM_FMTBIT_S24_LE) + +static struct snd_soc_dai_driver rt1316_sdw_dai[] = { + { + .name = "rt1316-aif", + .playback = { + .stream_name = "DP1 Playback", + .channels_min = 1, + .channels_max = 2, + .rates = RT1316_STEREO_RATES, + .formats = RT1316_FORMATS, + }, + .capture = { + .stream_name = "DP2 Capture", + .channels_min = 1, + .channels_max = 2, + .rates = RT1316_STEREO_RATES, + .formats = RT1316_FORMATS, + }, + .ops = &rt1316_aif_dai_ops, + }, +}; + +static int rt1316_sdw_init(struct device *dev, struct regmap *regmap, + struct sdw_slave *slave) +{ + struct rt1316_sdw_priv *rt1316; + int ret; + + rt1316 = devm_kzalloc(dev, sizeof(*rt1316), GFP_KERNEL); + if (!rt1316) + return -ENOMEM; + + dev_set_drvdata(dev, rt1316); + rt1316->sdw_slave = slave; + rt1316->regmap = regmap; + + /* + * Mark hw_init to false + * HW init will be performed when device reports present + */ + rt1316->hw_init = false; + rt1316->first_hw_init = false; + + ret = devm_snd_soc_register_component(dev, + &soc_component_sdw_rt1316, + rt1316_sdw_dai, + ARRAY_SIZE(rt1316_sdw_dai)); + + dev_dbg(&slave->dev, "%s\n", __func__); + + return ret; +} + +static int rt1316_sdw_probe(struct sdw_slave *slave, + const struct sdw_device_id *id) +{ + struct regmap *regmap; + + /* Regmap Initialization */ + regmap = devm_regmap_init_sdw(slave, &rt1316_sdw_regmap); + if (!regmap) + return -EINVAL; + + return rt1316_sdw_init(&slave->dev, regmap, slave); +} + +static const struct sdw_device_id rt1316_id[] = { + SDW_SLAVE_ENTRY_EXT(0x025d, 0x1316, 0x3, 0x1, 0), + {}, +}; +MODULE_DEVICE_TABLE(sdw, rt1316_id); + +static int __maybe_unused rt1316_dev_suspend(struct device *dev) +{ + struct rt1316_sdw_priv *rt1316 = dev_get_drvdata(dev); + + if (!rt1316->hw_init) + return 0; + + regcache_cache_only(rt1316->regmap, true); + + return 0; +} + +#define RT1316_PROBE_TIMEOUT 5000 + +static int __maybe_unused rt1316_dev_resume(struct device *dev) +{ + struct sdw_slave *slave = dev_to_sdw_dev(dev); + struct rt1316_sdw_priv *rt1316 = dev_get_drvdata(dev); + unsigned long time; + + if (!rt1316->hw_init) + return 0; + + if (!slave->unattach_request) + goto regmap_sync; + + time = wait_for_completion_timeout(&slave->initialization_complete, + msecs_to_jiffies(RT1316_PROBE_TIMEOUT)); + if (!time) { + dev_err(&slave->dev, "Initialization not complete, timed out\n"); + return -ETIMEDOUT; + } + +regmap_sync: + slave->unattach_request = 0; + regcache_cache_only(rt1316->regmap, false); + regcache_sync(rt1316->regmap); + + return 0; +} + +static const struct dev_pm_ops rt1316_pm = { + SET_SYSTEM_SLEEP_PM_OPS(rt1316_dev_suspend, rt1316_dev_resume) + SET_RUNTIME_PM_OPS(rt1316_dev_suspend, rt1316_dev_resume, NULL) +}; + +static struct sdw_driver rt1316_sdw_driver = { + .driver = { + .name = "rt1316-sdca", + .owner = THIS_MODULE, + .pm = &rt1316_pm, + }, + .probe = rt1316_sdw_probe, + .ops = &rt1316_slave_ops, + .id_table = rt1316_id, +}; +module_sdw_driver(rt1316_sdw_driver); + +MODULE_DESCRIPTION("ASoC RT1316 driver SDCA SDW"); +MODULE_AUTHOR("Shuming Fan "); +MODULE_LICENSE("GPL"); diff --git a/sound/soc/codecs/rt1316-sdw.h b/sound/soc/codecs/rt1316-sdw.h new file mode 100644 index 000000000000..cbcdaa8f8cfa --- /dev/null +++ b/sound/soc/codecs/rt1316-sdw.h @@ -0,0 +1,55 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * rt1316-sdw.h -- RT1316 SDCA ALSA SoC audio driver header + * + * Copyright(c) 2021 Realtek Semiconductor Corp. + */ + +#ifndef __RT1316_SDW_H__ +#define __RT1316_SDW_H__ + +#include +#include +#include +#include +#include + +/* RT1316 SDCA Control - function number */ +#define FUNC_NUM_SMART_AMP 0x04 + +/* RT1316 SDCA entity */ +#define RT1316_SDCA_ENT_PDE23 0x31 +#define RT1316_SDCA_ENT_PDE27 0x32 +#define RT1316_SDCA_ENT_PDE22 0x33 +#define RT1316_SDCA_ENT_PDE24 0x34 +#define RT1316_SDCA_ENT_XU24 0x24 +#define RT1316_SDCA_ENT_FU21 0x03 +#define RT1316_SDCA_ENT_UDMPU21 0x02 + +/* RT1316 SDCA control */ +#define RT1316_SDCA_CTL_SAMPLE_FREQ_INDEX 0x10 +#define RT1316_SDCA_CTL_REQ_POWER_STATE 0x01 +#define RT1316_SDCA_CTL_BYPASS 0x01 +#define RT1316_SDCA_CTL_FU_MUTE 0x01 +#define RT1316_SDCA_CTL_FU_VOLUME 0x02 +#define RT1316_SDCA_CTL_UDMPU_CLUSTER 0x10 + +/* RT1316 SDCA channel */ +#define CH_L 0x01 +#define CH_R 0x02 + +struct rt1316_sdw_priv { + struct snd_soc_component *component; + struct regmap *regmap; + struct sdw_slave *sdw_slave; + enum sdw_slave_status status; + struct sdw_bus_params params; + bool hw_init; + bool first_hw_init; +}; + +struct sdw_stream_data { + struct sdw_stream_runtime *sdw_stream; +}; + +#endif /* __RT1316_SDW_H__ */ From 99ac2f8d1508f31ecf28d5af0ce384bf0a033f90 Mon Sep 17 00:00:00 2001 From: Codrin Ciubotariu Date: Mon, 1 Mar 2021 19:09:00 +0200 Subject: [PATCH 110/587] ASoC: mchp-i2s-mcc: Add compatible for SAMA7G5 Microchip's new SAMA7G5 includes an updated I2S-MCC compatible with the previous version found on SAM9X60. The new controller includes 8 (4 * 2) input and output data pins for up to 8 channels for I2S and Left-Justified formats. Signed-off-by: Codrin Ciubotariu Link: https://lore.kernel.org/r/20210301170905.835091-3-codrin.ciubotariu@microchip.com Signed-off-by: Mark Brown --- sound/soc/atmel/Kconfig | 3 +++ sound/soc/atmel/mchp-i2s-mcc.c | 3 +++ 2 files changed, 6 insertions(+) diff --git a/sound/soc/atmel/Kconfig b/sound/soc/atmel/Kconfig index 9fe9471f4514..ec04e3386bc0 100644 --- a/sound/soc/atmel/Kconfig +++ b/sound/soc/atmel/Kconfig @@ -127,10 +127,13 @@ config SND_MCHP_SOC_I2S_MCC Say Y or M if you want to add support for I2S Multi-Channel ASoC driver on the following Microchip platforms: - sam9x60 + - sama7g5 The I2SMCC complies with the Inter-IC Sound (I2S) bus specification and supports a Time Division Multiplexed (TDM) interface with external multi-channel audio codecs. + Starting with sama7g5, I2S and Left-Justified multi-channel is + supported by using multiple data pins, output and input, without TDM. config SND_MCHP_SOC_SPDIFTX tristate "Microchip ASoC driver for boards using S/PDIF TX" diff --git a/sound/soc/atmel/mchp-i2s-mcc.c b/sound/soc/atmel/mchp-i2s-mcc.c index 6d5ae18f8b38..0ee01383e307 100644 --- a/sound/soc/atmel/mchp-i2s-mcc.c +++ b/sound/soc/atmel/mchp-i2s-mcc.c @@ -873,6 +873,9 @@ static const struct of_device_id mchp_i2s_mcc_dt_ids[] = { { .compatible = "microchip,sam9x60-i2smcc", }, + { + .compatible = "microchip,sama7g5-i2smcc", + }, { /* sentinel */ } }; MODULE_DEVICE_TABLE(of, mchp_i2s_mcc_dt_ids); From 13c1629d758aae97f329d25714e26edde4e5cf3e Mon Sep 17 00:00:00 2001 From: Codrin Ciubotariu Date: Mon, 1 Mar 2021 19:09:01 +0200 Subject: [PATCH 111/587] ASoC: mchp-i2s-mcc: Add multi-channel support for I2S and LEFT_J formats The latest I2S-MCC available in SAMA7G5 supports multi-channel for I2S and Left-Justified formats. For this, the new version uses 8 (4 * 2) input and output pins, with each pin being responsible for 2 channels. This sums up to a total of 8 channels for synchronous capture and playback. Signed-off-by: Codrin Ciubotariu Link: https://lore.kernel.org/r/20210301170905.835091-4-codrin.ciubotariu@microchip.com Signed-off-by: Mark Brown --- sound/soc/atmel/mchp-i2s-mcc.c | 38 ++++++++++++++++++++++++++++++++++ 1 file changed, 38 insertions(+) diff --git a/sound/soc/atmel/mchp-i2s-mcc.c b/sound/soc/atmel/mchp-i2s-mcc.c index 0ee01383e307..52d3f43148dc 100644 --- a/sound/soc/atmel/mchp-i2s-mcc.c +++ b/sound/soc/atmel/mchp-i2s-mcc.c @@ -16,6 +16,7 @@ #include #include #include +#include #include #include @@ -225,6 +226,10 @@ static const struct regmap_config mchp_i2s_mcc_regmap_config = { .max_register = MCHP_I2SMCC_VERSION, }; +struct mchp_i2s_mcc_soc_data { + unsigned int data_pin_pair_num; +}; + struct mchp_i2s_mcc_dev { struct wait_queue_head wq_txrdy; struct wait_queue_head wq_rxrdy; @@ -232,6 +237,7 @@ struct mchp_i2s_mcc_dev { struct regmap *regmap; struct clk *pclk; struct clk *gclk; + const struct mchp_i2s_mcc_soc_data *soc; struct snd_dmaengine_dai_dma_data playback; struct snd_dmaengine_dai_dma_data capture; unsigned int fmt; @@ -549,6 +555,17 @@ static int mchp_i2s_mcc_hw_params(struct snd_pcm_substream *substream, } if (dev->fmt & (SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_LEFT_J)) { + /* for I2S and LEFT_J one pin is needed for every 2 channels */ + if (channels > dev->soc->data_pin_pair_num * 2) { + dev_err(dev->dev, + "unsupported number of audio channels: %d\n", + channels); + return -EINVAL; + } + + /* enable for interleaved format */ + mrb |= MCHP_I2SMCC_MRB_CRAMODE_REGULAR; + switch (channels) { case 1: if (is_playback) @@ -558,6 +575,12 @@ static int mchp_i2s_mcc_hw_params(struct snd_pcm_substream *substream, break; case 2: break; + case 4: + mra |= MCHP_I2SMCC_MRA_WIRECFG_I2S_2_TDM_1; + break; + case 8: + mra |= MCHP_I2SMCC_MRA_WIRECFG_I2S_4_TDM_2; + break; default: dev_err(dev->dev, "unsupported number of audio channels\n"); return -EINVAL; @@ -869,12 +892,22 @@ static const struct snd_soc_component_driver mchp_i2s_mcc_component = { }; #ifdef CONFIG_OF +static struct mchp_i2s_mcc_soc_data mchp_i2s_mcc_sam9x60 = { + .data_pin_pair_num = 1, +}; + +static struct mchp_i2s_mcc_soc_data mchp_i2s_mcc_sama7g5 = { + .data_pin_pair_num = 4, +}; + static const struct of_device_id mchp_i2s_mcc_dt_ids[] = { { .compatible = "microchip,sam9x60-i2smcc", + .data = &mchp_i2s_mcc_sam9x60, }, { .compatible = "microchip,sama7g5-i2smcc", + .data = &mchp_i2s_mcc_sama7g5, }, { /* sentinel */ } }; @@ -932,6 +965,11 @@ static int mchp_i2s_mcc_probe(struct platform_device *pdev) dev->gclk = NULL; } + dev->soc = of_device_get_match_data(&pdev->dev); + if (!dev->soc) { + dev_err(&pdev->dev, "failed to get soc data\n"); + return -ENODEV; + } dev->dev = &pdev->dev; dev->regmap = regmap; platform_set_drvdata(pdev, dev); From bfdca489751ff765ee606c85bda1680040dedd8e Mon Sep 17 00:00:00 2001 From: Codrin Ciubotariu Date: Mon, 1 Mar 2021 19:09:03 +0200 Subject: [PATCH 112/587] ASoC: mchp-i2s-mcc: Add support to select TDM pins SAMA7G5's I2S-MCC has 4 pairs of DIN/DOUT pins. Since TDM only uses a single pair of pins for synchronous capture and playback, the controller needs to be told which of the pair is connected. This can be mentioned using the "microchip,tdm-data-pair" property from DT. The property is optional, useful only if TDM is used. If it's missing, DIN/DOUT 0 pins will be used by default. Signed-off-by: Codrin Ciubotariu Link: https://lore.kernel.org/r/20210301170905.835091-6-codrin.ciubotariu@microchip.com Signed-off-by: Mark Brown --- sound/soc/atmel/mchp-i2s-mcc.c | 52 +++++++++++++++++++++++++++++++--- 1 file changed, 48 insertions(+), 4 deletions(-) diff --git a/sound/soc/atmel/mchp-i2s-mcc.c b/sound/soc/atmel/mchp-i2s-mcc.c index 52d3f43148dc..515ba3634fdd 100644 --- a/sound/soc/atmel/mchp-i2s-mcc.c +++ b/sound/soc/atmel/mchp-i2s-mcc.c @@ -100,6 +100,8 @@ #define MCHP_I2SMCC_MRA_DATALENGTH_8_BITS_COMPACT (7 << 1) #define MCHP_I2SMCC_MRA_WIRECFG_MASK GENMASK(5, 4) +#define MCHP_I2SMCC_MRA_WIRECFG_TDM(pin) (((pin) << 4) & \ + MCHP_I2SMCC_MRA_WIRECFG_MASK) #define MCHP_I2SMCC_MRA_WIRECFG_I2S_1_TDM_0 (0 << 4) #define MCHP_I2SMCC_MRA_WIRECFG_I2S_2_TDM_1 (1 << 4) #define MCHP_I2SMCC_MRA_WIRECFG_I2S_4_TDM_2 (2 << 4) @@ -245,6 +247,7 @@ struct mchp_i2s_mcc_dev { unsigned int frame_length; int tdm_slots; int channels; + u8 tdm_data_pair; unsigned int gclk_use:1; unsigned int gclk_running:1; unsigned int tx_rdy:1; @@ -589,6 +592,8 @@ static int mchp_i2s_mcc_hw_params(struct snd_pcm_substream *substream, if (!frame_length) frame_length = 2 * params_physical_width(params); } else if (dev->fmt & SND_SOC_DAIFMT_DSP_A) { + mra |= MCHP_I2SMCC_MRA_WIRECFG_TDM(dev->tdm_data_pair); + if (dev->tdm_slots) { if (channels % 2 && channels * 2 <= dev->tdm_slots) { /* @@ -914,6 +919,45 @@ static const struct of_device_id mchp_i2s_mcc_dt_ids[] = { MODULE_DEVICE_TABLE(of, mchp_i2s_mcc_dt_ids); #endif +static int mchp_i2s_mcc_soc_data_parse(struct platform_device *pdev, + struct mchp_i2s_mcc_dev *dev) +{ + int err; + + if (!dev->soc) { + dev_err(&pdev->dev, "failed to get soc data\n"); + return -ENODEV; + } + + if (dev->soc->data_pin_pair_num == 1) + return 0; + + err = of_property_read_u8(pdev->dev.of_node, "microchip,tdm-data-pair", + &dev->tdm_data_pair); + if (err < 0 && err != -EINVAL) { + dev_err(&pdev->dev, + "bad property data for 'microchip,tdm-data-pair': %d", + err); + return err; + } + if (err == -EINVAL) { + dev_info(&pdev->dev, + "'microchip,tdm-data-pair' not found; assuming DIN/DOUT 0 for TDM\n"); + dev->tdm_data_pair = 0; + } else { + if (dev->tdm_data_pair > dev->soc->data_pin_pair_num - 1) { + dev_err(&pdev->dev, + "invalid value for 'microchip,tdm-data-pair': %d\n", + dev->tdm_data_pair); + return -EINVAL; + } + dev_dbg(&pdev->dev, "TMD format on DIN/DOUT %d pins\n", + dev->tdm_data_pair); + } + + return 0; +} + static int mchp_i2s_mcc_probe(struct platform_device *pdev) { struct mchp_i2s_mcc_dev *dev; @@ -966,10 +1010,10 @@ static int mchp_i2s_mcc_probe(struct platform_device *pdev) } dev->soc = of_device_get_match_data(&pdev->dev); - if (!dev->soc) { - dev_err(&pdev->dev, "failed to get soc data\n"); - return -ENODEV; - } + err = mchp_i2s_mcc_soc_data_parse(pdev, dev); + if (err < 0) + return err; + dev->dev = &pdev->dev; dev->regmap = regmap; platform_set_drvdata(pdev, dev); From 16135d66309a5ca67e05cd7d0b1b038597a0b0a3 Mon Sep 17 00:00:00 2001 From: Codrin Ciubotariu Date: Mon, 1 Mar 2021 19:09:04 +0200 Subject: [PATCH 113/587] ASoC: mchp-i2s-mcc: Add FIFOs support I2S-MCC found on SAMA7G5 includes 2 FIFOs (capture and playback). When FIFOs are enabled, bits I2SMCC_ISRA.TXLRDYx and I2SMCC_ISRA.TXRRDYx must not be used. Bits I2SMCC_ISRB.TXFFRDY and I2SMCC_ISRB.RXFFRDY must be used instead. Signed-off-by: Codrin Ciubotariu Link: https://lore.kernel.org/r/20210301170905.835091-7-codrin.ciubotariu@microchip.com Signed-off-by: Mark Brown --- sound/soc/atmel/mchp-i2s-mcc.c | 76 +++++++++++++++++++++++++--------- 1 file changed, 56 insertions(+), 20 deletions(-) diff --git a/sound/soc/atmel/mchp-i2s-mcc.c b/sound/soc/atmel/mchp-i2s-mcc.c index 515ba3634fdd..673bc16cb46a 100644 --- a/sound/soc/atmel/mchp-i2s-mcc.c +++ b/sound/soc/atmel/mchp-i2s-mcc.c @@ -176,7 +176,7 @@ */ #define MCHP_I2SMCC_MRB_CRAMODE_REGULAR (1 << 0) -#define MCHP_I2SMCC_MRB_FIFOEN BIT(1) +#define MCHP_I2SMCC_MRB_FIFOEN BIT(4) #define MCHP_I2SMCC_MRB_DMACHUNK_MASK GENMASK(9, 8) #define MCHP_I2SMCC_MRB_DMACHUNK(no_words) \ @@ -230,6 +230,7 @@ static const struct regmap_config mchp_i2s_mcc_regmap_config = { struct mchp_i2s_mcc_soc_data { unsigned int data_pin_pair_num; + bool has_fifo; }; struct mchp_i2s_mcc_dev { @@ -257,7 +258,7 @@ struct mchp_i2s_mcc_dev { static irqreturn_t mchp_i2s_mcc_interrupt(int irq, void *dev_id) { struct mchp_i2s_mcc_dev *dev = dev_id; - u32 sra, imra, srb, imrb, pendinga, pendingb, idra = 0; + u32 sra, imra, srb, imrb, pendinga, pendingb, idra = 0, idrb = 0; irqreturn_t ret = IRQ_NONE; regmap_read(dev->regmap, MCHP_I2SMCC_IMRA, &imra); @@ -275,24 +276,36 @@ static irqreturn_t mchp_i2s_mcc_interrupt(int irq, void *dev_id) * Tx/Rx ready interrupts are enabled when stopping only, to assure * availability and to disable clocks if necessary */ - idra |= pendinga & (MCHP_I2SMCC_INT_TXRDY_MASK(dev->channels) | - MCHP_I2SMCC_INT_RXRDY_MASK(dev->channels)); - if (idra) + if (dev->soc->has_fifo) { + idrb |= pendingb & (MCHP_I2SMCC_INT_TXFFRDY | + MCHP_I2SMCC_INT_RXFFRDY); + } else { + idra |= pendinga & (MCHP_I2SMCC_INT_TXRDY_MASK(dev->channels) | + MCHP_I2SMCC_INT_RXRDY_MASK(dev->channels)); + } + if (idra || idrb) ret = IRQ_HANDLED; - if ((imra & MCHP_I2SMCC_INT_TXRDY_MASK(dev->channels)) && - (imra & MCHP_I2SMCC_INT_TXRDY_MASK(dev->channels)) == - (idra & MCHP_I2SMCC_INT_TXRDY_MASK(dev->channels))) { + if ((!dev->soc->has_fifo && + (imra & MCHP_I2SMCC_INT_TXRDY_MASK(dev->channels)) && + (imra & MCHP_I2SMCC_INT_TXRDY_MASK(dev->channels)) == + (idra & MCHP_I2SMCC_INT_TXRDY_MASK(dev->channels))) || + (dev->soc->has_fifo && imrb & MCHP_I2SMCC_INT_TXFFRDY)) { dev->tx_rdy = 1; wake_up_interruptible(&dev->wq_txrdy); } - if ((imra & MCHP_I2SMCC_INT_RXRDY_MASK(dev->channels)) && - (imra & MCHP_I2SMCC_INT_RXRDY_MASK(dev->channels)) == - (idra & MCHP_I2SMCC_INT_RXRDY_MASK(dev->channels))) { + if ((!dev->soc->has_fifo && + (imra & MCHP_I2SMCC_INT_RXRDY_MASK(dev->channels)) && + (imra & MCHP_I2SMCC_INT_RXRDY_MASK(dev->channels)) == + (idra & MCHP_I2SMCC_INT_RXRDY_MASK(dev->channels))) || + (dev->soc->has_fifo && imrb & MCHP_I2SMCC_INT_RXFFRDY)) { dev->rx_rdy = 1; wake_up_interruptible(&dev->wq_rxrdy); } - regmap_write(dev->regmap, MCHP_I2SMCC_IDRA, idra); + if (dev->soc->has_fifo) + regmap_write(dev->regmap, MCHP_I2SMCC_IDRB, idrb); + else + regmap_write(dev->regmap, MCHP_I2SMCC_IDRA, idra); return ret; } @@ -664,6 +677,10 @@ static int mchp_i2s_mcc_hw_params(struct snd_pcm_substream *substream, } } + /* enable FIFO if available */ + if (dev->soc->has_fifo) + mrb |= MCHP_I2SMCC_MRB_FIFOEN; + /* * If we are already running, the wanted setup must be * the same with the one that's currently ongoing @@ -726,8 +743,13 @@ static int mchp_i2s_mcc_hw_free(struct snd_pcm_substream *substream, if (err == 0) { dev_warn_once(dev->dev, "Timeout waiting for Tx ready\n"); - regmap_write(dev->regmap, MCHP_I2SMCC_IDRA, - MCHP_I2SMCC_INT_TXRDY_MASK(dev->channels)); + if (dev->soc->has_fifo) + regmap_write(dev->regmap, MCHP_I2SMCC_IDRB, + MCHP_I2SMCC_INT_TXFFRDY); + else + regmap_write(dev->regmap, MCHP_I2SMCC_IDRA, + MCHP_I2SMCC_INT_TXRDY_MASK(dev->channels)); + dev->tx_rdy = 1; } } else { @@ -737,8 +759,12 @@ static int mchp_i2s_mcc_hw_free(struct snd_pcm_substream *substream, if (err == 0) { dev_warn_once(dev->dev, "Timeout waiting for Rx ready\n"); - regmap_write(dev->regmap, MCHP_I2SMCC_IDRA, - MCHP_I2SMCC_INT_RXRDY_MASK(dev->channels)); + if (dev->soc->has_fifo) + regmap_write(dev->regmap, MCHP_I2SMCC_IDRB, + MCHP_I2SMCC_INT_RXFFRDY); + else + regmap_write(dev->regmap, MCHP_I2SMCC_IDRA, + MCHP_I2SMCC_INT_RXRDY_MASK(dev->channels)); dev->rx_rdy = 1; } } @@ -765,7 +791,7 @@ static int mchp_i2s_mcc_trigger(struct snd_pcm_substream *substream, int cmd, struct mchp_i2s_mcc_dev *dev = snd_soc_dai_get_drvdata(dai); bool is_playback = (substream->stream == SNDRV_PCM_STREAM_PLAYBACK); u32 cr = 0; - u32 iera = 0; + u32 iera = 0, ierb = 0; u32 sr; int err; @@ -789,7 +815,10 @@ static int mchp_i2s_mcc_trigger(struct snd_pcm_substream *substream, int cmd, * Enable Tx Ready interrupts on all channels * to assure all data is sent */ - iera = MCHP_I2SMCC_INT_TXRDY_MASK(dev->channels); + if (dev->soc->has_fifo) + ierb = MCHP_I2SMCC_INT_TXFFRDY; + else + iera = MCHP_I2SMCC_INT_TXRDY_MASK(dev->channels); } else if (!is_playback && (sr & MCHP_I2SMCC_SR_RXEN)) { cr = MCHP_I2SMCC_CR_RXDIS; dev->rx_rdy = 0; @@ -797,7 +826,10 @@ static int mchp_i2s_mcc_trigger(struct snd_pcm_substream *substream, int cmd, * Enable Rx Ready interrupts on all channels * to assure all data is received */ - iera = MCHP_I2SMCC_INT_RXRDY_MASK(dev->channels); + if (dev->soc->has_fifo) + ierb = MCHP_I2SMCC_INT_RXFFRDY; + else + iera = MCHP_I2SMCC_INT_RXRDY_MASK(dev->channels); } break; default: @@ -815,7 +847,10 @@ static int mchp_i2s_mcc_trigger(struct snd_pcm_substream *substream, int cmd, } } - regmap_write(dev->regmap, MCHP_I2SMCC_IERA, iera); + if (dev->soc->has_fifo) + regmap_write(dev->regmap, MCHP_I2SMCC_IERB, ierb); + else + regmap_write(dev->regmap, MCHP_I2SMCC_IERA, iera); regmap_write(dev->regmap, MCHP_I2SMCC_CR, cr); return 0; @@ -903,6 +938,7 @@ static struct mchp_i2s_mcc_soc_data mchp_i2s_mcc_sam9x60 = { static struct mchp_i2s_mcc_soc_data mchp_i2s_mcc_sama7g5 = { .data_pin_pair_num = 4, + .has_fifo = true, }; static const struct of_device_id mchp_i2s_mcc_dt_ids[] = { From 153bb1feefd2a7c907d65ccf89953feb1548e60f Mon Sep 17 00:00:00 2001 From: Codrin Ciubotariu Date: Mon, 1 Mar 2021 19:08:59 +0200 Subject: [PATCH 114/587] ASoC: mchp,i2s-mcc: Add SAMA7G5 to binding SAMA7G5 includes an updated version of the I2S-MCC driver, that includes 3 more DIN/DOUT pin pairs for multi-channel. Signed-off-by: Codrin Ciubotariu Link: https://lore.kernel.org/r/20210301170905.835091-2-codrin.ciubotariu@microchip.com Signed-off-by: Mark Brown --- Documentation/devicetree/bindings/sound/mchp-i2s-mcc.txt | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/Documentation/devicetree/bindings/sound/mchp-i2s-mcc.txt b/Documentation/devicetree/bindings/sound/mchp-i2s-mcc.txt index 91ec83a6faed..2180dbd9ea81 100644 --- a/Documentation/devicetree/bindings/sound/mchp-i2s-mcc.txt +++ b/Documentation/devicetree/bindings/sound/mchp-i2s-mcc.txt @@ -1,7 +1,8 @@ * Microchip I2S Multi-Channel Controller Required properties: -- compatible: Should be "microchip,sam9x60-i2smcc". +- compatible: Should be "microchip,sam9x60-i2smcc" or + "microchip,sama7g5-i2smcc". - reg: Should be the physical base address of the controller and the length of memory mapped region. - interrupts: Should contain the interrupt for the controller. From ead2a3e43f0a6556e464a83ffba7d7baacf0d426 Mon Sep 17 00:00:00 2001 From: Codrin Ciubotariu Date: Mon, 1 Mar 2021 19:09:02 +0200 Subject: [PATCH 115/587] ASoC: mchp, i2s-mcc: Add property to specify pin pair for TDM SAMA7G5's I2S-MCC has 4 pairs of DIN/DOUT pins. Since TDM only uses a single pair of pins for synchronous capture and playback, the controller needs to be told which of the pair is connected. This can be mentioned using the new "microchip,tdm-data-pair" property. The property is optional, needed only if TDM is used, and if it's missing DIN/DOUT 0 pins will be used by default. Signed-off-by: Codrin Ciubotariu Link: https://lore.kernel.org/r/20210301170905.835091-5-codrin.ciubotariu@microchip.com Signed-off-by: Mark Brown --- Documentation/devicetree/bindings/sound/mchp-i2s-mcc.txt | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/Documentation/devicetree/bindings/sound/mchp-i2s-mcc.txt b/Documentation/devicetree/bindings/sound/mchp-i2s-mcc.txt index 2180dbd9ea81..af8fe3e657df 100644 --- a/Documentation/devicetree/bindings/sound/mchp-i2s-mcc.txt +++ b/Documentation/devicetree/bindings/sound/mchp-i2s-mcc.txt @@ -19,7 +19,12 @@ Required properties: Optional properties: - pinctrl-0: Should specify pin control groups used for this controller. - princtrl-names: Should contain only one value - "default". - +- microchip,tdm-data-pair: 8 bit value that represents the DIN/DOUT pair pins + which are used to receive/send TDM data. It is optional + and it is only needed if the controller uses the TDM + mode. Not available for "microchip,sam9x60-i2smcc" + compatible. If it's not present, the default value is 0, + so the DIN/DOUT 0 pins are used. (1) : Only the peripheral clock is required. The generated clock is optional and should be set mostly when Master Mode is required. From 4e8d9fe7f09bd975b85382af9fd301645ee8c0e8 Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Mon, 1 Mar 2021 17:56:36 -0600 Subject: [PATCH 116/587] ASoC: Intel: soc-acpi: remove unused TGL table with rt5682 only This patch partially reverts Commit 095ee71907ea ("ASoC: Intel: common: add match table for TGL RT5682 SoundWire driver"). This commit was added as an enabling patch before the Maxim98373 codec driver was available. This codec is now fully functional and the topology with only RT5682 no longer maintained or used. Signed-off-by: Pierre-Louis Bossart Reviewed-by: Kai Vehmanen Reviewed-by: Bard Liao Reviewed-by: Rander Wang Link: https://lore.kernel.org/r/20210301235637.1177525-2-pierre-louis.bossart@linux.intel.com Signed-off-by: Mark Brown --- sound/soc/intel/common/soc-acpi-intel-tgl-match.c | 6 ------ 1 file changed, 6 deletions(-) diff --git a/sound/soc/intel/common/soc-acpi-intel-tgl-match.c b/sound/soc/intel/common/soc-acpi-intel-tgl-match.c index 40f31c8a3aba..e8640ee10012 100644 --- a/sound/soc/intel/common/soc-acpi-intel-tgl-match.c +++ b/sound/soc/intel/common/soc-acpi-intel-tgl-match.c @@ -415,12 +415,6 @@ struct snd_soc_acpi_mach snd_soc_acpi_intel_tgl_sdw_machines[] = { .drv_name = "sof_sdw", .sof_tplg_filename = "sof-tgl-sdw-max98373-rt5682.tplg", }, - { - .link_mask = 0x1, /* this will only enable rt5682 for now */ - .links = tgl_chromebook_base, - .drv_name = "sof_sdw", - .sof_tplg_filename = "sof-tgl-rt5682.tplg", - }, {}, }; EXPORT_SYMBOL_GPL(snd_soc_acpi_intel_tgl_sdw_machines); From 5ed26a834b83a368f2c026f22db9becc56fd37f9 Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Mon, 1 Mar 2021 17:56:37 -0600 Subject: [PATCH 117/587] ASoC: Intel: soc-acpi: remove TGL RVP mixed SoundWire/TDM config The TGL RVP can be configured in many ways. We initially supported a mixed configuration with RT711 in SoundWire mode and RT1308 in TDM mode. However Intel teams no longer have any hardware with this configuration and there are no commercially-available devices using it either, so let's remove this entry. The corresponding topology will also be removed from the SOF tree. This patch partially reverts Commit d985d208bf8f ("ASoC: Intel: common: add match tables for TGL w/ SoundWire") Signed-off-by: Pierre-Louis Bossart Reviewed-by: Kai Vehmanen Reviewed-by: Bard Liao Reviewed-by: Rander Wang Link: https://lore.kernel.org/r/20210301235637.1177525-3-pierre-louis.bossart@linux.intel.com Signed-off-by: Mark Brown --- .../soc/intel/common/soc-acpi-intel-tgl-match.c | 17 ----------------- 1 file changed, 17 deletions(-) diff --git a/sound/soc/intel/common/soc-acpi-intel-tgl-match.c b/sound/soc/intel/common/soc-acpi-intel-tgl-match.c index e8640ee10012..b5f05b81a584 100644 --- a/sound/soc/intel/common/soc-acpi-intel-tgl-match.c +++ b/sound/soc/intel/common/soc-acpi-intel-tgl-match.c @@ -182,15 +182,6 @@ static const struct snd_soc_acpi_adr_device rt714_3_adr[] = { } }; -static const struct snd_soc_acpi_link_adr tgl_i2s_rt1308[] = { - { - .mask = BIT(0), - .num_adr = ARRAY_SIZE(rt711_0_adr), - .adr_d = rt711_0_adr, - }, - {} -}; - static const struct snd_soc_acpi_link_adr tgl_rvp[] = { { .mask = BIT(0), @@ -330,14 +321,6 @@ static const struct snd_soc_acpi_codecs tgl_rt1011_amp = { }; struct snd_soc_acpi_mach snd_soc_acpi_intel_tgl_machines[] = { - { - .id = "10EC1308", - .drv_name = "sof_sdw", - .link_mask = 0x1, /* RT711 on SoundWire link0 */ - .links = tgl_i2s_rt1308, - .sof_fw_filename = "sof-tgl.ri", - .sof_tplg_filename = "sof-tgl-rt711-i2s-rt1308.tplg", - }, { .id = "10EC5682", .drv_name = "tgl_max98357a_rt5682", From 075d7da7d6b42db90039a95f102d7d999ecc410e Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Mon, 1 Mar 2021 11:46:39 -0600 Subject: [PATCH 118/587] ASoC: codecs: nau8825: fix kernel-doc v5.12-rc1 flags new warnings with make W=1, fix missing or broken function descriptors. sound/soc/codecs/nau8825.c:298: warning: wrong kernel-doc identifier on line: * Ramp up the headphone volume change gradually to target level. sound/soc/codecs/nau8825.c:358: warning: expecting prototype for This func(). Prototype was for nau8825_intlog10_dec3() instead sound/soc/codecs/nau8825.c:411: warning: wrong kernel-doc identifier on line: * computes cross talk suppression sidetone gain. Signed-off-by: Pierre-Louis Bossart Link: https://lore.kernel.org/r/20210301174639.117017-1-pierre-louis.bossart@linux.intel.com Signed-off-by: Mark Brown --- sound/soc/codecs/nau8825.c | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/sound/soc/codecs/nau8825.c b/sound/soc/codecs/nau8825.c index f0cba7b5758b..e19db30c457b 100644 --- a/sound/soc/codecs/nau8825.c +++ b/sound/soc/codecs/nau8825.c @@ -295,7 +295,7 @@ static inline void nau8825_sema_reset(struct nau8825 *nau8825) } /** - * Ramp up the headphone volume change gradually to target level. + * nau8825_hpvol_ramp - Ramp up the headphone volume change gradually to target level. * * @nau8825: component to register the codec private data with * @vol_from: the volume to start up @@ -347,8 +347,9 @@ static void nau8825_hpvol_ramp(struct nau8825 *nau8825, } /** - * Computes log10 of a value; the result is round off to 3 decimal. This func- - * tion takes reference to dvb-math. The source code locates as the following. + * nau8825_intlog10_dec3 - Computes log10 of a value + * the result is round off to 3 decimal. This function takes reference to + * dvb-math. The source code locates as the following. * Linux/drivers/media/dvb-core/dvb_math.c * @value: input for log10 * @@ -408,7 +409,7 @@ static u32 nau8825_intlog10_dec3(u32 value) } /** - * computes cross talk suppression sidetone gain. + * nau8825_xtalk_sidetone - computes cross talk suppression sidetone gain. * * @sig_org: orignal signal level * @sig_cros: cross talk signal level From 2fb8711095a1f8b545b2cae307d9b0fc9591e36b Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Mon, 1 Mar 2021 11:46:59 -0600 Subject: [PATCH 119/587] ASoC: soc-dai: fix kernel-doc v5.12-rc1 flags new warnings with make W=1, fix missing or broken function descriptors. sound/soc/soc-dai.c:167: warning: expecting prototype for snd_soc_xlate_tdm_slot(). Prototype was for snd_soc_xlate_tdm_slot_mask() instead Signed-off-by: Pierre-Louis Bossart Link: https://lore.kernel.org/r/20210301174659.117122-1-pierre-louis.bossart@linux.intel.com Signed-off-by: Mark Brown --- sound/soc/soc-dai.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sound/soc/soc-dai.c b/sound/soc/soc-dai.c index cd3bb9a7983f..080fbe053fc5 100644 --- a/sound/soc/soc-dai.c +++ b/sound/soc/soc-dai.c @@ -154,7 +154,7 @@ int snd_soc_dai_set_fmt(struct snd_soc_dai *dai, unsigned int fmt) EXPORT_SYMBOL_GPL(snd_soc_dai_set_fmt); /** - * snd_soc_xlate_tdm_slot - generate tx/rx slot mask. + * snd_soc_xlate_tdm_slot_mask - generate tx/rx slot mask. * @slots: Number of slots in use. * @tx_mask: bitmask representing active TX slots. * @rx_mask: bitmask representing active RX slots. From 7810ea4c8f74ff904ac1ea06dde9201af566d679 Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Mon, 1 Mar 2021 10:53:47 -0600 Subject: [PATCH 120/587] ASoC: Intel: atom: fix kernel-doc v5.12-rc1 flags new warnings with make W=1, fix missing or broken function descriptors. sound/soc/intel/atom/sst/sst_loader.c:85: warning: expecting prototype for sst_start_merrifield(). Prototype was for sst_start_mrfld() instead sound/soc/intel/atom/sst/sst_acpi.c:339: warning: expecting prototype for intel_sst_remove(). Prototype was for sst_acpi_remove() instead Signed-off-by: Pierre-Louis Bossart Link: https://lore.kernel.org/r/20210301165349.114952-3-pierre-louis.bossart@linux.intel.com Signed-off-by: Mark Brown --- sound/soc/intel/atom/sst/sst_acpi.c | 2 +- sound/soc/intel/atom/sst/sst_loader.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/sound/soc/intel/atom/sst/sst_acpi.c b/sound/soc/intel/atom/sst/sst_acpi.c index 2c1b8a2e3506..3be64430c256 100644 --- a/sound/soc/intel/atom/sst/sst_acpi.c +++ b/sound/soc/intel/atom/sst/sst_acpi.c @@ -328,7 +328,7 @@ static int sst_acpi_probe(struct platform_device *pdev) } /** -* intel_sst_remove - remove function +* sst_acpi_remove - remove function * * @pdev: platform device structure * diff --git a/sound/soc/intel/atom/sst/sst_loader.c b/sound/soc/intel/atom/sst/sst_loader.c index 1c9b0c9ec483..eea889001c24 100644 --- a/sound/soc/intel/atom/sst/sst_loader.c +++ b/sound/soc/intel/atom/sst/sst_loader.c @@ -76,7 +76,7 @@ int intel_sst_reset_dsp_mrfld(struct intel_sst_drv *sst_drv_ctx) } /** - * sst_start_merrifield - Start the SST DSP processor + * sst_start_mrfld - Start the SST DSP processor * @sst_drv_ctx: intel_sst_drv context pointer * * This starts the DSP in MERRIFIELD platfroms From ee00e0bf7e4fe6c253219680b339add32686efee Mon Sep 17 00:00:00 2001 From: Fabio Estevam Date: Mon, 1 Mar 2021 16:33:28 -0300 Subject: [PATCH 121/587] ASoC: wm8524: Do not print probe defer error On an imx8mq-evk the following error is seen: [ 1.375809] wm8524-codec audio-codec: Failed to get mute line: -517 It happens because the codec driver may probe prior to the imx gpio driver, which causes a probe defer. Change to dev_err_probe() to avoid printing this error. Reported-by: Chris Healy Signed-off-by: Fabio Estevam Link: https://lore.kernel.org/r/20210301193328.2123511-1-festevam@gmail.com Signed-off-by: Mark Brown --- sound/soc/codecs/wm8524.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sound/soc/codecs/wm8524.c b/sound/soc/codecs/wm8524.c index 4e9ab542f648..81f858f6bd67 100644 --- a/sound/soc/codecs/wm8524.c +++ b/sound/soc/codecs/wm8524.c @@ -227,7 +227,7 @@ static int wm8524_codec_probe(struct platform_device *pdev) wm8524->mute = devm_gpiod_get(&pdev->dev, "wlf,mute", GPIOD_OUT_LOW); if (IS_ERR(wm8524->mute)) { ret = PTR_ERR(wm8524->mute); - dev_err(&pdev->dev, "Failed to get mute line: %d\n", ret); + dev_err_probe(&pdev->dev, ret, "Failed to get mute line\n"); return ret; } From e443858258a2e29eee96e919589448855aa2735e Mon Sep 17 00:00:00 2001 From: Ranjani Sridharan Date: Mon, 1 Mar 2021 09:01:57 -0800 Subject: [PATCH 122/587] ASoC: SOF: Intel: hda: enable async suspend The skylake driver disabled async suspend to prevent disabling the DSP before the card was suspended during system suspend. This code was carried over to the SOF driver. But, there is no risk of the DSP getting disabled before the card is suspended with the SOF driver. Therefore, it is safe to enable async suspend and thereby optimize the system resume time. Reviewed-by: Kai Vehmanen Reviewed-by: Pierre-Louis Bossart Signed-off-by: Ranjani Sridharan Link: https://lore.kernel.org/r/20210301170157.36584-1-ranjani.sridharan@linux.intel.com Signed-off-by: Mark Brown --- sound/soc/sof/intel/hda.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/sound/soc/sof/intel/hda.c b/sound/soc/sof/intel/hda.c index 0c096db07322..5317dfa4a4bf 100644 --- a/sound/soc/sof/intel/hda.c +++ b/sound/soc/sof/intel/hda.c @@ -616,8 +616,6 @@ static int hda_init_caps(struct snd_sof_dev *sdev) u32 link_mask; int ret = 0; - device_disable_async_suspend(bus->dev); - /* check if dsp is there */ if (bus->ppcap) dev_dbg(sdev->dev, "PP capability, will probe DSP later.\n"); From f7c5c16875c2d2b6e1a7f4f1915d125b79be4951 Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Tue, 2 Mar 2021 15:25:04 -0600 Subject: [PATCH 123/587] ASoC: rt1011: use logical OR cppcheck complains a lot about mixing booleans and bitwise operations. There is no good reason to use && and |, fix with || Signed-off-by: Pierre-Louis Bossart Link: https://lore.kernel.org/r/20210302212527.55158-2-pierre-louis.bossart@linux.intel.com Signed-off-by: Mark Brown --- sound/soc/codecs/rt1011.c | 34 +++++++++++++++------------------- 1 file changed, 15 insertions(+), 19 deletions(-) diff --git a/sound/soc/codecs/rt1011.c b/sound/soc/codecs/rt1011.c index 6877be5f36b9..b9dadc8243b3 100644 --- a/sound/soc/codecs/rt1011.c +++ b/sound/soc/codecs/rt1011.c @@ -1089,25 +1089,21 @@ static int rt1011_recv_spk_mode_put(struct snd_kcontrol *kcontrol, static bool rt1011_validate_bq_drc_coeff(unsigned short reg) { - if ((reg == RT1011_DAC_SET_1) | - (reg >= RT1011_ADC_SET && reg <= RT1011_ADC_SET_1) | - (reg == RT1011_ADC_SET_4) | (reg == RT1011_ADC_SET_5) | - (reg == RT1011_MIXER_1) | - (reg == RT1011_A_TIMING_1) | (reg >= RT1011_POWER_7 && - reg <= RT1011_POWER_8) | - (reg == RT1011_CLASS_D_POS) | (reg == RT1011_ANALOG_CTRL) | - (reg >= RT1011_SPK_TEMP_PROTECT_0 && - reg <= RT1011_SPK_TEMP_PROTECT_6) | - (reg >= RT1011_SPK_PRO_DC_DET_5 && reg <= RT1011_BAT_GAIN_1) | - (reg >= RT1011_RT_DRC_CROSS && reg <= RT1011_RT_DRC_POS_8) | - (reg >= RT1011_CROSS_BQ_SET_1 && reg <= RT1011_BQ_10_A2_15_0) | - (reg >= RT1011_SMART_BOOST_TIMING_1 && - reg <= RT1011_SMART_BOOST_TIMING_36) | - (reg == RT1011_SINE_GEN_REG_1) | - (reg >= RT1011_STP_ALPHA_RECIPROCAL_MSB && - reg <= RT1011_BQ_6_PARAMS_CHECK_5) | - (reg >= RT1011_BQ_7_PARAMS_CHECK_1 && - reg <= RT1011_BQ_10_PARAMS_CHECK_5)) + if ((reg == RT1011_DAC_SET_1) || + (reg >= RT1011_ADC_SET && reg <= RT1011_ADC_SET_1) || + (reg == RT1011_ADC_SET_4) || (reg == RT1011_ADC_SET_5) || + (reg == RT1011_MIXER_1) || + (reg == RT1011_A_TIMING_1) || + (reg >= RT1011_POWER_7 && reg <= RT1011_POWER_8) || + (reg == RT1011_CLASS_D_POS) || (reg == RT1011_ANALOG_CTRL) || + (reg >= RT1011_SPK_TEMP_PROTECT_0 && reg <= RT1011_SPK_TEMP_PROTECT_6) || + (reg >= RT1011_SPK_PRO_DC_DET_5 && reg <= RT1011_BAT_GAIN_1) || + (reg >= RT1011_RT_DRC_CROSS && reg <= RT1011_RT_DRC_POS_8) || + (reg >= RT1011_CROSS_BQ_SET_1 && reg <= RT1011_BQ_10_A2_15_0) || + (reg >= RT1011_SMART_BOOST_TIMING_1 && reg <= RT1011_SMART_BOOST_TIMING_36) || + (reg == RT1011_SINE_GEN_REG_1) || + (reg >= RT1011_STP_ALPHA_RECIPROCAL_MSB && reg <= RT1011_BQ_6_PARAMS_CHECK_5) || + (reg >= RT1011_BQ_7_PARAMS_CHECK_1 && reg <= RT1011_BQ_10_PARAMS_CHECK_5)) return true; return false; From 7e66f16251eb59410257a1e5e279e6c949f53171 Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Tue, 2 Mar 2021 15:25:05 -0600 Subject: [PATCH 124/587] ASoC: rt1011: remove redundant test cppcheck warning: sound/soc/codecs/rt1011.c:1994:6: style: Condition 'tx_slotnum' is always true [knownConditionTrueFalse] if (tx_slotnum) ^ sound/soc/codecs/rt1011.c:1895:24: note: Assuming that condition '!tx_slotnum' is not redundant if (tx_slotnum > 2 || !tx_slotnum) { ^ sound/soc/codecs/rt1011.c:1994:6: note: Condition 'tx_slotnum' is always true if (tx_slotnum) ^ Signed-off-by: Pierre-Louis Bossart Link: https://lore.kernel.org/r/20210302212527.55158-3-pierre-louis.bossart@linux.intel.com Signed-off-by: Mark Brown --- sound/soc/codecs/rt1011.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/sound/soc/codecs/rt1011.c b/sound/soc/codecs/rt1011.c index b9dadc8243b3..39a9f17ca0a9 100644 --- a/sound/soc/codecs/rt1011.c +++ b/sound/soc/codecs/rt1011.c @@ -1987,10 +1987,10 @@ static int rt1011_set_tdm_slot(struct snd_soc_dai *dai, RT1011_TDM_I2S_DOCK_EN_1_MASK, tdm_en); snd_soc_component_update_bits(component, RT1011_TDM2_SET_2, RT1011_TDM_I2S_DOCK_EN_2_MASK, tdm_en); - if (tx_slotnum) - snd_soc_component_update_bits(component, RT1011_TDM_TOTAL_SET, - RT1011_ADCDAT1_PIN_CONFIG | RT1011_ADCDAT2_PIN_CONFIG, - RT1011_ADCDAT1_OUTPUT | RT1011_ADCDAT2_OUTPUT); + + snd_soc_component_update_bits(component, RT1011_TDM_TOTAL_SET, + RT1011_ADCDAT1_PIN_CONFIG | RT1011_ADCDAT2_PIN_CONFIG, + RT1011_ADCDAT1_OUTPUT | RT1011_ADCDAT2_OUTPUT); _set_tdm_err_: snd_soc_dapm_mutex_unlock(dapm); From 5a2429926549a8828f7dedd690b498eb9ce0296a Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Tue, 2 Mar 2021 15:25:06 -0600 Subject: [PATCH 125/587] ASoC: rt1011: clarify expression cppcheck warning: sound/soc/codecs/rt1011.c:1781:63: style: Boolean result is used in bitwise operation. Clarify expression with parentheses. [clarifyCondition] (pll_code.m_bp ? 0 : pll_code.m_code) << RT1011_PLL1_QM_SFT | ^ Signed-off-by: Pierre-Louis Bossart Link: https://lore.kernel.org/r/20210302212527.55158-4-pierre-louis.bossart@linux.intel.com Signed-off-by: Mark Brown --- sound/soc/codecs/rt1011.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/sound/soc/codecs/rt1011.c b/sound/soc/codecs/rt1011.c index 39a9f17ca0a9..238cb66f4c6a 100644 --- a/sound/soc/codecs/rt1011.c +++ b/sound/soc/codecs/rt1011.c @@ -1778,8 +1778,9 @@ static int rt1011_set_component_pll(struct snd_soc_component *component, pll_code.n_code, pll_code.k_code); snd_soc_component_write(component, RT1011_PLL_1, - (pll_code.m_bp ? 0 : pll_code.m_code) << RT1011_PLL1_QM_SFT | - pll_code.m_bp << RT1011_PLL1_BPM_SFT | pll_code.n_code); + ((pll_code.m_bp ? 0 : pll_code.m_code) << RT1011_PLL1_QM_SFT) | + (pll_code.m_bp << RT1011_PLL1_BPM_SFT) | + pll_code.n_code); snd_soc_component_write(component, RT1011_PLL_2, pll_code.k_code); From 4354ad55cde7c50c738d11edf302549537bce504 Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Tue, 2 Mar 2021 15:25:07 -0600 Subject: [PATCH 126/587] ASoC: rt1015: clarify expression cppcheck warning: sound/soc/codecs/rt1015.c:894:61: style: Boolean result is used in bitwise operation. Clarify expression with parentheses. [clarifyCondition] (pll_code.m_bp ? 0 : pll_code.m_code) << RT1015_PLL_M_SFT | ^ Signed-off-by: Pierre-Louis Bossart Link: https://lore.kernel.org/r/20210302212527.55158-5-pierre-louis.bossart@linux.intel.com Signed-off-by: Mark Brown --- sound/soc/codecs/rt1015.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/sound/soc/codecs/rt1015.c b/sound/soc/codecs/rt1015.c index 3cd967ae999d..10a7b7745f4b 100644 --- a/sound/soc/codecs/rt1015.c +++ b/sound/soc/codecs/rt1015.c @@ -893,8 +893,9 @@ static int rt1015_set_component_pll(struct snd_soc_component *component, pll_code.n_code, pll_code.k_code); snd_soc_component_write(component, RT1015_PLL1, - (pll_code.m_bp ? 0 : pll_code.m_code) << RT1015_PLL_M_SFT | - pll_code.m_bp << RT1015_PLL_M_BP_SFT | pll_code.n_code); + ((pll_code.m_bp ? 0 : pll_code.m_code) << RT1015_PLL_M_SFT) | + (pll_code.m_bp << RT1015_PLL_M_BP_SFT) | + pll_code.n_code); snd_soc_component_write(component, RT1015_PLL2, pll_code.k_code); From a426017ed5932141da4f09a35ed562bc845fa281 Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Tue, 2 Mar 2021 15:25:08 -0600 Subject: [PATCH 127/587] ASoC: rt1016: clarify expression cppcheck warning: sound/soc/codecs/rt1016.c:503:61: style: Boolean result is used in bitwise operation. Clarify expression with parentheses. [clarifyCondition] (pll_code.m_bp ? 0 : pll_code.m_code) << RT1016_PLL_M_SFT | ^ sound/soc/codecs/rt1016.c:506:40: style: Boolean result is used in bitwise operation. Clarify expression with parentheses. [clarifyCondition] pll_code.k_bp << RT1016_PLL_K_BP_SFT | ^ Signed-off-by: Pierre-Louis Bossart Link: https://lore.kernel.org/r/20210302212527.55158-6-pierre-louis.bossart@linux.intel.com Signed-off-by: Mark Brown --- sound/soc/codecs/rt1016.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/sound/soc/codecs/rt1016.c b/sound/soc/codecs/rt1016.c index c14a809da52b..7561d202274c 100644 --- a/sound/soc/codecs/rt1016.c +++ b/sound/soc/codecs/rt1016.c @@ -500,10 +500,11 @@ static int rt1016_set_component_pll(struct snd_soc_component *component, (pll_code.k_bp ? 0 : pll_code.k_code)); snd_soc_component_write(component, RT1016_PLL1, - (pll_code.m_bp ? 0 : pll_code.m_code) << RT1016_PLL_M_SFT | - pll_code.m_bp << RT1016_PLL_M_BP_SFT | pll_code.n_code); + ((pll_code.m_bp ? 0 : pll_code.m_code) << RT1016_PLL_M_SFT) | + (pll_code.m_bp << RT1016_PLL_M_BP_SFT) | + pll_code.n_code); snd_soc_component_write(component, RT1016_PLL2, - pll_code.k_bp << RT1016_PLL_K_BP_SFT | + (pll_code.k_bp << RT1016_PLL_K_BP_SFT) | (pll_code.k_bp ? 0 : pll_code.k_code)); rt1016->pll_in = freq_in; From 9e884eed54c4138bfb77da18016131a6ec1b0af7 Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Tue, 2 Mar 2021 15:25:09 -0600 Subject: [PATCH 128/587] ASoC: rt1305: clarify expression cppcheck warning: sound/soc/codecs/rt1305.c:853:63: style: Boolean result is used in bitwise operation. Clarify expression with parentheses. [clarifyCondition] (pll_code.m_bp ? 0 : pll_code.m_code) << RT1305_PLL_1_M_SFT | ^ Signed-off-by: Pierre-Louis Bossart Link: https://lore.kernel.org/r/20210302212527.55158-7-pierre-louis.bossart@linux.intel.com Signed-off-by: Mark Brown --- sound/soc/codecs/rt1305.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/sound/soc/codecs/rt1305.c b/sound/soc/codecs/rt1305.c index 16aa405fb8f0..7a0094578e46 100644 --- a/sound/soc/codecs/rt1305.c +++ b/sound/soc/codecs/rt1305.c @@ -850,8 +850,8 @@ static int rt1305_set_component_pll(struct snd_soc_component *component, pll_code.n_code, pll_code.k_code); snd_soc_component_write(component, RT1305_PLL1_1, - (pll_code.m_bp ? 0 : pll_code.m_code) << RT1305_PLL_1_M_SFT | - pll_code.m_bp << RT1305_PLL_1_M_BYPASS_SFT | + ((pll_code.m_bp ? 0 : pll_code.m_code) << RT1305_PLL_1_M_SFT) | + (pll_code.m_bp << RT1305_PLL_1_M_BYPASS_SFT) | pll_code.n_code); snd_soc_component_write(component, RT1305_PLL1_2, pll_code.k_code); From 1dd9cca701468b6285dea5188efc9aa28aabbf56 Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Tue, 2 Mar 2021 15:25:10 -0600 Subject: [PATCH 129/587] ASoC: rt1308: clarify expression cppcheck warning: sound/soc/codecs/rt1308.c:676:40: style: Boolean result is used in bitwise operation. Clarify expression with parentheses. [clarifyCondition] pll_code.k_code << RT1308_PLL1_K_SFT | ^ Signed-off-by: Pierre-Louis Bossart Link: https://lore.kernel.org/r/20210302212527.55158-8-pierre-louis.bossart@linux.intel.com Signed-off-by: Mark Brown --- sound/soc/codecs/rt1308.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/sound/soc/codecs/rt1308.c b/sound/soc/codecs/rt1308.c index 76e65844543d..b4e5546e2e21 100644 --- a/sound/soc/codecs/rt1308.c +++ b/sound/soc/codecs/rt1308.c @@ -673,10 +673,10 @@ static int rt1308_set_component_pll(struct snd_soc_component *component, pll_code.n_code, pll_code.k_code); snd_soc_component_write(component, RT1308_PLL_1, - pll_code.k_code << RT1308_PLL1_K_SFT | - pll_code.m_bp << RT1308_PLL1_M_BYPASS_SFT | - (pll_code.m_bp ? 0 : pll_code.m_code) << RT1308_PLL1_M_SFT | - pll_code.n_code << RT1308_PLL1_N_SFT); + (pll_code.k_code << RT1308_PLL1_K_SFT) | + (pll_code.m_bp << RT1308_PLL1_M_BYPASS_SFT) | + ((pll_code.m_bp ? 0 : pll_code.m_code) << RT1308_PLL1_M_SFT) | + (pll_code.n_code << RT1308_PLL1_N_SFT)); rt1308->pll_in = freq_in; rt1308->pll_out = freq_out; From 4fbd2978944cff4e747f132cf86254956bb2f045 Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Tue, 2 Mar 2021 15:25:11 -0600 Subject: [PATCH 130/587] ASoC: rt5640: clarify expression cppcheck warning: sound/soc/codecs/rt5640.c:1923:61: style: Boolean result is used in bitwise operation. Clarify expression with parentheses. [clarifyCondition] (pll_code.m_bp ? 0 : pll_code.m_code) << RT5640_PLL_M_SFT | ^ Signed-off-by: Pierre-Louis Bossart Link: https://lore.kernel.org/r/20210302212527.55158-9-pierre-louis.bossart@linux.intel.com Signed-off-by: Mark Brown --- sound/soc/codecs/rt5640.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/sound/soc/codecs/rt5640.c b/sound/soc/codecs/rt5640.c index a5674c227b3a..8c1766954b92 100644 --- a/sound/soc/codecs/rt5640.c +++ b/sound/soc/codecs/rt5640.c @@ -1918,10 +1918,10 @@ static int rt5640_set_dai_pll(struct snd_soc_dai *dai, int pll_id, int source, pll_code.n_code, pll_code.k_code); snd_soc_component_write(component, RT5640_PLL_CTRL1, - pll_code.n_code << RT5640_PLL_N_SFT | pll_code.k_code); + (pll_code.n_code << RT5640_PLL_N_SFT) | pll_code.k_code); snd_soc_component_write(component, RT5640_PLL_CTRL2, - (pll_code.m_bp ? 0 : pll_code.m_code) << RT5640_PLL_M_SFT | - pll_code.m_bp << RT5640_PLL_M_BP_SFT); + ((pll_code.m_bp ? 0 : pll_code.m_code) << RT5640_PLL_M_SFT) | + (pll_code.m_bp << RT5640_PLL_M_BP_SFT)); rt5640->pll_in = freq_in; rt5640->pll_out = freq_out; From 5864cf7f26aed303c96bcc56f8c8af914fac9bfb Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Tue, 2 Mar 2021 15:25:12 -0600 Subject: [PATCH 131/587] ASoC: rt5645: use logical OR cppcheck warning: sound/soc/codecs/rt5645.c:693:37: style:inconclusive: Boolean expression 'reg>=420&®<=461' is used in bitwise operation. Did you mean '||'? [bitwiseOnBoolean] if ((reg >= 0x1a4 && reg <= 0x1cd) | (reg >= 0x1e5 && reg <= 0x1f8) | ^ sound/soc/codecs/rt5645.c:693:70: style:inconclusive: Boolean expression 'reg==177' is used in bitwise operation. Did you mean '||'? [bitwiseOnBoolean] if ((reg >= 0x1a4 && reg <= 0x1cd) | (reg >= 0x1e5 && reg <= 0x1f8) | ^ Signed-off-by: Pierre-Louis Bossart Link: https://lore.kernel.org/r/20210302212527.55158-10-pierre-louis.bossart@linux.intel.com Signed-off-by: Mark Brown --- sound/soc/codecs/rt5645.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sound/soc/codecs/rt5645.c b/sound/soc/codecs/rt5645.c index 63a7e052eaa0..4db6cd70e32b 100644 --- a/sound/soc/codecs/rt5645.c +++ b/sound/soc/codecs/rt5645.c @@ -690,7 +690,7 @@ static int rt5645_hweq_get(struct snd_kcontrol *kcontrol, static bool rt5645_validate_hweq(unsigned short reg) { - if ((reg >= 0x1a4 && reg <= 0x1cd) | (reg >= 0x1e5 && reg <= 0x1f8) | + if ((reg >= 0x1a4 && reg <= 0x1cd) || (reg >= 0x1e5 && reg <= 0x1f8) || (reg == RT5645_EQ_CTRL2)) return true; From fa0eb20cb38d8e41ff097b985755ba62e1b32b24 Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Tue, 2 Mar 2021 15:25:13 -0600 Subject: [PATCH 132/587] ASoC: rt5645: clarify expression cppcheck warning: sound/soc/codecs/rt5645.c:2959:61: style: Boolean result is used in bitwise operation. Clarify expression with parentheses. [clarifyCondition] (pll_code.m_bp ? 0 : pll_code.m_code) << RT5645_PLL_M_SFT | ^ Signed-off-by: Pierre-Louis Bossart Link: https://lore.kernel.org/r/20210302212527.55158-11-pierre-louis.bossart@linux.intel.com Signed-off-by: Mark Brown --- sound/soc/codecs/rt5645.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/sound/soc/codecs/rt5645.c b/sound/soc/codecs/rt5645.c index 4db6cd70e32b..c39095fa14ce 100644 --- a/sound/soc/codecs/rt5645.c +++ b/sound/soc/codecs/rt5645.c @@ -2956,8 +2956,8 @@ static int rt5645_set_dai_pll(struct snd_soc_dai *dai, int pll_id, int source, snd_soc_component_write(component, RT5645_PLL_CTRL1, pll_code.n_code << RT5645_PLL_N_SFT | pll_code.k_code); snd_soc_component_write(component, RT5645_PLL_CTRL2, - (pll_code.m_bp ? 0 : pll_code.m_code) << RT5645_PLL_M_SFT | - pll_code.m_bp << RT5645_PLL_M_BP_SFT); + ((pll_code.m_bp ? 0 : pll_code.m_code) << RT5645_PLL_M_SFT) | + (pll_code.m_bp << RT5645_PLL_M_BP_SFT)); rt5645->pll_in = freq_in; rt5645->pll_out = freq_out; From 33eaffe3706ab93ced1b4477f6598a5502028ce3 Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Tue, 2 Mar 2021 15:25:14 -0600 Subject: [PATCH 133/587] ASoC: rt5651: clarify expression cppcheck warning: sound/soc/codecs/rt5659.c:3515:61: style: Boolean result is used in bitwise operation. Clarify expression with parentheses. [clarifyCondition] (pll_code.m_bp ? 0 : pll_code.m_code) << RT5659_PLL_M_SFT | ^ Signed-off-by: Pierre-Louis Bossart Link: https://lore.kernel.org/r/20210302212527.55158-12-pierre-louis.bossart@linux.intel.com Signed-off-by: Mark Brown --- sound/soc/codecs/rt5651.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/sound/soc/codecs/rt5651.c b/sound/soc/codecs/rt5651.c index e59fdc81dbd4..49fab9db5917 100644 --- a/sound/soc/codecs/rt5651.c +++ b/sound/soc/codecs/rt5651.c @@ -1498,8 +1498,8 @@ static int rt5651_set_dai_pll(struct snd_soc_dai *dai, int pll_id, int source, snd_soc_component_write(component, RT5651_PLL_CTRL1, pll_code.n_code << RT5651_PLL_N_SFT | pll_code.k_code); snd_soc_component_write(component, RT5651_PLL_CTRL2, - (pll_code.m_bp ? 0 : pll_code.m_code) << RT5651_PLL_M_SFT | - pll_code.m_bp << RT5651_PLL_M_BP_SFT); + ((pll_code.m_bp ? 0 : pll_code.m_code) << RT5651_PLL_M_SFT) | + (pll_code.m_bp << RT5651_PLL_M_BP_SFT)); rt5651->pll_in = freq_in; rt5651->pll_out = freq_out; From 9b9adc5b749d2f31885f36e2adc6c13af70543bd Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Tue, 2 Mar 2021 15:25:15 -0600 Subject: [PATCH 134/587] ASoC: rt5651: remove useless assignment cppcheck warning: sound/soc/codecs/rt5651.c:1786:13: style: Variable 'report' is assigned a value that is never used. [unreadVariable] int report = 0; ^ Signed-off-by: Pierre-Louis Bossart Link: https://lore.kernel.org/r/20210302212527.55158-13-pierre-louis.bossart@linux.intel.com Signed-off-by: Mark Brown --- sound/soc/codecs/rt5651.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sound/soc/codecs/rt5651.c b/sound/soc/codecs/rt5651.c index 49fab9db5917..fc0c83b73f09 100644 --- a/sound/soc/codecs/rt5651.c +++ b/sound/soc/codecs/rt5651.c @@ -1783,7 +1783,7 @@ static void rt5651_jack_detect_work(struct work_struct *work) struct rt5651_priv *rt5651 = container_of(work, struct rt5651_priv, jack_detect_work); struct snd_soc_component *component = rt5651->component; - int report = 0; + int report; if (!rt5651_jack_inserted(component)) { /* Jack removed, or spurious IRQ? */ From bb133ec21f865a03b8798b57815461fe0e7e6ec8 Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Tue, 2 Mar 2021 15:25:16 -0600 Subject: [PATCH 135/587] ASoC: rt5659: clarify expression cppcheck warning: sound/soc/codecs/rt5659.c:3515:61: style: Boolean result is used in bitwise operation. Clarify expression with parentheses. [clarifyCondition] (pll_code.m_bp ? 0 : pll_code.m_code) << RT5659_PLL_M_SFT | ^ Signed-off-by: Pierre-Louis Bossart Link: https://lore.kernel.org/r/20210302212527.55158-14-pierre-louis.bossart@linux.intel.com Signed-off-by: Mark Brown --- sound/soc/codecs/rt5659.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/sound/soc/codecs/rt5659.c b/sound/soc/codecs/rt5659.c index 41e5917b16a5..67f0ab817135 100644 --- a/sound/soc/codecs/rt5659.c +++ b/sound/soc/codecs/rt5659.c @@ -3512,8 +3512,8 @@ static int rt5659_set_component_pll(struct snd_soc_component *component, int pll snd_soc_component_write(component, RT5659_PLL_CTRL_1, pll_code.n_code << RT5659_PLL_N_SFT | pll_code.k_code); snd_soc_component_write(component, RT5659_PLL_CTRL_2, - (pll_code.m_bp ? 0 : pll_code.m_code) << RT5659_PLL_M_SFT | - pll_code.m_bp << RT5659_PLL_M_BP_SFT); + ((pll_code.m_bp ? 0 : pll_code.m_code) << RT5659_PLL_M_SFT) | + (pll_code.m_bp << RT5659_PLL_M_BP_SFT)); rt5659->pll_in = freq_in; rt5659->pll_out = freq_out; From 9fd72391ae8fa0811603c7489b8afacd66f5f5e6 Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Tue, 2 Mar 2021 15:25:17 -0600 Subject: [PATCH 136/587] ASoC: rt5660: clarify expression cppcheck warning: sound/soc/codecs/rt5660.c:1060:61: style: Boolean result is used in bitwise operation. Clarify expression with parentheses. [clarifyCondition] (pll_code.m_bp ? 0 : pll_code.m_code) << RT5660_PLL_M_SFT | ^ Signed-off-by: Pierre-Louis Bossart Link: https://lore.kernel.org/r/20210302212527.55158-15-pierre-louis.bossart@linux.intel.com Signed-off-by: Mark Brown --- sound/soc/codecs/rt5660.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/sound/soc/codecs/rt5660.c b/sound/soc/codecs/rt5660.c index 0edf09d3a499..33ff9156358b 100644 --- a/sound/soc/codecs/rt5660.c +++ b/sound/soc/codecs/rt5660.c @@ -1057,8 +1057,8 @@ static int rt5660_set_dai_pll(struct snd_soc_dai *dai, int pll_id, int source, snd_soc_component_write(component, RT5660_PLL_CTRL1, pll_code.n_code << RT5660_PLL_N_SFT | pll_code.k_code); snd_soc_component_write(component, RT5660_PLL_CTRL2, - (pll_code.m_bp ? 0 : pll_code.m_code) << RT5660_PLL_M_SFT | - pll_code.m_bp << RT5660_PLL_M_BP_SFT); + ((pll_code.m_bp ? 0 : pll_code.m_code) << RT5660_PLL_M_SFT) | + (pll_code.m_bp << RT5660_PLL_M_BP_SFT)); rt5660->pll_in = freq_in; rt5660->pll_out = freq_out; From ca1107d305b58a9b47ac071e1547490327bff007 Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Tue, 2 Mar 2021 15:25:18 -0600 Subject: [PATCH 137/587] ASoC: rt5663: clarify expression cppcheck warning: bitwise operation. Clarify expression with parentheses. [clarifyCondition] (pll_code.m_bp ? 0 : pll_code.m_code) << RT5663_PLL_M_SHIFT | ^ sound/soc/codecs/rt5663.c:2955:63: style: Boolean result is used in Signed-off-by: Pierre-Louis Bossart Link: https://lore.kernel.org/r/20210302212527.55158-16-pierre-louis.bossart@linux.intel.com Signed-off-by: Mark Brown --- sound/soc/codecs/rt5663.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/sound/soc/codecs/rt5663.c b/sound/soc/codecs/rt5663.c index 619fb9a031e3..be9fc58ff681 100644 --- a/sound/soc/codecs/rt5663.c +++ b/sound/soc/codecs/rt5663.c @@ -2952,8 +2952,8 @@ static int rt5663_set_dai_pll(struct snd_soc_dai *dai, int pll_id, int source, snd_soc_component_write(component, RT5663_PLL_1, pll_code.n_code << RT5663_PLL_N_SHIFT | pll_code.k_code); snd_soc_component_write(component, RT5663_PLL_2, - (pll_code.m_bp ? 0 : pll_code.m_code) << RT5663_PLL_M_SHIFT | - pll_code.m_bp << RT5663_PLL_M_BP_SHIFT); + ((pll_code.m_bp ? 0 : pll_code.m_code) << RT5663_PLL_M_SHIFT) | + (pll_code.m_bp << RT5663_PLL_M_BP_SHIFT)); rt5663->pll_in = freq_in; rt5663->pll_out = freq_out; From 17d78e93114887033f0be1c3c574004d437f7608 Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Tue, 2 Mar 2021 15:25:19 -0600 Subject: [PATCH 138/587] ASoC: rt5665: clarify expression cppcheck warning: sound/soc/codecs/rt5665.c:4388:61: style: Boolean result is used in bitwise operation. Clarify expression with parentheses. [clarifyCondition] (pll_code.m_bp ? 0 : pll_code.m_code) << RT5665_PLL_M_SFT | ^ Signed-off-by: Pierre-Louis Bossart Link: https://lore.kernel.org/r/20210302212527.55158-17-pierre-louis.bossart@linux.intel.com Signed-off-by: Mark Brown --- sound/soc/codecs/rt5665.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/sound/soc/codecs/rt5665.c b/sound/soc/codecs/rt5665.c index 8a915cdce0fe..e59323fd5bf2 100644 --- a/sound/soc/codecs/rt5665.c +++ b/sound/soc/codecs/rt5665.c @@ -4385,8 +4385,8 @@ static int rt5665_set_component_pll(struct snd_soc_component *component, int pll snd_soc_component_write(component, RT5665_PLL_CTRL_1, pll_code.n_code << RT5665_PLL_N_SFT | pll_code.k_code); snd_soc_component_write(component, RT5665_PLL_CTRL_2, - (pll_code.m_bp ? 0 : pll_code.m_code) << RT5665_PLL_M_SFT | - pll_code.m_bp << RT5665_PLL_M_BP_SFT); + ((pll_code.m_bp ? 0 : pll_code.m_code) << RT5665_PLL_M_SFT) | + (pll_code.m_bp << RT5665_PLL_M_BP_SFT)); rt5665->pll_in = freq_in; rt5665->pll_out = freq_out; From 17de60946a65fb013753ff2d7d01f890cb82d446 Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Tue, 2 Mar 2021 15:25:20 -0600 Subject: [PATCH 139/587] ASoC: rt5668: clarify expression cppcheck warning: sound/soc/codecs/rt5668.c:2185:61: style: Boolean result is used in bitwise operation. Clarify expression with parentheses. [clarifyCondition] (pll_code.m_bp ? 0 : pll_code.m_code) << RT5668_PLL_M_SFT | ^ Signed-off-by: Pierre-Louis Bossart Link: https://lore.kernel.org/r/20210302212527.55158-18-pierre-louis.bossart@linux.intel.com Signed-off-by: Mark Brown --- sound/soc/codecs/rt5668.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/sound/soc/codecs/rt5668.c b/sound/soc/codecs/rt5668.c index bc69adc9c8b7..d966d6d1bf64 100644 --- a/sound/soc/codecs/rt5668.c +++ b/sound/soc/codecs/rt5668.c @@ -2182,8 +2182,8 @@ static int rt5668_set_component_pll(struct snd_soc_component *component, snd_soc_component_write(component, RT5668_PLL_CTRL_1, pll_code.n_code << RT5668_PLL_N_SFT | pll_code.k_code); snd_soc_component_write(component, RT5668_PLL_CTRL_2, - (pll_code.m_bp ? 0 : pll_code.m_code) << RT5668_PLL_M_SFT | - pll_code.m_bp << RT5668_PLL_M_BP_SFT); + ((pll_code.m_bp ? 0 : pll_code.m_code) << RT5668_PLL_M_SFT) | + (pll_code.m_bp << RT5668_PLL_M_BP_SFT)); rt5668->pll_in = freq_in; rt5668->pll_out = freq_out; From 6fa5445685150dee9930cdfe7a96353a4dcc1d50 Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Tue, 2 Mar 2021 15:25:21 -0600 Subject: [PATCH 140/587] ASoC: rt5668: remove useless assignments cppcheck warnings: sound/soc/codecs/rt5668.c:1177:6: style: Redundant initialization for 'idx'. The initialized value is overwritten before it is read. [redundantInitialization] idx = rt5668_div_sel(rt5668, 1500000, div, ARRAY_SIZE(div)); ^ sound/soc/codecs/rt5668.c:1174:10: note: idx is initialized int idx = -EINVAL; ^ sound/soc/codecs/rt5668.c:1177:6: note: idx is overwritten idx = rt5668_div_sel(rt5668, 1500000, div, ARRAY_SIZE(div)); ^ sound/soc/codecs/rt5668.c:1202:6: style: Redundant initialization for 'idx'. The initialized value is overwritten before it is read. [redundantInitialization] idx = rt5668_div_sel(rt5668, ref, div, ARRAY_SIZE(div)); ^ sound/soc/codecs/rt5668.c:1191:25: note: idx is initialized int ref, val, reg, idx = -EINVAL; ^ sound/soc/codecs/rt5668.c:1202:6: note: idx is overwritten idx = rt5668_div_sel(rt5668, ref, div, ARRAY_SIZE(div)); ^ Signed-off-by: Pierre-Louis Bossart Link: https://lore.kernel.org/r/20210302212527.55158-19-pierre-louis.bossart@linux.intel.com Signed-off-by: Mark Brown --- sound/soc/codecs/rt5668.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/sound/soc/codecs/rt5668.c b/sound/soc/codecs/rt5668.c index d966d6d1bf64..6ab1a8bc3735 100644 --- a/sound/soc/codecs/rt5668.c +++ b/sound/soc/codecs/rt5668.c @@ -1171,7 +1171,7 @@ static int set_dmic_clk(struct snd_soc_dapm_widget *w, struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm); struct rt5668_priv *rt5668 = snd_soc_component_get_drvdata(component); - int idx = -EINVAL; + int idx; static const int div[] = {2, 4, 6, 8, 12, 16, 24, 32, 48, 64, 96, 128}; idx = rt5668_div_sel(rt5668, 1500000, div, ARRAY_SIZE(div)); @@ -1188,7 +1188,7 @@ static int set_filter_clk(struct snd_soc_dapm_widget *w, struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm); struct rt5668_priv *rt5668 = snd_soc_component_get_drvdata(component); - int ref, val, reg, idx = -EINVAL; + int ref, val, reg, idx; static const int div[] = {1, 2, 3, 4, 6, 8, 12, 16, 24, 32, 48}; val = snd_soc_component_read(component, RT5668_GPIO_CTRL_1) & From 7ad9b8d28d3f2997b4af0a074e6f609ffb5d32a7 Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Tue, 2 Mar 2021 15:25:22 -0600 Subject: [PATCH 141/587] ASoC: rt5670: clarify expression cppcheck warning: sound/soc/codecs/rt5670.c:2519:61: style: Boolean result is used in bitwise operation. Clarify expression with parentheses. [clarifyCondition] (pll_code.m_bp ? 0 : pll_code.m_code) << RT5670_PLL_M_SFT | ^ Signed-off-by: Pierre-Louis Bossart Link: https://lore.kernel.org/r/20210302212527.55158-20-pierre-louis.bossart@linux.intel.com Signed-off-by: Mark Brown --- sound/soc/codecs/rt5670.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/sound/soc/codecs/rt5670.c b/sound/soc/codecs/rt5670.c index 4063aac2a443..8dcda24f3ceb 100644 --- a/sound/soc/codecs/rt5670.c +++ b/sound/soc/codecs/rt5670.c @@ -2588,8 +2588,8 @@ static int rt5670_set_dai_pll(struct snd_soc_dai *dai, int pll_id, int source, snd_soc_component_write(component, RT5670_PLL_CTRL1, pll_code.n_code << RT5670_PLL_N_SFT | pll_code.k_code); snd_soc_component_write(component, RT5670_PLL_CTRL2, - (pll_code.m_bp ? 0 : pll_code.m_code) << RT5670_PLL_M_SFT | - pll_code.m_bp << RT5670_PLL_M_BP_SFT); + ((pll_code.m_bp ? 0 : pll_code.m_code) << RT5670_PLL_M_SFT) | + (pll_code.m_bp << RT5670_PLL_M_BP_SFT)); rt5670->pll_in = freq_in; rt5670->pll_out = freq_out; From ae052909d1b1c8dcc2406f11eb3b5f9193dc3d2f Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Tue, 2 Mar 2021 15:25:23 -0600 Subject: [PATCH 142/587] ASoC: rt5677: clarify expression cppcheck warning: sound/soc/codecs/rt5677.c:4571:61: style: Boolean result is used in bitwise operation. Clarify expression with parentheses. [clarifyCondition] (pll_code.m_bp ? 0 : pll_code.m_code) << RT5677_PLL_M_SFT | ^ Signed-off-by: Pierre-Louis Bossart Link: https://lore.kernel.org/r/20210302212527.55158-21-pierre-louis.bossart@linux.intel.com Signed-off-by: Mark Brown --- sound/soc/codecs/rt5677.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/sound/soc/codecs/rt5677.c b/sound/soc/codecs/rt5677.c index 9e449d35fc28..bc5d1d73470e 100644 --- a/sound/soc/codecs/rt5677.c +++ b/sound/soc/codecs/rt5677.c @@ -4568,8 +4568,8 @@ static int rt5677_set_dai_pll(struct snd_soc_dai *dai, int pll_id, int source, regmap_write(rt5677->regmap, RT5677_PLL1_CTRL1, pll_code.n_code << RT5677_PLL_N_SFT | pll_code.k_code); regmap_write(rt5677->regmap, RT5677_PLL1_CTRL2, - (pll_code.m_bp ? 0 : pll_code.m_code) << RT5677_PLL_M_SFT | - pll_code.m_bp << RT5677_PLL_M_BP_SFT); + ((pll_code.m_bp ? 0 : pll_code.m_code) << RT5677_PLL_M_SFT) | + (pll_code.m_bp << RT5677_PLL_M_BP_SFT)); rt5677->pll_in = freq_in; rt5677->pll_out = freq_out; From 51cb94f6c34017845030f3c20668412469345ef0 Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Tue, 2 Mar 2021 15:25:24 -0600 Subject: [PATCH 143/587] ASoC: rt5677: remove useless assignment cppcheck warning: sound/soc/codecs/rt5677.c:5335:10: style: Variable 'ret' is assigned a value that is never used. [unreadVariable] int ret = 0, loop, i, reg_irq, virq; ^ Signed-off-by: Pierre-Louis Bossart Link: https://lore.kernel.org/r/20210302212527.55158-22-pierre-louis.bossart@linux.intel.com Signed-off-by: Mark Brown --- sound/soc/codecs/rt5677.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sound/soc/codecs/rt5677.c b/sound/soc/codecs/rt5677.c index bc5d1d73470e..f655228c8c4b 100644 --- a/sound/soc/codecs/rt5677.c +++ b/sound/soc/codecs/rt5677.c @@ -5332,7 +5332,7 @@ static bool rt5677_check_hotword(struct rt5677_priv *rt5677) static irqreturn_t rt5677_irq(int unused, void *data) { struct rt5677_priv *rt5677 = data; - int ret = 0, loop, i, reg_irq, virq; + int ret, loop, i, reg_irq, virq; bool irq_fired = false; mutex_lock(&rt5677->irq_lock); From e699b2c89f8302c600d3373ae0ab12689bbf0da5 Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Tue, 2 Mar 2021 15:25:25 -0600 Subject: [PATCH 144/587] ASoC: rt5682: clarify expression cppcheck warning: sound/soc/codecs/rt5682.c:2401:65: style: Boolean result is used in bitwise operation. Clarify expression with parentheses. [clarifyCondition] (pll_code.m_bp ? 0 : pll_code.m_code) << RT5682_PLL_M_SFT | Signed-off-by: Pierre-Louis Bossart Link: https://lore.kernel.org/r/20210302212527.55158-23-pierre-louis.bossart@linux.intel.com Signed-off-by: Mark Brown --- sound/soc/codecs/rt5682.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/sound/soc/codecs/rt5682.c b/sound/soc/codecs/rt5682.c index b306ac4b9b2e..e4542200009d 100644 --- a/sound/soc/codecs/rt5682.c +++ b/sound/soc/codecs/rt5682.c @@ -2396,10 +2396,10 @@ static int rt5682_set_component_pll(struct snd_soc_component *component, pll_code.n_code, pll_code.k_code); snd_soc_component_write(component, RT5682_PLL_CTRL_1, - pll_code.n_code << RT5682_PLL_N_SFT | pll_code.k_code); + (pll_code.n_code << RT5682_PLL_N_SFT) | pll_code.k_code); snd_soc_component_write(component, RT5682_PLL_CTRL_2, - (pll_code.m_bp ? 0 : pll_code.m_code) << RT5682_PLL_M_SFT | - pll_code.m_bp << RT5682_PLL_M_BP_SFT | RT5682_PLL_RST); + ((pll_code.m_bp ? 0 : pll_code.m_code) << RT5682_PLL_M_SFT) | + (pll_code.m_bp << RT5682_PLL_M_BP_SFT | RT5682_PLL_RST)); } rt5682->pll_in[pll_id] = freq_in; From ec6aa9b59dbfb6db9447d09977d574f77a31392a Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Tue, 2 Mar 2021 15:25:26 -0600 Subject: [PATCH 145/587] ASoC: rt5682: remove useless assignments cppcheck warnings: sound/soc/codecs/rt5682.c:1234:6: style: Redundant initialization for 'idx'. The initialized value is overwritten before it is read. [redundantInitialization] idx = rt5682_div_sel(rt5682, dmic_clk_rate, div, ARRAY_SIZE(div)); ^ sound/soc/codecs/rt5682.c:1228:10: note: idx is initialized int idx = -EINVAL, dmic_clk_rate = 3072000; ^ sound/soc/codecs/rt5682.c:1234:6: note: idx is overwritten idx = rt5682_div_sel(rt5682, dmic_clk_rate, div, ARRAY_SIZE(div)); ^ sound/soc/codecs/rt5682.c:1263:6: style: Redundant initialization for 'idx'. The initialized value is overwritten before it is read. [redundantInitialization] idx = rt5682_div_sel(rt5682, ref, div_f, ARRAY_SIZE(div_f)); ^ sound/soc/codecs/rt5682.c:1248:25: note: idx is initialized int ref, val, reg, idx = -EINVAL; ^ sound/soc/codecs/rt5682.c:1263:6: note: idx is overwritten idx = rt5682_div_sel(rt5682, ref, div_f, ARRAY_SIZE(div_f)); ^ Signed-off-by: Pierre-Louis Bossart Link: https://lore.kernel.org/r/20210302212527.55158-24-pierre-louis.bossart@linux.intel.com Signed-off-by: Mark Brown --- sound/soc/codecs/rt5682.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/sound/soc/codecs/rt5682.c b/sound/soc/codecs/rt5682.c index e4542200009d..8d5b8f01f55c 100644 --- a/sound/soc/codecs/rt5682.c +++ b/sound/soc/codecs/rt5682.c @@ -1225,7 +1225,7 @@ static int set_dmic_clk(struct snd_soc_dapm_widget *w, struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm); struct rt5682_priv *rt5682 = snd_soc_component_get_drvdata(component); - int idx = -EINVAL, dmic_clk_rate = 3072000; + int idx, dmic_clk_rate = 3072000; static const int div[] = {2, 4, 6, 8, 12, 16, 24, 32, 48, 64, 96, 128}; if (rt5682->pdata.dmic_clk_rate) @@ -1245,7 +1245,7 @@ static int set_filter_clk(struct snd_soc_dapm_widget *w, struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm); struct rt5682_priv *rt5682 = snd_soc_component_get_drvdata(component); - int ref, val, reg, idx = -EINVAL; + int ref, val, reg, idx; static const int div_f[] = {1, 2, 3, 4, 6, 8, 12, 16, 24, 32, 48}; static const int div_o[] = {1, 2, 4, 6, 8, 12, 16, 24, 32, 48}; From f1a1da09faa3a875ede33386863ea363270be097 Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Tue, 2 Mar 2021 15:25:27 -0600 Subject: [PATCH 146/587] ASoC: rt5682: remove useless initialization cppcheck complains about a possible null pointer dereference, but the problem is rather an useless initialization before walking through a list. Signed-off-by: Pierre-Louis Bossart Link: https://lore.kernel.org/r/20210302212527.55158-25-pierre-louis.bossart@linux.intel.com Signed-off-by: Mark Brown --- sound/soc/codecs/rt5682.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sound/soc/codecs/rt5682.c b/sound/soc/codecs/rt5682.c index 8d5b8f01f55c..559dc6db1f7c 100644 --- a/sound/soc/codecs/rt5682.c +++ b/sound/soc/codecs/rt5682.c @@ -2751,7 +2751,7 @@ static int rt5682_bclk_set_rate(struct clk_hw *hw, unsigned long rate, container_of(hw, struct rt5682_priv, dai_clks_hw[RT5682_DAI_BCLK_IDX]); struct snd_soc_component *component = rt5682->component; - struct snd_soc_dai *dai = NULL; + struct snd_soc_dai *dai; unsigned long factor; if (!rt5682_clk_check(rt5682)) From 80cd73094c4096b3ce4d57cb8cf2c3e341c6de97 Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Tue, 2 Mar 2021 14:59:18 -0600 Subject: [PATCH 147/587] ASoC: cs4270: fix kernel-doc Add missing parameter (which happens to be ignored) Signed-off-by: Pierre-Louis Bossart Link: https://lore.kernel.org/r/20210302205926.49063-2-pierre-louis.bossart@linux.intel.com Signed-off-by: Mark Brown --- sound/soc/codecs/cs4270.c | 1 + 1 file changed, 1 insertion(+) diff --git a/sound/soc/codecs/cs4270.c b/sound/soc/codecs/cs4270.c index ddd95c8269ed..2d239e983a83 100644 --- a/sound/soc/codecs/cs4270.c +++ b/sound/soc/codecs/cs4270.c @@ -400,6 +400,7 @@ static int cs4270_hw_params(struct snd_pcm_substream *substream, * cs4270_dai_mute - enable/disable the CS4270 external mute * @dai: the SOC DAI * @mute: 0 = disable mute, 1 = enable mute + * @direction: (ignored) * * This function toggles the mute bits in the MUTE register. The CS4270's * mute capability is intended for external muting circuitry, so if the From c5036b86678fcc17bc49f85b03bd1a0ac8524646 Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Tue, 2 Mar 2021 14:59:19 -0600 Subject: [PATCH 148/587] ASoC: jz4760: fix set but not used warning MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit make W=1 warning: sound/soc/codecs/jz4760.c: In function ‘jz4760_codec_startup’: sound/soc/codecs/jz4760.c:201:6: error: variable ‘ret’ set but not used [-Werror=unused-but-set-variable] 201 | int ret; | ^~~ Signed-off-by: Pierre-Louis Bossart Link: https://lore.kernel.org/r/20210302205926.49063-3-pierre-louis.bossart@linux.intel.com Signed-off-by: Mark Brown --- sound/soc/codecs/jz4760.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/sound/soc/codecs/jz4760.c b/sound/soc/codecs/jz4760.c index e8f28ccc145a..f62abf5ad917 100644 --- a/sound/soc/codecs/jz4760.c +++ b/sound/soc/codecs/jz4760.c @@ -198,7 +198,7 @@ static int jz4760_codec_startup(struct snd_pcm_substream *substream, { struct snd_soc_component *codec = dai->component; struct snd_soc_dapm_context *dapm = snd_soc_component_get_dapm(codec); - int ret; + int ret = 0; /* * SYSCLK output from the codec to the AIC is required to keep the @@ -207,7 +207,7 @@ static int jz4760_codec_startup(struct snd_pcm_substream *substream, */ if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) ret = snd_soc_dapm_force_enable_pin(dapm, "SYSCLK"); - return 0; + return ret; } static void jz4760_codec_shutdown(struct snd_pcm_substream *substream, From 79d77f7fd1de16ea5d5c778f426007edaeb4c365 Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Tue, 2 Mar 2021 14:59:20 -0600 Subject: [PATCH 149/587] ASoC: rt5631: fix kernel-doc warning make W=1 warning: sound/soc/codecs/rt5631.c:446: warning: expecting prototype for onebit_depop_power_stage(). Prototype was for depop_seq_power_stage() instead Signed-off-by: Pierre-Louis Bossart Link: https://lore.kernel.org/r/20210302205926.49063-4-pierre-louis.bossart@linux.intel.com Signed-off-by: Mark Brown --- sound/soc/codecs/rt5631.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sound/soc/codecs/rt5631.c b/sound/soc/codecs/rt5631.c index afc1305a7fa5..3000bc128b5b 100644 --- a/sound/soc/codecs/rt5631.c +++ b/sound/soc/codecs/rt5631.c @@ -436,7 +436,7 @@ static void onebit_depop_mute_stage(struct snd_soc_component *component, int ena } /** - * onebit_depop_power_stage - step by step depop sequence in power stage. + * depop_seq_power_stage - step by step depop sequence in power stage. * @component: ASoC component * @enable: power on/off * From 5dd902d99ebb63f490d73277340745e0bd9ea7f2 Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Tue, 2 Mar 2021 14:59:21 -0600 Subject: [PATCH 150/587] ASoC: sigmadsp-regmap: fix kernel-doc warning make W=1 warning: sound/soc/codecs/sigmadsp-regmap.c:42: warning: expecting prototype for devm_sigmadsp_init_i2c(). Prototype was for devm_sigmadsp_init_regmap() instead Signed-off-by: Pierre-Louis Bossart Link: https://lore.kernel.org/r/20210302205926.49063-5-pierre-louis.bossart@linux.intel.com Signed-off-by: Mark Brown --- sound/soc/codecs/sigmadsp-regmap.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sound/soc/codecs/sigmadsp-regmap.c b/sound/soc/codecs/sigmadsp-regmap.c index bf1c4086da9f..ba9a6795e470 100644 --- a/sound/soc/codecs/sigmadsp-regmap.c +++ b/sound/soc/codecs/sigmadsp-regmap.c @@ -26,7 +26,7 @@ static int sigmadsp_read_regmap(void *control_data, } /** - * devm_sigmadsp_init_i2c() - Initialize SigmaDSP instance + * devm_sigmadsp_init_regmap() - Initialize SigmaDSP instance * @dev: The parent device * @regmap: Regmap instance to use * @ops: The sigmadsp_ops to use for this instance From 7655e32685e809fd56daf02436a0826e08368805 Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Tue, 2 Mar 2021 14:59:22 -0600 Subject: [PATCH 151/587] ASoC: amd: renoir: remove invalid kernel-doc comment make W=1 warning: sound/soc/amd/renoir/rn-pci-acp3x.c:24: warning: wrong kernel-doc identifier on line: * dmic_acpi_check = -1 - Use ACPI/DMI method to detect the DMIC hardware presence at runtime Signed-off-by: Pierre-Louis Bossart Link: https://lore.kernel.org/r/20210302205926.49063-6-pierre-louis.bossart@linux.intel.com Signed-off-by: Mark Brown --- sound/soc/amd/renoir/rn-pci-acp3x.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sound/soc/amd/renoir/rn-pci-acp3x.c b/sound/soc/amd/renoir/rn-pci-acp3x.c index 050a61fe9693..19438da5dfa5 100644 --- a/sound/soc/amd/renoir/rn-pci-acp3x.c +++ b/sound/soc/amd/renoir/rn-pci-acp3x.c @@ -20,7 +20,7 @@ static int acp_power_gating; module_param(acp_power_gating, int, 0644); MODULE_PARM_DESC(acp_power_gating, "Enable acp power gating"); -/** +/* * dmic_acpi_check = -1 - Use ACPI/DMI method to detect the DMIC hardware presence at runtime * = 0 - Skip the DMIC device creation and return probe failure * = 1 - Force DMIC support From 6a9287f5beef9787a14b0ad63ef8078d9a409f22 Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Tue, 2 Mar 2021 14:59:23 -0600 Subject: [PATCH 152/587] ASoC: fsl: fsl_ssi: fix kernel-doc warning make W=1 warning: sound/soc/fsl/fsl_ssi.c:371: warning: expecting prototype for fsl_ssi_irq(). Prototype was for fsl_ssi_isr() instead Signed-off-by: Pierre-Louis Bossart Link: https://lore.kernel.org/r/20210302205926.49063-7-pierre-louis.bossart@linux.intel.com Signed-off-by: Mark Brown --- sound/soc/fsl/fsl_ssi.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sound/soc/fsl/fsl_ssi.c b/sound/soc/fsl/fsl_ssi.c index 4e2ce47a7c6e..2b57b60431bb 100644 --- a/sound/soc/fsl/fsl_ssi.c +++ b/sound/soc/fsl/fsl_ssi.c @@ -363,7 +363,7 @@ static bool fsl_ssi_is_i2s_cbm_cfs(struct fsl_ssi *ssi) } /** - * fsl_ssi_irq - Interrupt handler to gather states + * fsl_ssi_isr - Interrupt handler to gather states * @irq: irq number * @dev_id: context */ From 9d02a3021833d19d3c1ddfb4f26e9f58772ce89f Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Tue, 2 Mar 2021 14:59:24 -0600 Subject: [PATCH 153/587] ASoC: fsl: fsl_easrc: fix kernel-doc warning make W=1 warning: sound/soc/fsl/fsl_easrc.c:383: warning: wrong kernel-doc identifier on line: * Scale filter coefficients (64 bits float) Signed-off-by: Pierre-Louis Bossart Link: https://lore.kernel.org/r/20210302205926.49063-8-pierre-louis.bossart@linux.intel.com Signed-off-by: Mark Brown --- sound/soc/fsl/fsl_easrc.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sound/soc/fsl/fsl_easrc.c b/sound/soc/fsl/fsl_easrc.c index 725a5d3aaa02..60f9c0bad3e8 100644 --- a/sound/soc/fsl/fsl_easrc.c +++ b/sound/soc/fsl/fsl_easrc.c @@ -380,7 +380,7 @@ static int fsl_easrc_resampler_config(struct fsl_asrc *easrc) } /** - * Scale filter coefficients (64 bits float) + * fsl_easrc_normalize_filter - Scale filter coefficients (64 bits float) * For input float32 normalized range (1.0,-1.0) -> output int[16,24,32]: * scale it by multiplying filter coefficients by 2^31 * For input int[16, 24, 32] -> output float32 From 45468f2cfe9679eaeb7b7371b880548c5b74bede Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Tue, 2 Mar 2021 14:59:25 -0600 Subject: [PATCH 154/587] ASoC: Intel: bytcr_wm5102: remove unused static variable MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit make W=1 warning: sound/soc/intel/boards/bytcr_wm5102.c:216:40: error: ‘byt_wm5102_dai_params’ defined but not used [-Werror=unused-const-variable=] 216 | static const struct snd_soc_pcm_stream byt_wm5102_dai_params = { | ^~~~~~~~~~~~~~~~~~~~~ Signed-off-by: Pierre-Louis Bossart Link: https://lore.kernel.org/r/20210302205926.49063-9-pierre-louis.bossart@linux.intel.com Signed-off-by: Mark Brown --- sound/soc/intel/boards/bytcr_wm5102.c | 8 -------- 1 file changed, 8 deletions(-) diff --git a/sound/soc/intel/boards/bytcr_wm5102.c b/sound/soc/intel/boards/bytcr_wm5102.c index f38850eb2eaf..fd584e380340 100644 --- a/sound/soc/intel/boards/bytcr_wm5102.c +++ b/sound/soc/intel/boards/bytcr_wm5102.c @@ -213,14 +213,6 @@ static int byt_wm5102_init(struct snd_soc_pcm_runtime *runtime) return 0; } -static const struct snd_soc_pcm_stream byt_wm5102_dai_params = { - .formats = SNDRV_PCM_FMTBIT_S16_LE, - .rate_min = 48000, - .rate_max = 48000, - .channels_min = 2, - .channels_max = 2, -}; - static int byt_wm5102_codec_fixup(struct snd_soc_pcm_runtime *rtd, struct snd_pcm_hw_params *params) { From f323ecedf3221b4827c19a41a73f08a2da16ca11 Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Tue, 2 Mar 2021 14:59:26 -0600 Subject: [PATCH 155/587] ASoC: qcom: q6dsp: fix kernel-doc warning make W=1 warning: sound/soc/qcom/qdsp6/q6afe.c:1460: warning: expecting prototype for q6afe_dam_port_prepare(). Prototype was for q6afe_cdc_dma_port_prepare() instead Signed-off-by: Pierre-Louis Bossart Link: https://lore.kernel.org/r/20210302205926.49063-10-pierre-louis.bossart@linux.intel.com Signed-off-by: Mark Brown --- sound/soc/qcom/qdsp6/q6afe.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sound/soc/qcom/qdsp6/q6afe.c b/sound/soc/qcom/qdsp6/q6afe.c index 6f700c311337..38f6042fe893 100644 --- a/sound/soc/qcom/qdsp6/q6afe.c +++ b/sound/soc/qcom/qdsp6/q6afe.c @@ -1448,7 +1448,7 @@ int q6afe_i2s_port_prepare(struct q6afe_port *port, struct q6afe_i2s_cfg *cfg) EXPORT_SYMBOL_GPL(q6afe_i2s_port_prepare); /** - * q6afe_dam_port_prepare() - Prepare dma afe port. + * q6afe_cdc_dma_port_prepare() - Prepare dma afe port. * * @port: Instance of afe port * @cfg: DMA configuration for the afe port From 4c869beda489efa3accfc6ca3177c01b97bea99e Mon Sep 17 00:00:00 2001 From: Tang Bin Date: Tue, 2 Mar 2021 21:56:30 +0800 Subject: [PATCH 156/587] ASoC: codec: Omit superfluous error message in jz4760_codec_probe() The function devm_platform_ioremap_resource has already contained error message, so remove the redundant dev_err here. Signed-off-by: Tang Bin Acked-by: Paul Cercueil Link: https://lore.kernel.org/r/20210302135630.11456-1-tangbin@cmss.chinamobile.com Signed-off-by: Mark Brown --- sound/soc/codecs/jz4760.c | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/sound/soc/codecs/jz4760.c b/sound/soc/codecs/jz4760.c index e8f28ccc145a..5ae0e312bcfc 100644 --- a/sound/soc/codecs/jz4760.c +++ b/sound/soc/codecs/jz4760.c @@ -841,11 +841,8 @@ static int jz4760_codec_probe(struct platform_device *pdev) codec->dev = dev; codec->base = devm_platform_ioremap_resource(pdev, 0); - if (IS_ERR(codec->base)) { - ret = PTR_ERR(codec->base); - dev_err(dev, "Failed to ioremap mmio memory: %d\n", ret); - return ret; - } + if (IS_ERR(codec->base)) + return PTR_ERR(codec->base); codec->regmap = devm_regmap_init(dev, NULL, codec, &jz4760_codec_regmap_config); From 5d90fef6809138f0d31271b06940950896671677 Mon Sep 17 00:00:00 2001 From: Fabio Estevam Date: Tue, 2 Mar 2021 11:28:17 -0300 Subject: [PATCH 157/587] ASoC: sgtl5000: Fix identation of .driver elements The .driver elements are not correctly idented. Fix the identation of the .driver elements. Signed-off-by: Fabio Estevam Link: https://lore.kernel.org/r/20210302142817.2141923-1-festevam@gmail.com Signed-off-by: Mark Brown --- sound/soc/codecs/sgtl5000.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/sound/soc/codecs/sgtl5000.c b/sound/soc/codecs/sgtl5000.c index 6d9bb256a2cf..97bf1f222805 100644 --- a/sound/soc/codecs/sgtl5000.c +++ b/sound/soc/codecs/sgtl5000.c @@ -1819,9 +1819,9 @@ MODULE_DEVICE_TABLE(of, sgtl5000_dt_ids); static struct i2c_driver sgtl5000_i2c_driver = { .driver = { - .name = "sgtl5000", - .of_match_table = sgtl5000_dt_ids, - }, + .name = "sgtl5000", + .of_match_table = sgtl5000_dt_ids, + }, .probe = sgtl5000_i2c_probe, .remove = sgtl5000_i2c_remove, .id_table = sgtl5000_id, From 3d01f5ee19c37c2dcaa937f060014dfd46a8ab2f Mon Sep 17 00:00:00 2001 From: Wei Yongjun Date: Wed, 3 Mar 2021 06:40:41 +0000 Subject: [PATCH 158/587] ASoC: rt1316: Fix return value check in rt1316_sdw_probe() In case of error, the function devm_regmap_init_sdw() returns ERR_PTR() and never returns NULL. The NULL test in the return value check should be replaced with IS_ERR(). Fixes: a262057df513 ("ASoC: rt1316: Add RT1316 SDCA vendor-specific driver") Reported-by: Hulk Robot Signed-off-by: Wei Yongjun Link: https://lore.kernel.org/r/20210303064041.898281-1-weiyongjun1@huawei.com Signed-off-by: Mark Brown --- sound/soc/codecs/rt1316-sdw.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/sound/soc/codecs/rt1316-sdw.c b/sound/soc/codecs/rt1316-sdw.c index a6fb34a48f33..3b029c56467d 100644 --- a/sound/soc/codecs/rt1316-sdw.c +++ b/sound/soc/codecs/rt1316-sdw.c @@ -669,8 +669,8 @@ static int rt1316_sdw_probe(struct sdw_slave *slave, /* Regmap Initialization */ regmap = devm_regmap_init_sdw(slave, &rt1316_sdw_regmap); - if (!regmap) - return -EINVAL; + if (IS_ERR(regmap)) + return PTR_ERR(regmap); return rt1316_sdw_init(&slave->dev, regmap, slave); } From a5e78cfbd50e33c19236f32693516380d1a61c34 Mon Sep 17 00:00:00 2001 From: Yang Li Date: Wed, 3 Mar 2021 17:08:01 +0800 Subject: [PATCH 159/587] ASoC: codecs: fix platform_no_drv_owner.cocci warnings ./sound/soc/codecs/lpass-rx-macro.c:3588:3-8: No need to set .owner here. The core will do it. Remove .owner field if calls are used which set it automatically Reported-by: Abaci Robot Signed-off-by: Yang Li Link: https://lore.kernel.org/r/1614762481-102466-1-git-send-email-yang.lee@linux.alibaba.com Signed-off-by: Mark Brown --- sound/soc/codecs/lpass-rx-macro.c | 1 - 1 file changed, 1 deletion(-) diff --git a/sound/soc/codecs/lpass-rx-macro.c b/sound/soc/codecs/lpass-rx-macro.c index 76909c50d7b9..c0f7b5ecbf9e 100644 --- a/sound/soc/codecs/lpass-rx-macro.c +++ b/sound/soc/codecs/lpass-rx-macro.c @@ -3585,7 +3585,6 @@ static const struct of_device_id rx_macro_dt_match[] = { static struct platform_driver rx_macro_driver = { .driver = { .name = "rx_macro", - .owner = THIS_MODULE, .of_match_table = rx_macro_dt_match, .suppress_bind_attrs = true, }, From 51bc908fccb1b4ed322626185a786b790d081111 Mon Sep 17 00:00:00 2001 From: Colin Ian King Date: Wed, 3 Mar 2021 09:18:35 +0000 Subject: [PATCH 160/587] ASoC: fsl: fsl_easrc: Fix uninitialized variable st2_mem_alloc A previous cleanup commit removed the ininitialization of st2_mem_alloc. Fix this by restoring the original behaviour by initializing it to zero. Addresses-Coverity: ("Uninitialized scalar variable") Fixes: e80382fe721f ("ASoC: fsl: fsl_easrc: remove useless assignments") Signed-off-by: Colin Ian King Link: https://lore.kernel.org/r/20210303091835.5024-1-colin.king@canonical.com Signed-off-by: Mark Brown --- sound/soc/fsl/fsl_easrc.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sound/soc/fsl/fsl_easrc.c b/sound/soc/fsl/fsl_easrc.c index 725a5d3aaa02..e823c9c13764 100644 --- a/sound/soc/fsl/fsl_easrc.c +++ b/sound/soc/fsl/fsl_easrc.c @@ -710,7 +710,7 @@ static int fsl_easrc_max_ch_for_slot(struct fsl_asrc_pair *ctx, struct fsl_easrc_slot *slot) { struct fsl_easrc_ctx_priv *ctx_priv = ctx->private; - int st1_mem_alloc = 0, st2_mem_alloc; + int st1_mem_alloc = 0, st2_mem_alloc = 0; int pf_mem_alloc = 0; int max_channels = 8 - slot->num_channel; int channels = 0; From aa4890f673f9d54d3cb0ea156acfe41958ea7f08 Mon Sep 17 00:00:00 2001 From: Shengjiu Wang Date: Mon, 8 Mar 2021 10:34:37 +0800 Subject: [PATCH 161/587] ASoC: wm8962: Relax bit clock divider searching With S20_3LE format case, the sysclk = rate * 384, the bclk = rate * 20 * 2, there is no proper bclk divider for 384 / 40, because current condition needs exact match. So driver fails to configure the clocking: wm8962 3-001a: Unsupported BCLK ratio 9 Fix this by relaxing bitclk divider searching, so that when no exact value can be derived from sysclk pick the closest value greater than expected bitclk. Signed-off-by: Shengjiu Wang Reviewed-by: Daniel Baluta Acked-by: Charles Keepax Link: https://lore.kernel.org/r/1615170877-25918-1-git-send-email-shengjiu.wang@nxp.com Signed-off-by: Mark Brown --- sound/soc/codecs/wm8962.c | 23 +++++++++++++---------- 1 file changed, 13 insertions(+), 10 deletions(-) diff --git a/sound/soc/codecs/wm8962.c b/sound/soc/codecs/wm8962.c index ce4666a74793..34080f497584 100644 --- a/sound/soc/codecs/wm8962.c +++ b/sound/soc/codecs/wm8962.c @@ -2403,6 +2403,7 @@ static const int sysclk_rates[] = { static void wm8962_configure_bclk(struct snd_soc_component *component) { struct wm8962_priv *wm8962 = snd_soc_component_get_drvdata(component); + int best, min_diff, diff; int dspclk, i; int clocking2 = 0; int clocking4 = 0; @@ -2473,23 +2474,25 @@ static void wm8962_configure_bclk(struct snd_soc_component *component) dev_dbg(component->dev, "DSPCLK is %dHz, BCLK %d\n", dspclk, wm8962->bclk); - /* We're expecting an exact match */ + /* Search a proper bclk, not exact match. */ + best = 0; + min_diff = INT_MAX; for (i = 0; i < ARRAY_SIZE(bclk_divs); i++) { if (bclk_divs[i] < 0) continue; - if (dspclk / bclk_divs[i] == wm8962->bclk) { - dev_dbg(component->dev, "Selected BCLK_DIV %d for %dHz\n", - bclk_divs[i], wm8962->bclk); - clocking2 |= i; + diff = (dspclk / bclk_divs[i]) - wm8962->bclk; + if (diff < 0) /* Table is sorted */ break; + if (diff < min_diff) { + best = i; + min_diff = diff; } } - if (i == ARRAY_SIZE(bclk_divs)) { - dev_err(component->dev, "Unsupported BCLK ratio %d\n", - dspclk / wm8962->bclk); - return; - } + wm8962->bclk = dspclk / bclk_divs[best]; + clocking2 |= best; + dev_dbg(component->dev, "Selected BCLK_DIV %d for %dHz\n", + bclk_divs[best], wm8962->bclk); aif2 |= wm8962->bclk / wm8962->lrclk; dev_dbg(component->dev, "Selected LRCLK divisor %d for %dHz\n", From 90b2d37338791311df484d671b262b2ee392962c Mon Sep 17 00:00:00 2001 From: Tang Bin Date: Tue, 2 Mar 2021 20:50:02 +0800 Subject: [PATCH 162/587] ASoC: fsl_xcvr: Use devm_platform_ioremap_resource_byname() to simplify code In this function, devm_platform_ioremap_resource_byname() should be suitable to simplify code. Signed-off-by: Tang Bin Link: https://lore.kernel.org/r/20210302125002.23900-1-tangbin@cmss.chinamobile.com Signed-off-by: Mark Brown --- sound/soc/fsl/fsl_xcvr.c | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/sound/soc/fsl/fsl_xcvr.c b/sound/soc/fsl/fsl_xcvr.c index 80416e4ed53e..6cb558165848 100644 --- a/sound/soc/fsl/fsl_xcvr.c +++ b/sound/soc/fsl/fsl_xcvr.c @@ -1130,7 +1130,7 @@ static int fsl_xcvr_probe(struct platform_device *pdev) { struct device *dev = &pdev->dev; struct fsl_xcvr *xcvr; - struct resource *ram_res, *regs_res, *rx_res, *tx_res; + struct resource *rx_res, *tx_res; void __iomem *regs; int ret, irq; @@ -1165,13 +1165,11 @@ static int fsl_xcvr_probe(struct platform_device *pdev) return PTR_ERR(xcvr->pll_ipg_clk); } - ram_res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "ram"); - xcvr->ram_addr = devm_ioremap_resource(dev, ram_res); + xcvr->ram_addr = devm_platform_ioremap_resource_byname(pdev, "ram"); if (IS_ERR(xcvr->ram_addr)) return PTR_ERR(xcvr->ram_addr); - regs_res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "regs"); - regs = devm_ioremap_resource(dev, regs_res); + regs = devm_platform_ioremap_resource_byname(pdev, "regs"); if (IS_ERR(regs)) return PTR_ERR(regs); From 20d17057f0a8c7bfecfb9e05bd5ba33a100a9a15 Mon Sep 17 00:00:00 2001 From: Jack Yu Date: Tue, 2 Mar 2021 18:30:42 +0800 Subject: [PATCH 163/587] ASoC: rt715-sdca: Add RT715 sdca vendor-specific driver This is initial sdca version of codec driver for rt715. Signed-off-by: Jack Yu Link: https://lore.kernel.org/r/20210302103042.19528-1-jack.yu@realtek.com Signed-off-by: Mark Brown --- sound/soc/codecs/Kconfig | 7 + sound/soc/codecs/Makefile | 2 + sound/soc/codecs/rt715-sdca-sdw.c | 278 ++++++++ sound/soc/codecs/rt715-sdca-sdw.h | 170 +++++ sound/soc/codecs/rt715-sdca.c | 1076 +++++++++++++++++++++++++++++ sound/soc/codecs/rt715-sdca.h | 136 ++++ 6 files changed, 1669 insertions(+) create mode 100644 sound/soc/codecs/rt715-sdca-sdw.c create mode 100644 sound/soc/codecs/rt715-sdca-sdw.h create mode 100644 sound/soc/codecs/rt715-sdca.c create mode 100644 sound/soc/codecs/rt715-sdca.h diff --git a/sound/soc/codecs/Kconfig b/sound/soc/codecs/Kconfig index 0eb9f06660e7..00dfac882f94 100644 --- a/sound/soc/codecs/Kconfig +++ b/sound/soc/codecs/Kconfig @@ -181,6 +181,7 @@ config SND_SOC_ALL_CODECS imply SND_SOC_RT700_SDW imply SND_SOC_RT711_SDW imply SND_SOC_RT715_SDW + imply SND_SOC_RT715_SDCA_SDW imply SND_SOC_RT1308_SDW imply SND_SOC_RT1316_SDW imply SND_SOC_SGTL5000 @@ -1256,6 +1257,12 @@ config SND_SOC_RT715_SDW select SND_SOC_RT715 select REGMAP_SOUNDWIRE +config SND_SOC_RT715_SDCA_SDW + tristate "Realtek RT715 SDCA Codec - SDW" + depends on SOUNDWIRE + select REGMAP_SOUNDWIRE + select REGMAP_SOUNDWIRE_MBQ + #Freescale sgtl5000 codec config SND_SOC_SGTL5000 tristate "Freescale SGTL5000 CODEC" diff --git a/sound/soc/codecs/Makefile b/sound/soc/codecs/Makefile index 1585bc1d9a25..09dd9c168aac 100644 --- a/sound/soc/codecs/Makefile +++ b/sound/soc/codecs/Makefile @@ -198,6 +198,7 @@ snd-soc-rt5682-i2c-objs := rt5682-i2c.o snd-soc-rt700-objs := rt700.o rt700-sdw.o snd-soc-rt711-objs := rt711.o rt711-sdw.o snd-soc-rt715-objs := rt715.o rt715-sdw.o +snd-soc-rt715-sdca-objs := rt715-sdca.o rt715-sdca-sdw.o snd-soc-sgtl5000-objs := sgtl5000.o snd-soc-alc5623-objs := alc5623.o snd-soc-alc5632-objs := alc5632.o @@ -514,6 +515,7 @@ obj-$(CONFIG_SND_SOC_RT5682_SDW) += snd-soc-rt5682-sdw.o obj-$(CONFIG_SND_SOC_RT700) += snd-soc-rt700.o obj-$(CONFIG_SND_SOC_RT711) += snd-soc-rt711.o obj-$(CONFIG_SND_SOC_RT715) += snd-soc-rt715.o +obj-$(CONFIG_SND_SOC_RT715_SDCA_SDW) += snd-soc-rt715-sdca.o obj-$(CONFIG_SND_SOC_SGTL5000) += snd-soc-sgtl5000.o obj-$(CONFIG_SND_SOC_SIGMADSP) += snd-soc-sigmadsp.o obj-$(CONFIG_SND_SOC_SIGMADSP_I2C) += snd-soc-sigmadsp-i2c.o diff --git a/sound/soc/codecs/rt715-sdca-sdw.c b/sound/soc/codecs/rt715-sdca-sdw.c new file mode 100644 index 000000000000..bcced85876b0 --- /dev/null +++ b/sound/soc/codecs/rt715-sdca-sdw.c @@ -0,0 +1,278 @@ +// SPDX-License-Identifier: GPL-2.0-only +// +// rt715-sdca-sdw.c -- rt715 ALSA SoC audio driver +// +// Copyright(c) 2020 Realtek Semiconductor Corp. +// +// + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "rt715-sdca.h" +#include "rt715-sdca-sdw.h" + +static bool rt715_sdca_readable_register(struct device *dev, unsigned int reg) +{ + switch (reg) { + case 0x201a ... 0x2027: + case 0x2029 ... 0x202a: + case 0x202d ... 0x2034: + case 0x2200 ... 0x2204: + case 0x2206 ... 0x2212: + case 0x2230 ... 0x2239: + case 0x2f5b: + case SDW_SDCA_CTL(FUN_MIC_ARRAY, RT715_SDCA_SMPU_TRIG_ST_EN, + RT715_SDCA_SMPU_TRIG_ST_CTRL, CH_00): + return true; + default: + return false; + } +} + +static bool rt715_sdca_volatile_register(struct device *dev, unsigned int reg) +{ + switch (reg) { + case 0x201b: + case 0x201c: + case 0x201d: + case 0x201f: + case 0x2021: + case 0x2023: + case 0x2230: + case 0x202d ... 0x202f: /* BRA */ + case 0x2200 ... 0x2212: /* i2c debug */ + case 0x2f07: + case 0x2f1b ... 0x2f1e: + case 0x2f30 ... 0x2f34: + case 0x2f50 ... 0x2f51: + case 0x2f53 ... 0x2f59: + case 0x2f5c ... 0x2f5f: + case SDW_SDCA_CTL(FUN_MIC_ARRAY, RT715_SDCA_SMPU_TRIG_ST_EN, + RT715_SDCA_SMPU_TRIG_ST_CTRL, CH_00): /* VAD Searching status */ + return true; + default: + return false; + } +} + +static bool rt715_sdca_mbq_readable_register(struct device *dev, unsigned int reg) +{ + switch (reg) { + case 0x2000000: + case 0x200002b: + case 0x2000036: + case 0x2000037: + case 0x2000039: + case 0x6100000: + return true; + default: + return false; + } +} + +static bool rt715_sdca_mbq_volatile_register(struct device *dev, unsigned int reg) +{ + switch (reg) { + case 0x2000000: + return true; + default: + return false; + } +} + +static const struct regmap_config rt715_sdca_regmap = { + .reg_bits = 32, + .val_bits = 8, + .readable_reg = rt715_sdca_readable_register, + .volatile_reg = rt715_sdca_volatile_register, + .max_register = 0x43ffffff, + .reg_defaults = rt715_reg_defaults_sdca, + .num_reg_defaults = ARRAY_SIZE(rt715_reg_defaults_sdca), + .cache_type = REGCACHE_RBTREE, + .use_single_read = true, + .use_single_write = true, +}; + +static const struct regmap_config rt715_sdca_mbq_regmap = { + .name = "sdw-mbq", + .reg_bits = 32, + .val_bits = 16, + .readable_reg = rt715_sdca_mbq_readable_register, + .volatile_reg = rt715_sdca_mbq_volatile_register, + .max_register = 0x43ffffff, + .reg_defaults = rt715_mbq_reg_defaults_sdca, + .num_reg_defaults = ARRAY_SIZE(rt715_mbq_reg_defaults_sdca), + .cache_type = REGCACHE_RBTREE, + .use_single_read = true, + .use_single_write = true, +}; + +static int rt715_sdca_update_status(struct sdw_slave *slave, + enum sdw_slave_status status) +{ + struct rt715_sdca_priv *rt715 = dev_get_drvdata(&slave->dev); + + /* Update the status */ + rt715->status = status; + + /* + * Perform initialization only if slave status is present and + * hw_init flag is false + */ + if (rt715->hw_init || rt715->status != SDW_SLAVE_ATTACHED) + return 0; + + /* perform I/O transfers required for Slave initialization */ + return rt715_sdca_io_init(&slave->dev, slave); +} + +static int rt715_sdca_read_prop(struct sdw_slave *slave) +{ + struct sdw_slave_prop *prop = &slave->prop; + int nval, i; + u32 bit; + unsigned long addr; + struct sdw_dpn_prop *dpn; + + prop->paging_support = true; + + /* first we need to allocate memory for set bits in port lists */ + prop->source_ports = 0x50;/* BITMAP: 01010000 */ + prop->sink_ports = 0x0; /* BITMAP: 00000000 */ + + nval = hweight32(prop->source_ports); + prop->src_dpn_prop = devm_kcalloc(&slave->dev, nval, + sizeof(*prop->src_dpn_prop), + GFP_KERNEL); + if (!prop->src_dpn_prop) + return -ENOMEM; + + dpn = prop->src_dpn_prop; + i = 0; + addr = prop->source_ports; + for_each_set_bit(bit, &addr, 32) { + dpn[i].num = bit; + dpn[i].simple_ch_prep_sm = true; + dpn[i].ch_prep_timeout = 10; + i++; + } + + /* set the timeout values */ + prop->clk_stop_timeout = 20; + + return 0; +} + +static struct sdw_slave_ops rt715_sdca_slave_ops = { + .read_prop = rt715_sdca_read_prop, + .update_status = rt715_sdca_update_status, +}; + +static int rt715_sdca_sdw_probe(struct sdw_slave *slave, + const struct sdw_device_id *id) +{ + struct regmap *mbq_regmap, *regmap; + + slave->ops = &rt715_sdca_slave_ops; + + /* Regmap Initialization */ + mbq_regmap = devm_regmap_init_sdw_mbq(slave, &rt715_sdca_mbq_regmap); + if (!mbq_regmap) + return -EINVAL; + + regmap = devm_regmap_init_sdw(slave, &rt715_sdca_regmap); + if (!regmap) + return -EINVAL; + + return rt715_sdca_init(&slave->dev, mbq_regmap, regmap, slave); +} + +static const struct sdw_device_id rt715_sdca_id[] = { + SDW_SLAVE_ENTRY_EXT(0x025d, 0x715, 0x3, 0x1, 0), + SDW_SLAVE_ENTRY_EXT(0x025d, 0x714, 0x3, 0x1, 0), + {}, +}; +MODULE_DEVICE_TABLE(sdw, rt715_sdca_id); + +static int __maybe_unused rt715_dev_suspend(struct device *dev) +{ + struct rt715_sdca_priv *rt715 = dev_get_drvdata(dev); + + if (!rt715->hw_init) + return 0; + + regcache_cache_only(rt715->regmap, true); + regcache_mark_dirty(rt715->regmap); + regcache_cache_only(rt715->mbq_regmap, true); + regcache_mark_dirty(rt715->mbq_regmap); + + return 0; +} + +#define RT715_PROBE_TIMEOUT 5000 + +static int __maybe_unused rt715_dev_resume(struct device *dev) +{ + struct sdw_slave *slave = dev_to_sdw_dev(dev); + struct rt715_sdca_priv *rt715 = dev_get_drvdata(dev); + unsigned long time; + + if (!rt715->hw_init) + return 0; + + if (!slave->unattach_request) + goto regmap_sync; + + time = wait_for_completion_timeout(&slave->enumeration_complete, + msecs_to_jiffies(RT715_PROBE_TIMEOUT)); + if (!time) { + dev_err(&slave->dev, "Enumeration not complete, timed out\n"); + return -ETIMEDOUT; + } + +regmap_sync: + slave->unattach_request = 0; + regcache_cache_only(rt715->regmap, false); + regcache_sync_region(rt715->regmap, + SDW_SDCA_CTL(FUN_JACK_CODEC, RT715_SDCA_ST_EN, RT715_SDCA_ST_CTRL, + CH_00), + SDW_SDCA_CTL(FUN_MIC_ARRAY, RT715_SDCA_SMPU_TRIG_ST_EN, + RT715_SDCA_SMPU_TRIG_ST_CTRL, CH_00)); + regcache_cache_only(rt715->mbq_regmap, false); + regcache_sync_region(rt715->mbq_regmap, 0x2000000, 0x61020ff); + regcache_sync_region(rt715->mbq_regmap, + SDW_SDCA_CTL(FUN_JACK_CODEC, RT715_SDCA_ST_EN, RT715_SDCA_ST_CTRL, + CH_00), + SDW_SDCA_CTL(FUN_MIC_ARRAY, RT715_SDCA_SMPU_TRIG_ST_EN, + RT715_SDCA_SMPU_TRIG_ST_CTRL, CH_00)); + + return 0; +} + +static const struct dev_pm_ops rt715_pm = { + SET_SYSTEM_SLEEP_PM_OPS(rt715_dev_suspend, rt715_dev_resume) + SET_RUNTIME_PM_OPS(rt715_dev_suspend, rt715_dev_resume, NULL) +}; + +static struct sdw_driver rt715_sdw_driver = { + .driver = { + .name = "rt715-sdca", + .owner = THIS_MODULE, + .pm = &rt715_pm, + }, + .probe = rt715_sdca_sdw_probe, + .ops = &rt715_sdca_slave_ops, + .id_table = rt715_sdca_id, +}; +module_sdw_driver(rt715_sdw_driver); + +MODULE_DESCRIPTION("ASoC RT715 driver SDW SDCA"); +MODULE_AUTHOR("Jack Yu "); +MODULE_LICENSE("GPL v2"); diff --git a/sound/soc/codecs/rt715-sdca-sdw.h b/sound/soc/codecs/rt715-sdca-sdw.h new file mode 100644 index 000000000000..cd365bb60747 --- /dev/null +++ b/sound/soc/codecs/rt715-sdca-sdw.h @@ -0,0 +1,170 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * rt715-sdca-sdw.h -- RT715 ALSA SoC audio driver header + * + * Copyright(c) 2020 Realtek Semiconductor Corp. + */ + +#ifndef __RT715_SDW_SDCA_H__ +#define __RT715_SDW_SDCA_H__ + +#include + +static const struct reg_default rt715_reg_defaults_sdca[] = { + { 0x201a, 0x00 }, + { 0x201e, 0x00 }, + { 0x2020, 0x00 }, + { 0x2021, 0x00 }, + { 0x2022, 0x00 }, + { 0x2023, 0x00 }, + { 0x2024, 0x00 }, + { 0x2025, 0x01 }, + { 0x2026, 0x00 }, + { 0x2027, 0x00 }, + { 0x2029, 0x00 }, + { 0x202a, 0x00 }, + { 0x202d, 0x00 }, + { 0x202e, 0x00 }, + { 0x202f, 0x00 }, + { 0x2030, 0x00 }, + { 0x2031, 0x00 }, + { 0x2032, 0x00 }, + { 0x2033, 0x00 }, + { 0x2034, 0x00 }, + { 0x2230, 0x00 }, + { 0x2231, 0x2f }, + { 0x2232, 0x80 }, + { 0x2233, 0x00 }, + { 0x2234, 0x00 }, + { 0x2235, 0x00 }, + { 0x2236, 0x00 }, + { 0x2237, 0x00 }, + { 0x2238, 0x00 }, + { 0x2239, 0x00 }, + { 0x2f01, 0x00 }, + { 0x2f02, 0x09 }, + { 0x2f03, 0x0b }, + { 0x2f04, 0x00 }, + { 0x2f05, 0x0e }, + { 0x2f06, 0x01 }, + { 0x2f08, 0x00 }, + { 0x2f09, 0x00 }, + { 0x2f0a, 0x00 }, + { 0x2f0b, 0x00 }, + { 0x2f0c, 0x00 }, + { 0x2f0d, 0x00 }, + { 0x2f0e, 0x12 }, + { 0x2f0f, 0x00 }, + { 0x2f10, 0x00 }, + { 0x2f11, 0x00 }, + { 0x2f12, 0x00 }, + { 0x2f13, 0x00 }, + { 0x2f14, 0x00 }, + { 0x2f15, 0x00 }, + { 0x2f16, 0x00 }, + { 0x2f17, 0x00 }, + { 0x2f18, 0x00 }, + { 0x2f19, 0x03 }, + { 0x2f1a, 0x00 }, + { 0x2f1f, 0x10 }, + { 0x2f20, 0x00 }, + { 0x2f21, 0x00 }, + { 0x2f22, 0x00 }, + { 0x2f23, 0x00 }, + { 0x2f24, 0x00 }, + { 0x2f25, 0x00 }, + { 0x2f52, 0x01 }, + { 0x2f5a, 0x02 }, + { 0x2f5b, 0x05 }, + { SDW_SDCA_CTL(FUN_MIC_ARRAY, RT715_SDCA_CX_CLK_SEL_EN, + RT715_SDCA_CX_CLK_SEL_CTRL, CH_00), 0x1 }, + { SDW_SDCA_CTL(FUN_MIC_ARRAY, RT715_SDCA_FU_ADC8_9_VOL, + RT715_SDCA_FU_MUTE_CTRL, CH_01), 0x01 }, + { SDW_SDCA_CTL(FUN_MIC_ARRAY, RT715_SDCA_FU_ADC8_9_VOL, + RT715_SDCA_FU_MUTE_CTRL, CH_02), 0x01 }, + { SDW_SDCA_CTL(FUN_MIC_ARRAY, RT715_SDCA_FU_ADC8_9_VOL, + RT715_SDCA_FU_MUTE_CTRL, CH_03), 0x01 }, + { SDW_SDCA_CTL(FUN_MIC_ARRAY, RT715_SDCA_FU_ADC8_9_VOL, + RT715_SDCA_FU_MUTE_CTRL, CH_04), 0x01 }, + { SDW_SDCA_CTL(FUN_MIC_ARRAY, RT715_SDCA_FU_ADC10_11_VOL, + RT715_SDCA_FU_MUTE_CTRL, CH_01), 0x01 }, + { SDW_SDCA_CTL(FUN_MIC_ARRAY, RT715_SDCA_FU_ADC10_11_VOL, + RT715_SDCA_FU_MUTE_CTRL, CH_02), 0x01 }, + { SDW_SDCA_CTL(FUN_MIC_ARRAY, RT715_SDCA_FU_ADC10_11_VOL, + RT715_SDCA_FU_MUTE_CTRL, CH_03), 0x01 }, + { SDW_SDCA_CTL(FUN_MIC_ARRAY, RT715_SDCA_FU_ADC10_11_VOL, + RT715_SDCA_FU_MUTE_CTRL, CH_04), 0x01 }, + { SDW_SDCA_CTL(FUN_MIC_ARRAY, RT715_SDCA_FU_ADC7_27_VOL, + RT715_SDCA_FU_MUTE_CTRL, CH_01), 0x01 }, + { SDW_SDCA_CTL(FUN_MIC_ARRAY, RT715_SDCA_FU_ADC7_27_VOL, + RT715_SDCA_FU_MUTE_CTRL, CH_02), 0x01 }, + { SDW_SDCA_CTL(FUN_MIC_ARRAY, RT715_SDCA_SMPU_TRIG_ST_EN, + RT715_SDCA_SMPU_TRIG_EN_CTRL, CH_00), 0x02 }, + { SDW_SDCA_CTL(FUN_MIC_ARRAY, RT715_SDCA_SMPU_TRIG_ST_EN, + RT715_SDCA_SMPU_TRIG_ST_CTRL, CH_00), 0x00 }, + { SDW_SDCA_CTL(FUN_MIC_ARRAY, RT715_SDCA_FU_ADC7_27_VOL, + RT715_SDCA_FU_MUTE_CTRL, CH_01), 0x01 }, + { SDW_SDCA_CTL(FUN_MIC_ARRAY, RT715_SDCA_FU_ADC7_27_VOL, + RT715_SDCA_FU_MUTE_CTRL, CH_02), 0x01 }, +}; + +static const struct reg_default rt715_mbq_reg_defaults_sdca[] = { + { 0x200002b, 0x0420 }, + { 0x2000036, 0x0000 }, + { 0x2000037, 0x0000 }, + { 0x2000039, 0xaa81 }, + { 0x6100000, 0x0100 }, + { SDW_SDCA_CTL(FUN_MIC_ARRAY, RT715_SDCA_FU_ADC8_9_VOL, + RT715_SDCA_FU_VOL_CTRL, CH_01), 0x00 }, + { SDW_SDCA_CTL(FUN_MIC_ARRAY, RT715_SDCA_FU_ADC8_9_VOL, + RT715_SDCA_FU_VOL_CTRL, CH_02), 0x00 }, + { SDW_SDCA_CTL(FUN_MIC_ARRAY, RT715_SDCA_FU_ADC8_9_VOL, + RT715_SDCA_FU_VOL_CTRL, CH_03), 0x00 }, + { SDW_SDCA_CTL(FUN_MIC_ARRAY, RT715_SDCA_FU_ADC8_9_VOL, + RT715_SDCA_FU_VOL_CTRL, CH_04), 0x00 }, + { SDW_SDCA_CTL(FUN_MIC_ARRAY, RT715_SDCA_FU_ADC10_11_VOL, + RT715_SDCA_FU_VOL_CTRL, CH_01), 0x00 }, + { SDW_SDCA_CTL(FUN_MIC_ARRAY, RT715_SDCA_FU_ADC10_11_VOL, + RT715_SDCA_FU_VOL_CTRL, CH_02), 0x00 }, + { SDW_SDCA_CTL(FUN_MIC_ARRAY, RT715_SDCA_FU_ADC10_11_VOL, + RT715_SDCA_FU_VOL_CTRL, CH_03), 0x00 }, + { SDW_SDCA_CTL(FUN_MIC_ARRAY, RT715_SDCA_FU_ADC10_11_VOL, + RT715_SDCA_FU_VOL_CTRL, CH_04), 0x00 }, + { SDW_SDCA_CTL(FUN_MIC_ARRAY, RT715_SDCA_FU_ADC7_27_VOL, + RT715_SDCA_FU_VOL_CTRL, CH_01), 0x00 }, + { SDW_SDCA_CTL(FUN_MIC_ARRAY, RT715_SDCA_FU_ADC7_27_VOL, + RT715_SDCA_FU_VOL_CTRL, CH_02), 0x00 }, + { SDW_SDCA_CTL(FUN_MIC_ARRAY, RT715_SDCA_FU_AMIC_GAIN_EN, + RT715_SDCA_FU_DMIC_GAIN_CTRL, CH_01), 0x00 }, + { SDW_SDCA_CTL(FUN_MIC_ARRAY, RT715_SDCA_FU_AMIC_GAIN_EN, + RT715_SDCA_FU_DMIC_GAIN_CTRL, CH_02), 0x00 }, + { SDW_SDCA_CTL(FUN_MIC_ARRAY, RT715_SDCA_FU_AMIC_GAIN_EN, + RT715_SDCA_FU_DMIC_GAIN_CTRL, CH_03), 0x00 }, + { SDW_SDCA_CTL(FUN_MIC_ARRAY, RT715_SDCA_FU_AMIC_GAIN_EN, + RT715_SDCA_FU_DMIC_GAIN_CTRL, CH_04), 0x00 }, + { SDW_SDCA_CTL(FUN_MIC_ARRAY, RT715_SDCA_FU_AMIC_GAIN_EN, + RT715_SDCA_FU_DMIC_GAIN_CTRL, CH_05), 0x00 }, + { SDW_SDCA_CTL(FUN_MIC_ARRAY, RT715_SDCA_FU_AMIC_GAIN_EN, + RT715_SDCA_FU_DMIC_GAIN_CTRL, CH_06), 0x00 }, + { SDW_SDCA_CTL(FUN_MIC_ARRAY, RT715_SDCA_FU_AMIC_GAIN_EN, + RT715_SDCA_FU_DMIC_GAIN_CTRL, CH_07), 0x00 }, + { SDW_SDCA_CTL(FUN_MIC_ARRAY, RT715_SDCA_FU_AMIC_GAIN_EN, + RT715_SDCA_FU_DMIC_GAIN_CTRL, CH_08), 0x00 }, + { SDW_SDCA_CTL(FUN_MIC_ARRAY, RT715_SDCA_FU_DMIC_GAIN_EN, + RT715_SDCA_FU_DMIC_GAIN_CTRL, CH_01), 0x00 }, + { SDW_SDCA_CTL(FUN_MIC_ARRAY, RT715_SDCA_FU_DMIC_GAIN_EN, + RT715_SDCA_FU_DMIC_GAIN_CTRL, CH_02), 0x00 }, + { SDW_SDCA_CTL(FUN_MIC_ARRAY, RT715_SDCA_FU_DMIC_GAIN_EN, + RT715_SDCA_FU_DMIC_GAIN_CTRL, CH_03), 0x00 }, + { SDW_SDCA_CTL(FUN_MIC_ARRAY, RT715_SDCA_FU_DMIC_GAIN_EN, + RT715_SDCA_FU_DMIC_GAIN_CTRL, CH_04), 0x00 }, + { SDW_SDCA_CTL(FUN_MIC_ARRAY, RT715_SDCA_FU_DMIC_GAIN_EN, + RT715_SDCA_FU_DMIC_GAIN_CTRL, CH_05), 0x00 }, + { SDW_SDCA_CTL(FUN_MIC_ARRAY, RT715_SDCA_FU_DMIC_GAIN_EN, + RT715_SDCA_FU_DMIC_GAIN_CTRL, CH_06), 0x00 }, + { SDW_SDCA_CTL(FUN_MIC_ARRAY, RT715_SDCA_FU_DMIC_GAIN_EN, + RT715_SDCA_FU_DMIC_GAIN_CTRL, CH_07), 0x00 }, + { SDW_SDCA_CTL(FUN_MIC_ARRAY, RT715_SDCA_FU_DMIC_GAIN_EN, + RT715_SDCA_FU_DMIC_GAIN_CTRL, CH_08), 0x00 }, +}; +#endif /* __RT715_SDW_SDCA_H__ */ diff --git a/sound/soc/codecs/rt715-sdca.c b/sound/soc/codecs/rt715-sdca.c new file mode 100644 index 000000000000..92ad6fa408ec --- /dev/null +++ b/sound/soc/codecs/rt715-sdca.c @@ -0,0 +1,1076 @@ +// SPDX-License-Identifier: GPL-2.0-only +// +// rt715-sdca.c -- rt715 ALSA SoC audio driver +// +// Copyright(c) 2020 Realtek Semiconductor Corp. +// +// +// + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "rt715-sdca.h" + +static int rt715_sdca_index_write(struct rt715_sdca_priv *rt715, + unsigned int nid, unsigned int reg, unsigned int value) +{ + struct regmap *regmap = rt715->mbq_regmap; + unsigned int addr; + int ret; + + addr = (nid << 20) | reg; + + ret = regmap_write(regmap, addr, value); + if (ret < 0) + dev_err(&rt715->slave->dev, + "Failed to set private value: %08x <= %04x %d\n", ret, addr, + value); + + return ret; +} + +static int rt715_sdca_index_read(struct rt715_sdca_priv *rt715, + unsigned int nid, unsigned int reg, unsigned int *value) +{ + struct regmap *regmap = rt715->mbq_regmap; + unsigned int addr; + int ret; + + addr = (nid << 20) | reg; + + ret = regmap_read(regmap, addr, value); + if (ret < 0) + dev_err(&rt715->slave->dev, + "Failed to get private value: %06x => %04x ret=%d\n", + addr, *value, ret); + + return ret; +} + +static int rt715_sdca_index_update_bits(struct rt715_sdca_priv *rt715, + unsigned int nid, unsigned int reg, unsigned int mask, unsigned int val) +{ + unsigned int tmp; + int ret; + + ret = rt715_sdca_index_read(rt715, nid, reg, &tmp); + if (ret < 0) + return ret; + + set_mask_bits(&tmp, mask, val); + + return rt715_sdca_index_write(rt715, nid, reg, tmp); +} + +static inline unsigned int rt715_sdca_vol_gain(unsigned int u_ctrl_val, + unsigned int vol_max, unsigned int vol_gain_sft) +{ + unsigned int val; + + if (u_ctrl_val > vol_max) + u_ctrl_val = vol_max; + val = u_ctrl_val; + u_ctrl_val = + ((abs(u_ctrl_val - vol_gain_sft) * RT715_SDCA_DB_STEP) << 8) / 1000; + if (val <= vol_gain_sft) { + u_ctrl_val = ~u_ctrl_val; + u_ctrl_val += 1; + } + u_ctrl_val &= 0xffff; + + return u_ctrl_val; +} + +static inline unsigned int rt715_sdca_boost_gain(unsigned int u_ctrl_val, + unsigned int b_max, unsigned int b_gain_sft) +{ + if (u_ctrl_val > b_max) + u_ctrl_val = b_max; + + return (u_ctrl_val * 10) << b_gain_sft; +} + +static inline unsigned int rt715_sdca_get_gain(unsigned int reg_val, + unsigned int gain_sft) +{ + unsigned int neg_flag = 0; + + if (reg_val & BIT(15)) { + reg_val = ~(reg_val - 1) & 0xffff; + neg_flag = 1; + } + reg_val *= 1000; + reg_val >>= 8; + if (neg_flag) + reg_val = gain_sft - reg_val / RT715_SDCA_DB_STEP; + else + reg_val = gain_sft + reg_val / RT715_SDCA_DB_STEP; + + return reg_val; +} + +/* SDCA Volume/Boost control */ +static int rt715_sdca_set_amp_gain_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_component *component = snd_kcontrol_chip(kcontrol); + struct soc_mixer_control *mc = + (struct soc_mixer_control *)kcontrol->private_value; + struct rt715_sdca_priv *rt715 = snd_soc_component_get_drvdata(component); + unsigned int gain_val, i, k_changed = 0; + int ret; + + for (i = 0; i < 2; i++) { + if (ucontrol->value.integer.value[i] != rt715->kctl_2ch_orig[i]) { + k_changed = 1; + break; + } + } + + for (i = 0; i < 2; i++) { + rt715->kctl_2ch_orig[i] = ucontrol->value.integer.value[i]; + gain_val = + rt715_sdca_vol_gain(ucontrol->value.integer.value[i], mc->max, + mc->shift); + ret = regmap_write(rt715->mbq_regmap, mc->reg + i, gain_val); + if (ret != 0) { + dev_err(component->dev, "Failed to write 0x%x=0x%x\n", + mc->reg + i, gain_val); + return ret; + } + } + + return k_changed; +} + +static int rt715_sdca_set_amp_gain_4ch_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_component *component = snd_kcontrol_chip(kcontrol); + struct rt715_sdca_priv *rt715 = snd_soc_component_get_drvdata(component); + struct rt715_sdca_kcontrol_private *p = + (struct rt715_sdca_kcontrol_private *)kcontrol->private_value; + unsigned int reg_base = p->reg_base, k_changed = 0; + const unsigned int gain_sft = 0x2f; + unsigned int gain_val, i; + int ret; + + for (i = 0; i < 4; i++) { + if (ucontrol->value.integer.value[i] != rt715->kctl_4ch_orig[i]) { + k_changed = 1; + break; + } + } + + for (i = 0; i < 4; i++) { + rt715->kctl_4ch_orig[i] = ucontrol->value.integer.value[i]; + gain_val = + rt715_sdca_vol_gain(ucontrol->value.integer.value[i], p->max, + gain_sft); + ret = regmap_write(rt715->mbq_regmap, reg_base + i, + gain_val); + if (ret != 0) { + dev_err(component->dev, "Failed to write 0x%x=0x%x\n", + reg_base + i, gain_val); + return ret; + } + } + + return k_changed; +} + +static int rt715_sdca_set_amp_gain_8ch_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_component *component = snd_kcontrol_chip(kcontrol); + struct rt715_sdca_priv *rt715 = snd_soc_component_get_drvdata(component); + struct rt715_sdca_kcontrol_private *p = + (struct rt715_sdca_kcontrol_private *)kcontrol->private_value; + unsigned int reg_base = p->reg_base, i, k_changed = 0; + const unsigned int gain_sft = 8; + unsigned int gain_val, reg; + int ret; + + for (i = 0; i < 8; i++) { + if (ucontrol->value.integer.value[i] != rt715->kctl_8ch_orig[i]) { + k_changed = 1; + break; + } + } + + for (i = 0; i < 8; i++) { + rt715->kctl_8ch_orig[i] = ucontrol->value.integer.value[i]; + gain_val = + rt715_sdca_boost_gain(ucontrol->value.integer.value[i], p->max, + gain_sft); + reg = i < 7 ? reg_base + i : (reg_base - 1) | BIT(15); + ret = regmap_write(rt715->mbq_regmap, reg, gain_val); + if (ret != 0) { + dev_err(component->dev, "Failed to write 0x%x=0x%x\n", + reg, gain_val); + return ret; + } + } + + return k_changed; +} + +static int rt715_sdca_set_amp_gain_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_component *component = snd_kcontrol_chip(kcontrol); + struct soc_mixer_control *mc = + (struct soc_mixer_control *)kcontrol->private_value; + struct rt715_sdca_priv *rt715 = snd_soc_component_get_drvdata(component); + unsigned int val, i; + int ret; + + for (i = 0; i < 2; i++) { + ret = regmap_read(rt715->mbq_regmap, mc->reg + i, &val); + if (ret < 0) { + dev_err(component->dev, "Failed to read 0x%x, ret=%d\n", + mc->reg + i, ret); + return ret; + } + ucontrol->value.integer.value[i] = rt715_sdca_get_gain(val, mc->shift); + } + + return 0; +} + +static int rt715_sdca_set_amp_gain_4ch_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_component *component = snd_kcontrol_chip(kcontrol); + struct rt715_sdca_priv *rt715 = snd_soc_component_get_drvdata(component); + struct rt715_sdca_kcontrol_private *p = + (struct rt715_sdca_kcontrol_private *)kcontrol->private_value; + unsigned int reg_base = p->reg_base, i; + const unsigned int gain_sft = 0x2f; + unsigned int val; + int ret; + + for (i = 0; i < 4; i++) { + ret = regmap_read(rt715->mbq_regmap, reg_base + i, &val); + if (ret < 0) { + dev_err(component->dev, "Failed to read 0x%x, ret=%d\n", + reg_base + i, ret); + return ret; + } + ucontrol->value.integer.value[i] = rt715_sdca_get_gain(val, gain_sft); + } + + return 0; +} + +static int rt715_sdca_set_amp_gain_8ch_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_component *component = snd_kcontrol_chip(kcontrol); + struct rt715_sdca_priv *rt715 = snd_soc_component_get_drvdata(component); + struct rt715_sdca_kcontrol_private *p = + (struct rt715_sdca_kcontrol_private *)kcontrol->private_value; + unsigned int reg_base = p->reg_base; + const unsigned int gain_sft = 8; + unsigned int val_l, val_r; + unsigned int i, reg; + int ret; + + for (i = 0; i < 8; i += 2) { + ret = regmap_read(rt715->mbq_regmap, reg_base + i, &val_l); + if (ret < 0) { + dev_err(component->dev, "Failed to read 0x%x, ret=%d\n", + reg_base + i, ret); + return ret; + } + ucontrol->value.integer.value[i] = (val_l >> gain_sft) / 10; + + reg = (i == 6) ? (reg_base - 1) | BIT(15) : reg_base + 1 + i; + ret = regmap_read(rt715->mbq_regmap, reg, &val_r); + if (ret < 0) { + dev_err(component->dev, "Failed to read 0x%x, ret=%d\n", + reg, ret); + return ret; + } + ucontrol->value.integer.value[i + 1] = (val_r >> gain_sft) / 10; + } + + return 0; +} + +static const DECLARE_TLV_DB_SCALE(in_vol_tlv, -17625, 375, 0); +static const DECLARE_TLV_DB_SCALE(mic_vol_tlv, 0, 1000, 0); + +static int rt715_sdca_get_volsw(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_component *component = snd_kcontrol_chip(kcontrol); + struct rt715_sdca_kcontrol_private *p = + (struct rt715_sdca_kcontrol_private *)kcontrol->private_value; + unsigned int reg_base = p->reg_base; + unsigned int invert = p->invert, i; + int val; + + for (i = 0; i < p->count; i += 2) { + val = snd_soc_component_read(component, reg_base + i); + if (val < 0) + return -EINVAL; + ucontrol->value.integer.value[i] = invert ? p->max - val : val; + + val = snd_soc_component_read(component, reg_base + 1 + i); + if (val < 0) + return -EINVAL; + ucontrol->value.integer.value[i + 1] = + invert ? p->max - val : val; + } + + return 0; +} + +static int rt715_sdca_put_volsw(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_component *component = snd_kcontrol_chip(kcontrol); + struct rt715_sdca_priv *rt715 = snd_soc_component_get_drvdata(component); + struct rt715_sdca_kcontrol_private *p = + (struct rt715_sdca_kcontrol_private *)kcontrol->private_value; + unsigned int val[4] = {0}, val_mask, i, k_changed = 0; + unsigned int reg = p->reg_base; + unsigned int shift = p->shift; + unsigned int max = p->max; + unsigned int mask = (1 << fls(max)) - 1; + unsigned int invert = p->invert; + int err; + + for (i = 0; i < 4; i++) { + if (ucontrol->value.integer.value[i] != rt715->kctl_switch_orig[i]) { + k_changed = 1; + break; + } + } + + for (i = 0; i < 2; i++) { + rt715->kctl_switch_orig[i * 2] = ucontrol->value.integer.value[i * 2]; + val[i * 2] = ucontrol->value.integer.value[i * 2] & mask; + if (invert) + val[i * 2] = max - val[i * 2]; + val_mask = mask << shift; + val[i * 2] <<= shift; + + rt715->kctl_switch_orig[i * 2 + 1] = + ucontrol->value.integer.value[i * 2 + 1]; + val[i * 2 + 1] = + ucontrol->value.integer.value[i * 2 + 1] & mask; + if (invert) + val[i * 2 + 1] = max - val[i * 2 + 1]; + + val[i * 2 + 1] <<= shift; + + err = snd_soc_component_update_bits(component, reg + i * 2, val_mask, + val[i * 2]); + if (err < 0) + return err; + + err = snd_soc_component_update_bits(component, reg + 1 + i * 2, + val_mask, val[i * 2 + 1]); + if (err < 0) + return err; + } + + return k_changed; +} + +static int rt715_sdca_fu_info(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_info *uinfo) +{ + struct rt715_sdca_kcontrol_private *p = + (struct rt715_sdca_kcontrol_private *)kcontrol->private_value; + + if (p->max == 1) + uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN; + else + uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER; + uinfo->count = p->count; + uinfo->value.integer.min = 0; + uinfo->value.integer.max = p->max; + return 0; +} + +#define RT715_SDCA_PR_VALUE(xreg_base, xcount, xmax, xshift, xinvert) \ + ((unsigned long)&(struct rt715_sdca_kcontrol_private) \ + {.reg_base = xreg_base, .count = xcount, .max = xmax, \ + .shift = xshift, .invert = xinvert}) + +#define RT715_SDCA_FU_CTRL(xname, reg_base, xshift, xmax, xinvert, xcount) \ +{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = (xname), \ + .info = rt715_sdca_fu_info, \ + .get = rt715_sdca_get_volsw, \ + .put = rt715_sdca_put_volsw, \ + .private_value = RT715_SDCA_PR_VALUE(reg_base, xcount, xmax, \ + xshift, xinvert)} + +#define SOC_DOUBLE_R_EXT(xname, reg_left, reg_right, xshift, xmax, xinvert,\ + xhandler_get, xhandler_put) \ +{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = (xname), \ + .info = snd_soc_info_volsw, \ + .get = xhandler_get, .put = xhandler_put, \ + .private_value = SOC_DOUBLE_R_VALUE(reg_left, reg_right, xshift, \ + xmax, xinvert) } + +#define RT715_SDCA_EXT_TLV(xname, reg_base, xhandler_get,\ + xhandler_put, tlv_array, xcount, xmax) \ +{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = (xname), \ + .access = SNDRV_CTL_ELEM_ACCESS_TLV_READ | \ + SNDRV_CTL_ELEM_ACCESS_READWRITE, \ + .tlv.p = (tlv_array), \ + .info = rt715_sdca_fu_info, \ + .get = xhandler_get, .put = xhandler_put, \ + .private_value = RT715_SDCA_PR_VALUE(reg_base, xcount, xmax, 0, 0) } + +#define RT715_SDCA_BOOST_EXT_TLV(xname, reg_base, xhandler_get,\ + xhandler_put, tlv_array, xcount, xmax) \ +{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = (xname), \ + .access = SNDRV_CTL_ELEM_ACCESS_TLV_READ | \ + SNDRV_CTL_ELEM_ACCESS_READWRITE, \ + .tlv.p = (tlv_array), \ + .info = rt715_sdca_fu_info, \ + .get = xhandler_get, .put = xhandler_put, \ + .private_value = RT715_SDCA_PR_VALUE(reg_base, xcount, xmax, 0, 0) } + +static const struct snd_kcontrol_new rt715_sdca_snd_controls[] = { + /* Capture switch */ + SOC_DOUBLE_R("FU0A Capture Switch", + SDW_SDCA_CTL(FUN_MIC_ARRAY, RT715_SDCA_FU_ADC7_27_VOL, + RT715_SDCA_FU_MUTE_CTRL, CH_01), + SDW_SDCA_CTL(FUN_MIC_ARRAY, RT715_SDCA_FU_ADC7_27_VOL, + RT715_SDCA_FU_MUTE_CTRL, CH_02), + 0, 1, 1), + RT715_SDCA_FU_CTRL("FU02 Capture Switch", + SDW_SDCA_CTL(FUN_MIC_ARRAY, RT715_SDCA_FU_ADC8_9_VOL, + RT715_SDCA_FU_MUTE_CTRL, CH_01), + 0, 1, 1, 4), + RT715_SDCA_FU_CTRL("FU06 Capture Switch", + SDW_SDCA_CTL(FUN_MIC_ARRAY, RT715_SDCA_FU_ADC10_11_VOL, + RT715_SDCA_FU_MUTE_CTRL, CH_01), + 0, 1, 1, 4), + /* Volume Control */ + SOC_DOUBLE_R_EXT_TLV("FU0A Capture Volume", + SDW_SDCA_CTL(FUN_MIC_ARRAY, RT715_SDCA_FU_ADC7_27_VOL, + RT715_SDCA_FU_VOL_CTRL, CH_01), + SDW_SDCA_CTL(FUN_MIC_ARRAY, RT715_SDCA_FU_ADC7_27_VOL, + RT715_SDCA_FU_VOL_CTRL, CH_02), + 0x2f, 0x7f, 0, + rt715_sdca_set_amp_gain_get, rt715_sdca_set_amp_gain_put, + in_vol_tlv), + RT715_SDCA_EXT_TLV("FU02 Capture Volume", + SDW_SDCA_CTL(FUN_MIC_ARRAY, RT715_SDCA_FU_ADC8_9_VOL, + RT715_SDCA_FU_VOL_CTRL, CH_01), + rt715_sdca_set_amp_gain_4ch_get, + rt715_sdca_set_amp_gain_4ch_put, + in_vol_tlv, 4, 0x7f), + RT715_SDCA_EXT_TLV("FU06 Capture Volume", + SDW_SDCA_CTL(FUN_MIC_ARRAY, RT715_SDCA_FU_ADC10_11_VOL, + RT715_SDCA_FU_VOL_CTRL, CH_01), + rt715_sdca_set_amp_gain_4ch_get, + rt715_sdca_set_amp_gain_4ch_put, + in_vol_tlv, 4, 0x7f), + /* MIC Boost Control */ + RT715_SDCA_BOOST_EXT_TLV("FU0E Boost", + SDW_SDCA_CTL(FUN_MIC_ARRAY, RT715_SDCA_FU_DMIC_GAIN_EN, + RT715_SDCA_FU_DMIC_GAIN_CTRL, CH_01), + rt715_sdca_set_amp_gain_8ch_get, + rt715_sdca_set_amp_gain_8ch_put, + mic_vol_tlv, 8, 3), + RT715_SDCA_BOOST_EXT_TLV("FU0C Boost", + SDW_SDCA_CTL(FUN_MIC_ARRAY, RT715_SDCA_FU_AMIC_GAIN_EN, + RT715_SDCA_FU_DMIC_GAIN_CTRL, CH_01), + rt715_sdca_set_amp_gain_8ch_get, + rt715_sdca_set_amp_gain_8ch_put, + mic_vol_tlv, 8, 3), +}; + +static int rt715_sdca_mux_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_component *component = + snd_soc_dapm_kcontrol_component(kcontrol); + struct rt715_sdca_priv *rt715 = snd_soc_component_get_drvdata(component); + unsigned int val, mask_sft; + + if (strstr(ucontrol->id.name, "ADC 22 Mux")) + mask_sft = 12; + else if (strstr(ucontrol->id.name, "ADC 23 Mux")) + mask_sft = 8; + else if (strstr(ucontrol->id.name, "ADC 24 Mux")) + mask_sft = 4; + else if (strstr(ucontrol->id.name, "ADC 25 Mux")) + mask_sft = 0; + else + return -EINVAL; + + rt715_sdca_index_read(rt715, RT715_VENDOR_HDA_CTL, + RT715_HDA_LEGACY_MUX_CTL1, &val); + val = (val >> mask_sft) & 0xf; + + /* + * The first two indices of ADC Mux 24/25 are routed to the same + * hardware source. ie, ADC Mux 24 0/1 will both connect to MIC2. + * To have a unique set of inputs, we skip the index1 of the muxes. + */ + if ((strstr(ucontrol->id.name, "ADC 24 Mux") || + strstr(ucontrol->id.name, "ADC 25 Mux")) && val > 0) + val -= 1; + ucontrol->value.enumerated.item[0] = val; + + return 0; +} + +static int rt715_sdca_mux_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_component *component = + snd_soc_dapm_kcontrol_component(kcontrol); + struct snd_soc_dapm_context *dapm = + snd_soc_dapm_kcontrol_dapm(kcontrol); + struct rt715_sdca_priv *rt715 = snd_soc_component_get_drvdata(component); + struct soc_enum *e = (struct soc_enum *)kcontrol->private_value; + unsigned int *item = ucontrol->value.enumerated.item; + unsigned int val, val2 = 0, change, mask_sft; + + if (item[0] >= e->items) + return -EINVAL; + + if (strstr(ucontrol->id.name, "ADC 22 Mux")) + mask_sft = 12; + else if (strstr(ucontrol->id.name, "ADC 23 Mux")) + mask_sft = 8; + else if (strstr(ucontrol->id.name, "ADC 24 Mux")) + mask_sft = 4; + else if (strstr(ucontrol->id.name, "ADC 25 Mux")) + mask_sft = 0; + else + return -EINVAL; + + /* Verb ID = 0x701h, nid = e->reg */ + val = snd_soc_enum_item_to_val(e, item[0]) << e->shift_l; + + rt715_sdca_index_read(rt715, RT715_VENDOR_HDA_CTL, + RT715_HDA_LEGACY_MUX_CTL1, &val2); + val2 = (val2 >> mask_sft) & 0xf; + + change = val != val2; + + if (change) + rt715_sdca_index_update_bits(rt715, RT715_VENDOR_HDA_CTL, + RT715_HDA_LEGACY_MUX_CTL1, 0xf << mask_sft, val << mask_sft); + + snd_soc_dapm_mux_update_power(dapm, kcontrol, item[0], e, NULL); + + return change; +} + +static const char * const adc_22_23_mux_text[] = { + "MIC1", + "MIC2", + "LINE1", + "LINE2", + "DMIC1", + "DMIC2", + "DMIC3", + "DMIC4", +}; + +/* + * Due to mux design for nid 24 (MUX_IN3)/25 (MUX_IN4), connection index 0 and + * 1 will be connected to the same dmic source, therefore we skip index 1 to + * avoid misunderstanding on usage of dapm routing. + */ +static int rt715_adc_24_25_values[] = { + 0, + 2, + 3, + 4, + 5, +}; + +static const char * const adc_24_mux_text[] = { + "MIC2", + "DMIC1", + "DMIC2", + "DMIC3", + "DMIC4", +}; + +static const char * const adc_25_mux_text[] = { + "MIC1", + "DMIC1", + "DMIC2", + "DMIC3", + "DMIC4", +}; + +static SOC_ENUM_SINGLE_DECL(rt715_adc22_enum, SND_SOC_NOPM, 0, + adc_22_23_mux_text); + +static SOC_ENUM_SINGLE_DECL(rt715_adc23_enum, SND_SOC_NOPM, 0, + adc_22_23_mux_text); + +static SOC_VALUE_ENUM_SINGLE_DECL(rt715_adc24_enum, + SND_SOC_NOPM, 0, 0xf, + adc_24_mux_text, rt715_adc_24_25_values); +static SOC_VALUE_ENUM_SINGLE_DECL(rt715_adc25_enum, + SND_SOC_NOPM, 0, 0xf, + adc_25_mux_text, rt715_adc_24_25_values); + +static const struct snd_kcontrol_new rt715_adc22_mux = + SOC_DAPM_ENUM_EXT("ADC 22 Mux", rt715_adc22_enum, + rt715_sdca_mux_get, rt715_sdca_mux_put); + +static const struct snd_kcontrol_new rt715_adc23_mux = + SOC_DAPM_ENUM_EXT("ADC 23 Mux", rt715_adc23_enum, + rt715_sdca_mux_get, rt715_sdca_mux_put); + +static const struct snd_kcontrol_new rt715_adc24_mux = + SOC_DAPM_ENUM_EXT("ADC 24 Mux", rt715_adc24_enum, + rt715_sdca_mux_get, rt715_sdca_mux_put); + +static const struct snd_kcontrol_new rt715_adc25_mux = + SOC_DAPM_ENUM_EXT("ADC 25 Mux", rt715_adc25_enum, + rt715_sdca_mux_get, rt715_sdca_mux_put); + +static int rt715_sdca_pde23_24_event(struct snd_soc_dapm_widget *w, + struct snd_kcontrol *kcontrol, int event) +{ + struct snd_soc_component *component = + snd_soc_dapm_to_component(w->dapm); + struct rt715_sdca_priv *rt715 = snd_soc_component_get_drvdata(component); + + switch (event) { + case SND_SOC_DAPM_POST_PMU: + regmap_write(rt715->regmap, + SDW_SDCA_CTL(FUN_MIC_ARRAY, RT715_SDCA_CREQ_POW_EN, + RT715_SDCA_REQ_POW_CTRL, + CH_00), 0x00); + break; + case SND_SOC_DAPM_PRE_PMD: + regmap_write(rt715->regmap, + SDW_SDCA_CTL(FUN_MIC_ARRAY, RT715_SDCA_CREQ_POW_EN, + RT715_SDCA_REQ_POW_CTRL, + CH_00), 0x03); + break; + } + return 0; +} + +static const struct snd_soc_dapm_widget rt715_sdca_dapm_widgets[] = { + SND_SOC_DAPM_INPUT("DMIC1"), + SND_SOC_DAPM_INPUT("DMIC2"), + SND_SOC_DAPM_INPUT("DMIC3"), + SND_SOC_DAPM_INPUT("DMIC4"), + SND_SOC_DAPM_INPUT("MIC1"), + SND_SOC_DAPM_INPUT("MIC2"), + SND_SOC_DAPM_INPUT("LINE1"), + SND_SOC_DAPM_INPUT("LINE2"), + + SND_SOC_DAPM_SUPPLY("PDE23_24", SND_SOC_NOPM, 0, 0, + rt715_sdca_pde23_24_event, + SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD), + + SND_SOC_DAPM_ADC("ADC 07", NULL, SND_SOC_NOPM, 4, 0), + SND_SOC_DAPM_ADC("ADC 08", NULL, SND_SOC_NOPM, 4, 0), + SND_SOC_DAPM_ADC("ADC 09", NULL, SND_SOC_NOPM, 4, 0), + SND_SOC_DAPM_ADC("ADC 27", NULL, SND_SOC_NOPM, 4, 0), + SND_SOC_DAPM_MUX("ADC 22 Mux", SND_SOC_NOPM, 0, 0, + &rt715_adc22_mux), + SND_SOC_DAPM_MUX("ADC 23 Mux", SND_SOC_NOPM, 0, 0, + &rt715_adc23_mux), + SND_SOC_DAPM_MUX("ADC 24 Mux", SND_SOC_NOPM, 0, 0, + &rt715_adc24_mux), + SND_SOC_DAPM_MUX("ADC 25 Mux", SND_SOC_NOPM, 0, 0, + &rt715_adc25_mux), + SND_SOC_DAPM_AIF_OUT("DP4TX", "DP4 Capture", 0, SND_SOC_NOPM, 0, 0), + SND_SOC_DAPM_AIF_OUT("DP6TX", "DP6 Capture", 0, SND_SOC_NOPM, 0, 0), +}; + +static const struct snd_soc_dapm_route rt715_sdca_audio_map[] = { + {"DP6TX", NULL, "ADC 09"}, + {"DP6TX", NULL, "ADC 08"}, + {"DP4TX", NULL, "ADC 07"}, + {"DP4TX", NULL, "ADC 27"}, + {"DP4TX", NULL, "ADC 09"}, + {"DP4TX", NULL, "ADC 08"}, + + {"LINE1", NULL, "PDE23_24"}, + {"LINE2", NULL, "PDE23_24"}, + {"MIC1", NULL, "PDE23_24"}, + {"MIC2", NULL, "PDE23_24"}, + {"DMIC1", NULL, "PDE23_24"}, + {"DMIC2", NULL, "PDE23_24"}, + {"DMIC3", NULL, "PDE23_24"}, + {"DMIC4", NULL, "PDE23_24"}, + + {"ADC 09", NULL, "ADC 22 Mux"}, + {"ADC 08", NULL, "ADC 23 Mux"}, + {"ADC 07", NULL, "ADC 24 Mux"}, + {"ADC 27", NULL, "ADC 25 Mux"}, + {"ADC 22 Mux", "MIC1", "MIC1"}, + {"ADC 22 Mux", "MIC2", "MIC2"}, + {"ADC 22 Mux", "LINE1", "LINE1"}, + {"ADC 22 Mux", "LINE2", "LINE2"}, + {"ADC 22 Mux", "DMIC1", "DMIC1"}, + {"ADC 22 Mux", "DMIC2", "DMIC2"}, + {"ADC 22 Mux", "DMIC3", "DMIC3"}, + {"ADC 22 Mux", "DMIC4", "DMIC4"}, + {"ADC 23 Mux", "MIC1", "MIC1"}, + {"ADC 23 Mux", "MIC2", "MIC2"}, + {"ADC 23 Mux", "LINE1", "LINE1"}, + {"ADC 23 Mux", "LINE2", "LINE2"}, + {"ADC 23 Mux", "DMIC1", "DMIC1"}, + {"ADC 23 Mux", "DMIC2", "DMIC2"}, + {"ADC 23 Mux", "DMIC3", "DMIC3"}, + {"ADC 23 Mux", "DMIC4", "DMIC4"}, + {"ADC 24 Mux", "MIC2", "MIC2"}, + {"ADC 24 Mux", "DMIC1", "DMIC1"}, + {"ADC 24 Mux", "DMIC2", "DMIC2"}, + {"ADC 24 Mux", "DMIC3", "DMIC3"}, + {"ADC 24 Mux", "DMIC4", "DMIC4"}, + {"ADC 25 Mux", "MIC1", "MIC1"}, + {"ADC 25 Mux", "DMIC1", "DMIC1"}, + {"ADC 25 Mux", "DMIC2", "DMIC2"}, + {"ADC 25 Mux", "DMIC3", "DMIC3"}, + {"ADC 25 Mux", "DMIC4", "DMIC4"}, +}; + +static const struct snd_soc_component_driver soc_codec_dev_rt715_sdca = { + .controls = rt715_sdca_snd_controls, + .num_controls = ARRAY_SIZE(rt715_sdca_snd_controls), + .dapm_widgets = rt715_sdca_dapm_widgets, + .num_dapm_widgets = ARRAY_SIZE(rt715_sdca_dapm_widgets), + .dapm_routes = rt715_sdca_audio_map, + .num_dapm_routes = ARRAY_SIZE(rt715_sdca_audio_map), +}; + +static int rt715_sdca_set_sdw_stream(struct snd_soc_dai *dai, void *sdw_stream, + int direction) +{ + struct rt715_sdw_stream_data *stream; + + stream = kzalloc(sizeof(*stream), GFP_KERNEL); + if (!stream) + return -ENOMEM; + + stream->sdw_stream = sdw_stream; + + /* Use tx_mask or rx_mask to configure stream tag and set dma_data */ + if (direction == SNDRV_PCM_STREAM_PLAYBACK) + dai->playback_dma_data = stream; + else + dai->capture_dma_data = stream; + + return 0; +} + +static void rt715_sdca_shutdown(struct snd_pcm_substream *substream, + struct snd_soc_dai *dai) + +{ + struct rt715_sdw_stream_data *stream; + + stream = snd_soc_dai_get_dma_data(dai, substream); + if (!stream) + return; + + snd_soc_dai_set_dma_data(dai, substream, NULL); + kfree(stream); +} + +static int rt715_sdca_pcm_hw_params(struct snd_pcm_substream *substream, + struct snd_pcm_hw_params *params, + struct snd_soc_dai *dai) +{ + struct snd_soc_component *component = dai->component; + struct rt715_sdca_priv *rt715 = snd_soc_component_get_drvdata(component); + struct sdw_stream_config stream_config; + struct sdw_port_config port_config; + enum sdw_data_direction direction; + struct rt715_sdw_stream_data *stream; + int retval, port, num_channels; + unsigned int val; + + stream = snd_soc_dai_get_dma_data(dai, substream); + + if (!stream) + return -EINVAL; + + if (!rt715->slave) + return -EINVAL; + + switch (dai->id) { + case RT715_AIF1: + direction = SDW_DATA_DIR_TX; + port = 6; + rt715_sdca_index_write(rt715, RT715_VENDOR_REG, RT715_SDW_INPUT_SEL, + 0xa500); + break; + case RT715_AIF2: + direction = SDW_DATA_DIR_TX; + port = 4; + rt715_sdca_index_write(rt715, RT715_VENDOR_REG, RT715_SDW_INPUT_SEL, + 0xaf00); + break; + default: + dev_err(component->dev, "Invalid DAI id %d\n", dai->id); + return -EINVAL; + } + + stream_config.frame_rate = params_rate(params); + stream_config.ch_count = params_channels(params); + stream_config.bps = snd_pcm_format_width(params_format(params)); + stream_config.direction = direction; + + num_channels = params_channels(params); + port_config.ch_mask = GENMASK(num_channels - 1, 0); + port_config.num = port; + + retval = sdw_stream_add_slave(rt715->slave, &stream_config, + &port_config, 1, stream->sdw_stream); + if (retval) { + dev_err(component->dev, "Unable to configure port, retval:%d\n", + retval); + return retval; + } + + switch (params_rate(params)) { + case 8000: + val = 0x1; + break; + case 11025: + val = 0x2; + break; + case 12000: + val = 0x3; + break; + case 16000: + val = 0x4; + break; + case 22050: + val = 0x5; + break; + case 24000: + val = 0x6; + break; + case 32000: + val = 0x7; + break; + case 44100: + val = 0x8; + break; + case 48000: + val = 0x9; + break; + case 88200: + val = 0xa; + break; + case 96000: + val = 0xb; + break; + case 176400: + val = 0xc; + break; + case 192000: + val = 0xd; + break; + case 384000: + val = 0xe; + break; + case 768000: + val = 0xf; + break; + default: + dev_err(component->dev, "Unsupported sample rate %d\n", + params_rate(params)); + return -EINVAL; + } + + regmap_write(rt715->regmap, + SDW_SDCA_CTL(FUN_MIC_ARRAY, RT715_SDCA_CS_FREQ_IND_EN, + RT715_SDCA_FREQ_IND_CTRL, CH_00), val); + + return 0; +} + +static int rt715_sdca_pcm_hw_free(struct snd_pcm_substream *substream, + struct snd_soc_dai *dai) +{ + struct snd_soc_component *component = dai->component; + struct rt715_sdca_priv *rt715 = snd_soc_component_get_drvdata(component); + struct rt715_sdw_stream_data *stream = + snd_soc_dai_get_dma_data(dai, substream); + + if (!rt715->slave) + return -EINVAL; + + sdw_stream_remove_slave(rt715->slave, stream->sdw_stream); + return 0; +} + +#define RT715_STEREO_RATES (SNDRV_PCM_RATE_44100 | SNDRV_PCM_RATE_48000) +#define RT715_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S20_3LE | \ + SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S8) + +static struct snd_soc_dai_ops rt715_sdca_ops = { + .hw_params = rt715_sdca_pcm_hw_params, + .hw_free = rt715_sdca_pcm_hw_free, + .set_sdw_stream = rt715_sdca_set_sdw_stream, + .shutdown = rt715_sdca_shutdown, +}; + +static struct snd_soc_dai_driver rt715_sdca_dai[] = { + { + .name = "rt715-aif1", + .id = RT715_AIF1, + .capture = { + .stream_name = "DP6 Capture", + .channels_min = 1, + .channels_max = 2, + .rates = RT715_STEREO_RATES, + .formats = RT715_FORMATS, + }, + .ops = &rt715_sdca_ops, + }, + { + .name = "rt715-aif2", + .id = RT715_AIF2, + .capture = { + .stream_name = "DP4 Capture", + .channels_min = 1, + .channels_max = 2, + .rates = RT715_STEREO_RATES, + .formats = RT715_FORMATS, + }, + .ops = &rt715_sdca_ops, + }, +}; + +/* Bus clock frequency */ +#define RT715_CLK_FREQ_9600000HZ 9600000 +#define RT715_CLK_FREQ_12000000HZ 12000000 +#define RT715_CLK_FREQ_6000000HZ 6000000 +#define RT715_CLK_FREQ_4800000HZ 4800000 +#define RT715_CLK_FREQ_2400000HZ 2400000 +#define RT715_CLK_FREQ_12288000HZ 12288000 + +int rt715_sdca_init(struct device *dev, struct regmap *mbq_regmap, + struct regmap *regmap, struct sdw_slave *slave) +{ + struct rt715_sdca_priv *rt715; + int ret; + + rt715 = devm_kzalloc(dev, sizeof(*rt715), GFP_KERNEL); + if (!rt715) + return -ENOMEM; + + dev_set_drvdata(dev, rt715); + rt715->slave = slave; + rt715->regmap = regmap; + rt715->mbq_regmap = mbq_regmap; + rt715->hw_sdw_ver = slave->id.sdw_version; + /* + * Mark hw_init to false + * HW init will be performed when device reports present + */ + rt715->hw_init = false; + rt715->first_init = false; + + ret = devm_snd_soc_register_component(dev, + &soc_codec_dev_rt715_sdca, + rt715_sdca_dai, + ARRAY_SIZE(rt715_sdca_dai)); + + return ret; +} + +int rt715_sdca_io_init(struct device *dev, struct sdw_slave *slave) +{ + struct rt715_sdca_priv *rt715 = dev_get_drvdata(dev); + unsigned int hw_ver; + + if (rt715->hw_init) + return 0; + + /* + * PM runtime is only enabled when a Slave reports as Attached + */ + if (!rt715->first_init) { + /* set autosuspend parameters */ + pm_runtime_set_autosuspend_delay(&slave->dev, 3000); + pm_runtime_use_autosuspend(&slave->dev); + + /* update count of parent 'active' children */ + pm_runtime_set_active(&slave->dev); + + /* make sure the device does not suspend immediately */ + pm_runtime_mark_last_busy(&slave->dev); + + pm_runtime_enable(&slave->dev); + + rt715->first_init = true; + } + + pm_runtime_get_noresume(&slave->dev); + + rt715_sdca_index_read(rt715, RT715_VENDOR_REG, + RT715_PRODUCT_NUM, &hw_ver); + hw_ver = hw_ver & 0x000f; + + /* set clock selector = external */ + regmap_write(rt715->regmap, + SDW_SDCA_CTL(FUN_MIC_ARRAY, RT715_SDCA_CX_CLK_SEL_EN, + RT715_SDCA_CX_CLK_SEL_CTRL, CH_00), 0x1); + /* set GPIO_4/5/6 to be 3rd/4th DMIC usage */ + if (hw_ver == 0x0) + rt715_sdca_index_update_bits(rt715, RT715_VENDOR_REG, + RT715_AD_FUNC_EN, 0x54, 0x54); + else if (hw_ver == 0x1) { + rt715_sdca_index_update_bits(rt715, RT715_VENDOR_REG, + RT715_AD_FUNC_EN, 0x55, 0x55); + rt715_sdca_index_update_bits(rt715, RT715_VENDOR_REG, + RT715_REV_1, 0x40, 0x40); + } + /* trigger mode = VAD enable */ + regmap_write(rt715->regmap, + SDW_SDCA_CTL(FUN_MIC_ARRAY, RT715_SDCA_SMPU_TRIG_ST_EN, + RT715_SDCA_SMPU_TRIG_EN_CTRL, CH_00), 0x2); + /* SMPU-1 interrupt enable mask */ + regmap_update_bits(rt715->regmap, RT715_INT_MASK, 0x1, 0x1); + + /* Mark Slave initialization complete */ + rt715->hw_init = true; + + pm_runtime_mark_last_busy(&slave->dev); + pm_runtime_put_autosuspend(&slave->dev); + + return 0; +} + +MODULE_DESCRIPTION("ASoC rt715 driver SDW SDCA"); +MODULE_AUTHOR("Jack Yu "); +MODULE_LICENSE("GPL v2"); diff --git a/sound/soc/codecs/rt715-sdca.h b/sound/soc/codecs/rt715-sdca.h new file mode 100644 index 000000000000..85ce4d95e5eb --- /dev/null +++ b/sound/soc/codecs/rt715-sdca.h @@ -0,0 +1,136 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * rt715-sdca.h -- RT715 ALSA SoC audio driver header + * + * Copyright(c) 2020 Realtek Semiconductor Corp. + */ + +#ifndef __RT715_SDCA_H__ +#define __RT715_SDCA_H__ + +#include +#include +#include +#include +#include +#include + +struct rt715_sdca_priv { + struct regmap *regmap; + struct regmap *mbq_regmap; + struct snd_soc_codec *codec; + struct sdw_slave *slave; + struct delayed_work adc_mute_work; + int dbg_nid; + int dbg_vid; + int dbg_payload; + enum sdw_slave_status status; + struct sdw_bus_params params; + bool hw_init; + bool first_init; + int l_is_unmute; + int r_is_unmute; + int hw_sdw_ver; + int kctl_switch_orig[4]; + int kctl_2ch_orig[2]; + int kctl_4ch_orig[4]; + int kctl_8ch_orig[8]; +}; + +struct rt715_sdw_stream_data { + struct sdw_stream_runtime *sdw_stream; +}; + +struct rt715_sdca_kcontrol_private { + unsigned int reg_base; + unsigned int count; + unsigned int max; + unsigned int shift; + unsigned int invert; +}; + +/* MIPI Register */ +#define RT715_INT_CTRL 0x005a +#define RT715_INT_MASK 0x005e + +/* NID */ +#define RT715_AUDIO_FUNCTION_GROUP 0x01 +#define RT715_MIC_ADC 0x07 +#define RT715_LINE_ADC 0x08 +#define RT715_MIX_ADC 0x09 +#define RT715_DMIC1 0x12 +#define RT715_DMIC2 0x13 +#define RT715_MIC1 0x18 +#define RT715_MIC2 0x19 +#define RT715_LINE1 0x1a +#define RT715_LINE2 0x1b +#define RT715_DMIC3 0x1d +#define RT715_DMIC4 0x29 +#define RT715_VENDOR_REG 0x20 +#define RT715_MUX_IN1 0x22 +#define RT715_MUX_IN2 0x23 +#define RT715_MUX_IN3 0x24 +#define RT715_MUX_IN4 0x25 +#define RT715_MIX_ADC2 0x27 +#define RT715_INLINE_CMD 0x55 +#define RT715_VENDOR_HDA_CTL 0x61 + +/* Index (NID:20h) */ +#define RT715_PRODUCT_NUM 0x0 +#define RT715_IRQ_CTRL 0x2b +#define RT715_AD_FUNC_EN 0x36 +#define RT715_REV_1 0x37 +#define RT715_SDW_INPUT_SEL 0x39 +#define RT715_EXT_DMIC_CLK_CTRL2 0x54 + +/* Index (NID:61h) */ +#define RT715_HDA_LEGACY_MUX_CTL1 0x00 + +/* SDCA (Function) */ +#define FUN_JACK_CODEC 0x01 +#define FUN_MIC_ARRAY 0x02 +#define FUN_HID 0x03 +/* SDCA (Entity) */ +#define RT715_SDCA_ST_EN 0x00 +#define RT715_SDCA_CS_FREQ_IND_EN 0x01 +#define RT715_SDCA_FU_ADC8_9_VOL 0x02 +#define RT715_SDCA_SMPU_TRIG_ST_EN 0x05 +#define RT715_SDCA_FU_ADC10_11_VOL 0x06 +#define RT715_SDCA_FU_ADC7_27_VOL 0x0a +#define RT715_SDCA_FU_AMIC_GAIN_EN 0x0c +#define RT715_SDCA_FU_DMIC_GAIN_EN 0x0e +#define RT715_SDCA_CX_CLK_SEL_EN 0x10 +#define RT715_SDCA_CREQ_POW_EN 0x18 +/* SDCA (Control) */ +#define RT715_SDCA_ST_CTRL 0x00 +#define RT715_SDCA_CX_CLK_SEL_CTRL 0x01 +#define RT715_SDCA_REQ_POW_CTRL 0x01 +#define RT715_SDCA_FU_MUTE_CTRL 0x01 +#define RT715_SDCA_FU_VOL_CTRL 0x02 +#define RT715_SDCA_FU_DMIC_GAIN_CTRL 0x0b +#define RT715_SDCA_FREQ_IND_CTRL 0x10 +#define RT715_SDCA_SMPU_TRIG_EN_CTRL 0x10 +#define RT715_SDCA_SMPU_TRIG_ST_CTRL 0x11 +/* SDCA (Channel) */ +#define CH_00 0x00 +#define CH_01 0x01 +#define CH_02 0x02 +#define CH_03 0x03 +#define CH_04 0x04 +#define CH_05 0x05 +#define CH_06 0x06 +#define CH_07 0x07 +#define CH_08 0x08 + +#define RT715_SDCA_DB_STEP 375 + +enum { + RT715_AIF1, + RT715_AIF2, +}; + +int rt715_sdca_io_init(struct device *dev, struct sdw_slave *slave); +int rt715_sdca_init(struct device *dev, struct regmap *mbq_regmap, + struct regmap *regmap, struct sdw_slave *slave); + +#endif /* __RT715_SDCA_H__ */ From cc2d7429d65c7ea9dc2f84694f47b030248d0d89 Mon Sep 17 00:00:00 2001 From: Tang Bin Date: Sun, 7 Mar 2021 15:21:33 +0800 Subject: [PATCH 164/587] ASoC: codecs/jz4770: Remove superfluous error message The function devm_platform_ioremap_resource has already contained error message if failed, so remove superfluous dev_err here. Signed-off-by: Zhang Shengju Signed-off-by: Tang Bin Acked-by: Paul Cercueil Link: https://lore.kernel.org/r/20210307072133.10832-1-tangbin@cmss.chinamobile.com Signed-off-by: Mark Brown --- sound/soc/codecs/jz4770.c | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/sound/soc/codecs/jz4770.c b/sound/soc/codecs/jz4770.c index c9fe7f72bfcb..6b60120f59a6 100644 --- a/sound/soc/codecs/jz4770.c +++ b/sound/soc/codecs/jz4770.c @@ -893,11 +893,8 @@ static int jz4770_codec_probe(struct platform_device *pdev) codec->dev = dev; codec->base = devm_platform_ioremap_resource(pdev, 0); - if (IS_ERR(codec->base)) { - ret = PTR_ERR(codec->base); - dev_err(dev, "Failed to ioremap mmio memory: %d\n", ret); - return ret; - } + if (IS_ERR(codec->base)) + return PTR_ERR(codec->base); codec->regmap = devm_regmap_init(dev, NULL, codec, &jz4770_codec_regmap_config); From 452801cabc0a0f0cb742e98617d3f0e8a2b11295 Mon Sep 17 00:00:00 2001 From: Hans de Goede Date: Sun, 7 Mar 2021 00:02:22 +0100 Subject: [PATCH 165/587] ASoC: rt5645: Move rt5645_platform_data to sound/soc/codecs/rt5645.c sound/soc/codecs/rt5645.c is the only user of the rt5645_platform_data, move its definition to sound/soc/codecs/rt5645.c and remove the now empty include/sound/rt5645.h file. Note since the DMI quirk mechanism uses pointers to the rt5645_platform_data struct we can NOT simply add its members to the rt5645_priv struct and completely remove the struct. Signed-off-by: Hans de Goede Link: https://lore.kernel.org/r/20210306230223.516566-1-hdegoede@redhat.com Signed-off-by: Mark Brown --- include/sound/rt5645.h | 32 -------------------------------- sound/soc/codecs/rt5645.c | 23 ++++++++++++++++++++++- sound/soc/codecs/rt5645.h | 2 -- 3 files changed, 22 insertions(+), 35 deletions(-) delete mode 100644 include/sound/rt5645.h diff --git a/include/sound/rt5645.h b/include/sound/rt5645.h deleted file mode 100644 index 710c95be5509..000000000000 --- a/include/sound/rt5645.h +++ /dev/null @@ -1,32 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0-only */ -/* - * linux/sound/rt5645.h -- Platform data for RT5645 - * - * Copyright 2013 Realtek Microelectronics - */ - -#ifndef __LINUX_SND_RT5645_H -#define __LINUX_SND_RT5645_H - -struct rt5645_platform_data { - /* IN2 can optionally be differential */ - bool in2_diff; - - unsigned int dmic1_data_pin; - /* 0 = IN2N; 1 = GPIO5; 2 = GPIO11 */ - unsigned int dmic2_data_pin; - /* 0 = IN2P; 1 = GPIO6; 2 = GPIO10; 3 = GPIO12 */ - - unsigned int jd_mode; - /* Use level triggered irq */ - bool level_trigger_irq; - /* Invert JD1_1 status polarity */ - bool inv_jd1_1; - /* Invert HP detect status polarity */ - bool inv_hp_pol; - - /* Value to asign to snd_soc_card.long_name */ - const char *long_name; -}; - -#endif diff --git a/sound/soc/codecs/rt5645.c b/sound/soc/codecs/rt5645.c index c39095fa14ce..3849a9987541 100644 --- a/sound/soc/codecs/rt5645.c +++ b/sound/soc/codecs/rt5645.c @@ -411,6 +411,27 @@ static const char *const rt5645_supply_names[] = { "cpvdd", }; +struct rt5645_platform_data { + /* IN2 can optionally be differential */ + bool in2_diff; + + unsigned int dmic1_data_pin; + /* 0 = IN2N; 1 = GPIO5; 2 = GPIO11 */ + unsigned int dmic2_data_pin; + /* 0 = IN2P; 1 = GPIO6; 2 = GPIO10; 3 = GPIO12 */ + + unsigned int jd_mode; + /* Use level triggered irq */ + bool level_trigger_irq; + /* Invert JD1_1 status polarity */ + bool inv_jd1_1; + /* Invert HP detect status polarity */ + bool inv_hp_pol; + + /* Value to assign to snd_soc_card.long_name */ + const char *long_name; +}; + struct rt5645_priv { struct snd_soc_component *component; struct rt5645_platform_data pdata; @@ -3834,7 +3855,7 @@ static int rt5645_parse_dt(struct rt5645_priv *rt5645, struct device *dev) static int rt5645_i2c_probe(struct i2c_client *i2c, const struct i2c_device_id *id) { - struct rt5645_platform_data *pdata = dev_get_platdata(&i2c->dev); + struct rt5645_platform_data *pdata = NULL; const struct dmi_system_id *dmi_data; struct rt5645_priv *rt5645; int ret, i; diff --git a/sound/soc/codecs/rt5645.h b/sound/soc/codecs/rt5645.h index e2d72ae17484..ac3de6f3bc2f 100644 --- a/sound/soc/codecs/rt5645.h +++ b/sound/soc/codecs/rt5645.h @@ -9,8 +9,6 @@ #ifndef __RT5645_H__ #define __RT5645_H__ -#include - /* Info */ #define RT5645_RESET 0x00 #define RT5645_VENDOR_ID 0xfd From 3f004d2dc118e5e5d0162a077618aaa4bff9e555 Mon Sep 17 00:00:00 2001 From: Hans de Goede Date: Sun, 7 Mar 2021 00:02:23 +0100 Subject: [PATCH 166/587] ASoC: rt5645: The ALC3270 variant does not have a headset-mic pin The Asus T100HA and T101HA 2-in-1s use a rt5645 family codec and always report that a headset (rather then headphones) are plugged in even when regular headphones are plugged in. And when a headset is used, then the headset-microphone does not work. According to RealTek the ALC3270 variant used in these devices does not support headsets only headphones. Since the ALC3270 is a budget version of the regular ALC5645 codec, I assume that it is using a package with less pins and the headset-mic pin is simply not connected. Detect if the codec is an ALC3270 based on the ACPI HID and if it is an ALC3270 then always report SND_JACK_MICROPHONE as false, so that userspace will not try to use the not-connected headset-mic. Signed-off-by: Hans de Goede Link: https://lore.kernel.org/r/20210306230223.516566-2-hdegoede@redhat.com Signed-off-by: Mark Brown --- sound/soc/codecs/rt5645.c | 18 ++++++++++++++---- 1 file changed, 14 insertions(+), 4 deletions(-) diff --git a/sound/soc/codecs/rt5645.c b/sound/soc/codecs/rt5645.c index 3849a9987541..9408ee63cb26 100644 --- a/sound/soc/codecs/rt5645.c +++ b/sound/soc/codecs/rt5645.c @@ -430,6 +430,9 @@ struct rt5645_platform_data { /* Value to assign to snd_soc_card.long_name */ const char *long_name; + + /* Some (package) variants have the headset-mic pin not-connected */ + bool no_headset_mic; }; struct rt5645_priv { @@ -3180,7 +3183,7 @@ static int rt5645_jack_detect(struct snd_soc_component *component, int jack_inse val &= 0x7; dev_dbg(component->dev, "val = %d\n", val); - if (val == 1 || val == 2) { + if ((val == 1 || val == 2) && !rt5645->pdata.no_headset_mic) { rt5645->jack_type = SND_JACK_HEADSET; if (rt5645->en_button_func) { rt5645_enable_push_button_irq(component, true); @@ -3893,9 +3896,16 @@ static int rt5645_i2c_probe(struct i2c_client *i2c, rt5645->pdata.dmic2_data_pin = QUIRK_DMIC2_DATA_PIN(quirk); } - if (cht_rt5645_gpios && has_acpi_companion(&i2c->dev)) - if (devm_acpi_dev_add_driver_gpios(&i2c->dev, cht_rt5645_gpios)) - dev_dbg(&i2c->dev, "Failed to add driver gpios\n"); + if (has_acpi_companion(&i2c->dev)) { + if (cht_rt5645_gpios) { + if (devm_acpi_dev_add_driver_gpios(&i2c->dev, cht_rt5645_gpios)) + dev_dbg(&i2c->dev, "Failed to add driver gpios\n"); + } + + /* The ALC3270 package has the headset-mic pin not-connected */ + if (acpi_dev_hid_uid_match(ACPI_COMPANION(&i2c->dev), "10EC3270", NULL)) + rt5645->pdata.no_headset_mic = true; + } rt5645->gpiod_hp_det = devm_gpiod_get_optional(&i2c->dev, "hp-detect", GPIOD_IN); From 7ad4d237e7c4a5dcc71cf438f646744b4484f1da Mon Sep 17 00:00:00 2001 From: Shuming Fan Date: Tue, 2 Mar 2021 17:15:06 +0800 Subject: [PATCH 167/587] ASoC: rt711-sdca: Add RT711 SDCA vendor-specific driver This is the initial codec driver for rt711 SDCA version. Signed-off-by: Shuming Fan Link: https://lore.kernel.org/r/20210302091506.18745-1-shumingf@realtek.com Signed-off-by: Mark Brown --- sound/soc/codecs/Kconfig | 7 + sound/soc/codecs/Makefile | 2 + sound/soc/codecs/rt711-sdca-sdw.c | 425 ++++++++ sound/soc/codecs/rt711-sdca-sdw.h | 99 ++ sound/soc/codecs/rt711-sdca.c | 1492 +++++++++++++++++++++++++++++ sound/soc/codecs/rt711-sdca.h | 238 +++++ 6 files changed, 2263 insertions(+) create mode 100644 sound/soc/codecs/rt711-sdca-sdw.c create mode 100644 sound/soc/codecs/rt711-sdca-sdw.h create mode 100644 sound/soc/codecs/rt711-sdca.c create mode 100644 sound/soc/codecs/rt711-sdca.h diff --git a/sound/soc/codecs/Kconfig b/sound/soc/codecs/Kconfig index 00dfac882f94..6ce74c99a305 100644 --- a/sound/soc/codecs/Kconfig +++ b/sound/soc/codecs/Kconfig @@ -180,6 +180,7 @@ config SND_SOC_ALL_CODECS imply SND_SOC_RT5682_SDW imply SND_SOC_RT700_SDW imply SND_SOC_RT711_SDW + imply SND_SOC_RT711_SDCA_SDW imply SND_SOC_RT715_SDW imply SND_SOC_RT715_SDCA_SDW imply SND_SOC_RT1308_SDW @@ -1248,6 +1249,12 @@ config SND_SOC_RT711_SDW select SND_SOC_RT711 select REGMAP_SOUNDWIRE +config SND_SOC_RT711_SDCA_SDW + tristate "Realtek RT711 SDCA Codec - SDW" + depends on SOUNDWIRE + select REGMAP_SOUNDWIRE + select REGMAP_SOUNDWIRE_MBQ + config SND_SOC_RT715 tristate diff --git a/sound/soc/codecs/Makefile b/sound/soc/codecs/Makefile index 09dd9c168aac..dcc2f757bb82 100644 --- a/sound/soc/codecs/Makefile +++ b/sound/soc/codecs/Makefile @@ -197,6 +197,7 @@ snd-soc-rt5682-sdw-objs := rt5682-sdw.o snd-soc-rt5682-i2c-objs := rt5682-i2c.o snd-soc-rt700-objs := rt700.o rt700-sdw.o snd-soc-rt711-objs := rt711.o rt711-sdw.o +snd-soc-rt711-sdca-objs := rt711-sdca.o rt711-sdca-sdw.o snd-soc-rt715-objs := rt715.o rt715-sdw.o snd-soc-rt715-sdca-objs := rt715-sdca.o rt715-sdca-sdw.o snd-soc-sgtl5000-objs := sgtl5000.o @@ -514,6 +515,7 @@ obj-$(CONFIG_SND_SOC_RT5682_I2C) += snd-soc-rt5682-i2c.o obj-$(CONFIG_SND_SOC_RT5682_SDW) += snd-soc-rt5682-sdw.o obj-$(CONFIG_SND_SOC_RT700) += snd-soc-rt700.o obj-$(CONFIG_SND_SOC_RT711) += snd-soc-rt711.o +obj-$(CONFIG_SND_SOC_RT711_SDCA_SDW) += snd-soc-rt711-sdca.o obj-$(CONFIG_SND_SOC_RT715) += snd-soc-rt715.o obj-$(CONFIG_SND_SOC_RT715_SDCA_SDW) += snd-soc-rt715-sdca.o obj-$(CONFIG_SND_SOC_SGTL5000) += snd-soc-sgtl5000.o diff --git a/sound/soc/codecs/rt711-sdca-sdw.c b/sound/soc/codecs/rt711-sdca-sdw.c new file mode 100644 index 000000000000..9685c8905468 --- /dev/null +++ b/sound/soc/codecs/rt711-sdca-sdw.c @@ -0,0 +1,425 @@ +// SPDX-License-Identifier: GPL-2.0-only +// +// rt711-sdw-sdca.c -- rt711 SDCA ALSA SoC audio driver +// +// Copyright(c) 2021 Realtek Semiconductor Corp. +// +// + +#include +#include +#include +#include +#include + +#include "rt711-sdca.h" +#include "rt711-sdca-sdw.h" + +static bool rt711_sdca_readable_register(struct device *dev, unsigned int reg) +{ + switch (reg) { + case 0x201a ... 0x2027: + case 0x2029 ... 0x202a: + case 0x202d ... 0x2034: + case 0x2200 ... 0x2204: + case 0x2206 ... 0x2212: + case 0x2220 ... 0x2223: + case 0x2230 ... 0x2239: + case 0x2f01 ... 0x2f0f: + case 0x2f30 ... 0x2f36: + case 0x2f50 ... 0x2f5a: + case 0x2f60: + case 0x3200 ... 0x3212: + case SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT711_SDCA_ENT_GE49, RT711_SDCA_CTL_SELECTED_MODE, 0): + case SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT711_SDCA_ENT_GE49, RT711_SDCA_CTL_DETECTED_MODE, 0): + case SDW_SDCA_CTL(FUNC_NUM_HID, RT711_SDCA_ENT_HID01, RT711_SDCA_CTL_HIDTX_CURRENT_OWNER, 0) ... + SDW_SDCA_CTL(FUNC_NUM_HID, RT711_SDCA_ENT_HID01, RT711_SDCA_CTL_HIDTX_MESSAGE_LENGTH, 0): + case RT711_BUF_ADDR_HID1 ... RT711_BUF_ADDR_HID2: + return true; + default: + return false; + } +} + +static bool rt711_sdca_volatile_register(struct device *dev, unsigned int reg) +{ + switch (reg) { + case 0x201b: + case 0x201c: + case 0x201d: + case 0x201f: + case 0x2021: + case 0x2023: + case 0x2230: + case 0x202d ... 0x202f: /* BRA */ + case 0x2200 ... 0x2212: /* i2c debug */ + case RT711_RC_CAL_STATUS: + case SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT711_SDCA_ENT_GE49, RT711_SDCA_CTL_DETECTED_MODE, 0): + case SDW_SDCA_CTL(FUNC_NUM_HID, RT711_SDCA_ENT_HID01, RT711_SDCA_CTL_HIDTX_CURRENT_OWNER, 0) ... + SDW_SDCA_CTL(FUNC_NUM_HID, RT711_SDCA_ENT_HID01, RT711_SDCA_CTL_HIDTX_MESSAGE_LENGTH, 0): + case RT711_BUF_ADDR_HID1 ... RT711_BUF_ADDR_HID2: + return true; + default: + return false; + } +} + +static bool rt711_sdca_mbq_readable_register(struct device *dev, unsigned int reg) +{ + switch (reg) { + case 0x2000000 ... 0x20000ff: + case 0x5600000 ... 0x56000ff: + case 0x5700000 ... 0x57000ff: + case 0x5800000 ... 0x58000ff: + case 0x5900000 ... 0x59000ff: + case 0x5b00000 ... 0x5b000ff: + case 0x5f00000 ... 0x5f000ff: + case 0x6100000 ... 0x61000ff: + return true; + default: + return false; + } +} + +static bool rt711_sdca_mbq_volatile_register(struct device *dev, unsigned int reg) +{ + switch (reg) { + case 0x2000000: + case 0x200001a: + case 0x2000046: + case 0x2000080: + case 0x2000081: + case 0x2000083: + case 0x5800000: + case 0x5800001: + case 0x5f00001: + case 0x6100008: + return true; + default: + return false; + } +} + +static const struct regmap_config rt711_sdca_regmap = { + .reg_bits = 32, + .val_bits = 8, + .readable_reg = rt711_sdca_readable_register, + .volatile_reg = rt711_sdca_volatile_register, + .max_register = 0x44ffffff, + .reg_defaults = rt711_sdca_reg_defaults, + .num_reg_defaults = ARRAY_SIZE(rt711_sdca_reg_defaults), + .cache_type = REGCACHE_RBTREE, + .use_single_read = true, + .use_single_write = true, +}; + +static const struct regmap_config rt711_sdca_mbq_regmap = { + .name = "sdw-mbq", + .reg_bits = 32, + .val_bits = 16, + .readable_reg = rt711_sdca_mbq_readable_register, + .volatile_reg = rt711_sdca_mbq_volatile_register, + .max_register = 0x40800f12, + .reg_defaults = rt711_sdca_mbq_defaults, + .num_reg_defaults = ARRAY_SIZE(rt711_sdca_mbq_defaults), + .cache_type = REGCACHE_RBTREE, + .use_single_read = true, + .use_single_write = true, +}; + +static int rt711_sdca_update_status(struct sdw_slave *slave, + enum sdw_slave_status status) +{ + struct rt711_sdca_priv *rt711 = dev_get_drvdata(&slave->dev); + + /* Update the status */ + rt711->status = status; + + if (status == SDW_SLAVE_UNATTACHED) + rt711->hw_init = false; + + if (status == SDW_SLAVE_ATTACHED) { + if (rt711->hs_jack) { + /* + * Due to the SCP_SDCA_INTMASK will be cleared by any reset, and then + * if the device attached again, we will need to set the setting back. + * It could avoid losing the jack detection interrupt. + * This also could sync with the cache value as the rt711_sdca_jack_init set. + */ + sdw_write_no_pm(rt711->slave, SDW_SCP_SDCA_INTMASK1, + SDW_SCP_SDCA_INTMASK_SDCA_0); + sdw_write_no_pm(rt711->slave, SDW_SCP_SDCA_INTMASK2, + SDW_SCP_SDCA_INTMASK_SDCA_8); + } + } + + /* + * Perform initialization only if slave status is present and + * hw_init flag is false + */ + if (rt711->hw_init || rt711->status != SDW_SLAVE_ATTACHED) + return 0; + + /* perform I/O transfers required for Slave initialization */ + return rt711_sdca_io_init(&slave->dev, slave); +} + +static int rt711_sdca_read_prop(struct sdw_slave *slave) +{ + struct sdw_slave_prop *prop = &slave->prop; + int nval; + int i, j; + u32 bit; + unsigned long addr; + struct sdw_dpn_prop *dpn; + + prop->scp_int1_mask = SDW_SCP_INT1_BUS_CLASH | SDW_SCP_INT1_PARITY; + prop->quirks = SDW_SLAVE_QUIRKS_INVALID_INITIAL_PARITY; + prop->is_sdca = true; + + prop->paging_support = true; + + /* first we need to allocate memory for set bits in port lists */ + prop->source_ports = 0x14; /* BITMAP: 00010100 */ + prop->sink_ports = 0x8; /* BITMAP: 00001000 */ + + nval = hweight32(prop->source_ports); + prop->src_dpn_prop = devm_kcalloc(&slave->dev, nval, + sizeof(*prop->src_dpn_prop), GFP_KERNEL); + if (!prop->src_dpn_prop) + return -ENOMEM; + + i = 0; + dpn = prop->src_dpn_prop; + addr = prop->source_ports; + for_each_set_bit(bit, &addr, 32) { + dpn[i].num = bit; + dpn[i].type = SDW_DPN_FULL; + dpn[i].simple_ch_prep_sm = true; + dpn[i].ch_prep_timeout = 10; + i++; + } + + /* do this again for sink now */ + nval = hweight32(prop->sink_ports); + prop->sink_dpn_prop = devm_kcalloc(&slave->dev, nval, + sizeof(*prop->sink_dpn_prop), GFP_KERNEL); + if (!prop->sink_dpn_prop) + return -ENOMEM; + + j = 0; + dpn = prop->sink_dpn_prop; + addr = prop->sink_ports; + for_each_set_bit(bit, &addr, 32) { + dpn[j].num = bit; + dpn[j].type = SDW_DPN_FULL; + dpn[j].simple_ch_prep_sm = true; + dpn[j].ch_prep_timeout = 10; + j++; + } + + /* set the timeout values */ + prop->clk_stop_timeout = 20; + + /* wake-up event */ + prop->wake_capable = 1; + + return 0; +} + +static int rt711_sdca_interrupt_callback(struct sdw_slave *slave, + struct sdw_slave_intr_status *status) +{ + struct rt711_sdca_priv *rt711 = dev_get_drvdata(&slave->dev); + int ret, stat; + int count = 0, retry = 3; + unsigned int sdca_cascade, scp_sdca_stat1, scp_sdca_stat2 = 0; + + dev_dbg(&slave->dev, + "%s control_port_stat=%x, sdca_cascade=%x", __func__, + status->control_port, status->sdca_cascade); + + if (cancel_delayed_work_sync(&rt711->jack_detect_work)) { + dev_warn(&slave->dev, "%s the pending delayed_work was cancelled", __func__); + /* avoid the HID owner doesn't change to device */ + if (rt711->scp_sdca_stat2) + scp_sdca_stat2 = rt711->scp_sdca_stat2; + } + + ret = sdw_read_no_pm(rt711->slave, SDW_SCP_SDCA_INT1); + if (ret < 0) + goto io_error; + rt711->scp_sdca_stat1 = ret; + ret = sdw_read_no_pm(rt711->slave, SDW_SCP_SDCA_INT2); + if (ret < 0) + goto io_error; + rt711->scp_sdca_stat2 = ret; + if (scp_sdca_stat2) + rt711->scp_sdca_stat2 |= scp_sdca_stat2; + + do { + /* clear flag */ + ret = sdw_read_no_pm(rt711->slave, SDW_SCP_SDCA_INT1); + if (ret < 0) + goto io_error; + if (ret & SDW_SCP_SDCA_INTMASK_SDCA_0) { + ret = sdw_write_no_pm(rt711->slave, SDW_SCP_SDCA_INT1, + SDW_SCP_SDCA_INTMASK_SDCA_0); + if (ret < 0) + goto io_error; + } + ret = sdw_read_no_pm(rt711->slave, SDW_SCP_SDCA_INT2); + if (ret < 0) + goto io_error; + if (ret & SDW_SCP_SDCA_INTMASK_SDCA_8) { + ret = sdw_write_no_pm(rt711->slave, SDW_SCP_SDCA_INT2, + SDW_SCP_SDCA_INTMASK_SDCA_8); + if (ret < 0) + goto io_error; + } + + /* check if flag clear or not */ + ret = sdw_read_no_pm(rt711->slave, SDW_DP0_INT); + if (ret < 0) + goto io_error; + sdca_cascade = ret & SDW_DP0_SDCA_CASCADE; + + ret = sdw_read_no_pm(rt711->slave, SDW_SCP_SDCA_INT1); + if (ret < 0) + goto io_error; + scp_sdca_stat1 = ret & SDW_SCP_SDCA_INTMASK_SDCA_0; + + ret = sdw_read_no_pm(rt711->slave, SDW_SCP_SDCA_INT2); + if (ret < 0) + goto io_error; + scp_sdca_stat2 = ret & SDW_SCP_SDCA_INTMASK_SDCA_8; + + stat = scp_sdca_stat1 || scp_sdca_stat2 || sdca_cascade; + + count++; + } while (stat != 0 && count < retry); + + if (stat) + dev_warn(&slave->dev, + "%s scp_sdca_stat1=0x%x, scp_sdca_stat2=0x%x\n", __func__, + rt711->scp_sdca_stat1, rt711->scp_sdca_stat2); + + if (status->sdca_cascade) + mod_delayed_work(system_power_efficient_wq, + &rt711->jack_detect_work, msecs_to_jiffies(30)); + + return 0; + +io_error: + pr_err_ratelimited("IO error in %s, ret %d\n", __func__, ret); + return ret; +} + +static struct sdw_slave_ops rt711_sdca_slave_ops = { + .read_prop = rt711_sdca_read_prop, + .interrupt_callback = rt711_sdca_interrupt_callback, + .update_status = rt711_sdca_update_status, +}; + +static int rt711_sdca_sdw_probe(struct sdw_slave *slave, + const struct sdw_device_id *id) +{ + struct regmap *regmap, *mbq_regmap; + + /* Regmap Initialization */ + mbq_regmap = devm_regmap_init_sdw_mbq(slave, &rt711_sdca_mbq_regmap); + if (IS_ERR(mbq_regmap)) + return PTR_ERR(mbq_regmap); + + regmap = devm_regmap_init_sdw(slave, &rt711_sdca_regmap); + if (IS_ERR(regmap)) + return PTR_ERR(regmap); + + return rt711_sdca_init(&slave->dev, regmap, mbq_regmap, slave); +} + +static int rt711_sdca_sdw_remove(struct sdw_slave *slave) +{ + struct rt711_sdca_priv *rt711 = dev_get_drvdata(&slave->dev); + + if (rt711 && rt711->hw_init) { + cancel_delayed_work_sync(&rt711->jack_detect_work); + cancel_delayed_work_sync(&rt711->jack_btn_check_work); + } + + return 0; +} + +static const struct sdw_device_id rt711_sdca_id[] = { + SDW_SLAVE_ENTRY_EXT(0x025d, 0x711, 0x3, 0x1, 0), + {}, +}; +MODULE_DEVICE_TABLE(sdw, rt711_sdca_id); + +static int __maybe_unused rt711_sdca_dev_suspend(struct device *dev) +{ + struct rt711_sdca_priv *rt711 = dev_get_drvdata(dev); + + if (!rt711->hw_init) + return 0; + + cancel_delayed_work_sync(&rt711->jack_detect_work); + cancel_delayed_work_sync(&rt711->jack_btn_check_work); + + regcache_cache_only(rt711->regmap, true); + regcache_cache_only(rt711->mbq_regmap, true); + + return 0; +} + +#define RT711_PROBE_TIMEOUT 5000 + +static int __maybe_unused rt711_sdca_dev_resume(struct device *dev) +{ + struct sdw_slave *slave = dev_to_sdw_dev(dev); + struct rt711_sdca_priv *rt711 = dev_get_drvdata(dev); + unsigned long time; + + if (!rt711->hw_init) + return 0; + + if (!slave->unattach_request) + goto regmap_sync; + + time = wait_for_completion_timeout(&slave->initialization_complete, + msecs_to_jiffies(RT711_PROBE_TIMEOUT)); + if (!time) { + dev_err(&slave->dev, "Initialization not complete, timed out\n"); + return -ETIMEDOUT; + } + +regmap_sync: + slave->unattach_request = 0; + regcache_cache_only(rt711->regmap, false); + regcache_sync(rt711->regmap); + regcache_cache_only(rt711->mbq_regmap, false); + regcache_sync(rt711->mbq_regmap); + return 0; +} + +static const struct dev_pm_ops rt711_sdca_pm = { + SET_SYSTEM_SLEEP_PM_OPS(rt711_sdca_dev_suspend, rt711_sdca_dev_resume) + SET_RUNTIME_PM_OPS(rt711_sdca_dev_suspend, rt711_sdca_dev_resume, NULL) +}; + +static struct sdw_driver rt711_sdca_sdw_driver = { + .driver = { + .name = "rt711-sdca", + .owner = THIS_MODULE, + .pm = &rt711_sdca_pm, + }, + .probe = rt711_sdca_sdw_probe, + .remove = rt711_sdca_sdw_remove, + .ops = &rt711_sdca_slave_ops, + .id_table = rt711_sdca_id, +}; +module_sdw_driver(rt711_sdca_sdw_driver); + +MODULE_DESCRIPTION("ASoC RT711 SDCA SDW driver"); +MODULE_AUTHOR("Shuming Fan "); +MODULE_LICENSE("GPL"); diff --git a/sound/soc/codecs/rt711-sdca-sdw.h b/sound/soc/codecs/rt711-sdca-sdw.h new file mode 100644 index 000000000000..0d774e473ab9 --- /dev/null +++ b/sound/soc/codecs/rt711-sdca-sdw.h @@ -0,0 +1,99 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * rt711-sdw-sdca.h -- RT711 SDCA ALSA SoC audio driver header + * + * Copyright(c) 2021 Realtek Semiconductor Corp. + */ + +#ifndef __RT711_SDW_SDCA_H__ +#define __RT711_SDW_SDCA_H__ + +#include +#include + +static const struct reg_default rt711_sdca_reg_defaults[] = { + { 0x201a, 0x00 }, + { 0x201e, 0x00 }, + { 0x201f, 0x00 }, + { 0x2020, 0x00 }, + { 0x2021, 0x00 }, + { 0x2022, 0x00 }, + { 0x2023, 0x00 }, + { 0x2024, 0x00 }, + { 0x2025, 0x01 }, + { 0x2026, 0x00 }, + { 0x2027, 0x00 }, + { 0x2029, 0x00 }, + { 0x202a, 0x00 }, + { 0x202d, 0x00 }, + { 0x202e, 0x00 }, + { 0x202f, 0x00 }, + { 0x2030, 0x00 }, + { 0x2031, 0x00 }, + { 0x2032, 0x00 }, + { 0x2033, 0x00 }, + { 0x2230, 0x00 }, + { 0x2231, 0x2f }, + { 0x2232, 0x80 }, + { 0x2233, 0x00 }, + { 0x2234, 0x00 }, + { 0x2235, 0x00 }, + { 0x2236, 0x00 }, + { 0x2237, 0x00 }, + { 0x2238, 0x00 }, + { 0x2239, 0x00 }, + { 0x2f01, 0x00 }, + { 0x2f02, 0x09 }, + { 0x2f03, 0x00 }, + { 0x2f04, 0x00 }, + { 0x2f05, 0x0b }, + { 0x2f06, 0x01 }, + { 0x2f08, 0x00 }, + { 0x2f09, 0x00 }, + { 0x2f0a, 0x00 }, + { 0x2f0b, 0x00 }, + { 0x2f0c, 0x00 }, + { 0x2f0d, 0x00 }, + { 0x2f0e, 0x14 }, + { 0x2f0f, 0x00 }, + { 0x2f50, 0x03 }, + { 0x2f5a, 0x00 }, + { SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT711_SDCA_ENT_CS01, RT711_SDCA_CTL_SAMPLE_FREQ_INDEX, 0), 0x09 }, + { SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT711_SDCA_ENT_USER_FU05, RT711_SDCA_CTL_FU_MUTE, CH_L), 0x01 }, + { SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT711_SDCA_ENT_USER_FU05, RT711_SDCA_CTL_FU_MUTE, CH_R), 0x01 }, + { SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT711_SDCA_ENT_USER_FU0F, RT711_SDCA_CTL_FU_MUTE, CH_L), 0x01 }, + { SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT711_SDCA_ENT_USER_FU0F, RT711_SDCA_CTL_FU_MUTE, CH_R), 0x01 }, + { SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT711_SDCA_ENT_PDE28, RT711_SDCA_CTL_REQ_POWER_STATE, 0), 0x03 }, + { SDW_SDCA_CTL(FUNC_NUM_MIC_ARRAY, RT711_SDCA_ENT_USER_FU1E, RT711_SDCA_CTL_FU_MUTE, CH_L), 0x01 }, + { SDW_SDCA_CTL(FUNC_NUM_MIC_ARRAY, RT711_SDCA_ENT_USER_FU1E, RT711_SDCA_CTL_FU_MUTE, CH_R), 0x01 }, +}; + +static const struct reg_default rt711_sdca_mbq_defaults[] = { + { 0x2000009, 0x1029 }, + { 0x2000011, 0x007a }, + { 0x200001a, 0x8003 }, + { 0x2000045, 0x5289 }, + { 0x2000048, 0x8049 }, + { 0x200004a, 0xa83b }, + { 0x200006b, 0x5064 }, + { 0x200006f, 0x058b }, + { 0x5800000, 0x0008 }, + { 0x5800001, 0x0000 }, + { 0x5f00001, 0x000a }, + { 0x6100000, 0x6100 }, + { 0x6100035, 0x0060 }, + { 0x6100036, 0x0029 }, + { 0x610003f, 0xff12 }, + { SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT711_SDCA_ENT_USER_FU05, RT711_SDCA_CTL_FU_VOLUME, CH_L), 0x00 }, + { SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT711_SDCA_ENT_USER_FU05, RT711_SDCA_CTL_FU_VOLUME, CH_R), 0x00 }, + { SDW_SDCA_CTL(FUNC_NUM_MIC_ARRAY, RT711_SDCA_ENT_USER_FU1E, RT711_SDCA_CTL_FU_VOLUME, CH_L), 0x00 }, + { SDW_SDCA_CTL(FUNC_NUM_MIC_ARRAY, RT711_SDCA_ENT_USER_FU1E, RT711_SDCA_CTL_FU_VOLUME, CH_R), 0x00 }, + { SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT711_SDCA_ENT_USER_FU0F, RT711_SDCA_CTL_FU_VOLUME, CH_L), 0x00 }, + { SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT711_SDCA_ENT_USER_FU0F, RT711_SDCA_CTL_FU_VOLUME, CH_R), 0x00 }, + { SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT711_SDCA_ENT_PLATFORM_FU44, RT711_SDCA_CTL_FU_CH_GAIN, CH_L), 0x00 }, + { SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT711_SDCA_ENT_PLATFORM_FU44, RT711_SDCA_CTL_FU_CH_GAIN, CH_R), 0x00 }, + { SDW_SDCA_CTL(FUNC_NUM_MIC_ARRAY, RT711_SDCA_ENT_PLATFORM_FU15, RT711_SDCA_CTL_FU_CH_GAIN, CH_L), 0x00 }, + { SDW_SDCA_CTL(FUNC_NUM_MIC_ARRAY, RT711_SDCA_ENT_PLATFORM_FU15, RT711_SDCA_CTL_FU_CH_GAIN, CH_R), 0x00 }, +}; + +#endif /* __RT711_SDW_SDCA_H__ */ diff --git a/sound/soc/codecs/rt711-sdca.c b/sound/soc/codecs/rt711-sdca.c new file mode 100644 index 000000000000..381893b640c6 --- /dev/null +++ b/sound/soc/codecs/rt711-sdca.c @@ -0,0 +1,1492 @@ +// SPDX-License-Identifier: GPL-2.0-only +// +// rt711-sdca.c -- rt711 SDCA ALSA SoC audio driver +// +// Copyright(c) 2021 Realtek Semiconductor Corp. +// +// + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "rt711-sdca.h" + +static int rt711_sdca_index_write(struct rt711_sdca_priv *rt711, + unsigned int nid, unsigned int reg, unsigned int value) +{ + int ret; + struct regmap *regmap = rt711->mbq_regmap; + unsigned int addr = (nid << 20) | reg; + + ret = regmap_write(regmap, addr, value); + if (ret < 0) + dev_err(rt711->component->dev, + "Failed to set private value: %06x <= %04x ret=%d\n", + addr, value, ret); + + return ret; +} + +static int rt711_sdca_index_read(struct rt711_sdca_priv *rt711, + unsigned int nid, unsigned int reg, unsigned int *value) +{ + int ret; + struct regmap *regmap = rt711->mbq_regmap; + unsigned int addr = (nid << 20) | reg; + + ret = regmap_read(regmap, addr, value); + if (ret < 0) + dev_err(rt711->component->dev, + "Failed to get private value: %06x => %04x ret=%d\n", + addr, *value, ret); + + return ret; +} + +static int rt711_sdca_index_update_bits(struct rt711_sdca_priv *rt711, + unsigned int nid, unsigned int reg, unsigned int mask, unsigned int val) +{ + unsigned int tmp; + int ret; + + ret = rt711_sdca_index_read(rt711, nid, reg, &tmp); + if (ret < 0) + return ret; + + set_mask_bits(&tmp, mask, val); + return rt711_sdca_index_write(rt711, nid, reg, tmp); +} + +static void rt711_sdca_reset(struct rt711_sdca_priv *rt711) +{ + rt711_sdca_index_update_bits(rt711, RT711_VENDOR_REG, + RT711_PARA_VERB_CTL, RT711_HIDDEN_REG_SW_RESET, + RT711_HIDDEN_REG_SW_RESET); + rt711_sdca_index_update_bits(rt711, RT711_VENDOR_HDA_CTL, + RT711_HDA_LEGACY_RESET_CTL, 0x1, 0x1); +} + +static int rt711_sdca_calibration(struct rt711_sdca_priv *rt711) +{ + unsigned int val, loop_rc = 0, loop_dc = 0; + struct device *dev; + struct regmap *regmap = rt711->regmap; + int chk_cnt = 100; + int ret = 0; + + mutex_lock(&rt711->calibrate_mutex); + dev = regmap_get_device(regmap); + + regmap_read(rt711->regmap, RT711_RC_CAL_STATUS, &val); + /* RC calibration */ + if (!(val & 0x40)) + rt711_sdca_index_update_bits(rt711, RT711_VENDOR_ANALOG_CTL, + RT711_MISC_POWER_CTL0, 0x0010, 0x0010); + + for (loop_rc = 0; loop_rc < chk_cnt && !(val & 0x40); loop_rc++) { + usleep_range(10000, 11000); + ret = regmap_read(rt711->regmap, RT711_RC_CAL_STATUS, &val); + if (ret < 0) + goto _cali_fail_; + } + if (loop_rc == chk_cnt) + dev_err(dev, "%s, RC calibration time-out!\n", __func__); + + /* HP calibration by manual mode setting */ + rt711_sdca_index_update_bits(rt711, RT711_VENDOR_REG, + RT711_FSM_CTL, 0x2000, 0x2000); + + /* Calibration manual mode */ + rt711_sdca_index_update_bits(rt711, RT711_VENDOR_REG, + RT711_FSM_CTL, 0xf, RT711_CALI_CTL); + + /* reset HP calibration */ + rt711_sdca_index_update_bits(rt711, RT711_VENDOR_CALI, + RT711_DAC_DC_CALI_CTL1, RT711_DAC_DC_FORCE_CALI_RST, 0x00); + rt711_sdca_index_update_bits(rt711, RT711_VENDOR_CALI, + RT711_DAC_DC_CALI_CTL1, RT711_DAC_DC_FORCE_CALI_RST, + RT711_DAC_DC_FORCE_CALI_RST); + + /* cal_clk_en_reg */ + if (rt711->hw_ver == RT711_VER_VD0) + rt711_sdca_index_update_bits(rt711, RT711_VENDOR_CALI, + RT711_DAC_DC_CALI_CTL1, RT711_DAC_DC_CALI_CLK_EN, + RT711_DAC_DC_CALI_CLK_EN); + + /* trigger */ + rt711_sdca_index_update_bits(rt711, RT711_VENDOR_CALI, + RT711_DAC_DC_CALI_CTL1, RT711_DAC_DC_CALI_TRIGGER, + RT711_DAC_DC_CALI_TRIGGER); + + /* wait for calibration process */ + rt711_sdca_index_read(rt711, RT711_VENDOR_CALI, + RT711_DAC_DC_CALI_CTL1, &val); + + for (loop_dc = 0; loop_dc < chk_cnt && + (val & RT711_DAC_DC_CALI_TRIGGER); loop_dc++) { + usleep_range(10000, 11000); + ret = rt711_sdca_index_read(rt711, RT711_VENDOR_CALI, + RT711_DAC_DC_CALI_CTL1, &val); + if (ret < 0) + goto _cali_fail_; + } + if (loop_dc == chk_cnt) + dev_err(dev, "%s, calibration time-out!\n", __func__); + + if (loop_dc == chk_cnt || loop_rc == chk_cnt) + ret = -ETIMEDOUT; + +_cali_fail_: + /* enable impedance sense */ + rt711_sdca_index_update_bits(rt711, RT711_VENDOR_REG, + RT711_FSM_CTL, RT711_FSM_IMP_EN, RT711_FSM_IMP_EN); + + /* release HP-JD and trigger FSM */ + rt711_sdca_index_write(rt711, RT711_VENDOR_REG, + RT711_DIGITAL_MISC_CTRL4, 0x201b); + + mutex_unlock(&rt711->calibrate_mutex); + dev_dbg(dev, "%s calibration complete, ret=%d\n", __func__, ret); + return ret; +} + +static unsigned int rt711_sdca_button_detect(struct rt711_sdca_priv *rt711) +{ + unsigned int btn_type = 0, offset, idx, val, owner; + int ret; + unsigned char buf[3]; + + /* get current UMP message owner */ + ret = regmap_read(rt711->regmap, + SDW_SDCA_CTL(FUNC_NUM_HID, RT711_SDCA_ENT_HID01, RT711_SDCA_CTL_HIDTX_CURRENT_OWNER, 0), + &owner); + if (ret < 0) + return 0; + + /* if owner is device then there is no button event from device */ + if (owner == 1) + return 0; + + /* read UMP message offset */ + ret = regmap_read(rt711->regmap, + SDW_SDCA_CTL(FUNC_NUM_HID, RT711_SDCA_ENT_HID01, RT711_SDCA_CTL_HIDTX_MESSAGE_OFFSET, 0), + &offset); + if (ret < 0) + goto _end_btn_det_; + + for (idx = 0; idx < sizeof(buf); idx++) { + ret = regmap_read(rt711->regmap, + RT711_BUF_ADDR_HID1 + offset + idx, &val); + if (ret < 0) + goto _end_btn_det_; + buf[idx] = val & 0xff; + } + + if (buf[0] == 0x11) { + switch (buf[1] & 0xf0) { + case 0x10: + btn_type |= SND_JACK_BTN_2; + break; + case 0x20: + btn_type |= SND_JACK_BTN_3; + break; + case 0x40: + btn_type |= SND_JACK_BTN_0; + break; + case 0x80: + btn_type |= SND_JACK_BTN_1; + break; + } + switch (buf[2]) { + case 0x01: + case 0x10: + btn_type |= SND_JACK_BTN_2; + break; + case 0x02: + case 0x20: + btn_type |= SND_JACK_BTN_3; + break; + case 0x04: + case 0x40: + btn_type |= SND_JACK_BTN_0; + break; + case 0x08: + case 0x80: + btn_type |= SND_JACK_BTN_1; + break; + } + } + +_end_btn_det_: + /* Host is owner, so set back to device */ + if (owner == 0) + /* set owner to device */ + regmap_write(rt711->regmap, + SDW_SDCA_CTL(FUNC_NUM_HID, RT711_SDCA_ENT_HID01, + RT711_SDCA_CTL_HIDTX_SET_OWNER_TO_DEVICE, 0), 0x01); + + return btn_type; +} + +static int rt711_sdca_headset_detect(struct rt711_sdca_priv *rt711) +{ + unsigned int det_mode; + int ret; + + /* get detected_mode */ + ret = regmap_read(rt711->regmap, + SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT711_SDCA_ENT_GE49, RT711_SDCA_CTL_DETECTED_MODE, 0), + &det_mode); + if (ret < 0) + goto io_error; + + switch (det_mode) { + case 0x00: + rt711->jack_type = 0; + break; + case 0x03: + rt711->jack_type = SND_JACK_HEADPHONE; + break; + case 0x05: + rt711->jack_type = SND_JACK_HEADSET; + break; + } + + /* write selected_mode */ + if (det_mode) { + ret = regmap_write(rt711->regmap, + SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT711_SDCA_ENT_GE49, RT711_SDCA_CTL_SELECTED_MODE, 0), + det_mode); + if (ret < 0) + goto io_error; + } + + dev_dbg(&rt711->slave->dev, + "%s, detected_mode=0x%x\n", __func__, det_mode); + + return 0; + +io_error: + pr_err_ratelimited("IO error in %s, ret %d\n", __func__, ret); + return ret; +} + +static void rt711_sdca_jack_detect_handler(struct work_struct *work) +{ + struct rt711_sdca_priv *rt711 = + container_of(work, struct rt711_sdca_priv, jack_detect_work.work); + int btn_type = 0, ret; + + if (!rt711->hs_jack) + return; + + if (!rt711->component->card->instantiated) + return; + + /* SDW_SCP_SDCA_INT_SDCA_0 is used for jack detection */ + if (rt711->scp_sdca_stat1 & SDW_SCP_SDCA_INT_SDCA_0) { + ret = rt711_sdca_headset_detect(rt711); + if (ret < 0) + return; + } + + /* SDW_SCP_SDCA_INT_SDCA_8 is used for button detection */ + if (rt711->scp_sdca_stat2 & SDW_SCP_SDCA_INT_SDCA_8) + btn_type = rt711_sdca_button_detect(rt711); + + if (rt711->jack_type == 0) + btn_type = 0; + + dev_dbg(&rt711->slave->dev, + "in %s, jack_type=0x%x\n", __func__, rt711->jack_type); + dev_dbg(&rt711->slave->dev, + "in %s, btn_type=0x%x\n", __func__, btn_type); + dev_dbg(&rt711->slave->dev, + "in %s, scp_sdca_stat1=0x%x, scp_sdca_stat2=0x%x\n", __func__, + rt711->scp_sdca_stat1, rt711->scp_sdca_stat2); + + snd_soc_jack_report(rt711->hs_jack, rt711->jack_type | btn_type, + SND_JACK_HEADSET | + SND_JACK_BTN_0 | SND_JACK_BTN_1 | + SND_JACK_BTN_2 | SND_JACK_BTN_3); + + if (btn_type) { + /* button released */ + snd_soc_jack_report(rt711->hs_jack, rt711->jack_type, + SND_JACK_HEADSET | + SND_JACK_BTN_0 | SND_JACK_BTN_1 | + SND_JACK_BTN_2 | SND_JACK_BTN_3); + + mod_delayed_work(system_power_efficient_wq, + &rt711->jack_btn_check_work, msecs_to_jiffies(200)); + } +} + +static void rt711_sdca_btn_check_handler(struct work_struct *work) +{ + struct rt711_sdca_priv *rt711 = + container_of(work, struct rt711_sdca_priv, jack_btn_check_work.work); + int btn_type = 0, ret, idx; + unsigned int det_mode, offset, val; + unsigned char buf[3]; + + ret = regmap_read(rt711->regmap, + SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT711_SDCA_ENT_GE49, RT711_SDCA_CTL_DETECTED_MODE, 0), + &det_mode); + if (ret < 0) + goto io_error; + + /* pin attached */ + if (det_mode) { + /* read UMP message offset */ + ret = regmap_read(rt711->regmap, + SDW_SDCA_CTL(FUNC_NUM_HID, RT711_SDCA_ENT_HID01, RT711_SDCA_CTL_HIDTX_MESSAGE_OFFSET, 0), + &offset); + if (ret < 0) + goto io_error; + + for (idx = 0; idx < sizeof(buf); idx++) { + ret = regmap_read(rt711->regmap, + RT711_BUF_ADDR_HID1 + offset + idx, &val); + if (ret < 0) + goto io_error; + buf[idx] = val & 0xff; + } + + if (buf[0] == 0x11) { + switch (buf[1] & 0xf0) { + case 0x10: + btn_type |= SND_JACK_BTN_2; + break; + case 0x20: + btn_type |= SND_JACK_BTN_3; + break; + case 0x40: + btn_type |= SND_JACK_BTN_0; + break; + case 0x80: + btn_type |= SND_JACK_BTN_1; + break; + } + switch (buf[2]) { + case 0x01: + case 0x10: + btn_type |= SND_JACK_BTN_2; + break; + case 0x02: + case 0x20: + btn_type |= SND_JACK_BTN_3; + break; + case 0x04: + case 0x40: + btn_type |= SND_JACK_BTN_0; + break; + case 0x08: + case 0x80: + btn_type |= SND_JACK_BTN_1; + break; + } + } + } else + rt711->jack_type = 0; + + dev_dbg(&rt711->slave->dev, "%s, btn_type=0x%x\n", __func__, btn_type); + snd_soc_jack_report(rt711->hs_jack, rt711->jack_type | btn_type, + SND_JACK_HEADSET | + SND_JACK_BTN_0 | SND_JACK_BTN_1 | + SND_JACK_BTN_2 | SND_JACK_BTN_3); + + if (btn_type) { + /* button released */ + snd_soc_jack_report(rt711->hs_jack, rt711->jack_type, + SND_JACK_HEADSET | + SND_JACK_BTN_0 | SND_JACK_BTN_1 | + SND_JACK_BTN_2 | SND_JACK_BTN_3); + + mod_delayed_work(system_power_efficient_wq, + &rt711->jack_btn_check_work, msecs_to_jiffies(200)); + } + + return; + +io_error: + pr_err_ratelimited("IO error in %s, ret %d\n", __func__, ret); +} + +static void rt711_sdca_jack_init(struct rt711_sdca_priv *rt711) +{ + mutex_lock(&rt711->calibrate_mutex); + + if (rt711->hs_jack) { + /* Enable HID1 event & set button RTC mode */ + rt711_sdca_index_update_bits(rt711, RT711_VENDOR_HDA_CTL, + RT711_PUSH_BTN_INT_CTL6, 0x80f0, 0x8000); + rt711_sdca_index_update_bits(rt711, RT711_VENDOR_HDA_CTL, + RT711_PUSH_BTN_INT_CTL2, 0x11dd, 0x11dd); + rt711_sdca_index_write(rt711, RT711_VENDOR_HDA_CTL, + RT711_PUSH_BTN_INT_CTL7, 0xffff); + rt711_sdca_index_update_bits(rt711, RT711_VENDOR_HDA_CTL, + RT711_PUSH_BTN_INT_CTL9, 0xf000, 0x0000); + + /* GE_mode_change_event_en & Hid1_push_button_event_en */ + rt711_sdca_index_update_bits(rt711, RT711_VENDOR_HDA_CTL, + RT711_GE_MODE_RELATED_CTL, 0x0c00, 0x0c00); + + switch (rt711->jd_src) { + case RT711_JD1: + /* default settings was already for JD1 */ + break; + case RT711_JD2: + rt711_sdca_index_update_bits(rt711, RT711_VENDOR_REG, + RT711_JD_CTL1, RT711_JD2_DIGITAL_MODE_SEL, + RT711_JD2_DIGITAL_MODE_SEL); + rt711_sdca_index_update_bits(rt711, RT711_VENDOR_REG, + RT711_JD_CTL2, RT711_JD2_2PORT_200K_DECODE_HP | RT711_HP_JD_SEL_JD2, + RT711_JD2_2PORT_200K_DECODE_HP | RT711_HP_JD_SEL_JD2); + rt711_sdca_index_update_bits(rt711, RT711_VENDOR_REG, + RT711_CC_DET1, + RT711_HP_JD_FINAL_RESULT_CTL_JD12, + RT711_HP_JD_FINAL_RESULT_CTL_JD12); + break; + default: + dev_warn(rt711->component->dev, "Wrong JD source\n"); + break; + } + + /* set SCP_SDCA_IntMask1[0]=1 */ + sdw_write_no_pm(rt711->slave, SDW_SCP_SDCA_INTMASK1, SDW_SCP_SDCA_INTMASK_SDCA_0); + /* set SCP_SDCA_IntMask2[0]=1 */ + sdw_write_no_pm(rt711->slave, SDW_SCP_SDCA_INTMASK2, SDW_SCP_SDCA_INTMASK_SDCA_8); + dev_dbg(&rt711->slave->dev, "in %s enable\n", __func__); + } else { + /* disable HID 1/2 event */ + rt711_sdca_index_update_bits(rt711, RT711_VENDOR_HDA_CTL, + RT711_GE_MODE_RELATED_CTL, 0x0c00, 0x0000); + + dev_dbg(&rt711->slave->dev, "in %s disable\n", __func__); + } + + mutex_unlock(&rt711->calibrate_mutex); +} + +static int rt711_sdca_set_jack_detect(struct snd_soc_component *component, + struct snd_soc_jack *hs_jack, void *data) +{ + struct rt711_sdca_priv *rt711 = snd_soc_component_get_drvdata(component); + + rt711->hs_jack = hs_jack; + + if (!rt711->hw_init) { + dev_dbg(&rt711->slave->dev, + "%s hw_init not ready yet\n", __func__); + return 0; + } + + rt711_sdca_jack_init(rt711); + return 0; +} + +/* For SDCA control DAC/ADC Gain */ +static int rt711_sdca_set_gain_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_component *component = snd_kcontrol_chip(kcontrol); + struct soc_mixer_control *mc = + (struct soc_mixer_control *)kcontrol->private_value; + struct rt711_sdca_priv *rt711 = snd_soc_component_get_drvdata(component); + unsigned int read_l, read_r, gain_l_val, gain_r_val; + unsigned int i, adc_vol_flag = 0; + + if (strstr(ucontrol->id.name, "FU1E Capture Volume") || + strstr(ucontrol->id.name, "FU0F Capture Volume")) + adc_vol_flag = 1; + + /* control value to 2's complement value */ + /* L Channel */ + gain_l_val = ucontrol->value.integer.value[0]; + if (gain_l_val > mc->max) + gain_l_val = mc->max; + read_l = gain_l_val; + + if (mc->shift == 8) /* boost gain */ + gain_l_val = (gain_l_val * 10) << mc->shift; + else { /* ADC/DAC gain */ + if (adc_vol_flag && gain_l_val > mc->shift) + gain_l_val = (gain_l_val - mc->shift) * 75; + else + gain_l_val = (mc->shift - gain_l_val) * 75; + gain_l_val <<= 8; + gain_l_val /= 100; + if (!(adc_vol_flag && read_l > mc->shift)) { + gain_l_val = ~gain_l_val; + gain_l_val += 1; + } + gain_l_val &= 0xffff; + } + + /* R Channel */ + gain_r_val = ucontrol->value.integer.value[1]; + if (gain_r_val > mc->max) + gain_r_val = mc->max; + read_r = gain_r_val; + + if (mc->shift == 8) /* boost gain */ + gain_r_val = (gain_r_val * 10) << mc->shift; + else { /* ADC/DAC gain */ + if (adc_vol_flag && gain_r_val > mc->shift) + gain_r_val = (gain_r_val - mc->shift) * 75; + else + gain_r_val = (mc->shift - gain_r_val) * 75; + gain_r_val <<= 8; + gain_r_val /= 100; + if (!(adc_vol_flag && read_r > mc->shift)) { + gain_r_val = ~gain_r_val; + gain_r_val += 1; + } + gain_r_val &= 0xffff; + } + + for (i = 0; i < 3; i++) { /* retry 3 times at most */ + /* Lch*/ + regmap_write(rt711->mbq_regmap, mc->reg, gain_l_val); + + /* Rch */ + regmap_write(rt711->mbq_regmap, mc->rreg, gain_r_val); + + regmap_read(rt711->mbq_regmap, mc->reg, &read_l); + regmap_read(rt711->mbq_regmap, mc->rreg, &read_r); + if (read_r == gain_r_val && read_l == gain_l_val) + break; + } + + return i == 3 ? -EIO : 0; +} + +static int rt711_sdca_set_gain_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_component *component = snd_kcontrol_chip(kcontrol); + struct rt711_sdca_priv *rt711 = snd_soc_component_get_drvdata(component); + struct soc_mixer_control *mc = + (struct soc_mixer_control *)kcontrol->private_value; + unsigned int read_l, read_r, ctl_l = 0, ctl_r = 0; + unsigned int adc_vol_flag = 0, neg_flag = 0; + + if (strstr(ucontrol->id.name, "FU1E Capture Volume") || + strstr(ucontrol->id.name, "FU0F Capture Volume")) + adc_vol_flag = 1; + + regmap_read(rt711->mbq_regmap, mc->reg, &read_l); + regmap_read(rt711->mbq_regmap, mc->rreg, &read_r); + + /* 2's complement value to control value */ + if (mc->shift == 8) /* boost gain */ + ctl_l = (read_l >> mc->shift) / 10; + else { /* ADC/DAC gain */ + ctl_l = read_l; + if (read_l & BIT(15)) { + ctl_l = 0xffff & ~(read_l - 1); + neg_flag = 1; + } + ctl_l *= 100; + ctl_l >>= 8; + if (adc_vol_flag) { + if (neg_flag) + ctl_l = mc->shift - (ctl_l / 75); + else + ctl_l = mc->shift + (ctl_l / 75); + } else + ctl_l = mc->max - (ctl_l / 75); + } + + neg_flag = 0; + if (read_l != read_r) { + if (mc->shift == 8) /* boost gain */ + ctl_r = (read_r >> mc->shift) / 10; + else { /* ADC/DAC gain */ + ctl_r = read_r; + if (read_r & BIT(15)) { + ctl_r = 0xffff & ~(read_r - 1); + neg_flag = 1; + } + ctl_r *= 100; + ctl_r >>= 8; + if (adc_vol_flag) { + if (neg_flag) + ctl_r = mc->shift - (ctl_r / 75); + else + ctl_r = mc->shift + (ctl_r / 75); + } else + ctl_r = mc->max - (ctl_r / 75); + } + } else + ctl_r = ctl_l; + + ucontrol->value.integer.value[0] = ctl_l; + ucontrol->value.integer.value[1] = ctl_r; + + return 0; +} + +static const DECLARE_TLV_DB_SCALE(out_vol_tlv, -6525, 75, 0); +static const DECLARE_TLV_DB_SCALE(in_vol_tlv, -1725, 75, 0); +static const DECLARE_TLV_DB_SCALE(mic_vol_tlv, 0, 1000, 0); + +static const struct snd_kcontrol_new rt711_sdca_snd_controls[] = { + SOC_DOUBLE_R_EXT_TLV("FU05 Playback Volume", + SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT711_SDCA_ENT_USER_FU05, RT711_SDCA_CTL_FU_VOLUME, CH_L), + SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT711_SDCA_ENT_USER_FU05, RT711_SDCA_CTL_FU_VOLUME, CH_R), + 0x57, 0x57, 0, + rt711_sdca_set_gain_get, rt711_sdca_set_gain_put, out_vol_tlv), + SOC_DOUBLE_R("FU1E Capture Switch", + SDW_SDCA_CTL(FUNC_NUM_MIC_ARRAY, RT711_SDCA_ENT_USER_FU1E, RT711_SDCA_CTL_FU_MUTE, CH_L), + SDW_SDCA_CTL(FUNC_NUM_MIC_ARRAY, RT711_SDCA_ENT_USER_FU1E, RT711_SDCA_CTL_FU_MUTE, CH_R), + 0, 1, 1), + SOC_DOUBLE_R("FU0F Capture Switch", + SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT711_SDCA_ENT_USER_FU0F, RT711_SDCA_CTL_FU_MUTE, CH_L), + SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT711_SDCA_ENT_USER_FU0F, RT711_SDCA_CTL_FU_MUTE, CH_R), + 0, 1, 1), + SOC_DOUBLE_R_EXT_TLV("FU1E Capture Volume", + SDW_SDCA_CTL(FUNC_NUM_MIC_ARRAY, RT711_SDCA_ENT_USER_FU1E, RT711_SDCA_CTL_FU_VOLUME, CH_L), + SDW_SDCA_CTL(FUNC_NUM_MIC_ARRAY, RT711_SDCA_ENT_USER_FU1E, RT711_SDCA_CTL_FU_VOLUME, CH_R), + 0x17, 0x3f, 0, + rt711_sdca_set_gain_get, rt711_sdca_set_gain_put, in_vol_tlv), + SOC_DOUBLE_R_EXT_TLV("FU0F Capture Volume", + SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT711_SDCA_ENT_USER_FU0F, RT711_SDCA_CTL_FU_VOLUME, CH_L), + SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT711_SDCA_ENT_USER_FU0F, RT711_SDCA_CTL_FU_VOLUME, CH_R), + 0x17, 0x3f, 0, + rt711_sdca_set_gain_get, rt711_sdca_set_gain_put, in_vol_tlv), + SOC_DOUBLE_R_EXT_TLV("FU44 Gain Volume", + SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT711_SDCA_ENT_PLATFORM_FU44, RT711_SDCA_CTL_FU_CH_GAIN, CH_L), + SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT711_SDCA_ENT_PLATFORM_FU44, RT711_SDCA_CTL_FU_CH_GAIN, CH_R), + 8, 3, 0, + rt711_sdca_set_gain_get, rt711_sdca_set_gain_put, mic_vol_tlv), + SOC_DOUBLE_R_EXT_TLV("FU15 Gain Volume", + SDW_SDCA_CTL(FUNC_NUM_MIC_ARRAY, RT711_SDCA_ENT_PLATFORM_FU15, RT711_SDCA_CTL_FU_CH_GAIN, CH_L), + SDW_SDCA_CTL(FUNC_NUM_MIC_ARRAY, RT711_SDCA_ENT_PLATFORM_FU15, RT711_SDCA_CTL_FU_CH_GAIN, CH_R), + 8, 3, 0, + rt711_sdca_set_gain_get, rt711_sdca_set_gain_put, mic_vol_tlv), +}; + +static int rt711_sdca_mux_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_component *component = + snd_soc_dapm_kcontrol_component(kcontrol); + struct rt711_sdca_priv *rt711 = snd_soc_component_get_drvdata(component); + unsigned int val = 0, mask_sft; + + if (strstr(ucontrol->id.name, "ADC 22 Mux")) + mask_sft = 10; + else if (strstr(ucontrol->id.name, "ADC 23 Mux")) + mask_sft = 13; + else + return -EINVAL; + + rt711_sdca_index_read(rt711, RT711_VENDOR_HDA_CTL, + RT711_HDA_LEGACY_MUX_CTL1, &val); + + ucontrol->value.enumerated.item[0] = (val >> mask_sft) & 0x7; + + return 0; +} + +static int rt711_sdca_mux_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_component *component = + snd_soc_dapm_kcontrol_component(kcontrol); + struct snd_soc_dapm_context *dapm = + snd_soc_dapm_kcontrol_dapm(kcontrol); + struct rt711_sdca_priv *rt711 = snd_soc_component_get_drvdata(component); + struct soc_enum *e = (struct soc_enum *)kcontrol->private_value; + unsigned int *item = ucontrol->value.enumerated.item; + unsigned int val, val2 = 0, change, mask_sft; + + if (item[0] >= e->items) + return -EINVAL; + + if (strstr(ucontrol->id.name, "ADC 22 Mux")) + mask_sft = 10; + else if (strstr(ucontrol->id.name, "ADC 23 Mux")) + mask_sft = 13; + else + return -EINVAL; + + val = snd_soc_enum_item_to_val(e, item[0]) << e->shift_l; + + rt711_sdca_index_read(rt711, RT711_VENDOR_HDA_CTL, + RT711_HDA_LEGACY_MUX_CTL1, &val2); + val2 = (val2 >> mask_sft) & 0x7; + + if (val == val2) + change = 0; + else + change = 1; + + if (change) + rt711_sdca_index_update_bits(rt711, RT711_VENDOR_HDA_CTL, + RT711_HDA_LEGACY_MUX_CTL1, 0x7 << mask_sft, + val << mask_sft); + + snd_soc_dapm_mux_update_power(dapm, kcontrol, + item[0], e, NULL); + + return change; +} + +static const char * const adc_mux_text[] = { + "MIC2", + "LINE1", + "LINE2", + "DMIC", +}; + +static SOC_ENUM_SINGLE_DECL( + rt711_adc22_enum, SND_SOC_NOPM, 0, adc_mux_text); + +static SOC_ENUM_SINGLE_DECL( + rt711_adc23_enum, SND_SOC_NOPM, 0, adc_mux_text); + +static const struct snd_kcontrol_new rt711_sdca_adc22_mux = + SOC_DAPM_ENUM_EXT("ADC 22 Mux", rt711_adc22_enum, + rt711_sdca_mux_get, rt711_sdca_mux_put); + +static const struct snd_kcontrol_new rt711_sdca_adc23_mux = + SOC_DAPM_ENUM_EXT("ADC 23 Mux", rt711_adc23_enum, + rt711_sdca_mux_get, rt711_sdca_mux_put); + +static int rt711_sdca_fu05_event(struct snd_soc_dapm_widget *w, + struct snd_kcontrol *kcontrol, int event) +{ + struct snd_soc_component *component = + snd_soc_dapm_to_component(w->dapm); + struct rt711_sdca_priv *rt711 = snd_soc_component_get_drvdata(component); + unsigned char unmute = 0x0, mute = 0x1; + + switch (event) { + case SND_SOC_DAPM_POST_PMU: + regmap_write(rt711->regmap, + SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT711_SDCA_ENT_USER_FU05, + RT711_SDCA_CTL_FU_MUTE, CH_L), + unmute); + regmap_write(rt711->regmap, + SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT711_SDCA_ENT_USER_FU05, + RT711_SDCA_CTL_FU_MUTE, CH_R), + unmute); + break; + case SND_SOC_DAPM_PRE_PMD: + regmap_write(rt711->regmap, + SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT711_SDCA_ENT_USER_FU05, + RT711_SDCA_CTL_FU_MUTE, CH_L), + mute); + regmap_write(rt711->regmap, + SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT711_SDCA_ENT_USER_FU05, + RT711_SDCA_CTL_FU_MUTE, CH_R), + mute); + break; + } + return 0; +} + +static int rt711_sdca_fu0f_event(struct snd_soc_dapm_widget *w, + struct snd_kcontrol *kcontrol, int event) +{ + struct snd_soc_component *component = + snd_soc_dapm_to_component(w->dapm); + struct rt711_sdca_priv *rt711 = snd_soc_component_get_drvdata(component); + unsigned char unmute = 0x0, mute = 0x1; + + switch (event) { + case SND_SOC_DAPM_POST_PMU: + regmap_write(rt711->regmap, + SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT711_SDCA_ENT_USER_FU0F, + RT711_SDCA_CTL_FU_MUTE, CH_L), + unmute); + regmap_write(rt711->regmap, + SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT711_SDCA_ENT_USER_FU0F, + RT711_SDCA_CTL_FU_MUTE, CH_R), + unmute); + break; + case SND_SOC_DAPM_PRE_PMD: + regmap_write(rt711->regmap, + SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT711_SDCA_ENT_USER_FU0F, + RT711_SDCA_CTL_FU_MUTE, CH_L), + mute); + regmap_write(rt711->regmap, + SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT711_SDCA_ENT_USER_FU0F, + RT711_SDCA_CTL_FU_MUTE, CH_R), + mute); + break; + } + return 0; +} + +static int rt711_sdca_fu1e_event(struct snd_soc_dapm_widget *w, + struct snd_kcontrol *kcontrol, int event) +{ + struct snd_soc_component *component = + snd_soc_dapm_to_component(w->dapm); + struct rt711_sdca_priv *rt711 = snd_soc_component_get_drvdata(component); + unsigned char unmute = 0x0, mute = 0x1; + + switch (event) { + case SND_SOC_DAPM_POST_PMU: + regmap_write(rt711->regmap, + SDW_SDCA_CTL(FUNC_NUM_MIC_ARRAY, RT711_SDCA_ENT_USER_FU1E, + RT711_SDCA_CTL_FU_MUTE, CH_L), + unmute); + regmap_write(rt711->regmap, + SDW_SDCA_CTL(FUNC_NUM_MIC_ARRAY, RT711_SDCA_ENT_USER_FU1E, + RT711_SDCA_CTL_FU_MUTE, CH_R), + unmute); + break; + case SND_SOC_DAPM_PRE_PMD: + regmap_write(rt711->regmap, + SDW_SDCA_CTL(FUNC_NUM_MIC_ARRAY, RT711_SDCA_ENT_USER_FU1E, + RT711_SDCA_CTL_FU_MUTE, CH_L), + mute); + regmap_write(rt711->regmap, + SDW_SDCA_CTL(FUNC_NUM_MIC_ARRAY, RT711_SDCA_ENT_USER_FU1E, + RT711_SDCA_CTL_FU_MUTE, CH_R), + mute); + break; + } + return 0; +} + +static int rt711_sdca_pde28_event(struct snd_soc_dapm_widget *w, + struct snd_kcontrol *kcontrol, int event) +{ + struct snd_soc_component *component = + snd_soc_dapm_to_component(w->dapm); + struct rt711_sdca_priv *rt711 = snd_soc_component_get_drvdata(component); + unsigned char ps0 = 0x0, ps3 = 0x3; + + switch (event) { + case SND_SOC_DAPM_POST_PMU: + regmap_write(rt711->regmap, + SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT711_SDCA_ENT_PDE28, + RT711_SDCA_CTL_REQ_POWER_STATE, 0), + ps0); + break; + case SND_SOC_DAPM_PRE_PMD: + regmap_write(rt711->regmap, + SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT711_SDCA_ENT_PDE28, + RT711_SDCA_CTL_REQ_POWER_STATE, 0), + ps3); + break; + } + return 0; +} + +static int rt711_sdca_pde29_event(struct snd_soc_dapm_widget *w, + struct snd_kcontrol *kcontrol, int event) +{ + struct snd_soc_component *component = + snd_soc_dapm_to_component(w->dapm); + struct rt711_sdca_priv *rt711 = snd_soc_component_get_drvdata(component); + unsigned char ps0 = 0x0, ps3 = 0x3; + + switch (event) { + case SND_SOC_DAPM_POST_PMU: + regmap_write(rt711->regmap, + SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT711_SDCA_ENT_PDE29, + RT711_SDCA_CTL_REQ_POWER_STATE, 0), + ps0); + break; + case SND_SOC_DAPM_PRE_PMD: + regmap_write(rt711->regmap, + SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT711_SDCA_ENT_PDE29, + RT711_SDCA_CTL_REQ_POWER_STATE, 0), + ps3); + break; + } + return 0; +} + +static int rt711_sdca_pde2a_event(struct snd_soc_dapm_widget *w, + struct snd_kcontrol *kcontrol, int event) +{ + struct snd_soc_component *component = + snd_soc_dapm_to_component(w->dapm); + struct rt711_sdca_priv *rt711 = snd_soc_component_get_drvdata(component); + unsigned char ps0 = 0x0, ps3 = 0x3; + + switch (event) { + case SND_SOC_DAPM_POST_PMU: + regmap_write(rt711->regmap, + SDW_SDCA_CTL(FUNC_NUM_MIC_ARRAY, RT711_SDCA_ENT_PDE2A, + RT711_SDCA_CTL_REQ_POWER_STATE, 0), + ps0); + break; + case SND_SOC_DAPM_PRE_PMD: + regmap_write(rt711->regmap, + SDW_SDCA_CTL(FUNC_NUM_MIC_ARRAY, RT711_SDCA_ENT_PDE2A, + RT711_SDCA_CTL_REQ_POWER_STATE, 0), + ps3); + break; + } + return 0; +} + +static int rt711_sdca_line1_power_event(struct snd_soc_dapm_widget *w, + struct snd_kcontrol *kcontrol, int event) +{ + struct snd_soc_component *component = + snd_soc_dapm_to_component(w->dapm); + struct rt711_sdca_priv *rt711 = snd_soc_component_get_drvdata(component); + static unsigned int sel_mode = 0xffff; + + switch (event) { + case SND_SOC_DAPM_POST_PMU: + regmap_read(rt711->regmap, + SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT711_SDCA_ENT_GE49, + RT711_SDCA_CTL_SELECTED_MODE, 0), + &sel_mode); + regmap_write(rt711->regmap, + SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT711_SDCA_ENT_LINE1, + RT711_SDCA_CTL_VENDOR_DEF, 0), + 0x1); + regmap_write(rt711->regmap, + SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT711_SDCA_ENT_GE49, + RT711_SDCA_CTL_SELECTED_MODE, 0), + 0x7); + break; + case SND_SOC_DAPM_PRE_PMD: + regmap_write(rt711->regmap, + SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT711_SDCA_ENT_LINE1, + RT711_SDCA_CTL_VENDOR_DEF, 0), + 0x0); + if (sel_mode != 0xffff) + regmap_write(rt711->regmap, + SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT711_SDCA_ENT_GE49, + RT711_SDCA_CTL_SELECTED_MODE, 0), + sel_mode); + break; + } + + return 0; +} + +static int rt711_sdca_line2_power_event(struct snd_soc_dapm_widget *w, + struct snd_kcontrol *kcontrol, int event) +{ + struct snd_soc_component *component = + snd_soc_dapm_to_component(w->dapm); + struct rt711_sdca_priv *rt711 = snd_soc_component_get_drvdata(component); + unsigned char ps0 = 0x0, ps3 = 0x3; + + switch (event) { + case SND_SOC_DAPM_POST_PMU: + regmap_write(rt711->regmap, + SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT711_SDCA_ENT_PDELINE2, + RT711_SDCA_CTL_REQ_POWER_STATE, 0), + ps0); + regmap_write(rt711->regmap, + SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT711_SDCA_ENT_LINE2, + RT711_SDCA_CTL_VENDOR_DEF, 0), + 0x1); + break; + case SND_SOC_DAPM_PRE_PMD: + regmap_write(rt711->regmap, + SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT711_SDCA_ENT_LINE2, + RT711_SDCA_CTL_VENDOR_DEF, 0), + 0x0); + regmap_write(rt711->regmap, + SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT711_SDCA_ENT_PDELINE2, + RT711_SDCA_CTL_REQ_POWER_STATE, 0), + ps3); + break; + } + + return 0; +} + +static const struct snd_soc_dapm_widget rt711_sdca_dapm_widgets[] = { + SND_SOC_DAPM_OUTPUT("HP"), + SND_SOC_DAPM_INPUT("MIC2"), + SND_SOC_DAPM_INPUT("DMIC1"), + SND_SOC_DAPM_INPUT("DMIC2"), + SND_SOC_DAPM_INPUT("LINE1"), + SND_SOC_DAPM_INPUT("LINE2"), + + SND_SOC_DAPM_PGA_E("LINE1 Power", SND_SOC_NOPM, + 0, 0, NULL, 0, rt711_sdca_line1_power_event, + SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD), + SND_SOC_DAPM_PGA_E("LINE2 Power", SND_SOC_NOPM, + 0, 0, NULL, 0, rt711_sdca_line2_power_event, + SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD), + + SND_SOC_DAPM_SUPPLY("PDE 28", SND_SOC_NOPM, 0, 0, + rt711_sdca_pde28_event, + SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD), + SND_SOC_DAPM_SUPPLY("PDE 29", SND_SOC_NOPM, 0, 0, + rt711_sdca_pde29_event, + SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD), + SND_SOC_DAPM_SUPPLY("PDE 2A", SND_SOC_NOPM, 0, 0, + rt711_sdca_pde2a_event, + SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD), + + SND_SOC_DAPM_DAC_E("FU 05", NULL, SND_SOC_NOPM, 0, 0, + rt711_sdca_fu05_event, + SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD), + SND_SOC_DAPM_ADC_E("FU 0F", NULL, SND_SOC_NOPM, 0, 0, + rt711_sdca_fu0f_event, + SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD), + SND_SOC_DAPM_ADC_E("FU 1E", NULL, SND_SOC_NOPM, 0, 0, + rt711_sdca_fu1e_event, + SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD), + SND_SOC_DAPM_MUX("ADC 22 Mux", SND_SOC_NOPM, 0, 0, + &rt711_sdca_adc22_mux), + SND_SOC_DAPM_MUX("ADC 23 Mux", SND_SOC_NOPM, 0, 0, + &rt711_sdca_adc23_mux), + + SND_SOC_DAPM_AIF_IN("DP3RX", "DP3 Playback", 0, SND_SOC_NOPM, 0, 0), + SND_SOC_DAPM_AIF_OUT("DP2TX", "DP2 Capture", 0, SND_SOC_NOPM, 0, 0), + SND_SOC_DAPM_AIF_OUT("DP4TX", "DP4 Capture", 0, SND_SOC_NOPM, 0, 0), +}; + +static const struct snd_soc_dapm_route rt711_sdca_audio_map[] = { + {"FU 05", NULL, "DP3RX"}, + {"DP2TX", NULL, "FU 0F"}, + {"DP4TX", NULL, "FU 1E"}, + + {"LINE1 Power", NULL, "LINE1"}, + {"LINE2 Power", NULL, "LINE2"}, + {"HP", NULL, "PDE 28"}, + {"FU 0F", NULL, "PDE 29"}, + {"FU 1E", NULL, "PDE 2A"}, + + {"FU 0F", NULL, "ADC 22 Mux"}, + {"FU 1E", NULL, "ADC 23 Mux"}, + {"ADC 22 Mux", "DMIC", "DMIC1"}, + {"ADC 22 Mux", "LINE1", "LINE1 Power"}, + {"ADC 22 Mux", "LINE2", "LINE2 Power"}, + {"ADC 22 Mux", "MIC2", "MIC2"}, + {"ADC 23 Mux", "DMIC", "DMIC2"}, + {"ADC 23 Mux", "LINE1", "LINE1 Power"}, + {"ADC 23 Mux", "LINE2", "LINE2 Power"}, + {"ADC 23 Mux", "MIC2", "MIC2"}, + + {"HP", NULL, "FU 05"}, +}; + +static int rt711_sdca_parse_dt(struct rt711_sdca_priv *rt711, struct device *dev) +{ + device_property_read_u32(dev, "realtek,jd-src", &rt711->jd_src); + + return 0; +} + +static int rt711_sdca_probe(struct snd_soc_component *component) +{ + struct rt711_sdca_priv *rt711 = snd_soc_component_get_drvdata(component); + + rt711_sdca_parse_dt(rt711, &rt711->slave->dev); + rt711->component = component; + + return 0; +} + +static void rt711_sdca_remove(struct snd_soc_component *component) +{ + struct rt711_sdca_priv *rt711 = snd_soc_component_get_drvdata(component); + + regcache_cache_only(rt711->regmap, true); + regcache_cache_only(rt711->mbq_regmap, true); +} + +static const struct snd_soc_component_driver soc_sdca_dev_rt711 = { + .probe = rt711_sdca_probe, + .controls = rt711_sdca_snd_controls, + .num_controls = ARRAY_SIZE(rt711_sdca_snd_controls), + .dapm_widgets = rt711_sdca_dapm_widgets, + .num_dapm_widgets = ARRAY_SIZE(rt711_sdca_dapm_widgets), + .dapm_routes = rt711_sdca_audio_map, + .num_dapm_routes = ARRAY_SIZE(rt711_sdca_audio_map), + .set_jack = rt711_sdca_set_jack_detect, + .remove = rt711_sdca_remove, +}; + +static int rt711_sdca_set_sdw_stream(struct snd_soc_dai *dai, void *sdw_stream, + int direction) +{ + struct sdw_stream_data *stream; + + if (!sdw_stream) + return 0; + + stream = kzalloc(sizeof(*stream), GFP_KERNEL); + if (!stream) + return -ENOMEM; + + stream->sdw_stream = sdw_stream; + + /* Use tx_mask or rx_mask to configure stream tag and set dma_data */ + if (direction == SNDRV_PCM_STREAM_PLAYBACK) + dai->playback_dma_data = stream; + else + dai->capture_dma_data = stream; + + return 0; +} + +static void rt711_sdca_shutdown(struct snd_pcm_substream *substream, + struct snd_soc_dai *dai) +{ + struct sdw_stream_data *stream; + + stream = snd_soc_dai_get_dma_data(dai, substream); + snd_soc_dai_set_dma_data(dai, substream, NULL); + kfree(stream); +} + +static int rt711_sdca_pcm_hw_params(struct snd_pcm_substream *substream, + struct snd_pcm_hw_params *params, + struct snd_soc_dai *dai) +{ + struct snd_soc_component *component = dai->component; + struct rt711_sdca_priv *rt711 = snd_soc_component_get_drvdata(component); + struct sdw_stream_config stream_config; + struct sdw_port_config port_config; + enum sdw_data_direction direction; + struct sdw_stream_data *stream; + int retval, port, num_channels; + unsigned int sampling_rate; + + dev_dbg(dai->dev, "%s %s", __func__, dai->name); + stream = snd_soc_dai_get_dma_data(dai, substream); + + if (!stream) + return -EINVAL; + + if (!rt711->slave) + return -EINVAL; + + /* SoundWire specific configuration */ + if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { + direction = SDW_DATA_DIR_RX; + port = 3; + } else { + direction = SDW_DATA_DIR_TX; + if (dai->id == RT711_AIF1) + port = 2; + else if (dai->id == RT711_AIF2) + port = 4; + else + return -EINVAL; + } + + stream_config.frame_rate = params_rate(params); + stream_config.ch_count = params_channels(params); + stream_config.bps = snd_pcm_format_width(params_format(params)); + stream_config.direction = direction; + + num_channels = params_channels(params); + port_config.ch_mask = GENMASK(num_channels - 1, 0); + port_config.num = port; + + retval = sdw_stream_add_slave(rt711->slave, &stream_config, + &port_config, 1, stream->sdw_stream); + if (retval) { + dev_err(dai->dev, "Unable to configure port\n"); + return retval; + } + + if (params_channels(params) > 16) { + dev_err(component->dev, "Unsupported channels %d\n", + params_channels(params)); + return -EINVAL; + } + + /* sampling rate configuration */ + switch (params_rate(params)) { + case 44100: + sampling_rate = RT711_SDCA_RATE_44100HZ; + break; + case 48000: + sampling_rate = RT711_SDCA_RATE_48000HZ; + break; + case 96000: + sampling_rate = RT711_SDCA_RATE_96000HZ; + break; + case 192000: + sampling_rate = RT711_SDCA_RATE_192000HZ; + break; + default: + dev_err(component->dev, "Rate %d is not supported\n", + params_rate(params)); + return -EINVAL; + } + + /* set sampling frequency */ + regmap_write(rt711->regmap, + SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT711_SDCA_ENT_CS01, RT711_SDCA_CTL_SAMPLE_FREQ_INDEX, 0), + sampling_rate); + regmap_write(rt711->regmap, + SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT711_SDCA_ENT_CS11, RT711_SDCA_CTL_SAMPLE_FREQ_INDEX, 0), + sampling_rate); + regmap_write(rt711->regmap, + SDW_SDCA_CTL(FUNC_NUM_MIC_ARRAY, RT711_SDCA_ENT_CS1F, RT711_SDCA_CTL_SAMPLE_FREQ_INDEX, 0), + sampling_rate); + + return 0; +} + +static int rt711_sdca_pcm_hw_free(struct snd_pcm_substream *substream, + struct snd_soc_dai *dai) +{ + struct snd_soc_component *component = dai->component; + struct rt711_sdca_priv *rt711 = snd_soc_component_get_drvdata(component); + struct sdw_stream_data *stream = + snd_soc_dai_get_dma_data(dai, substream); + + if (!rt711->slave) + return -EINVAL; + + sdw_stream_remove_slave(rt711->slave, stream->sdw_stream); + return 0; +} + +#define RT711_STEREO_RATES (SNDRV_PCM_RATE_44100 | SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_96000 | \ + SNDRV_PCM_RATE_192000) +#define RT711_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S20_3LE | \ + SNDRV_PCM_FMTBIT_S24_LE) + +static struct snd_soc_dai_ops rt711_sdca_ops = { + .hw_params = rt711_sdca_pcm_hw_params, + .hw_free = rt711_sdca_pcm_hw_free, + .set_sdw_stream = rt711_sdca_set_sdw_stream, + .shutdown = rt711_sdca_shutdown, +}; + +static struct snd_soc_dai_driver rt711_sdca_dai[] = { + { + .name = "rt711-sdca-aif1", + .id = RT711_AIF1, + .playback = { + .stream_name = "DP3 Playback", + .channels_min = 1, + .channels_max = 2, + .rates = RT711_STEREO_RATES, + .formats = RT711_FORMATS, + }, + .capture = { + .stream_name = "DP2 Capture", + .channels_min = 1, + .channels_max = 2, + .rates = RT711_STEREO_RATES, + .formats = RT711_FORMATS, + }, + .ops = &rt711_sdca_ops, + }, + { + .name = "rt711-sdca-aif2", + .id = RT711_AIF2, + .capture = { + .stream_name = "DP4 Capture", + .channels_min = 1, + .channels_max = 2, + .rates = RT711_STEREO_RATES, + .formats = RT711_FORMATS, + }, + .ops = &rt711_sdca_ops, + } +}; + +int rt711_sdca_init(struct device *dev, struct regmap *regmap, + struct regmap *mbq_regmap, struct sdw_slave *slave) +{ + struct rt711_sdca_priv *rt711; + int ret; + + rt711 = devm_kzalloc(dev, sizeof(*rt711), GFP_KERNEL); + if (!rt711) + return -ENOMEM; + + dev_set_drvdata(dev, rt711); + rt711->slave = slave; + rt711->regmap = regmap; + rt711->mbq_regmap = mbq_regmap; + + /* + * Mark hw_init to false + * HW init will be performed when device reports present + */ + rt711->hw_init = false; + rt711->first_hw_init = false; + + /* JD source uses JD2 in default */ + rt711->jd_src = RT711_JD2; + + ret = devm_snd_soc_register_component(dev, + &soc_sdca_dev_rt711, + rt711_sdca_dai, + ARRAY_SIZE(rt711_sdca_dai)); + + dev_dbg(&slave->dev, "%s\n", __func__); + + return ret; +} + +static void rt711_sdca_vd0_io_init(struct rt711_sdca_priv *rt711) +{ + rt711_sdca_index_write(rt711, RT711_VENDOR_REG, + RT711_GPIO_TEST_MODE_CTL2, 0x0e00); + rt711_sdca_index_write(rt711, RT711_VENDOR_HDA_CTL, + RT711_HDA_LEGACY_GPIO_CTL, 0x0008); + + regmap_write(rt711->regmap, 0x2f5a, 0x01); + + rt711_sdca_index_write(rt711, RT711_VENDOR_REG, + RT711_ADC27_VOL_SET, 0x8728); + + rt711_sdca_index_write(rt711, RT711_VENDOR_REG, + RT711_COMBO_JACK_AUTO_CTL3, 0xa472); + + regmap_write(rt711->regmap, 0x2f50, 0x02); + + rt711_sdca_index_update_bits(rt711, RT711_VENDOR_ANALOG_CTL, + RT711_MISC_POWER_CTL4, 0x6000, 0x6000); + + rt711_sdca_index_update_bits(rt711, RT711_VENDOR_REG, + RT711_COMBO_JACK_AUTO_CTL3, 0x000c, 0x000c); + + rt711_sdca_index_write(rt711, RT711_VENDOR_HDA_CTL, + RT711_HDA_LEGACY_CONFIG_CTL, 0x0000); + + rt711_sdca_index_write(rt711, RT711_VENDOR_VAD, + RT711_VAD_SRAM_CTL1, 0x0050); +} + +static void rt711_sdca_vd1_io_init(struct rt711_sdca_priv *rt711) +{ + rt711_sdca_index_update_bits(rt711, RT711_VENDOR_HDA_CTL, + RT711_HDA_LEGACY_UNSOLICITED_CTL, 0x0300, 0x0000); + + rt711_sdca_index_write(rt711, RT711_VENDOR_REG, + RT711_COMBO_JACK_AUTO_CTL3, 0xa43e); + + regmap_write(rt711->regmap, 0x2f5a, 0x05); + + rt711_sdca_index_write(rt711, RT711_VENDOR_REG, + RT711_JD_CTRL6, 0x0500); + + rt711_sdca_index_write(rt711, RT711_VENDOR_REG, + RT711_DMIC_CTL1, 0x6173); + + rt711_sdca_index_write(rt711, RT711_VENDOR_HDA_CTL, + RT711_HDA_LEGACY_CONFIG_CTL, 0x0000); + + rt711_sdca_index_write(rt711, RT711_VENDOR_VAD, + RT711_VAD_SRAM_CTL1, 0x0050); +} + +int rt711_sdca_io_init(struct device *dev, struct sdw_slave *slave) +{ + struct rt711_sdca_priv *rt711 = dev_get_drvdata(dev); + int ret = 0; + unsigned int val; + + if (rt711->hw_init) + return 0; + + if (rt711->first_hw_init) { + regcache_cache_only(rt711->regmap, false); + regcache_cache_bypass(rt711->regmap, true); + } else { + /* + * PM runtime is only enabled when a Slave reports as Attached + */ + + /* set autosuspend parameters */ + pm_runtime_set_autosuspend_delay(&slave->dev, 3000); + pm_runtime_use_autosuspend(&slave->dev); + + /* update count of parent 'active' children */ + pm_runtime_set_active(&slave->dev); + + /* make sure the device does not suspend immediately */ + pm_runtime_mark_last_busy(&slave->dev); + + pm_runtime_enable(&slave->dev); + } + + pm_runtime_get_noresume(&slave->dev); + + rt711_sdca_reset(rt711); + + rt711_sdca_index_read(rt711, RT711_VENDOR_REG, RT711_JD_PRODUCT_NUM, &val); + rt711->hw_ver = val & 0xf; + + if (rt711->hw_ver == RT711_VER_VD0) + rt711_sdca_vd0_io_init(rt711); + else + rt711_sdca_vd1_io_init(rt711); + + /* DP4 mux select from 08_filter_Out_pri */ + rt711_sdca_index_update_bits(rt711, RT711_VENDOR_REG, + RT711_FILTER_SRC_SEL, 0x1800, 0x0800); + + /* ge_exclusive_inbox_en disable */ + rt711_sdca_index_update_bits(rt711, RT711_VENDOR_HDA_CTL, + RT711_PUSH_BTN_INT_CTL0, 0x20, 0x00); + + if (!rt711->first_hw_init) { + INIT_DELAYED_WORK(&rt711->jack_detect_work, + rt711_sdca_jack_detect_handler); + INIT_DELAYED_WORK(&rt711->jack_btn_check_work, + rt711_sdca_btn_check_handler); + mutex_init(&rt711->calibrate_mutex); + } + + /* calibration */ + ret = rt711_sdca_calibration(rt711); + if (ret < 0) + dev_err(dev, "%s, calibration failed!\n", __func__); + + /* HP output enable */ + regmap_write(rt711->regmap, + SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT711_SDCA_ENT_OT1, RT711_SDCA_CTL_VENDOR_DEF, 0), 0x4); + + /* + * if set_jack callback occurred early than io_init, + * we set up the jack detection function now + */ + if (rt711->hs_jack) + rt711_sdca_jack_init(rt711); + + if (rt711->first_hw_init) { + regcache_cache_bypass(rt711->regmap, false); + regcache_mark_dirty(rt711->regmap); + } else + rt711->first_hw_init = true; + + /* Mark Slave initialization complete */ + rt711->hw_init = true; + + pm_runtime_mark_last_busy(&slave->dev); + pm_runtime_put_autosuspend(&slave->dev); + + dev_dbg(&slave->dev, "%s hw_init complete\n", __func__); + return 0; +} + +MODULE_DESCRIPTION("ASoC RT711 SDCA SDW driver"); +MODULE_AUTHOR("Shuming Fan "); +MODULE_LICENSE("GPL"); diff --git a/sound/soc/codecs/rt711-sdca.h b/sound/soc/codecs/rt711-sdca.h new file mode 100644 index 000000000000..98a022cec0bd --- /dev/null +++ b/sound/soc/codecs/rt711-sdca.h @@ -0,0 +1,238 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * rt711-sdca.h -- RT711 SDCA ALSA SoC audio driver header + * + * Copyright(c) 2021 Realtek Semiconductor Corp. + */ + +#ifndef __RT711_SDCA_H__ +#define __RT711_SDCA_H__ + +#include +#include +#include +#include +#include +#include + +struct rt711_sdca_priv { + struct regmap *regmap, *mbq_regmap; + struct snd_soc_component *component; + struct sdw_slave *slave; + enum sdw_slave_status status; + struct sdw_bus_params params; + bool hw_init; + bool first_hw_init; + struct snd_soc_jack *hs_jack; + struct delayed_work jack_detect_work; + struct delayed_work jack_btn_check_work; + struct mutex calibrate_mutex; /* for headset calibration */ + int jack_type, jd_src; + unsigned int scp_sdca_stat1, scp_sdca_stat2; + int hw_ver; +}; + +struct sdw_stream_data { + struct sdw_stream_runtime *sdw_stream; +}; + +/* NID */ +#define RT711_AUDIO_FUNCTION_GROUP 0x01 +#define RT711_DAC_OUT2 0x03 +#define RT711_ADC_IN1 0x09 +#define RT711_ADC_IN2 0x08 +#define RT711_DMIC1 0x12 +#define RT711_DMIC2 0x13 +#define RT711_MIC2 0x19 +#define RT711_LINE1 0x1a +#define RT711_LINE2 0x1b +#define RT711_BEEP 0x1d +#define RT711_VENDOR_REG 0x20 +#define RT711_HP_OUT 0x21 +#define RT711_MIXER_IN1 0x22 +#define RT711_MIXER_IN2 0x23 +#define RT711_INLINE_CMD 0x55 +#define RT711_VENDOR_CALI 0x58 +#define RT711_VENDOR_IMS_DRE 0x5b +#define RT711_VENDOR_VAD 0x5e +#define RT711_VENDOR_ANALOG_CTL 0x5f +#define RT711_VENDOR_HDA_CTL 0x61 + +/* Index (NID:20h) */ +#define RT711_JD_PRODUCT_NUM 0x00 +#define RT711_DMIC_CTL1 0x06 +#define RT711_JD_CTL1 0x08 +#define RT711_JD_CTL2 0x09 +#define RT711_CC_DET1 0x11 +#define RT711_PARA_VERB_CTL 0x1a +#define RT711_COMBO_JACK_AUTO_CTL1 0x45 +#define RT711_COMBO_JACK_AUTO_CTL2 0x46 +#define RT711_COMBO_JACK_AUTO_CTL3 0x47 +#define RT711_INLINE_CMD_CTL 0x48 +#define RT711_DIGITAL_MISC_CTRL4 0x4a +#define RT711_JD_CTRL6 0x6a +#define RT711_VREFOUT_CTL 0x6b +#define RT711_GPIO_TEST_MODE_CTL2 0x6d +#define RT711_FSM_CTL 0x6f +#define RT711_IRQ_FLAG_TABLE1 0x80 +#define RT711_IRQ_FLAG_TABLE2 0x81 +#define RT711_IRQ_FLAG_TABLE3 0x82 +#define RT711_HP_FSM_CTL 0x83 +#define RT711_TX_RX_MUX_CTL 0x91 +#define RT711_FILTER_SRC_SEL 0xb0 +#define RT711_ADC27_VOL_SET 0xb7 + +/* Index (NID:58h) */ +#define RT711_DAC_DC_CALI_CTL1 0x00 +#define RT711_DAC_DC_CALI_CTL2 0x01 + +/* Index (NID:5bh) */ +#define RT711_IMS_DIGITAL_CTL1 0x00 +#define RT711_HP_IMS_RESULT_L 0x20 +#define RT711_HP_IMS_RESULT_R 0x21 + +/* Index (NID:5eh) */ +#define RT711_VAD_SRAM_CTL1 0x10 + +/* Index (NID:5fh) */ +#define RT711_MISC_POWER_CTL0 0x01 +#define RT711_MISC_POWER_CTL4 0x05 + +/* Index (NID:61h) */ +#define RT711_HDA_LEGACY_MUX_CTL1 0x00 +#define RT711_HDA_LEGACY_UNSOLICITED_CTL 0x03 +#define RT711_HDA_LEGACY_CONFIG_CTL 0x06 +#define RT711_HDA_LEGACY_RESET_CTL 0x08 +#define RT711_HDA_LEGACY_GPIO_CTL 0x0a +#define RT711_ADC08_09_PDE_CTL 0x24 +#define RT711_GE_MODE_RELATED_CTL 0x35 +#define RT711_PUSH_BTN_INT_CTL0 0x36 +#define RT711_PUSH_BTN_INT_CTL1 0x37 +#define RT711_PUSH_BTN_INT_CTL2 0x38 +#define RT711_PUSH_BTN_INT_CTL6 0x3c +#define RT711_PUSH_BTN_INT_CTL7 0x3d +#define RT711_PUSH_BTN_INT_CTL9 0x3f + +/* DAC DC offset calibration control-1 (0x00)(NID:20h) */ +#define RT711_DAC_DC_CALI_TRIGGER (0x1 << 15) +#define RT711_DAC_DC_CALI_CLK_EN (0x1 << 14) +#define RT711_DAC_DC_FORCE_CALI_RST (0x1 << 3) + +/* jack detect control 1 (0x08)(NID:20h) */ +#define RT711_JD2_DIGITAL_MODE_SEL (0x1 << 1) + +/* jack detect control 2 (0x09)(NID:20h) */ +#define RT711_JD2_2PORT_200K_DECODE_HP (0x1 << 13) +#define RT711_HP_JD_SEL_JD1 (0x0 << 1) +#define RT711_HP_JD_SEL_JD2 (0x1 << 1) + +/* CC DET1 (0x11)(NID:20h) */ +#define RT711_HP_JD_FINAL_RESULT_CTL_JD12 (0x1 << 10) +#define RT711_HP_JD_FINAL_RESULT_CTL_CCDET (0x0 << 10) + +/* Parameter & Verb control (0x1a)(NID:20h) */ +#define RT711_HIDDEN_REG_SW_RESET (0x1 << 14) + +/* combo jack auto switch control 2 (0x46)(NID:20h) */ +#define RT711_COMBOJACK_AUTO_DET_STATUS (0x1 << 11) +#define RT711_COMBOJACK_AUTO_DET_TRS (0x1 << 10) +#define RT711_COMBOJACK_AUTO_DET_CTIA (0x1 << 9) +#define RT711_COMBOJACK_AUTO_DET_OMTP (0x1 << 8) + +/* FSM control (0x6f)(NID:20h) */ +#define RT711_CALI_CTL (0x0 << 0) +#define RT711_COMBOJACK_CTL (0x1 << 0) +#define RT711_IMS_CTL (0x2 << 0) +#define RT711_DEPOP_CTL (0x3 << 0) +#define RT711_FSM_IMP_EN (0x1 << 6) + +/* Impedance Sense Digital Control 1 (0x00)(NID:5bh) */ +#define RT711_TRIGGER_IMS (0x1 << 15) +#define RT711_IMS_EN (0x1 << 6) + +#define RT711_EAPD_HIGH 0x2 +#define RT711_EAPD_LOW 0x0 +#define RT711_MUTE_SFT 7 +/* set input/output mapping to payload[14][15] separately */ +#define RT711_DIR_IN_SFT 6 +#define RT711_DIR_OUT_SFT 7 + +/* RC Calibration register */ +#define RT711_RC_CAL_STATUS 0x320c + +/* Buffer address for HID */ +#define RT711_BUF_ADDR_HID1 0x44030000 +#define RT711_BUF_ADDR_HID2 0x44030020 + +/* RT711 SDCA Control - function number */ +#define FUNC_NUM_JACK_CODEC 0x01 +#define FUNC_NUM_MIC_ARRAY 0x02 +#define FUNC_NUM_HID 0x03 + +/* RT711 SDCA entity */ +#define RT711_SDCA_ENT_HID01 0x01 +#define RT711_SDCA_ENT_GE49 0x49 +#define RT711_SDCA_ENT_USER_FU05 0x05 +#define RT711_SDCA_ENT_USER_FU0F 0x0f +#define RT711_SDCA_ENT_USER_FU1E 0x1e +#define RT711_SDCA_ENT_PLATFORM_FU15 0x15 +#define RT711_SDCA_ENT_PLATFORM_FU44 0x44 +#define RT711_SDCA_ENT_PDE28 0x28 +#define RT711_SDCA_ENT_PDE29 0x29 +#define RT711_SDCA_ENT_PDE2A 0x2a +#define RT711_SDCA_ENT_CS01 0x01 +#define RT711_SDCA_ENT_CS11 0x11 +#define RT711_SDCA_ENT_CS1F 0x1f +#define RT711_SDCA_ENT_OT1 0x06 +#define RT711_SDCA_ENT_LINE1 0x09 +#define RT711_SDCA_ENT_LINE2 0x31 +#define RT711_SDCA_ENT_PDELINE2 0x36 +#define RT711_SDCA_ENT_USER_FU9 0x41 + +/* RT711 SDCA control */ +#define RT711_SDCA_CTL_SAMPLE_FREQ_INDEX 0x10 +#define RT711_SDCA_CTL_FU_CH_GAIN 0x0b +#define RT711_SDCA_CTL_FU_MUTE 0x01 +#define RT711_SDCA_CTL_FU_VOLUME 0x02 +#define RT711_SDCA_CTL_HIDTX_CURRENT_OWNER 0x10 +#define RT711_SDCA_CTL_HIDTX_SET_OWNER_TO_DEVICE 0x11 +#define RT711_SDCA_CTL_HIDTX_MESSAGE_OFFSET 0x12 +#define RT711_SDCA_CTL_HIDTX_MESSAGE_LENGTH 0x13 +#define RT711_SDCA_CTL_SELECTED_MODE 0x01 +#define RT711_SDCA_CTL_DETECTED_MODE 0x02 +#define RT711_SDCA_CTL_REQ_POWER_STATE 0x01 +#define RT711_SDCA_CTL_VENDOR_DEF 0x30 + +/* RT711 SDCA channel */ +#define CH_L 0x01 +#define CH_R 0x02 + +/* sample frequency index */ +#define RT711_SDCA_RATE_44100HZ 0x08 +#define RT711_SDCA_RATE_48000HZ 0x09 +#define RT711_SDCA_RATE_96000HZ 0x0b +#define RT711_SDCA_RATE_192000HZ 0x0d + +enum { + RT711_AIF1, + RT711_AIF2, + RT711_AIFS, +}; + +enum rt711_sdca_jd_src { + RT711_JD_NULL, + RT711_JD1, + RT711_JD2 +}; + +enum rt711_sdca_ver { + RT711_VER_VD0, + RT711_VER_VD1 +}; + +int rt711_sdca_io_init(struct device *dev, struct sdw_slave *slave); +int rt711_sdca_init(struct device *dev, struct regmap *regmap, + struct regmap *mbq_regmap, struct sdw_slave *slave); + +int rt711_sdca_jack_detect(struct rt711_sdca_priv *rt711, bool *hp, bool *mic); +#endif /* __RT711_SDCA_H__ */ From ac922edc80aa0b83f4760e3086bc154fdc2a4837 Mon Sep 17 00:00:00 2001 From: Codrin Ciubotariu Date: Mon, 1 Mar 2021 19:09:05 +0200 Subject: [PATCH 168/587] ASoC: convert Microchip I2SMCC binding to yaml This patch converts the Microchip I2SMCC bindings to DT schema format using json-schema. Signed-off-by: Codrin Ciubotariu Reviewed-by: Rob Herring Link: https://lore.kernel.org/r/20210301170905.835091-8-codrin.ciubotariu@microchip.com Signed-off-by: Mark Brown --- .../bindings/sound/mchp,i2s-mcc.yaml | 108 ++++++++++++++++++ .../bindings/sound/mchp-i2s-mcc.txt | 49 -------- 2 files changed, 108 insertions(+), 49 deletions(-) create mode 100644 Documentation/devicetree/bindings/sound/mchp,i2s-mcc.yaml delete mode 100644 Documentation/devicetree/bindings/sound/mchp-i2s-mcc.txt diff --git a/Documentation/devicetree/bindings/sound/mchp,i2s-mcc.yaml b/Documentation/devicetree/bindings/sound/mchp,i2s-mcc.yaml new file mode 100644 index 000000000000..0481315cb5f2 --- /dev/null +++ b/Documentation/devicetree/bindings/sound/mchp,i2s-mcc.yaml @@ -0,0 +1,108 @@ +# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/sound/mchp,i2s-mcc.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Microchip I2S Multi-Channel Controller + +maintainers: + - Codrin Ciubotariu + +description: + The I2SMCC complies with the Inter-IC Sound (I2S) bus specification and + supports a Time Division Multiplexed (TDM) interface with external + multi-channel audio codecs. It consists of a receiver, a transmitter and a + common clock generator that can be enabled separately to provide Adapter, + Client or Controller modes with receiver and/or transmitter active. + On later I2SMCC versions (starting with Microchip's SAMA7G5) I2S + multi-channel is supported by using multiple data pins, output and + input, without TDM. + +properties: + "#sound-dai-cells": + const: 0 + + compatible: + enum: + - microchip,sam9x60-i2smcc + - microchip,sama7g5-i2smcc + + reg: + maxItems: 1 + + interrupts: + maxItems: 1 + + clocks: + items: + - description: Peripheral Bus Clock + - description: Generic Clock (Optional). Should be set mostly when Master + Mode is required. + minItems: 1 + + clock-names: + items: + - const: pclk + - const: gclk + minItems: 1 + + dmas: + items: + - description: TX DMA Channel + - description: RX DMA Channel + + dma-names: + items: + - const: tx + - const: rx + + microchip,tdm-data-pair: + description: + Represents the DIN/DOUT pair pins that are used to receive/send + TDM data. It is optional and it is only needed if the controller + uses the TDM mode. + $ref: /schemas/types.yaml#/definitions/uint8 + enum: [0, 1, 2, 3] + default: 0 + +if: + properties: + compatible: + const: microchip,sam9x60-i2smcc +then: + properties: + microchip,tdm-data-pair: false + +required: + - "#sound-dai-cells" + - compatible + - reg + - interrupts + - clocks + - clock-names + - dmas + - dma-names + +additionalProperties: false + +examples: + - | + #include + #include + + i2s@f001c000 { + #sound-dai-cells = <0>; + compatible = "microchip,sam9x60-i2smcc"; + reg = <0xf001c000 0x100>; + interrupts = <34 IRQ_TYPE_LEVEL_HIGH 7>; + dmas = <&dma0 (AT91_XDMAC_DT_MEM_IF(0) | AT91_XDMAC_DT_PER_IF(1) | + AT91_XDMAC_DT_PERID(36))>, + <&dma0 (AT91_XDMAC_DT_MEM_IF(0) | AT91_XDMAC_DT_PER_IF(1) | + AT91_XDMAC_DT_PERID(37))>; + dma-names = "tx", "rx"; + clocks = <&i2s_clk>, <&i2s_gclk>; + clock-names = "pclk", "gclk"; + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_i2s_default>; + }; diff --git a/Documentation/devicetree/bindings/sound/mchp-i2s-mcc.txt b/Documentation/devicetree/bindings/sound/mchp-i2s-mcc.txt deleted file mode 100644 index af8fe3e657df..000000000000 --- a/Documentation/devicetree/bindings/sound/mchp-i2s-mcc.txt +++ /dev/null @@ -1,49 +0,0 @@ -* Microchip I2S Multi-Channel Controller - -Required properties: -- compatible: Should be "microchip,sam9x60-i2smcc" or - "microchip,sama7g5-i2smcc". -- reg: Should be the physical base address of the controller and the - length of memory mapped region. -- interrupts: Should contain the interrupt for the controller. -- dmas: Should be one per channel name listed in the dma-names property, - as described in atmel-dma.txt and dma.txt files. -- dma-names: Identifier string for each DMA request line in the dmas property. - Two dmas have to be defined, "tx" and "rx". -- clocks: Must contain an entry for each entry in clock-names. - Please refer to clock-bindings.txt. -- clock-names: Should be one of each entry matching the clocks phandles list: - - "pclk" (peripheral clock) Required. - - "gclk" (generated clock) Optional (1). - -Optional properties: -- pinctrl-0: Should specify pin control groups used for this controller. -- princtrl-names: Should contain only one value - "default". -- microchip,tdm-data-pair: 8 bit value that represents the DIN/DOUT pair pins - which are used to receive/send TDM data. It is optional - and it is only needed if the controller uses the TDM - mode. Not available for "microchip,sam9x60-i2smcc" - compatible. If it's not present, the default value is 0, - so the DIN/DOUT 0 pins are used. - -(1) : Only the peripheral clock is required. The generated clock is optional - and should be set mostly when Master Mode is required. - -Example: - - i2s@f001c000 { - compatible = "microchip,sam9x60-i2smcc"; - reg = <0xf001c000 0x100>; - interrupts = <34 IRQ_TYPE_LEVEL_HIGH 7>; - dmas = <&dma0 - (AT91_XDMAC_DT_MEM_IF(0) | AT91_XDMAC_DT_PER_IF(1) | - AT91_XDMAC_DT_PERID(36))>, - <&dma0 - (AT91_XDMAC_DT_MEM_IF(0) | AT91_XDMAC_DT_PER_IF(1) | - AT91_XDMAC_DT_PERID(37))>; - dma-names = "tx", "rx"; - clocks = <&i2s_clk>, <&i2s_gclk>; - clock-names = "pclk", "gclk"; - pinctrl-names = "default"; - pinctrl-0 = <&pinctrl_i2s_default>; - }; From 2b869e0ea598263e0fd60872430899fa0660b2fa Mon Sep 17 00:00:00 2001 From: Lucas Tanure Date: Sat, 6 Mar 2021 18:55:44 +0000 Subject: [PATCH 169/587] ASoC: cs42l42: Remove power if the driver is being removed Ensure the power supplies are turned off when removing the driver Signed-off-by: Lucas Tanure Link: https://lore.kernel.org/r/20210306185553.62053-7-tanureal@opensource.cirrus.com Signed-off-by: Mark Brown --- sound/soc/codecs/cs42l42.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/sound/soc/codecs/cs42l42.c b/sound/soc/codecs/cs42l42.c index 811b7b1c9732..f61404de139b 100644 --- a/sound/soc/codecs/cs42l42.c +++ b/sound/soc/codecs/cs42l42.c @@ -25,6 +25,7 @@ #include #include #include +#include #include #include #include @@ -1842,8 +1843,9 @@ static int cs42l42_i2c_remove(struct i2c_client *i2c_client) { struct cs42l42_private *cs42l42 = i2c_get_clientdata(i2c_client); - /* Hold down reset */ - gpiod_set_value_cansleep(cs42l42->reset_gpio, 0); + devm_free_irq(&i2c_client->dev, i2c_client->irq, cs42l42); + pm_runtime_suspend(&i2c_client->dev); + pm_runtime_disable(&i2c_client->dev); return 0; } From 1abca8e1c77bd9c5f5c0bed21c5b075b6852a178 Mon Sep 17 00:00:00 2001 From: Lucas Tanure Date: Sat, 6 Mar 2021 18:55:45 +0000 Subject: [PATCH 170/587] ASoC: cs42l42: Disable regulators if probe fails In case of cs42l42_i2c_probe() fail, the regulators were left enabled. Signed-off-by: Lucas Tanure Link: https://lore.kernel.org/r/20210306185553.62053-8-tanureal@opensource.cirrus.com Signed-off-by: Mark Brown --- sound/soc/codecs/cs42l42.c | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/sound/soc/codecs/cs42l42.c b/sound/soc/codecs/cs42l42.c index f61404de139b..81cdd09d80bb 100644 --- a/sound/soc/codecs/cs42l42.c +++ b/sound/soc/codecs/cs42l42.c @@ -1750,8 +1750,10 @@ static int cs42l42_i2c_probe(struct i2c_client *i2c_client, /* Reset the Device */ cs42l42->reset_gpio = devm_gpiod_get_optional(&i2c_client->dev, "reset", GPIOD_OUT_LOW); - if (IS_ERR(cs42l42->reset_gpio)) - return PTR_ERR(cs42l42->reset_gpio); + if (IS_ERR(cs42l42->reset_gpio)) { + ret = PTR_ERR(cs42l42->reset_gpio); + goto err_disable; + } if (cs42l42->reset_gpio) { dev_dbg(&i2c_client->dev, "Found reset GPIO\n"); @@ -1785,13 +1787,13 @@ static int cs42l42_i2c_probe(struct i2c_client *i2c_client, dev_err(&i2c_client->dev, "CS42L42 Device ID (%X). Expected %X\n", devid, CS42L42_CHIP_ID); - return ret; + goto err_disable; } ret = regmap_read(cs42l42->regmap, CS42L42_REVID, ®); if (ret < 0) { dev_err(&i2c_client->dev, "Get Revision ID failed\n"); - return ret; + goto err_disable; } dev_info(&i2c_client->dev, @@ -1817,7 +1819,7 @@ static int cs42l42_i2c_probe(struct i2c_client *i2c_client, if (i2c_client->dev.of_node) { ret = cs42l42_handle_device_data(i2c_client, cs42l42); if (ret != 0) - return ret; + goto err_disable; } /* Setup headset detection */ From 621d65f3b868611df62ae4dc4eb1a37b85e4e8c0 Mon Sep 17 00:00:00 2001 From: Lucas Tanure Date: Sat, 6 Mar 2021 18:55:46 +0000 Subject: [PATCH 171/587] ASoC: cs42l42: Provide finer control on playback path Removing cs42l42_hpdrv_evt that enables the entire chain and replace by a set of widgets that can better define the codec Signed-off-by: Lucas Tanure Link: https://lore.kernel.org/r/20210306185553.62053-9-tanureal@opensource.cirrus.com Signed-off-by: Mark Brown --- sound/soc/codecs/cs42l42.c | 65 +++++++++++++------------------------- sound/soc/codecs/cs42l42.h | 8 ++--- 2 files changed, 26 insertions(+), 47 deletions(-) diff --git a/sound/soc/codecs/cs42l42.c b/sound/soc/codecs/cs42l42.c index 81cdd09d80bb..0b5c8e4afff0 100644 --- a/sound/soc/codecs/cs42l42.c +++ b/sound/soc/codecs/cs42l42.c @@ -462,54 +462,33 @@ static const struct snd_kcontrol_new cs42l42_snd_controls[] = { 0x3f, 1, mixer_tlv) }; -static int cs42l42_hpdrv_evt(struct snd_soc_dapm_widget *w, - struct snd_kcontrol *kcontrol, int event) -{ - struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm); - - if (event & SND_SOC_DAPM_POST_PMU) { - /* Enable the channels */ - snd_soc_component_update_bits(component, CS42L42_ASP_RX_DAI0_EN, - CS42L42_ASP_RX0_CH_EN_MASK, - (CS42L42_ASP_RX0_CH1_EN | - CS42L42_ASP_RX0_CH2_EN) << - CS42L42_ASP_RX0_CH_EN_SHIFT); - - /* Power up */ - snd_soc_component_update_bits(component, CS42L42_PWR_CTL1, - CS42L42_ASP_DAI_PDN_MASK | CS42L42_MIXER_PDN_MASK | - CS42L42_HP_PDN_MASK, 0); - } else if (event & SND_SOC_DAPM_PRE_PMD) { - /* Disable the channels */ - snd_soc_component_update_bits(component, CS42L42_ASP_RX_DAI0_EN, - CS42L42_ASP_RX0_CH_EN_MASK, 0); - - /* Power down */ - snd_soc_component_update_bits(component, CS42L42_PWR_CTL1, - CS42L42_ASP_DAI_PDN_MASK | CS42L42_MIXER_PDN_MASK | - CS42L42_HP_PDN_MASK, - CS42L42_ASP_DAI_PDN_MASK | CS42L42_MIXER_PDN_MASK | - CS42L42_HP_PDN_MASK); - } else { - dev_err(component->dev, "Invalid event 0x%x\n", event); - } - return 0; -} - static const struct snd_soc_dapm_widget cs42l42_dapm_widgets[] = { + /* Playback Path */ SND_SOC_DAPM_OUTPUT("HP"), - SND_SOC_DAPM_AIF_IN("SDIN", NULL, 0, CS42L42_ASP_CLK_CFG, - CS42L42_ASP_SCLK_EN_SHIFT, false), - SND_SOC_DAPM_OUT_DRV_E("HPDRV", SND_SOC_NOPM, 0, - 0, NULL, 0, cs42l42_hpdrv_evt, - SND_SOC_DAPM_POST_PMU | - SND_SOC_DAPM_PRE_PMD) + SND_SOC_DAPM_DAC("DAC", NULL, CS42L42_PWR_CTL1, CS42L42_HP_PDN_SHIFT, 1), + SND_SOC_DAPM_MIXER("MIXER", CS42L42_PWR_CTL1, CS42L42_MIXER_PDN_SHIFT, 1, NULL, 0), + SND_SOC_DAPM_AIF_IN("SDIN1", NULL, 0, CS42L42_ASP_RX_DAI0_EN, CS42L42_ASP_RX0_CH1_SHIFT, 0), + SND_SOC_DAPM_AIF_IN("SDIN2", NULL, 1, CS42L42_ASP_RX_DAI0_EN, CS42L42_ASP_RX0_CH2_SHIFT, 0), + + /* Playback Requirements */ + SND_SOC_DAPM_SUPPLY("ASP DAI0", CS42L42_PWR_CTL1, CS42L42_ASP_DAI_PDN_SHIFT, 1, NULL, 0), + SND_SOC_DAPM_SUPPLY("SCLK", CS42L42_ASP_CLK_CFG, CS42L42_ASP_SCLK_EN_SHIFT, 0, NULL, 0), }; static const struct snd_soc_dapm_route cs42l42_audio_map[] = { - {"SDIN", NULL, "Playback"}, - {"HPDRV", NULL, "SDIN"}, - {"HP", NULL, "HPDRV"} + /* Playback Path */ + {"HP", NULL, "DAC"}, + {"DAC", NULL, "MIXER"}, + {"MIXER", NULL, "SDIN1"}, + {"MIXER", NULL, "SDIN2"}, + {"SDIN1", NULL, "Playback"}, + {"SDIN2", NULL, "Playback"}, + + /* Playback Requirements */ + {"SDIN1", NULL, "ASP DAI0"}, + {"SDIN2", NULL, "ASP DAI0"}, + {"SDIN1", NULL, "SCLK"}, + {"SDIN2", NULL, "SCLK"}, }; static int cs42l42_component_probe(struct snd_soc_component *component) diff --git a/sound/soc/codecs/cs42l42.h b/sound/soc/codecs/cs42l42.h index 866d7c873e3c..4b448c102f53 100644 --- a/sound/soc/codecs/cs42l42.h +++ b/sound/soc/codecs/cs42l42.h @@ -695,10 +695,10 @@ #define CS42L42_ASP_RX_DAI0_EN (CS42L42_PAGE_2A + 0x01) #define CS42L42_ASP_RX0_CH_EN_SHIFT 2 #define CS42L42_ASP_RX0_CH_EN_MASK (0xf << CS42L42_ASP_RX0_CH_EN_SHIFT) -#define CS42L42_ASP_RX0_CH1_EN 1 -#define CS42L42_ASP_RX0_CH2_EN 2 -#define CS42L42_ASP_RX0_CH3_EN 4 -#define CS42L42_ASP_RX0_CH4_EN 8 +#define CS42L42_ASP_RX0_CH1_SHIFT 2 +#define CS42L42_ASP_RX0_CH2_SHIFT 3 +#define CS42L42_ASP_RX0_CH3_SHIFT 4 +#define CS42L42_ASP_RX0_CH4_SHIFT 5 #define CS42L42_ASP_RX_DAI0_CH1_AP_RES (CS42L42_PAGE_2A + 0x02) #define CS42L42_ASP_RX_DAI0_CH1_BIT_MSB (CS42L42_PAGE_2A + 0x03) From 43fc357199f90c0e6ee7082fb0a989b0560be2d6 Mon Sep 17 00:00:00 2001 From: Lucas Tanure Date: Sat, 6 Mar 2021 18:55:47 +0000 Subject: [PATCH 172/587] ASoC: cs42l42: Set clock source for both ways of stream Move the enable/disable of clocks to cs42l42_mute_stream so the record path also get clocks. Signed-off-by: Lucas Tanure Link: https://lore.kernel.org/r/20210306185553.62053-10-tanureal@opensource.cirrus.com Signed-off-by: Mark Brown --- sound/soc/codecs/cs42l42.c | 86 +++++++++++++++++++++----------------- sound/soc/codecs/cs42l42.h | 1 + 2 files changed, 49 insertions(+), 38 deletions(-) diff --git a/sound/soc/codecs/cs42l42.c b/sound/soc/codecs/cs42l42.c index 0b5c8e4afff0..2dca55dfa46d 100644 --- a/sound/soc/codecs/cs42l42.c +++ b/sound/soc/codecs/cs42l42.c @@ -784,52 +784,63 @@ static int cs42l42_set_sysclk(struct snd_soc_dai *dai, return 0; } -static int cs42l42_mute(struct snd_soc_dai *dai, int mute, int direction) +static int cs42l42_mute_stream(struct snd_soc_dai *dai, int mute, int stream) { struct snd_soc_component *component = dai->component; + struct cs42l42_private *cs42l42 = snd_soc_component_get_drvdata(component); unsigned int regval; u8 fullScaleVol; if (mute) { - /* Mark SCLK as not present to turn on the internal - * oscillator. - */ - snd_soc_component_update_bits(component, CS42L42_OSC_SWITCH, - CS42L42_SCLK_PRESENT_MASK, 0); - - snd_soc_component_update_bits(component, CS42L42_PLL_CTL1, - CS42L42_PLL_START_MASK, - 0 << CS42L42_PLL_START_SHIFT); - /* Mute the headphone */ - snd_soc_component_update_bits(component, CS42L42_HP_CTL, - CS42L42_HP_ANA_AMUTE_MASK | - CS42L42_HP_ANA_BMUTE_MASK, - CS42L42_HP_ANA_AMUTE_MASK | - CS42L42_HP_ANA_BMUTE_MASK); - } else { - snd_soc_component_update_bits(component, CS42L42_PLL_CTL1, - CS42L42_PLL_START_MASK, - 1 << CS42L42_PLL_START_SHIFT); - /* Read the headphone load */ - regval = snd_soc_component_read(component, CS42L42_LOAD_DET_RCSTAT); - if (((regval & CS42L42_RLA_STAT_MASK) >> - CS42L42_RLA_STAT_SHIFT) == CS42L42_RLA_STAT_15_OHM) { - fullScaleVol = CS42L42_HP_FULL_SCALE_VOL_MASK; - } else { - fullScaleVol = 0; + if (stream == SNDRV_PCM_STREAM_PLAYBACK) + snd_soc_component_update_bits(component, CS42L42_HP_CTL, + CS42L42_HP_ANA_AMUTE_MASK | + CS42L42_HP_ANA_BMUTE_MASK, + CS42L42_HP_ANA_AMUTE_MASK | + CS42L42_HP_ANA_BMUTE_MASK); + + cs42l42->stream_use &= ~(1 << stream); + if(!cs42l42->stream_use) { + /* + * Switch to the internal oscillator. + * SCLK must remain running until after this clock switch. + * Without a source of clock the I2C bus doesn't work. + */ + snd_soc_component_update_bits(component, CS42L42_OSC_SWITCH, + CS42L42_SCLK_PRESENT_MASK, 0); + snd_soc_component_update_bits(component, CS42L42_PLL_CTL1, + CS42L42_PLL_START_MASK, 0); } + } else { + if (!cs42l42->stream_use) { + /* SCLK must be running before codec unmute */ + snd_soc_component_update_bits(component, CS42L42_PLL_CTL1, + CS42L42_PLL_START_MASK, 1); - /* Un-mute the headphone, set the full scale volume flag */ - snd_soc_component_update_bits(component, CS42L42_HP_CTL, - CS42L42_HP_ANA_AMUTE_MASK | - CS42L42_HP_ANA_BMUTE_MASK | - CS42L42_HP_FULL_SCALE_VOL_MASK, fullScaleVol); + /* Mark SCLK as present, turn off internal oscillator */ + snd_soc_component_update_bits(component, CS42L42_OSC_SWITCH, + CS42L42_SCLK_PRESENT_MASK, + CS42L42_SCLK_PRESENT_MASK); + } + cs42l42->stream_use |= 1 << stream; - /* Mark SCLK as present, turn off internal oscillator */ - snd_soc_component_update_bits(component, CS42L42_OSC_SWITCH, - CS42L42_SCLK_PRESENT_MASK, - CS42L42_SCLK_PRESENT_MASK); + if (stream == SNDRV_PCM_STREAM_PLAYBACK) { + /* Read the headphone load */ + regval = snd_soc_component_read(component, CS42L42_LOAD_DET_RCSTAT); + if (((regval & CS42L42_RLA_STAT_MASK) >> CS42L42_RLA_STAT_SHIFT) == + CS42L42_RLA_STAT_15_OHM) { + fullScaleVol = CS42L42_HP_FULL_SCALE_VOL_MASK; + } else { + fullScaleVol = 0; + } + + /* Un-mute the headphone, set the full scale volume flag */ + snd_soc_component_update_bits(component, CS42L42_HP_CTL, + CS42L42_HP_ANA_AMUTE_MASK | + CS42L42_HP_ANA_BMUTE_MASK | + CS42L42_HP_FULL_SCALE_VOL_MASK, fullScaleVol); + } } return 0; @@ -844,8 +855,7 @@ static const struct snd_soc_dai_ops cs42l42_ops = { .hw_params = cs42l42_pcm_hw_params, .set_fmt = cs42l42_set_dai_fmt, .set_sysclk = cs42l42_set_sysclk, - .mute_stream = cs42l42_mute, - .no_capture_mute = 1, + .mute_stream = cs42l42_mute_stream, }; static struct snd_soc_dai_driver cs42l42_dai = { diff --git a/sound/soc/codecs/cs42l42.h b/sound/soc/codecs/cs42l42.h index 4b448c102f53..3dcbfebc53b0 100644 --- a/sound/soc/codecs/cs42l42.h +++ b/sound/soc/codecs/cs42l42.h @@ -768,6 +768,7 @@ struct cs42l42_private { u8 bias_thresholds[CS42L42_NUM_BIASES]; u8 hs_bias_ramp_rate; u8 hs_bias_ramp_time; + u8 stream_use; }; #endif /* __CS42L42_H__ */ From 585e7079de0eac555bcdfe6284e439ee05fb18cb Mon Sep 17 00:00:00 2001 From: Lucas Tanure Date: Sat, 6 Mar 2021 18:55:48 +0000 Subject: [PATCH 173/587] ASoC: cs42l42: Add Capture Support Add support for capture path on headseat pins Signed-off-by: Lucas Tanure Link: https://lore.kernel.org/r/20210306185553.62053-11-tanureal@opensource.cirrus.com Signed-off-by: Mark Brown --- sound/soc/codecs/cs42l42.c | 39 ++++++++++++++++++++++++++++++++++++++ sound/soc/codecs/cs42l42.h | 12 ++++++++++++ 2 files changed, 51 insertions(+) diff --git a/sound/soc/codecs/cs42l42.c b/sound/soc/codecs/cs42l42.c index 2dca55dfa46d..b5084681aaab 100644 --- a/sound/soc/codecs/cs42l42.c +++ b/sound/soc/codecs/cs42l42.c @@ -472,6 +472,18 @@ static const struct snd_soc_dapm_widget cs42l42_dapm_widgets[] = { /* Playback Requirements */ SND_SOC_DAPM_SUPPLY("ASP DAI0", CS42L42_PWR_CTL1, CS42L42_ASP_DAI_PDN_SHIFT, 1, NULL, 0), + + /* Capture Path */ + SND_SOC_DAPM_INPUT("HS"), + SND_SOC_DAPM_ADC("ADC", NULL, CS42L42_PWR_CTL1, CS42L42_ADC_PDN_SHIFT, 1), + SND_SOC_DAPM_AIF_OUT("SDOUT1", NULL, 0, CS42L42_ASP_TX_CH_EN, CS42L42_ASP_TX0_CH1_SHIFT, 0), + SND_SOC_DAPM_AIF_OUT("SDOUT2", NULL, 1, CS42L42_ASP_TX_CH_EN, CS42L42_ASP_TX0_CH2_SHIFT, 0), + + /* Capture Requirements */ + SND_SOC_DAPM_SUPPLY("ASP DAO0", CS42L42_PWR_CTL1, CS42L42_ASP_DAO_PDN_SHIFT, 1, NULL, 0), + SND_SOC_DAPM_SUPPLY("ASP TX EN", CS42L42_ASP_TX_SZ_EN, CS42L42_ASP_TX_EN_SHIFT, 0, NULL, 0), + + /* Playback/Capture Requirements */ SND_SOC_DAPM_SUPPLY("SCLK", CS42L42_ASP_CLK_CFG, CS42L42_ASP_SCLK_EN_SHIFT, 0, NULL, 0), }; @@ -489,6 +501,21 @@ static const struct snd_soc_dapm_route cs42l42_audio_map[] = { {"SDIN2", NULL, "ASP DAI0"}, {"SDIN1", NULL, "SCLK"}, {"SDIN2", NULL, "SCLK"}, + + /* Capture Path */ + {"ADC", NULL, "HS"}, + { "SDOUT1", NULL, "ADC" }, + { "SDOUT2", NULL, "ADC" }, + { "Capture", NULL, "SDOUT1" }, + { "Capture", NULL, "SDOUT2" }, + + /* Capture Requirements */ + { "SDOUT1", NULL, "ASP DAO0" }, + { "SDOUT2", NULL, "ASP DAO0" }, + { "SDOUT1", NULL, "SCLK" }, + { "SDOUT2", NULL, "SCLK" }, + { "SDOUT1", NULL, "ASP TX EN" }, + { "SDOUT2", NULL, "ASP TX EN" }, }; static int cs42l42_component_probe(struct snd_soc_component *component) @@ -748,12 +775,24 @@ static int cs42l42_pcm_hw_params(struct snd_pcm_substream *substream, { struct snd_soc_component *component = dai->component; struct cs42l42_private *cs42l42 = snd_soc_component_get_drvdata(component); + unsigned int channels = params_channels(params); unsigned int width = (params_width(params) / 8) - 1; unsigned int val = 0; cs42l42->srate = params_rate(params); switch(substream->stream) { + case SNDRV_PCM_STREAM_CAPTURE: + if (channels == 2) { + val |= CS42L42_ASP_TX_CH2_AP_MASK; + val |= width << CS42L42_ASP_TX_CH2_RES_SHIFT; + } + val |= width << CS42L42_ASP_TX_CH1_RES_SHIFT; + + snd_soc_component_update_bits(component, CS42L42_ASP_TX_CH_AP_RES, + CS42L42_ASP_TX_CH1_AP_MASK | CS42L42_ASP_TX_CH2_AP_MASK | + CS42L42_ASP_TX_CH2_RES_MASK | CS42L42_ASP_TX_CH1_RES_MASK, val); + break; case SNDRV_PCM_STREAM_PLAYBACK: val |= width << CS42L42_ASP_RX_CH_RES_SHIFT; /* channel 1 on low LRCLK */ diff --git a/sound/soc/codecs/cs42l42.h b/sound/soc/codecs/cs42l42.h index 3dcbfebc53b0..c373259ed46f 100644 --- a/sound/soc/codecs/cs42l42.h +++ b/sound/soc/codecs/cs42l42.h @@ -683,8 +683,20 @@ /* Page 0x29 Serial Port TX Registers */ #define CS42L42_ASP_TX_SZ_EN (CS42L42_PAGE_29 + 0x01) +#define CS42L42_ASP_TX_EN_SHIFT 0 #define CS42L42_ASP_TX_CH_EN (CS42L42_PAGE_29 + 0x02) +#define CS42L42_ASP_TX0_CH2_SHIFT 1 +#define CS42L42_ASP_TX0_CH1_SHIFT 0 + #define CS42L42_ASP_TX_CH_AP_RES (CS42L42_PAGE_29 + 0x03) +#define CS42L42_ASP_TX_CH1_AP_SHIFT 7 +#define CS42L42_ASP_TX_CH1_AP_MASK (1 << CS42L42_ASP_TX_CH1_AP_SHIFT) +#define CS42L42_ASP_TX_CH2_AP_SHIFT 6 +#define CS42L42_ASP_TX_CH2_AP_MASK (1 << CS42L42_ASP_TX_CH2_AP_SHIFT) +#define CS42L42_ASP_TX_CH2_RES_SHIFT 2 +#define CS42L42_ASP_TX_CH2_RES_MASK (3 << CS42L42_ASP_TX_CH2_RES_SHIFT) +#define CS42L42_ASP_TX_CH1_RES_SHIFT 0 +#define CS42L42_ASP_TX_CH1_RES_MASK (3 << CS42L42_ASP_TX_CH1_RES_SHIFT) #define CS42L42_ASP_TX_CH1_BIT_MSB (CS42L42_PAGE_29 + 0x04) #define CS42L42_ASP_TX_CH1_BIT_LSB (CS42L42_PAGE_29 + 0x05) #define CS42L42_ASP_TX_HIZ_DLY_CFG (CS42L42_PAGE_29 + 0x06) From c5b8ee0879bcdc5082d42fe92d3c235b74feef37 Mon Sep 17 00:00:00 2001 From: Lucas Tanure Date: Sat, 6 Mar 2021 18:55:49 +0000 Subject: [PATCH 174/587] ASoC: cs42l42: Report jack and button detection Report the Jack events to the user space through ALSA. Also moves request_threaded_irq() to component_probe so it don't get interrupts before the initialization the struct snd_soc_jack. Signed-off-by: Lucas Tanure Link: https://lore.kernel.org/r/20210306185553.62053-12-tanureal@opensource.cirrus.com Signed-off-by: Mark Brown --- sound/soc/codecs/cs42l42.c | 70 ++++++++++++++++++++++++++++++-------- sound/soc/codecs/cs42l42.h | 3 ++ 2 files changed, 59 insertions(+), 14 deletions(-) diff --git a/sound/soc/codecs/cs42l42.c b/sound/soc/codecs/cs42l42.c index b5084681aaab..594bf2252103 100644 --- a/sound/soc/codecs/cs42l42.c +++ b/sound/soc/codecs/cs42l42.c @@ -522,10 +522,18 @@ static int cs42l42_component_probe(struct snd_soc_component *component) { struct cs42l42_private *cs42l42 = (struct cs42l42_private *)snd_soc_component_get_drvdata(component); + struct snd_soc_card *crd = component->card; + int ret = 0; cs42l42->component = component; - return 0; + ret = snd_soc_card_jack_new(crd, "CS42L42 Headset", SND_JACK_HEADSET | SND_JACK_BTN_0 | + SND_JACK_BTN_1 | SND_JACK_BTN_2 | SND_JACK_BTN_3, + &cs42l42->jack, NULL, 0); + if (ret < 0) + dev_err(component->dev, "Cannot create CS42L42 Headset: %d\n", ret); + + return ret; } static const struct snd_soc_component_driver soc_component_dev_cs42l42 = { @@ -1198,7 +1206,7 @@ static void cs42l42_cancel_hs_type_detect(struct cs42l42_private *cs42l42) (3 << CS42L42_HSDET_AUTO_TIME_SHIFT)); } -static void cs42l42_handle_button_press(struct cs42l42_private *cs42l42) +static int cs42l42_handle_button_press(struct cs42l42_private *cs42l42) { int bias_level; unsigned int detect_status; @@ -1241,17 +1249,24 @@ static void cs42l42_handle_button_press(struct cs42l42_private *cs42l42) switch (bias_level) { case 1: /* Function C button press */ + bias_level = SND_JACK_BTN_2; dev_dbg(cs42l42->component->dev, "Function C button press\n"); break; case 2: /* Function B button press */ + bias_level = SND_JACK_BTN_1; dev_dbg(cs42l42->component->dev, "Function B button press\n"); break; case 3: /* Function D button press */ + bias_level = SND_JACK_BTN_3; dev_dbg(cs42l42->component->dev, "Function D button press\n"); break; case 4: /* Function A button press */ + bias_level = SND_JACK_BTN_0; dev_dbg(cs42l42->component->dev, "Function A button press\n"); break; + default: + bias_level = 0; + break; } /* Set button detect level sensitivity back to default */ @@ -1281,6 +1296,8 @@ static void cs42l42_handle_button_press(struct cs42l42_private *cs42l42) (0 << CS42L42_M_HSBIAS_HIZ_SHIFT) | (1 << CS42L42_M_SHORT_RLS_SHIFT) | (1 << CS42L42_M_SHORT_DET_SHIFT)); + + return bias_level; } struct cs42l42_irq_params { @@ -1325,6 +1342,8 @@ static irqreturn_t cs42l42_irq_thread(int irq, void *data) unsigned int current_plug_status; unsigned int current_button_status; unsigned int i; + int report = 0; + /* Read sticky registers to clear interurpt */ for (i = 0; i < ARRAY_SIZE(stickies); i++) { @@ -1351,9 +1370,20 @@ static irqreturn_t cs42l42_irq_thread(int irq, void *data) if ((~masks[5]) & irq_params_table[5].mask) { if (stickies[5] & CS42L42_HSDET_AUTO_DONE_MASK) { cs42l42_process_hs_type_detect(cs42l42); - dev_dbg(component->dev, - "Auto detect done (%d)\n", - cs42l42->hs_type); + switch(cs42l42->hs_type){ + case CS42L42_PLUG_CTIA: + case CS42L42_PLUG_OMTP: + snd_soc_jack_report(&cs42l42->jack, SND_JACK_HEADSET, + SND_JACK_HEADSET); + break; + case CS42L42_PLUG_HEADPHONE: + snd_soc_jack_report(&cs42l42->jack, SND_JACK_HEADPHONE, + SND_JACK_HEADPHONE); + break; + default: + break; + } + dev_dbg(component->dev, "Auto detect done (%d)\n", cs42l42->hs_type); } } @@ -1371,8 +1401,19 @@ static irqreturn_t cs42l42_irq_thread(int irq, void *data) if (cs42l42->plug_state != CS42L42_TS_UNPLUG) { cs42l42->plug_state = CS42L42_TS_UNPLUG; cs42l42_cancel_hs_type_detect(cs42l42); - dev_dbg(component->dev, - "Unplug event\n"); + + switch(cs42l42->hs_type){ + case CS42L42_PLUG_CTIA: + case CS42L42_PLUG_OMTP: + snd_soc_jack_report(&cs42l42->jack, 0, SND_JACK_HEADSET); + break; + case CS42L42_PLUG_HEADPHONE: + snd_soc_jack_report(&cs42l42->jack, 0, SND_JACK_HEADPHONE); + break; + default: + break; + } + dev_dbg(component->dev, "Unplug event\n"); } break; @@ -1387,14 +1428,15 @@ static irqreturn_t cs42l42_irq_thread(int irq, void *data) if (!(current_button_status & CS42L42_M_HSBIAS_HIZ_MASK)) { - if (current_button_status & - CS42L42_M_DETECT_TF_MASK) { - dev_dbg(component->dev, - "Button released\n"); - } else if (current_button_status & - CS42L42_M_DETECT_FT_MASK) { - cs42l42_handle_button_press(cs42l42); + if (current_button_status & CS42L42_M_DETECT_TF_MASK) { + dev_dbg(component->dev, "Button released\n"); + report = 0; + } else if (current_button_status & CS42L42_M_DETECT_FT_MASK) { + report = cs42l42_handle_button_press(cs42l42); + } + snd_soc_jack_report(&cs42l42->jack, report, SND_JACK_BTN_0 | SND_JACK_BTN_1 | + SND_JACK_BTN_2 | SND_JACK_BTN_3); } } diff --git a/sound/soc/codecs/cs42l42.h b/sound/soc/codecs/cs42l42.h index c373259ed46f..e12828877a20 100644 --- a/sound/soc/codecs/cs42l42.h +++ b/sound/soc/codecs/cs42l42.h @@ -12,6 +12,8 @@ #ifndef __CS42L42_H__ #define __CS42L42_H__ +#include + #define CS42L42_PAGE_REGISTER 0x00 /* Page Select Register */ #define CS42L42_WIN_START 0x00 #define CS42L42_WIN_LEN 0x100 @@ -768,6 +770,7 @@ struct cs42l42_private { struct regulator_bulk_data supplies[CS42L42_NUM_SUPPLIES]; struct gpio_desc *reset_gpio; struct completion pdn_done; + struct snd_soc_jack jack; u32 sclk; u32 srate; u8 plug_state; From 2cdba9b045c745139ae56227d71f261f5d3c6fae Mon Sep 17 00:00:00 2001 From: Lucas Tanure Date: Sat, 6 Mar 2021 18:55:50 +0000 Subject: [PATCH 175/587] ASoC: cs42l42: Use bclk from hw_params if set_sysclk was not called Add support for reading the source clock from snd_soc_params_to_bclk so the machine driver is not required to call cs42l42_set_sysclk Signed-off-by: Lucas Tanure Link: https://lore.kernel.org/r/20210306185553.62053-13-tanureal@opensource.cirrus.com Signed-off-by: Mark Brown --- sound/soc/codecs/cs42l42.c | 17 +++++++++++++---- sound/soc/codecs/cs42l42.h | 1 + 2 files changed, 14 insertions(+), 4 deletions(-) diff --git a/sound/soc/codecs/cs42l42.c b/sound/soc/codecs/cs42l42.c index 594bf2252103..68b7ed71ad54 100644 --- a/sound/soc/codecs/cs42l42.c +++ b/sound/soc/codecs/cs42l42.c @@ -588,10 +588,16 @@ static int cs42l42_pll_config(struct snd_soc_component *component) { struct cs42l42_private *cs42l42 = snd_soc_component_get_drvdata(component); int i; + u32 clk; u32 fsync; + if (!cs42l42->sclk) + clk = cs42l42->bclk; + else + clk = cs42l42->sclk; + for (i = 0; i < ARRAY_SIZE(pll_ratio_table); i++) { - if (pll_ratio_table[i].sclk == cs42l42->sclk) { + if (pll_ratio_table[i].sclk == clk) { /* Configure the internal sample rate */ snd_soc_component_update_bits(component, CS42L42_MCLK_CTL, CS42L42_INTERNAL_FS_MASK, @@ -611,12 +617,12 @@ static int cs42l42_pll_config(struct snd_soc_component *component) (pll_ratio_table[i].mclk_div << CS42L42_MCLKDIV_SHIFT)); /* Set up the LRCLK */ - fsync = cs42l42->sclk / cs42l42->srate; - if (((fsync * cs42l42->srate) != cs42l42->sclk) + fsync = clk / cs42l42->srate; + if (((fsync * cs42l42->srate) != clk) || ((fsync % 2) != 0)) { dev_err(component->dev, "Unsupported sclk %d/sample rate %d\n", - cs42l42->sclk, + clk, cs42l42->srate); return -EINVAL; } @@ -788,6 +794,7 @@ static int cs42l42_pcm_hw_params(struct snd_pcm_substream *substream, unsigned int val = 0; cs42l42->srate = params_rate(params); + cs42l42->bclk = snd_soc_params_to_bclk(params); switch(substream->stream) { case SNDRV_PCM_STREAM_CAPTURE: @@ -921,6 +928,8 @@ static struct snd_soc_dai_driver cs42l42_dai = { .rates = SNDRV_PCM_RATE_8000_192000, .formats = CS42L42_FORMATS, }, + .symmetric_rate = 1, + .symmetric_sample_bits = 1, .ops = &cs42l42_ops, }; diff --git a/sound/soc/codecs/cs42l42.h b/sound/soc/codecs/cs42l42.h index e12828877a20..429c6833fc81 100644 --- a/sound/soc/codecs/cs42l42.h +++ b/sound/soc/codecs/cs42l42.h @@ -771,6 +771,7 @@ struct cs42l42_private { struct gpio_desc *reset_gpio; struct completion pdn_done; struct snd_soc_jack jack; + int bclk; u32 sclk; u32 srate; u8 plug_state; From 0ea23660c7170124fc06ec363b4d2adfa350cf2f Mon Sep 17 00:00:00 2001 From: Richard Fitzgerald Date: Sat, 6 Mar 2021 18:55:51 +0000 Subject: [PATCH 176/587] ASoC: cs42l42: Wait at least 150us after writing SCLK_PRESENT There must be a delay of at least 150us after writing SCLK_PRESENT before issuing another I2C write. This is done using struct reg_sequence because it can specify a delay after the write and the whole sequence is written atomically. Signed-off-by: Richard Fitzgerald Signed-off-by: Lucas Tanure Link: https://lore.kernel.org/r/20210306185553.62053-14-tanureal@opensource.cirrus.com Signed-off-by: Mark Brown --- sound/soc/codecs/cs42l42.c | 27 ++++++++++++++++++++++----- sound/soc/codecs/cs42l42.h | 1 + 2 files changed, 23 insertions(+), 5 deletions(-) diff --git a/sound/soc/codecs/cs42l42.c b/sound/soc/codecs/cs42l42.c index 68b7ed71ad54..08718fd10fb9 100644 --- a/sound/soc/codecs/cs42l42.c +++ b/sound/soc/codecs/cs42l42.c @@ -549,6 +549,24 @@ static const struct snd_soc_component_driver soc_component_dev_cs42l42 = { .non_legacy_dai_naming = 1, }; +/* Switch to SCLK. Atomic delay after the write to allow the switch to complete. */ +static const struct reg_sequence cs42l42_to_sclk_seq[] = { + { + .reg = CS42L42_OSC_SWITCH, + .def = CS42L42_SCLK_PRESENT_MASK, + .delay_us = CS42L42_CLOCK_SWITCH_DELAY_US, + }, +}; + +/* Switch to OSC. Atomic delay after the write to allow the switch to complete. */ +static const struct reg_sequence cs42l42_to_osc_seq[] = { + { + .reg = CS42L42_OSC_SWITCH, + .def = 0, + .delay_us = CS42L42_CLOCK_SWITCH_DELAY_US, + }, +}; + struct cs42l42_pll_params { u32 sclk; u8 mclk_div; @@ -861,8 +879,8 @@ static int cs42l42_mute_stream(struct snd_soc_dai *dai, int mute, int stream) * SCLK must remain running until after this clock switch. * Without a source of clock the I2C bus doesn't work. */ - snd_soc_component_update_bits(component, CS42L42_OSC_SWITCH, - CS42L42_SCLK_PRESENT_MASK, 0); + regmap_multi_reg_write(cs42l42->regmap, cs42l42_to_osc_seq, + ARRAY_SIZE(cs42l42_to_osc_seq)); snd_soc_component_update_bits(component, CS42L42_PLL_CTL1, CS42L42_PLL_START_MASK, 0); } @@ -873,9 +891,8 @@ static int cs42l42_mute_stream(struct snd_soc_dai *dai, int mute, int stream) CS42L42_PLL_START_MASK, 1); /* Mark SCLK as present, turn off internal oscillator */ - snd_soc_component_update_bits(component, CS42L42_OSC_SWITCH, - CS42L42_SCLK_PRESENT_MASK, - CS42L42_SCLK_PRESENT_MASK); + regmap_multi_reg_write(cs42l42->regmap, cs42l42_to_sclk_seq, + ARRAY_SIZE(cs42l42_to_sclk_seq)); } cs42l42->stream_use |= 1 << stream; diff --git a/sound/soc/codecs/cs42l42.h b/sound/soc/codecs/cs42l42.h index 429c6833fc81..214cee762709 100644 --- a/sound/soc/codecs/cs42l42.h +++ b/sound/soc/codecs/cs42l42.h @@ -755,6 +755,7 @@ #define CS42L42_NUM_SUPPLIES 5 #define CS42L42_BOOT_TIME_US 3000 +#define CS42L42_CLOCK_SWITCH_DELAY_US 150 static const char *const cs42l42_supply_names[CS42L42_NUM_SUPPLIES] = { "VA", From 882589bb707ba78d25dd193beefde97e00a3da6b Mon Sep 17 00:00:00 2001 From: Richard Fitzgerald Date: Sat, 6 Mar 2021 18:55:52 +0000 Subject: [PATCH 177/587] ASoC: cs42l42: Only start PLL if it is needed The PLL is only needed for sclk < 11289600 Hz and cs42l42_pll_config() will not configure it for higher rates. So it must only be enabled when it is needed. Signed-off-by: Richard Fitzgerald Signed-off-by: Lucas Tanure Link: https://lore.kernel.org/r/20210306185553.62053-15-tanureal@opensource.cirrus.com Signed-off-by: Mark Brown --- sound/soc/codecs/cs42l42.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/sound/soc/codecs/cs42l42.c b/sound/soc/codecs/cs42l42.c index 08718fd10fb9..d7a314aa59b7 100644 --- a/sound/soc/codecs/cs42l42.c +++ b/sound/soc/codecs/cs42l42.c @@ -887,8 +887,9 @@ static int cs42l42_mute_stream(struct snd_soc_dai *dai, int mute, int stream) } else { if (!cs42l42->stream_use) { /* SCLK must be running before codec unmute */ - snd_soc_component_update_bits(component, CS42L42_PLL_CTL1, - CS42L42_PLL_START_MASK, 1); + if ((cs42l42->bclk < 11289600) && (cs42l42->sclk < 11289600)) + snd_soc_component_update_bits(component, CS42L42_PLL_CTL1, + CS42L42_PLL_START_MASK, 1); /* Mark SCLK as present, turn off internal oscillator */ regmap_multi_reg_write(cs42l42->regmap, cs42l42_to_sclk_seq, From b7d00776ebf79402216434ce24a87f072e1438e1 Mon Sep 17 00:00:00 2001 From: Richard Fitzgerald Date: Sat, 6 Mar 2021 18:55:53 +0000 Subject: [PATCH 178/587] ASoC: cs42l42: Wait for PLL to lock before switching to it The PLL should have locked before using it to supply MCLK. Signed-off-by: Richard Fitzgerald Signed-off-by: Lucas Tanure Link: https://lore.kernel.org/r/20210306185553.62053-16-tanureal@opensource.cirrus.com Signed-off-by: Mark Brown --- sound/soc/codecs/cs42l42.c | 12 +++++++++++- sound/soc/codecs/cs42l42.h | 2 ++ 2 files changed, 13 insertions(+), 1 deletion(-) diff --git a/sound/soc/codecs/cs42l42.c b/sound/soc/codecs/cs42l42.c index d7a314aa59b7..bf982e145e94 100644 --- a/sound/soc/codecs/cs42l42.c +++ b/sound/soc/codecs/cs42l42.c @@ -862,6 +862,7 @@ static int cs42l42_mute_stream(struct snd_soc_dai *dai, int mute, int stream) struct cs42l42_private *cs42l42 = snd_soc_component_get_drvdata(component); unsigned int regval; u8 fullScaleVol; + int ret; if (mute) { /* Mute the headphone */ @@ -887,9 +888,18 @@ static int cs42l42_mute_stream(struct snd_soc_dai *dai, int mute, int stream) } else { if (!cs42l42->stream_use) { /* SCLK must be running before codec unmute */ - if ((cs42l42->bclk < 11289600) && (cs42l42->sclk < 11289600)) + if ((cs42l42->bclk < 11289600) && (cs42l42->sclk < 11289600)) { snd_soc_component_update_bits(component, CS42L42_PLL_CTL1, CS42L42_PLL_START_MASK, 1); + ret = regmap_read_poll_timeout(cs42l42->regmap, + CS42L42_PLL_LOCK_STATUS, + regval, + (regval & 1), + CS42L42_PLL_LOCK_POLL_US, + CS42L42_PLL_LOCK_TIMEOUT_US); + if (ret < 0) + dev_warn(component->dev, "PLL failed to lock: %d\n", ret); + } /* Mark SCLK as present, turn off internal oscillator */ regmap_multi_reg_write(cs42l42->regmap, cs42l42_to_sclk_seq, diff --git a/sound/soc/codecs/cs42l42.h b/sound/soc/codecs/cs42l42.h index 214cee762709..36b763f0d1a0 100644 --- a/sound/soc/codecs/cs42l42.h +++ b/sound/soc/codecs/cs42l42.h @@ -756,6 +756,8 @@ #define CS42L42_NUM_SUPPLIES 5 #define CS42L42_BOOT_TIME_US 3000 #define CS42L42_CLOCK_SWITCH_DELAY_US 150 +#define CS42L42_PLL_LOCK_POLL_US 250 +#define CS42L42_PLL_LOCK_TIMEOUT_US 1250 static const char *const cs42l42_supply_names[CS42L42_NUM_SUPPLIES] = { "VA", From d3223608c5bcd938bcf751702ebf4a8b130976da Mon Sep 17 00:00:00 2001 From: Wei Yongjun Date: Tue, 9 Mar 2021 13:14:58 +0000 Subject: [PATCH 179/587] ASoC: rt715-sdca: Fix return value check in rt715_sdca_sdw_probe() In case of error, the function devm_regmap_init_sdw_mbq() and devm_regmap_init_sdw() returns ERR_PTR() not NULL. The NULL test in the return value check should be replaced with IS_ERR(). Fixes: 393c52d2d109 ("ASoC: rt715-sdca: Add RT715 sdca vendor-specific driver") Reported-by: Hulk Robot Signed-off-by: Wei Yongjun Link: https://lore.kernel.org/r/20210309131458.1884899-1-weiyongjun1@huawei.com Signed-off-by: Mark Brown --- sound/soc/codecs/rt715-sdca-sdw.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/sound/soc/codecs/rt715-sdca-sdw.c b/sound/soc/codecs/rt715-sdca-sdw.c index bcced85876b0..1350798406f0 100644 --- a/sound/soc/codecs/rt715-sdca-sdw.c +++ b/sound/soc/codecs/rt715-sdca-sdw.c @@ -184,12 +184,12 @@ static int rt715_sdca_sdw_probe(struct sdw_slave *slave, /* Regmap Initialization */ mbq_regmap = devm_regmap_init_sdw_mbq(slave, &rt715_sdca_mbq_regmap); - if (!mbq_regmap) - return -EINVAL; + if (IS_ERR(mbq_regmap)) + return PTR_ERR(mbq_regmap); regmap = devm_regmap_init_sdw(slave, &rt715_sdca_regmap); - if (!regmap) - return -EINVAL; + if (IS_ERR(regmap)) + return PTR_ERR(regmap); return rt715_sdca_init(&slave->dev, mbq_regmap, regmap, slave); } From d59cfc6544dc19a1d1c1e47d95dd2150da3daf56 Mon Sep 17 00:00:00 2001 From: Wei Yongjun Date: Tue, 9 Mar 2021 13:14:55 +0000 Subject: [PATCH 180/587] ASoC: rt715-sdca: Remove unused including Remove including that don't need it. Reported-by: Hulk Robot Signed-off-by: Wei Yongjun Link: https://lore.kernel.org/r/20210309131455.1883120-1-weiyongjun1@huawei.com Signed-off-by: Mark Brown --- sound/soc/codecs/rt715-sdca.c | 1 - 1 file changed, 1 deletion(-) diff --git a/sound/soc/codecs/rt715-sdca.c b/sound/soc/codecs/rt715-sdca.c index 92ad6fa408ec..20528afbdc57 100644 --- a/sound/soc/codecs/rt715-sdca.c +++ b/sound/soc/codecs/rt715-sdca.c @@ -9,7 +9,6 @@ #include #include -#include #include #include #include From 542712826f8d3b0a72e66d7feec2dedba5dfa297 Mon Sep 17 00:00:00 2001 From: Shuming Fan Date: Tue, 9 Mar 2021 16:58:27 +0800 Subject: [PATCH 181/587] ASoC: rt5682: add delay time of workqueue to control next IRQ event This patch keeps the delay time (50 ms) for jack detection and zero delay time for the button press. This patch improves the reaction of the button press. Signed-off-by: Shuming Fan Link: https://lore.kernel.org/r/20210309085827.32032-1-shumingf@realtek.com Tested-by Curtis Malainey Signed-off-by: Mark Brown --- sound/soc/codecs/rt5682-i2c.c | 2 +- sound/soc/codecs/rt5682-sdw.c | 2 +- sound/soc/codecs/rt5682.c | 2 ++ sound/soc/codecs/rt5682.h | 1 + 4 files changed, 5 insertions(+), 2 deletions(-) diff --git a/sound/soc/codecs/rt5682-i2c.c b/sound/soc/codecs/rt5682-i2c.c index 93c1603b42f1..8ea9f1d9fec0 100644 --- a/sound/soc/codecs/rt5682-i2c.c +++ b/sound/soc/codecs/rt5682-i2c.c @@ -78,7 +78,7 @@ static irqreturn_t rt5682_irq(int irq, void *data) struct rt5682_priv *rt5682 = data; mod_delayed_work(system_power_efficient_wq, - &rt5682->jack_detect_work, msecs_to_jiffies(250)); + &rt5682->jack_detect_work, msecs_to_jiffies(rt5682->irq_work_delay_time)); return IRQ_HANDLED; } diff --git a/sound/soc/codecs/rt5682-sdw.c b/sound/soc/codecs/rt5682-sdw.c index 5e097f776561..fed80c8f994f 100644 --- a/sound/soc/codecs/rt5682-sdw.c +++ b/sound/soc/codecs/rt5682-sdw.c @@ -677,7 +677,7 @@ static int rt5682_interrupt_callback(struct sdw_slave *slave, if (status->control_port & 0x4) { mod_delayed_work(system_power_efficient_wq, - &rt5682->jack_detect_work, msecs_to_jiffies(250)); + &rt5682->jack_detect_work, msecs_to_jiffies(rt5682->irq_work_delay_time)); } return 0; diff --git a/sound/soc/codecs/rt5682.c b/sound/soc/codecs/rt5682.c index 559dc6db1f7c..0e2a10ed11da 100644 --- a/sound/soc/codecs/rt5682.c +++ b/sound/soc/codecs/rt5682.c @@ -1094,6 +1094,7 @@ void rt5682_jack_detect_handler(struct work_struct *work) /* jack was out, report jack type */ rt5682->jack_type = rt5682_headset_detect(rt5682->component, 1); + rt5682->irq_work_delay_time = 0; } else if ((rt5682->jack_type & SND_JACK_HEADSET) == SND_JACK_HEADSET) { /* jack is already in, report button event */ @@ -1139,6 +1140,7 @@ void rt5682_jack_detect_handler(struct work_struct *work) } else { /* jack out */ rt5682->jack_type = rt5682_headset_detect(rt5682->component, 0); + rt5682->irq_work_delay_time = 50; } snd_soc_jack_report(rt5682->hs_jack, rt5682->jack_type, diff --git a/sound/soc/codecs/rt5682.h b/sound/soc/codecs/rt5682.h index 1f9c51a5b9bf..74ff66767016 100644 --- a/sound/soc/codecs/rt5682.h +++ b/sound/soc/codecs/rt5682.h @@ -1439,6 +1439,7 @@ struct rt5682_priv { int pll_out[RT5682_PLLS]; int jack_type; + int irq_work_delay_time; }; extern const char *rt5682_supply_names[RT5682_NUM_SUPPLIES]; From 9c896eeca4578507faa067d62daa2d66b1541bc8 Mon Sep 17 00:00:00 2001 From: Wolfram Sang Date: Wed, 10 Mar 2021 20:32:27 +0100 Subject: [PATCH 182/587] ALSA: ppc: keywest: remove outdated comment The I2C attach_adapter callback is gone. Remove this reference. Signed-off-by: Wolfram Sang Link: https://lore.kernel.org/r/20210310193227.333140-1-wsa@kernel.org Signed-off-by: Takashi Iwai --- sound/ppc/keywest.c | 5 ----- 1 file changed, 5 deletions(-) diff --git a/sound/ppc/keywest.c b/sound/ppc/keywest.c index a6c1905039de..a8915100d6bb 100644 --- a/sound/ppc/keywest.c +++ b/sound/ppc/keywest.c @@ -13,12 +13,7 @@ #include #include "pmac.h" -/* - * we have to keep a static variable here since i2c attach_adapter - * callback cannot pass a private data. - */ static struct pmac_keywest *keywest_ctx; - static bool keywest_probed; static int keywest_probe(struct i2c_client *client, From 4988f0cc254a1955d5c3244298055f5f7b538e6b Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Wed, 10 Mar 2021 18:43:23 -0600 Subject: [PATCH 183/587] ASoC: arizona: fix function argument Cppcheck warning: sound/soc/codecs/arizona.c:2042:53: style:inconclusive: Function 'arizona_init_dai' argument 2 names different: declaration 'dai' definition 'id'. [funcArgNamesDifferent] int arizona_init_dai(struct arizona_priv *priv, int id) ^ sound/soc/codecs/arizona.h:320:53: note: Function 'arizona_init_dai' argument 2 names different: declaration 'dai' definition 'id'. int arizona_init_dai(struct arizona_priv *priv, int dai); ^ sound/soc/codecs/arizona.c:2042:53: note: Function 'arizona_init_dai' argument 2 names different: declaration 'dai' definition 'id'. int arizona_init_dai(struct arizona_priv *priv, int id) ^ Signed-off-by: Pierre-Louis Bossart Acked-by: Charles Keepax Link: https://lore.kernel.org/r/20210311004332.120901-2-pierre-louis.bossart@linux.intel.com Signed-off-by: Mark Brown --- sound/soc/codecs/arizona.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sound/soc/codecs/arizona.h b/sound/soc/codecs/arizona.h index b893d3e4c97c..b3abbe80f11d 100644 --- a/sound/soc/codecs/arizona.h +++ b/sound/soc/codecs/arizona.h @@ -317,7 +317,7 @@ int arizona_init_vol_limit(struct arizona *arizona); int arizona_init_spk_irqs(struct arizona *arizona); int arizona_free_spk_irqs(struct arizona *arizona); -int arizona_init_dai(struct arizona_priv *priv, int dai); +int arizona_init_dai(struct arizona_priv *priv, int id); int arizona_set_output_mode(struct snd_soc_component *component, int output, bool diff); From b6021b5623b93da05375ae8060f8e8d5dcae0ba9 Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Wed, 10 Mar 2021 18:43:24 -0600 Subject: [PATCH 184/587] ASoC: madera: align function prototype cppcheck warning: sound/soc/codecs/madera.c:3372:51: style:inconclusive: Function 'madera_init_dai' argument 2 names different: declaration 'dai' definition 'id'. [funcArgNamesDifferent] int madera_init_dai(struct madera_priv *priv, int id) ^ sound/soc/codecs/madera.h:433:51: note: Function 'madera_init_dai' argument 2 names different: declaration 'dai' definition 'id'. int madera_init_dai(struct madera_priv *priv, int dai); ^ sound/soc/codecs/madera.c:3372:51: note: Function 'madera_init_dai' argument 2 names different: declaration 'dai' definition 'id'. int madera_init_dai(struct madera_priv *priv, int id) ^ Signed-off-by: Pierre-Louis Bossart Acked-by: Charles Keepax Link: https://lore.kernel.org/r/20210311004332.120901-3-pierre-louis.bossart@linux.intel.com Signed-off-by: Mark Brown --- sound/soc/codecs/madera.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sound/soc/codecs/madera.h b/sound/soc/codecs/madera.h index e0c0be59e2ef..09ad6e9bce4b 100644 --- a/sound/soc/codecs/madera.h +++ b/sound/soc/codecs/madera.h @@ -430,7 +430,7 @@ int madera_init_bus_error_irq(struct madera_priv *priv, int dsp_num, irq_handler_t handler); void madera_free_bus_error_irq(struct madera_priv *priv, int dsp_num); -int madera_init_dai(struct madera_priv *priv, int dai); +int madera_init_dai(struct madera_priv *priv, int id); int madera_set_output_mode(struct snd_soc_component *component, int output, bool differential); From 43fe3fe8b31685ccb2e248799ce3e9f9a15938fb Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Wed, 10 Mar 2021 18:43:25 -0600 Subject: [PATCH 185/587] ASoC: wm2200: remove unused structure cppcheck complains about some members not being used, but it's really the entire structure that is never used anywhere. Signed-off-by: Pierre-Louis Bossart Acked-by: Charles Keepax Link: https://lore.kernel.org/r/20210311004332.120901-4-pierre-louis.bossart@linux.intel.com Signed-off-by: Mark Brown --- sound/soc/codecs/wm2200.c | 7 ------- 1 file changed, 7 deletions(-) diff --git a/sound/soc/codecs/wm2200.c b/sound/soc/codecs/wm2200.c index c62f7ad0022c..b0a6d31299bb 100644 --- a/sound/soc/codecs/wm2200.c +++ b/sound/soc/codecs/wm2200.c @@ -72,13 +72,6 @@ static const char *wm2200_core_supply_names[WM2200_NUM_CORE_SUPPLIES] = { "LDOVDD", }; -struct wm2200_fll { - int fref; - int fout; - int src; - struct completion lock; -}; - /* codec private data */ struct wm2200_priv { struct wm_adsp dsp[2]; From 13119a311aeb5a91ea751f10e4158a86361c2f08 Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Wed, 10 Mar 2021 18:43:26 -0600 Subject: [PATCH 186/587] ASoC: wm8903: remove useless assignments cppcheck warnings: sound/soc/codecs/wm8903.c:1552:11: style: Variable 'best_val' is assigned a value that is never used. [unreadVariable] best_val = ((clk_sys * 10) / bclk_divs[0].ratio) - bclk; ^ sound/soc/codecs/wm8903.c:1559:12: style: Variable 'best_val' is assigned a value that is never used. [unreadVariable] best_val = cur_val; ^ Indeed what matters in the code is the blck_div, the best_val is assigned but never tested or used. Signed-off-by: Pierre-Louis Bossart Acked-by: Charles Keepax Link: https://lore.kernel.org/r/20210311004332.120901-5-pierre-louis.bossart@linux.intel.com Signed-off-by: Mark Brown --- sound/soc/codecs/wm8903.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/sound/soc/codecs/wm8903.c b/sound/soc/codecs/wm8903.c index 026603ae44ce..75f30154c809 100644 --- a/sound/soc/codecs/wm8903.c +++ b/sound/soc/codecs/wm8903.c @@ -1549,14 +1549,12 @@ static int wm8903_hw_params(struct snd_pcm_substream *substream, * BCLKs to clock out the samples). */ bclk_div = 0; - best_val = ((clk_sys * 10) / bclk_divs[0].ratio) - bclk; i = 1; while (i < ARRAY_SIZE(bclk_divs)) { cur_val = ((clk_sys * 10) / bclk_divs[i].ratio) - bclk; if (cur_val < 0) /* BCLK table is sorted */ break; bclk_div = i; - best_val = cur_val; i++; } From d28a9dfeb8071b9ac0e79c8b8b4a0111c3b54c70 Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Wed, 10 Mar 2021 18:43:27 -0600 Subject: [PATCH 187/587] ASoC: wm8958-dsp2: rename local 'control' arrays cppcheck complains about shadowed variables: sound/soc/codecs/wm8958-dsp2.c:926:27: style: Local variable 'control' shadows outer variable [shadowVariable] struct snd_kcontrol_new control[] = { ^ sound/soc/codecs/wm8958-dsp2.c:900:17: note: Shadowed declaration struct wm8994 *control = wm8994->wm8994; ^ sound/soc/codecs/wm8958-dsp2.c:926:27: note: Shadow variable struct snd_kcontrol_new control[] = { ^ sound/soc/codecs/wm8958-dsp2.c:952:27: style: Local variable 'control' shadows outer variable [shadowVariable] struct snd_kcontrol_new control[] = { ^ sound/soc/codecs/wm8958-dsp2.c:900:17: note: Shadowed declaration struct wm8994 *control = wm8994->wm8994; ^ sound/soc/codecs/wm8958-dsp2.c:952:27: note: Shadow variable struct snd_kcontrol_new control[] = { ^ sound/soc/codecs/wm8958-dsp2.c:978:27: style: Local variable 'control' shadows outer variable [shadowVariable] struct snd_kcontrol_new control[] = { ^ sound/soc/codecs/wm8958-dsp2.c:900:17: note: Shadowed declaration struct wm8994 *control = wm8994->wm8994; ^ sound/soc/codecs/wm8958-dsp2.c:978:27: note: Shadow variable struct snd_kcontrol_new control[] = { ^ sound/soc/codecs/wm8958-dsp2.c:1006:27: style: Local variable 'control' shadows outer variable [shadowVariable] struct snd_kcontrol_new control[] = { ^ sound/soc/codecs/wm8958-dsp2.c:900:17: note: Shadowed declaration struct wm8994 *control = wm8994->wm8994; ^ sound/soc/codecs/wm8958-dsp2.c:1006:27: note: Shadow variable struct snd_kcontrol_new control[] = { ^ fix by adding a prefix related to each control. Signed-off-by: Pierre-Louis Bossart Acked-by: Charles Keepax Link: https://lore.kernel.org/r/20210311004332.120901-6-pierre-louis.bossart@linux.intel.com Signed-off-by: Mark Brown --- sound/soc/codecs/wm8958-dsp2.c | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/sound/soc/codecs/wm8958-dsp2.c b/sound/soc/codecs/wm8958-dsp2.c index 3bce9a14f0f3..536339e43dc7 100644 --- a/sound/soc/codecs/wm8958-dsp2.c +++ b/sound/soc/codecs/wm8958-dsp2.c @@ -923,7 +923,7 @@ void wm8958_dsp2_init(struct snd_soc_component *component) component, wm8958_enh_eq_loaded); if (pdata->num_mbc_cfgs) { - struct snd_kcontrol_new control[] = { + struct snd_kcontrol_new mbc_control[] = { SOC_ENUM_EXT("MBC Mode", wm8994->mbc_enum, wm8958_get_mbc_enum, wm8958_put_mbc_enum), }; @@ -942,14 +942,14 @@ void wm8958_dsp2_init(struct snd_soc_component *component) wm8994->mbc_enum.texts = wm8994->mbc_texts; ret = snd_soc_add_component_controls(wm8994->hubs.component, - control, 1); + mbc_control, 1); if (ret != 0) dev_err(wm8994->hubs.component->dev, "Failed to add MBC mode controls: %d\n", ret); } if (pdata->num_vss_cfgs) { - struct snd_kcontrol_new control[] = { + struct snd_kcontrol_new vss_control[] = { SOC_ENUM_EXT("VSS Mode", wm8994->vss_enum, wm8958_get_vss_enum, wm8958_put_vss_enum), }; @@ -968,14 +968,14 @@ void wm8958_dsp2_init(struct snd_soc_component *component) wm8994->vss_enum.texts = wm8994->vss_texts; ret = snd_soc_add_component_controls(wm8994->hubs.component, - control, 1); + vss_control, 1); if (ret != 0) dev_err(wm8994->hubs.component->dev, "Failed to add VSS mode controls: %d\n", ret); } if (pdata->num_vss_hpf_cfgs) { - struct snd_kcontrol_new control[] = { + struct snd_kcontrol_new hpf_control[] = { SOC_ENUM_EXT("VSS HPF Mode", wm8994->vss_hpf_enum, wm8958_get_vss_hpf_enum, wm8958_put_vss_hpf_enum), @@ -995,7 +995,7 @@ void wm8958_dsp2_init(struct snd_soc_component *component) wm8994->vss_hpf_enum.texts = wm8994->vss_hpf_texts; ret = snd_soc_add_component_controls(wm8994->hubs.component, - control, 1); + hpf_control, 1); if (ret != 0) dev_err(wm8994->hubs.component->dev, "Failed to add VSS HPFmode controls: %d\n", @@ -1003,7 +1003,7 @@ void wm8958_dsp2_init(struct snd_soc_component *component) } if (pdata->num_enh_eq_cfgs) { - struct snd_kcontrol_new control[] = { + struct snd_kcontrol_new eq_control[] = { SOC_ENUM_EXT("Enhanced EQ Mode", wm8994->enh_eq_enum, wm8958_get_enh_eq_enum, wm8958_put_enh_eq_enum), @@ -1023,7 +1023,7 @@ void wm8958_dsp2_init(struct snd_soc_component *component) wm8994->enh_eq_enum.texts = wm8994->enh_eq_texts; ret = snd_soc_add_component_controls(wm8994->hubs.component, - control, 1); + eq_control, 1); if (ret != 0) dev_err(wm8994->hubs.component->dev, "Failed to add enhanced EQ controls: %d\n", From 729d42a4ab1a7bc9f4b5c37c57a3a4270333351f Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Wed, 10 Mar 2021 18:43:28 -0600 Subject: [PATCH 188/587] ASoC: wm8978: clarify expression cppcheck warning: sound/soc/codecs/wm8978.c:727:57: style: Clarify calculation precedence for '&' and '?'. [clarifyCalculation] enum wm8978_sysclk_src current_clk_id = clking & 0x100 ? ^ Signed-off-by: Pierre-Louis Bossart Acked-by: Charles Keepax Link: https://lore.kernel.org/r/20210311004332.120901-7-pierre-louis.bossart@linux.intel.com Signed-off-by: Mark Brown --- sound/soc/codecs/wm8978.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sound/soc/codecs/wm8978.c b/sound/soc/codecs/wm8978.c index 4b5ecd142249..7091e1a9d516 100644 --- a/sound/soc/codecs/wm8978.c +++ b/sound/soc/codecs/wm8978.c @@ -724,7 +724,7 @@ static int wm8978_hw_params(struct snd_pcm_substream *substream, /* Sampling rate mask = 0xe (for filters) */ u16 add_ctl = snd_soc_component_read(component, WM8978_ADDITIONAL_CONTROL) & ~0xe; u16 clking = snd_soc_component_read(component, WM8978_CLOCKING); - enum wm8978_sysclk_src current_clk_id = clking & 0x100 ? + enum wm8978_sysclk_src current_clk_id = (clking & 0x100) ? WM8978_PLL : WM8978_MCLK; unsigned int f_sel, diff, diff_best = INT_MAX; int i, best = 0; From b564fdb756918557fb4ca5086e67929bd2eafdd6 Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Wed, 10 Mar 2021 18:43:29 -0600 Subject: [PATCH 189/587] ASoC: wm8994: align function prototype cppcheck warning: sound/soc/codecs/wm8994.c:3923:26: style:inconclusive: Function 'wm8958_mic_detect' argument 3 names different: declaration 'cb' definition 'det_cb'. [funcArgNamesDifferent] wm1811_micdet_cb det_cb, void *det_cb_data, ^ sound/soc/codecs/wm8994.h:53:26: note: Function 'wm8958_mic_detect' argument 3 names different: declaration 'cb' definition 'det_cb'. wm1811_micdet_cb cb, void *det_cb_data, ^ sound/soc/codecs/wm8994.c:3923:26: note: Function 'wm8958_mic_detect' argument 3 names different: declaration 'cb' definition 'det_cb'. wm1811_micdet_cb det_cb, void *det_cb_data, ^ Signed-off-by: Pierre-Louis Bossart Acked-by: Charles Keepax Link: https://lore.kernel.org/r/20210311004332.120901-8-pierre-louis.bossart@linux.intel.com Signed-off-by: Mark Brown --- sound/soc/codecs/wm8994.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sound/soc/codecs/wm8994.h b/sound/soc/codecs/wm8994.h index 41c4b126114d..bc584b17bf28 100644 --- a/sound/soc/codecs/wm8994.h +++ b/sound/soc/codecs/wm8994.h @@ -50,7 +50,7 @@ typedef void (*wm1811_mic_id_cb)(void *data, u16 status); int wm8994_mic_detect(struct snd_soc_component *component, struct snd_soc_jack *jack, int micbias); int wm8958_mic_detect(struct snd_soc_component *component, struct snd_soc_jack *jack, - wm1811_micdet_cb cb, void *det_cb_data, + wm1811_micdet_cb det_cb, void *det_cb_data, wm1811_mic_id_cb id_cb, void *id_cb_data); int wm8994_vmid_mode(struct snd_soc_component *component, enum wm8994_vmid_mode mode); From ea80d4991b76dc101b87228b74515d818ff03bcd Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Wed, 10 Mar 2021 18:43:30 -0600 Subject: [PATCH 190/587] ASoC: wm8996: clarify expression cppcheck warning: sound/soc/codecs/wm8996.c:2109:23: style: Clarify calculation precedence for '/' and '?'. [clarifyCalculation] timeout = timeout/2 ? : 1; ^ Signed-off-by: Pierre-Louis Bossart Acked-by: Charles Keepax Link: https://lore.kernel.org/r/20210311004332.120901-9-pierre-louis.bossart@linux.intel.com Signed-off-by: Mark Brown --- sound/soc/codecs/wm8996.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sound/soc/codecs/wm8996.c b/sound/soc/codecs/wm8996.c index d303ef7571e9..197ae7d84a49 100644 --- a/sound/soc/codecs/wm8996.c +++ b/sound/soc/codecs/wm8996.c @@ -2106,7 +2106,7 @@ static int wm8996_set_fll(struct snd_soc_component *component, int fll_id, int s timeout *= 10; else /* ensure timeout of atleast 1 jiffies */ - timeout = timeout/2 ? : 1; + timeout = (timeout/2) ? : 1; for (retry = 0; retry < 10; retry++) { time_left = wait_for_completion_timeout(&wm8996->fll_lock, From 492df5b0748ada592119dc19dd713e4a60c4e69f Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Wed, 10 Mar 2021 18:43:31 -0600 Subject: [PATCH 191/587] ASoC: wm_adsp: simplify return value cppcheck warning: sound/soc/codecs/wm_adsp.c:2092:9: warning: Identical condition and return expression 'ret', return value is always 0 [identicalConditionAfterEarlyExit] return ret; ^ sound/soc/codecs/wm_adsp.c:2070:6: note: If condition 'ret' is true, the function will return/exit if (ret) ^ sound/soc/codecs/wm_adsp.c:2092:9: note: Returning identical expression 'ret' return ret; ^ Signed-off-by: Pierre-Louis Bossart Acked-by: Charles Keepax Link: https://lore.kernel.org/r/20210311004332.120901-10-pierre-louis.bossart@linux.intel.com Signed-off-by: Mark Brown --- sound/soc/codecs/wm_adsp.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sound/soc/codecs/wm_adsp.c b/sound/soc/codecs/wm_adsp.c index 070ca7d8c661..3dc119daf2f6 100644 --- a/sound/soc/codecs/wm_adsp.c +++ b/sound/soc/codecs/wm_adsp.c @@ -2079,7 +2079,7 @@ int wm_adsp_write_ctl(struct wm_adsp *dsp, const char *name, int type, snd_ctl_notify(dsp->component->card->snd_card, SNDRV_CTL_EVENT_MASK_VALUE, &kcontrol->id); - return ret; + return 0; } EXPORT_SYMBOL_GPL(wm_adsp_write_ctl); From 8ea9e29cc7fc966885018628e123f4113f1ce4b2 Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Wed, 10 Mar 2021 18:43:32 -0600 Subject: [PATCH 192/587] ASoC: wm_hubs: align function prototype cppcheck warnings: sound/soc/codecs/wm_hubs.c:1194:11: style:inconclusive: Function 'wm_hubs_handle_analogue_pdata' argument 8 names different: declaration 'micbias1_dly' definition 'micbias1_delay'. [funcArgNamesDifferent] int micbias1_delay, int micbias2_delay, ^ sound/soc/codecs/wm_hubs.h:59:11: note: Function 'wm_hubs_handle_analogue_pdata' argument 8 names different: declaration 'micbias1_dly' definition 'micbias1_delay'. int micbias1_dly, int micbias2_dly, ^ sound/soc/codecs/wm_hubs.c:1194:11: note: Function 'wm_hubs_handle_analogue_pdata' argument 8 names different: declaration 'micbias1_dly' definition 'micbias1_delay'. int micbias1_delay, int micbias2_delay, ^ sound/soc/codecs/wm_hubs.c:1194:31: style:inconclusive: Function 'wm_hubs_handle_analogue_pdata' argument 9 names different: declaration 'micbias2_dly' definition 'micbias2_delay'. [funcArgNamesDifferent] int micbias1_delay, int micbias2_delay, ^ sound/soc/codecs/wm_hubs.h:59:29: note: Function 'wm_hubs_handle_analogue_pdata' argument 9 names different: declaration 'micbias2_dly' definition 'micbias2_delay'. int micbias1_dly, int micbias2_dly, ^ sound/soc/codecs/wm_hubs.c:1194:31: note: Function 'wm_hubs_handle_analogue_pdata' argument 9 names different: declaration 'micbias2_dly' definition 'micbias2_delay'. int micbias1_delay, int micbias2_delay, ^ Signed-off-by: Pierre-Louis Bossart Acked-by: Charles Keepax Link: https://lore.kernel.org/r/20210311004332.120901-11-pierre-louis.bossart@linux.intel.com Signed-off-by: Mark Brown --- sound/soc/codecs/wm_hubs.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sound/soc/codecs/wm_hubs.h b/sound/soc/codecs/wm_hubs.h index 988b29e63060..a4ed9bd31426 100644 --- a/sound/soc/codecs/wm_hubs.h +++ b/sound/soc/codecs/wm_hubs.h @@ -56,7 +56,7 @@ extern int wm_hubs_handle_analogue_pdata(struct snd_soc_component *, int lineout1_diff, int lineout2_diff, int lineout1fb, int lineout2fb, int jd_scthr, int jd_thr, - int micbias1_dly, int micbias2_dly, + int micbias1_delay, int micbias2_delay, int micbias1_lvl, int micbias2_lvl); extern irqreturn_t wm_hubs_dcs_done(int irq, void *data); From 5fd6b9b8b1c477fb695e3ae313ffb70b3cc88dc9 Mon Sep 17 00:00:00 2001 From: Tzung-Bi Shih Date: Thu, 11 Mar 2021 11:31:50 +0800 Subject: [PATCH 193/587] ASoC: dt-bindings: mt8183: add compatible string for using rt1015p Machines with rt1015p should use the compatible string "mt8183-mt6358-ts3a227-rt1015p". Signed-off-by: Tzung-Bi Shih Link: https://lore.kernel.org/r/20210311033151.1818603-2-tzungbi@google.com Signed-off-by: Mark Brown --- .../devicetree/bindings/sound/mt8183-mt6358-ts3a227-max98357.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/Documentation/devicetree/bindings/sound/mt8183-mt6358-ts3a227-max98357.txt b/Documentation/devicetree/bindings/sound/mt8183-mt6358-ts3a227-max98357.txt index 235eac8aea7b..ecd46ed8eb98 100644 --- a/Documentation/devicetree/bindings/sound/mt8183-mt6358-ts3a227-max98357.txt +++ b/Documentation/devicetree/bindings/sound/mt8183-mt6358-ts3a227-max98357.txt @@ -4,6 +4,7 @@ Required properties: - compatible : "mediatek,mt8183_mt6358_ts3a227_max98357" for MAX98357A codec "mediatek,mt8183_mt6358_ts3a227_max98357b" for MAX98357B codec "mediatek,mt8183_mt6358_ts3a227_rt1015" for RT1015 codec + "mediatek,mt8183_mt6358_ts3a227_rt1015p" for RT1015P codec - mediatek,platform: the phandle of MT8183 ASoC platform Optional properties: From 9dc21a066bb6bff55d889f22460f1bf236a9a4a3 Mon Sep 17 00:00:00 2001 From: Tzung-Bi Shih Date: Thu, 11 Mar 2021 11:31:51 +0800 Subject: [PATCH 194/587] ASoC: mediatek: mt8183: support machine driver with rt1015p Supports machine driver with rt1015p ("mt8183_mt6358_ts3a227_rt1015p"). Embeds in the existing mt8183-mt6358-ts3a227-max98357.c because they share most of the code. Signed-off-by: Tzung-Bi Shih Link: https://lore.kernel.org/r/20210311033151.1818603-3-tzungbi@google.com Signed-off-by: Mark Brown --- sound/soc/mediatek/Kconfig | 1 + .../mt8183/mt8183-mt6358-ts3a227-max98357.c | 29 +++++++++++++++++++ 2 files changed, 30 insertions(+) diff --git a/sound/soc/mediatek/Kconfig b/sound/soc/mediatek/Kconfig index effdb76369e4..74dae4332d17 100644 --- a/sound/soc/mediatek/Kconfig +++ b/sound/soc/mediatek/Kconfig @@ -124,6 +124,7 @@ config SND_SOC_MT8183_MT6358_TS3A227E_MAX98357A select SND_SOC_MT6358 select SND_SOC_MAX98357A select SND_SOC_RT1015 + select SND_SOC_RT1015P select SND_SOC_BT_SCO select SND_SOC_TS3A227E select SND_SOC_CROS_EC_CODEC if CROS_EC diff --git a/sound/soc/mediatek/mt8183/mt8183-mt6358-ts3a227-max98357.c b/sound/soc/mediatek/mt8183/mt8183-mt6358-ts3a227-max98357.c index 271413e719e3..94dcbd36c869 100644 --- a/sound/soc/mediatek/mt8183/mt8183-mt6358-ts3a227-max98357.c +++ b/sound/soc/mediatek/mt8183/mt8183-mt6358-ts3a227-max98357.c @@ -284,6 +284,11 @@ SND_SOC_DAILINK_DEFS(i2s3_rt1015, COMP_CODEC(RT1015_DEV1_NAME, RT1015_CODEC_DAI)), DAILINK_COMP_ARRAY(COMP_EMPTY())); +SND_SOC_DAILINK_DEFS(i2s3_rt1015p, + DAILINK_COMP_ARRAY(COMP_CPU("I2S3")), + DAILINK_COMP_ARRAY(COMP_CODEC("rt1015p", "HiFi")), + DAILINK_COMP_ARRAY(COMP_EMPTY())); + SND_SOC_DAILINK_DEFS(i2s5, DAILINK_COMP_ARRAY(COMP_CPU("I2S5")), DAILINK_COMP_ARRAY(COMP_CODEC("bt-sco", "bt-sco-pcm")), @@ -590,6 +595,13 @@ static struct snd_soc_card mt8183_mt6358_ts3a227_rt1015_card = { .num_configs = ARRAY_SIZE(mt8183_mt6358_ts3a227_rt1015_amp_conf), }; +static struct snd_soc_card mt8183_mt6358_ts3a227_rt1015p_card = { + .name = "mt8183_mt6358_ts3a227_rt1015p", + .owner = THIS_MODULE, + .dai_link = mt8183_mt6358_ts3a227_dai_links, + .num_links = ARRAY_SIZE(mt8183_mt6358_ts3a227_dai_links), +}; + static int mt8183_mt6358_ts3a227_max98357_headset_init(struct snd_soc_component *component) { @@ -686,6 +698,19 @@ mt8183_mt6358_ts3a227_max98357_dev_probe(struct platform_device *pdev) dai_link->platforms = i2s3_rt1015_platforms; dai_link->num_platforms = ARRAY_SIZE(i2s3_rt1015_platforms); + } else if (card == &mt8183_mt6358_ts3a227_rt1015p_card) { + dai_link->be_hw_params_fixup = + mt8183_rt1015_i2s_hw_params_fixup; + dai_link->ops = &mt8183_mt6358_i2s_ops; + dai_link->cpus = i2s3_rt1015p_cpus; + dai_link->num_cpus = + ARRAY_SIZE(i2s3_rt1015p_cpus); + dai_link->codecs = i2s3_rt1015p_codecs; + dai_link->num_codecs = + ARRAY_SIZE(i2s3_rt1015p_codecs); + dai_link->platforms = i2s3_rt1015p_platforms; + dai_link->num_platforms = + ARRAY_SIZE(i2s3_rt1015p_platforms); } } @@ -772,6 +797,10 @@ static const struct of_device_id mt8183_mt6358_ts3a227_max98357_dt_match[] = { .compatible = "mediatek,mt8183_mt6358_ts3a227_rt1015", .data = &mt8183_mt6358_ts3a227_rt1015_card, }, + { + .compatible = "mediatek,mt8183_mt6358_ts3a227_rt1015p", + .data = &mt8183_mt6358_ts3a227_rt1015p_card, + }, {} }; #endif From c68fded79a9fe1376a60049f2ab45d611969de5c Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Wed, 10 Mar 2021 13:39:27 -0600 Subject: [PATCH 195/587] ASoC: soc-core: fix DMI handling When DMI information is not present, trying to assign the card long name results in the following warning. WARNING KERN tegra-audio-graph-card sound: ASoC: no DMI vendor name! The initial solution suggested was to test if the card device is an ACPI one. This causes a regression visible to userspace on all Intel platforms, with UCM unable to load card profiles based on DMI information: the card devices are not necessarily ACPI ones, e.g. when the parent creates platform devices on Intel devices. To fix this problem, this patch exports the existing dmi_available variable and tests it in the ASoC core. Fixes: c014170408bc ("ASoC: soc-core: Prevent warning if no DMI table is present") Signed-off-by: Pierre-Louis Bossart Reviewed-by: Takashi Iwai Acked-by: Jean Delvare Link: https://lore.kernel.org/r/20210310193928.108850-1-pierre-louis.bossart@linux.intel.com Signed-off-by: Mark Brown --- drivers/firmware/dmi_scan.c | 1 + sound/soc/soc-core.c | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/firmware/dmi_scan.c b/drivers/firmware/dmi_scan.c index d51ca0428bb8..f191a1f901ac 100644 --- a/drivers/firmware/dmi_scan.c +++ b/drivers/firmware/dmi_scan.c @@ -166,6 +166,7 @@ static int __init dmi_checksum(const u8 *buf, u8 len) static const char *dmi_ident[DMI_STRING_MAX]; static LIST_HEAD(dmi_devices); int dmi_available; +EXPORT_SYMBOL_GPL(dmi_available); /* * Save a DMI string diff --git a/sound/soc/soc-core.c b/sound/soc/soc-core.c index 16ba54eb8164..c7e4600b2dd4 100644 --- a/sound/soc/soc-core.c +++ b/sound/soc/soc-core.c @@ -1574,7 +1574,7 @@ int snd_soc_set_dmi_name(struct snd_soc_card *card, const char *flavour) if (card->long_name) return 0; /* long name already set by driver or from DMI */ - if (!is_acpi_device_node(card->dev->fwnode)) + if (!dmi_available) return 0; /* make up dmi long name as: vendor-product-version-board */ From f8fc9ec56f341c2a7aa263049340b11c9956962f Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Tue, 9 Mar 2021 10:07:42 +0900 Subject: [PATCH 196/587] ASoC: soc-pcm: check DAI activity under soc_pcm_apply_symmetry() soc_pcm_apply_symmetry() is used like below in all cases. if (snd_soc_dai_active(dai)) { err = soc_pcm_apply_symmetry(fe_substream, dai); ... } Because of this style, the code is deep nested. This patch checks it under soc_pcm_apply_symmetry(), and makes code simple. static int soc_pcm_apply_symmetry(...) { ... => if (!snd_soc_dai_active(...)) return 0; ... } => ret = soc_pcm_apply_symmetry(); if (ret < 0) ... Signed-off-by: Kuninori Morimoto Link: https://lore.kernel.org/r/87k0qhuobl.wl-kuninori.morimoto.gx@renesas.com Signed-off-by: Mark Brown --- sound/soc/soc-pcm.c | 27 ++++++++++++--------------- 1 file changed, 12 insertions(+), 15 deletions(-) diff --git a/sound/soc/soc-pcm.c b/sound/soc/soc-pcm.c index ba8ffbf8a5d3..9b5ab7a05f65 100644 --- a/sound/soc/soc-pcm.c +++ b/sound/soc/soc-pcm.c @@ -349,6 +349,9 @@ static int soc_pcm_apply_symmetry(struct snd_pcm_substream *substream, struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream); int ret; + if (!snd_soc_dai_active(soc_dai)) + return 0; + #define __soc_pcm_apply_symmetry(name, NAME) \ if (soc_dai->name && (soc_dai->driver->symmetric_##name || \ rtd->dai_link->symmetric_##name)) { \ @@ -765,11 +768,9 @@ static int soc_pcm_open(struct snd_pcm_substream *substream) /* Symmetry only applies if we've already got an active stream. */ for_each_rtd_dais(rtd, i, dai) { - if (snd_soc_dai_active(dai)) { - ret = soc_pcm_apply_symmetry(substream, dai); - if (ret != 0) - goto err; - } + ret = soc_pcm_apply_symmetry(substream, dai); + if (ret != 0) + goto err; } pr_debug("ASoC: %s <-> %s info:\n", @@ -1693,11 +1694,9 @@ static int dpcm_apply_symmetry(struct snd_pcm_substream *fe_substream, for_each_rtd_cpu_dais (fe, i, fe_cpu_dai) { /* Symmetry only applies if we've got an active stream. */ - if (snd_soc_dai_active(fe_cpu_dai)) { - err = soc_pcm_apply_symmetry(fe_substream, fe_cpu_dai); - if (err < 0) - return err; - } + err = soc_pcm_apply_symmetry(fe_substream, fe_cpu_dai); + if (err < 0) + return err; } /* apply symmetry for BE */ @@ -1721,11 +1720,9 @@ static int dpcm_apply_symmetry(struct snd_pcm_substream *fe_substream, /* Symmetry only applies if we've got an active stream. */ for_each_rtd_dais(rtd, i, dai) { - if (snd_soc_dai_active(dai)) { - err = soc_pcm_apply_symmetry(fe_substream, dai); - if (err < 0) - return err; - } + err = soc_pcm_apply_symmetry(fe_substream, dai); + if (err < 0) + return err; } } From 6fb8944cd2892e018d13955c2d51579a30744904 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Tue, 9 Mar 2021 10:07:48 +0900 Subject: [PATCH 197/587] ASoC: soc-pcm: add soc_cpu/codec_dai_name() macro soc-pcm needs DAI name and it will be "multicpu/multicodec" if it has many DAIs. But current code is using very verbose for it. This patch uses macro and makes code simple. Signed-off-by: Kuninori Morimoto Link: https://lore.kernel.org/r/87im61uobf.wl-kuninori.morimoto.gx@renesas.com Signed-off-by: Mark Brown --- sound/soc/soc-pcm.c | 25 +++++++++++++------------ 1 file changed, 13 insertions(+), 12 deletions(-) diff --git a/sound/soc/soc-pcm.c b/sound/soc/soc-pcm.c index 9b5ab7a05f65..60e688b103d8 100644 --- a/sound/soc/soc-pcm.c +++ b/sound/soc/soc-pcm.c @@ -29,6 +29,15 @@ #define DPCM_MAX_BE_USERS 8 +static inline const char *soc_cpu_dai_name(struct snd_soc_pcm_runtime *rtd) +{ + return (rtd)->num_cpus == 1 ? asoc_rtd_to_cpu(rtd, 0)->name : "multicpu"; +} +static inline const char *soc_codec_dai_name(struct snd_soc_pcm_runtime *rtd) +{ + return (rtd)->num_codecs == 1 ? asoc_rtd_to_codec(rtd, 0)->name : "multicodec"; +} + #ifdef CONFIG_DEBUG_FS static const char *dpcm_state_string(enum snd_soc_dpcm_state state) { @@ -697,8 +706,8 @@ static int soc_pcm_open(struct snd_pcm_substream *substream) struct snd_pcm_runtime *runtime = substream->runtime; struct snd_soc_component *component; struct snd_soc_dai *dai; - const char *codec_dai_name = "multicodec"; - const char *cpu_dai_name = "multicpu"; + const char *codec_dai_name = soc_codec_dai_name(rtd); + const char *cpu_dai_name = soc_cpu_dai_name(rtd); int i, ret = 0; for_each_rtd_components(rtd, i, component) @@ -737,12 +746,6 @@ static int soc_pcm_open(struct snd_pcm_substream *substream) /* Check that the codec and cpu DAIs are compatible */ soc_pcm_init_runtime_hw(substream); - if (rtd->num_codecs == 1) - codec_dai_name = asoc_rtd_to_codec(rtd, 0)->name; - - if (rtd->num_cpus == 1) - cpu_dai_name = asoc_rtd_to_cpu(rtd, 0)->name; - if (soc_pcm_has_symmetry(substream)) runtime->hw.info |= SNDRV_PCM_INFO_JOINT_DUPLEX; @@ -2741,8 +2744,7 @@ static int soc_create_pcm(struct snd_pcm **pcm, else snprintf(new_name, sizeof(new_name), "%s %s-%d", rtd->dai_link->stream_name, - (rtd->num_codecs > 1) ? - "multicodec" : asoc_rtd_to_codec(rtd, 0)->name, num); + soc_codec_dai_name(rtd), num); ret = snd_pcm_new(rtd->card->snd_card, new_name, num, playback, capture, pcm); @@ -2841,8 +2843,7 @@ int soc_new_pcm(struct snd_soc_pcm_runtime *rtd, int num) pcm->no_device_suspend = true; out: dev_dbg(rtd->card->dev, "%s <-> %s mapping ok\n", - (rtd->num_codecs > 1) ? "multicodec" : asoc_rtd_to_codec(rtd, 0)->name, - (rtd->num_cpus > 1) ? "multicpu" : asoc_rtd_to_cpu(rtd, 0)->name); + soc_codec_dai_name(rtd), soc_cpu_dai_name(rtd)); return ret; } From 56e749ba756fdc2eff332b8eadda8fca231ad782 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Tue, 9 Mar 2021 10:07:53 +0900 Subject: [PATCH 198/587] ASoC: soc-pcm: direct copy at snd_soc_set_runtime_hwparams() snd_soc_set_runtime_hwparams() is called from each driver to initialize hw parameters, but coping each parameters one-by-one. Current code is not copying all parameters, but no big effect if we do it. This patch copies all parameters by simple code. Signed-off-by: Kuninori Morimoto Link: https://lore.kernel.org/r/87h7lluoba.wl-kuninori.morimoto.gx@renesas.com Signed-off-by: Mark Brown --- sound/soc/soc-pcm.c | 11 ++--------- 1 file changed, 2 insertions(+), 9 deletions(-) diff --git a/sound/soc/soc-pcm.c b/sound/soc/soc-pcm.c index 60e688b103d8..6f2de27cf18f 100644 --- a/sound/soc/soc-pcm.c +++ b/sound/soc/soc-pcm.c @@ -300,15 +300,8 @@ bool snd_soc_runtime_ignore_pmdown_time(struct snd_soc_pcm_runtime *rtd) int snd_soc_set_runtime_hwparams(struct snd_pcm_substream *substream, const struct snd_pcm_hardware *hw) { - struct snd_pcm_runtime *runtime = substream->runtime; - runtime->hw.info = hw->info; - runtime->hw.formats = hw->formats; - runtime->hw.period_bytes_min = hw->period_bytes_min; - runtime->hw.period_bytes_max = hw->period_bytes_max; - runtime->hw.periods_min = hw->periods_min; - runtime->hw.periods_max = hw->periods_max; - runtime->hw.buffer_bytes_max = hw->buffer_bytes_max; - runtime->hw.fifo_size = hw->fifo_size; + substream->runtime->hw = *hw; + return 0; } EXPORT_SYMBOL_GPL(snd_soc_set_runtime_hwparams); From 68cbc557375e22e921c9fd007dfcb35faeff4908 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Tue, 9 Mar 2021 10:07:57 +0900 Subject: [PATCH 199/587] ASoC: soc-pcm: add soc_pcm_update_symmetry() Current soc-pcm has soc_pcm_has_symmetry() and using it as if (soc_pcm_has_symmetry(substream)) substream->runtime->hw.info |= SNDRV_PCM_INFO_JOINT_DUPLEX; We want to share same operation as same function. This patch adds soc_pcm_update_symmetry() and pack above code in one function. Signed-off-by: Kuninori Morimoto Link: https://lore.kernel.org/r/87ft15uob6.wl-kuninori.morimoto.gx@renesas.com Signed-off-by: Mark Brown --- sound/soc/soc-pcm.c | 14 ++++++-------- 1 file changed, 6 insertions(+), 8 deletions(-) diff --git a/sound/soc/soc-pcm.c b/sound/soc/soc-pcm.c index 6f2de27cf18f..4ea4e2af9134 100644 --- a/sound/soc/soc-pcm.c +++ b/sound/soc/soc-pcm.c @@ -410,7 +410,7 @@ static int soc_pcm_params_symmetry(struct snd_pcm_substream *substream, return 0; } -static bool soc_pcm_has_symmetry(struct snd_pcm_substream *substream) +static void soc_pcm_update_symmetry(struct snd_pcm_substream *substream) { struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream); struct snd_soc_dai_link *link = rtd->dai_link; @@ -427,7 +427,8 @@ static bool soc_pcm_has_symmetry(struct snd_pcm_substream *substream) dai->driver->symmetric_channels || dai->driver->symmetric_sample_bits; - return symmetry; + if (symmetry) + substream->runtime->hw.info |= SNDRV_PCM_INFO_JOINT_DUPLEX; } static void soc_pcm_set_msb(struct snd_pcm_substream *substream, int bits) @@ -739,8 +740,7 @@ static int soc_pcm_open(struct snd_pcm_substream *substream) /* Check that the codec and cpu DAIs are compatible */ soc_pcm_init_runtime_hw(substream); - if (soc_pcm_has_symmetry(substream)) - runtime->hw.info |= SNDRV_PCM_INFO_JOINT_DUPLEX; + soc_pcm_update_symmetry(substream); ret = -EINVAL; if (!runtime->hw.rates) { @@ -1685,8 +1685,7 @@ static int dpcm_apply_symmetry(struct snd_pcm_substream *fe_substream, int i; /* apply symmetry for FE */ - if (soc_pcm_has_symmetry(fe_substream)) - fe_substream->runtime->hw.info |= SNDRV_PCM_INFO_JOINT_DUPLEX; + soc_pcm_update_symmetry(fe_substream); for_each_rtd_cpu_dais (fe, i, fe_cpu_dai) { /* Symmetry only applies if we've got an active stream. */ @@ -1711,8 +1710,7 @@ static int dpcm_apply_symmetry(struct snd_pcm_substream *fe_substream, if (rtd->dai_link->be_hw_params_fixup) continue; - if (soc_pcm_has_symmetry(be_substream)) - be_substream->runtime->hw.info |= SNDRV_PCM_INFO_JOINT_DUPLEX; + soc_pcm_update_symmetry(be_substream); /* Symmetry only applies if we've got an active stream. */ for_each_rtd_dais(rtd, i, dai) { From c393281a3c1cb252735c46efbf8501a3782f9afa Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Tue, 9 Mar 2021 10:08:02 +0900 Subject: [PATCH 200/587] ASoC: soc-pcm: add soc_hw_sanity_check() Current soc_pcm_open() is checking runtime->hw parameters, but having such function is very helpful for reading code. This patch adds new soc_hw_sanity_check() and checks runtime->hw parameters there. And print its debug message there, too. Debug message print out timing is exchanged after this patch, but it is not a big deal, because it is for debug. Signed-off-by: Kuninori Morimoto Link: https://lore.kernel.org/r/87eegpuob1.wl-kuninori.morimoto.gx@renesas.com Signed-off-by: Mark Brown --- sound/soc/soc-pcm.c | 67 +++++++++++++++++++++++++++------------------ 1 file changed, 40 insertions(+), 27 deletions(-) diff --git a/sound/soc/soc-pcm.c b/sound/soc/soc-pcm.c index 4ea4e2af9134..910a6afe9f48 100644 --- a/sound/soc/soc-pcm.c +++ b/sound/soc/soc-pcm.c @@ -689,6 +689,44 @@ static int soc_pcm_close(struct snd_pcm_substream *substream) return soc_pcm_clean(substream, 0); } +static int soc_hw_sanity_check(struct snd_pcm_substream *substream) +{ + struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream); + struct snd_pcm_hardware *hw = &substream->runtime->hw; + const char *name_cpu = soc_cpu_dai_name(rtd); + const char *name_codec = soc_codec_dai_name(rtd); + const char *err_msg; + struct device *dev = rtd->dev; + + err_msg = "rates"; + if (!hw->rates) + goto config_err; + + err_msg = "formats"; + if (!hw->formats) + goto config_err; + + err_msg = "channels"; + if (!hw->channels_min || !hw->channels_max || + hw->channels_min > hw->channels_max) + goto config_err; + + dev_dbg(dev, "ASoC: %s <-> %s info:\n", name_codec, + name_cpu); + dev_dbg(dev, "ASoC: rate mask 0x%x\n", hw->rates); + dev_dbg(dev, "ASoC: ch min %d max %d\n", hw->channels_min, + hw->channels_max); + dev_dbg(dev, "ASoC: rate min %d max %d\n", hw->rate_min, + hw->rate_max); + + return 0; + +config_err: + dev_err(dev, "ASoC: %s <-> %s No matching %s\n", + name_codec, name_cpu, err_msg); + return -EINVAL; +} + /* * Called by ALSA when a PCM substream is opened, the runtime->hw record is * then initialized and any private data can be allocated. This also calls @@ -697,11 +735,8 @@ static int soc_pcm_close(struct snd_pcm_substream *substream) static int soc_pcm_open(struct snd_pcm_substream *substream) { struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream); - struct snd_pcm_runtime *runtime = substream->runtime; struct snd_soc_component *component; struct snd_soc_dai *dai; - const char *codec_dai_name = soc_codec_dai_name(rtd); - const char *cpu_dai_name = soc_cpu_dai_name(rtd); int i, ret = 0; for_each_rtd_components(rtd, i, component) @@ -742,23 +777,9 @@ static int soc_pcm_open(struct snd_pcm_substream *substream) soc_pcm_update_symmetry(substream); - ret = -EINVAL; - if (!runtime->hw.rates) { - printk(KERN_ERR "ASoC: %s <-> %s No matching rates\n", - codec_dai_name, cpu_dai_name); + ret = soc_hw_sanity_check(substream); + if (ret < 0) goto err; - } - if (!runtime->hw.formats) { - printk(KERN_ERR "ASoC: %s <-> %s No matching formats\n", - codec_dai_name, cpu_dai_name); - goto err; - } - if (!runtime->hw.channels_min || !runtime->hw.channels_max || - runtime->hw.channels_min > runtime->hw.channels_max) { - printk(KERN_ERR "ASoC: %s <-> %s No matching channels\n", - codec_dai_name, cpu_dai_name); - goto err; - } soc_pcm_apply_msb(substream); @@ -768,14 +789,6 @@ static int soc_pcm_open(struct snd_pcm_substream *substream) if (ret != 0) goto err; } - - pr_debug("ASoC: %s <-> %s info:\n", - codec_dai_name, cpu_dai_name); - pr_debug("ASoC: rate mask 0x%x\n", runtime->hw.rates); - pr_debug("ASoC: min ch %d max ch %d\n", runtime->hw.channels_min, - runtime->hw.channels_max); - pr_debug("ASoC: min rate %d max rate %d\n", runtime->hw.rate_min, - runtime->hw.rate_max); dynamic: snd_soc_runtime_activate(rtd, substream->stream); ret = 0; From 1db19c151819dea7a0dc4d888250d25abaf229ca Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Tue, 9 Mar 2021 10:08:08 +0900 Subject: [PATCH 201/587] ASoC: soc-pcm: fixup dpcm_be_dai_startup() user count At dpcm_be_dai_startup_unwind(), it indicates error message at (1) if this function was called with no users. But, it doesn't use "continue" here. Thus, users will be a negative number at (2) void dpcm_be_dai_startup_unwind(...) { ... for_each_dpcm_be(...) { ... (1) if (be->dpcm[stream].users == 0) dev_err(...); (2) if (--be->dpcm[stream].users != 0) continue; At dpcm_be_dai_startup(), it indicates error message if user reached to MAX USERS at (A). But, it doesn't use "continue" here. Thus, it will be over MAX USERS at (B). int dpcm_be_dai_startup(...) { ... for_each_dpcm_be(...) { ... (A) if (be->dpcm[stream].users == DPCM_MAX_BE_USERS) dev_err(...); (B) if (be->dpcm[stream].users++ != 0) continue; These are just bug. This patch fixup these. Signed-off-by: Kuninori Morimoto Link: https://lore.kernel.org/r/87czw9uoav.wl-kuninori.morimoto.gx@renesas.com Signed-off-by: Mark Brown --- sound/soc/soc-pcm.c | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/sound/soc/soc-pcm.c b/sound/soc/soc-pcm.c index 910a6afe9f48..626d6e0a3a15 100644 --- a/sound/soc/soc-pcm.c +++ b/sound/soc/soc-pcm.c @@ -1432,10 +1432,12 @@ static void dpcm_be_dai_startup_unwind(struct snd_soc_pcm_runtime *fe, struct snd_pcm_substream *be_substream = snd_soc_dpcm_get_substream(be, stream); - if (be->dpcm[stream].users == 0) + if (be->dpcm[stream].users == 0) { dev_err(be->dev, "ASoC: no users %s at close - state %d\n", stream ? "capture" : "playback", be->dpcm[stream].state); + continue; + } if (--be->dpcm[stream].users != 0) continue; @@ -1472,10 +1474,12 @@ int dpcm_be_dai_startup(struct snd_soc_pcm_runtime *fe, int stream) continue; /* first time the dpcm is open ? */ - if (be->dpcm[stream].users == DPCM_MAX_BE_USERS) + if (be->dpcm[stream].users == DPCM_MAX_BE_USERS) { dev_err(be->dev, "ASoC: too many users %s at open %d\n", stream ? "capture" : "playback", be->dpcm[stream].state); + continue; + } if (be->dpcm[stream].users++ != 0) continue; @@ -1517,10 +1521,12 @@ unwind: if (!snd_soc_dpcm_be_can_update(fe, be, stream)) continue; - if (be->dpcm[stream].users == 0) + if (be->dpcm[stream].users == 0) { dev_err(be->dev, "ASoC: no users %s at close %d\n", stream ? "capture" : "playback", be->dpcm[stream].state); + continue; + } if (--be->dpcm[stream].users != 0) continue; From 20048a9a4070d046a868c3be3b4f7bdc139cc203 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Tue, 9 Mar 2021 10:08:12 +0900 Subject: [PATCH 202/587] ASoC: soc-pcm: remove unneeded !rtd->dai_link check rtd->dai_link is setuped at soc_new_pcm_runtime(), thus "rtd->dai_link == NULL" is never happen. This patch removes unneeded !rtd->dai_link check Signed-off-by: Kuninori Morimoto Link: https://lore.kernel.org/r/87blbtuoar.wl-kuninori.morimoto.gx@renesas.com Signed-off-by: Mark Brown --- sound/soc/soc-pcm.c | 3 --- 1 file changed, 3 deletions(-) diff --git a/sound/soc/soc-pcm.c b/sound/soc/soc-pcm.c index 626d6e0a3a15..0ae386f0790e 100644 --- a/sound/soc/soc-pcm.c +++ b/sound/soc/soc-pcm.c @@ -165,9 +165,6 @@ static const struct file_operations dpcm_state_fops = { void soc_dpcm_debugfs_add(struct snd_soc_pcm_runtime *rtd) { - if (!rtd->dai_link) - return; - if (!rtd->dai_link->dynamic) return; From 531590bb40f827fb3c4398148af0797f95bbaee2 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Tue, 9 Mar 2021 10:08:17 +0900 Subject: [PATCH 203/587] ASoC: soc-pcm: share DPCM BE DAI stop operation soc-pcm has very similar but different DPCM BE DAI stop operation at 1) dpcm_be_dai_startup() error case rollback 2) dpcm_be_dai_startup_unwind() 3) dpcm_be_dai_shutdown() The differences are 1) for rollback 2) Doesn't check by snd_soc_dpcm_be_can_update() (Is this bug ?) 3) Do soc_pcm_hw_free() if it was not !OPENed and !HW_FREEed, and call soc_pcm_close(). We can share same code by 1) hw_free is not needed. Needs last dpcm as rollback. 2) hw_free is not needed. 3) hw_free is needed. This patch adds new dpcm_be_dai_stop() and share these 3. Signed-off-by: Kuninori Morimoto Link: https://lore.kernel.org/r/87a6rduoam.wl-kuninori.morimoto.gx@renesas.com Signed-off-by: Mark Brown --- include/sound/soc-dpcm.h | 8 +++- sound/soc/soc-compress.c | 2 +- sound/soc/soc-pcm.c | 94 +++++++++------------------------------- 3 files changed, 28 insertions(+), 76 deletions(-) diff --git a/include/sound/soc-dpcm.h b/include/sound/soc-dpcm.h index 0f6c50b17bba..d76cb1eeeaca 100644 --- a/include/sound/soc-dpcm.h +++ b/include/sound/soc-dpcm.h @@ -149,7 +149,8 @@ void dpcm_path_put(struct snd_soc_dapm_widget_list **list); int dpcm_process_paths(struct snd_soc_pcm_runtime *fe, int stream, struct snd_soc_dapm_widget_list **list, int new); int dpcm_be_dai_startup(struct snd_soc_pcm_runtime *fe, int stream); -int dpcm_be_dai_shutdown(struct snd_soc_pcm_runtime *fe, int stream); +void dpcm_be_dai_stop(struct snd_soc_pcm_runtime *fe, int stream, + int do_hw_free, struct snd_soc_dpcm *last); void dpcm_be_disconnect(struct snd_soc_pcm_runtime *fe, int stream); void dpcm_clear_pending_state(struct snd_soc_pcm_runtime *fe, int stream); int dpcm_be_dai_hw_free(struct snd_soc_pcm_runtime *fe, int stream); @@ -159,4 +160,9 @@ int dpcm_be_dai_prepare(struct snd_soc_pcm_runtime *fe, int stream); int dpcm_dapm_stream_event(struct snd_soc_pcm_runtime *fe, int dir, int event); +#define dpcm_be_dai_startup_rollback(fe, stream, last) \ + dpcm_be_dai_stop(fe, stream, 0, last) +#define dpcm_be_dai_startup_unwind(fe, stream) dpcm_be_dai_stop(fe, stream, 0, NULL) +#define dpcm_be_dai_shutdown(fe, stream) dpcm_be_dai_stop(fe, stream, 1, NULL) + #endif diff --git a/sound/soc/soc-compress.c b/sound/soc/soc-compress.c index 246a5e32e22a..89445ba0e86b 100644 --- a/sound/soc/soc-compress.c +++ b/sound/soc/soc-compress.c @@ -189,7 +189,7 @@ static int soc_compr_free_fe(struct snd_compr_stream *cstream) if (ret < 0) dev_err(fe->dev, "Compressed ASoC: hw_free failed: %d\n", ret); - ret = dpcm_be_dai_shutdown(fe, stream); + dpcm_be_dai_shutdown(fe, stream); /* mark FE's links ready to prune */ for_each_dpcm_be(fe, stream, dpcm) diff --git a/sound/soc/soc-pcm.c b/sound/soc/soc-pcm.c index 0ae386f0790e..a27385ab7b55 100644 --- a/sound/soc/soc-pcm.c +++ b/sound/soc/soc-pcm.c @@ -1417,18 +1417,24 @@ void dpcm_clear_pending_state(struct snd_soc_pcm_runtime *fe, int stream) spin_unlock_irqrestore(&fe->card->dpcm_lock, flags); } -static void dpcm_be_dai_startup_unwind(struct snd_soc_pcm_runtime *fe, - int stream) +void dpcm_be_dai_stop(struct snd_soc_pcm_runtime *fe, int stream, + int do_hw_free, struct snd_soc_dpcm *last) { struct snd_soc_dpcm *dpcm; /* disable any enabled and non active backends */ for_each_dpcm_be(fe, stream, dpcm) { - struct snd_soc_pcm_runtime *be = dpcm->be; struct snd_pcm_substream *be_substream = snd_soc_dpcm_get_substream(be, stream); + if (dpcm == last) + return; + + /* is this op for this BE ? */ + if (!snd_soc_dpcm_be_can_update(fe, be, stream)) + continue; + if (be->dpcm[stream].users == 0) { dev_err(be->dev, "ASoC: no users %s at close - state %d\n", stream ? "capture" : "playback", @@ -1439,8 +1445,15 @@ static void dpcm_be_dai_startup_unwind(struct snd_soc_pcm_runtime *fe, if (--be->dpcm[stream].users != 0) continue; - if (be->dpcm[stream].state != SND_SOC_DPCM_STATE_OPEN) - continue; + if (be->dpcm[stream].state != SND_SOC_DPCM_STATE_OPEN) { + if (!do_hw_free) + continue; + + if (be->dpcm[stream].state != SND_SOC_DPCM_STATE_HW_FREE) { + soc_pcm_hw_free(be_substream); + be->dpcm[stream].state = SND_SOC_DPCM_STATE_HW_FREE; + } + } soc_pcm_close(be_substream); be_substream->runtime = NULL; @@ -1509,32 +1522,7 @@ int dpcm_be_dai_startup(struct snd_soc_pcm_runtime *fe, int stream) return count; unwind: - /* disable any enabled and non active backends */ - for_each_dpcm_be_rollback(fe, stream, dpcm) { - struct snd_soc_pcm_runtime *be = dpcm->be; - struct snd_pcm_substream *be_substream = - snd_soc_dpcm_get_substream(be, stream); - - if (!snd_soc_dpcm_be_can_update(fe, be, stream)) - continue; - - if (be->dpcm[stream].users == 0) { - dev_err(be->dev, "ASoC: no users %s at close %d\n", - stream ? "capture" : "playback", - be->dpcm[stream].state); - continue; - } - - if (--be->dpcm[stream].users != 0) - continue; - - if (be->dpcm[stream].state != SND_SOC_DPCM_STATE_OPEN) - continue; - - soc_pcm_close(be_substream); - be_substream->runtime = NULL; - be->dpcm[stream].state = SND_SOC_DPCM_STATE_CLOSE; - } + dpcm_be_dai_startup_rollback(fe, stream, dpcm); return err; } @@ -1782,46 +1770,6 @@ be_err: return ret; } -int dpcm_be_dai_shutdown(struct snd_soc_pcm_runtime *fe, int stream) -{ - struct snd_soc_dpcm *dpcm; - - /* only shutdown BEs that are either sinks or sources to this FE DAI */ - for_each_dpcm_be(fe, stream, dpcm) { - - struct snd_soc_pcm_runtime *be = dpcm->be; - struct snd_pcm_substream *be_substream = - snd_soc_dpcm_get_substream(be, stream); - - /* is this op for this BE ? */ - if (!snd_soc_dpcm_be_can_update(fe, be, stream)) - continue; - - if (be->dpcm[stream].users == 0) - dev_err(be->dev, "ASoC: no users %s at close - state %d\n", - stream ? "capture" : "playback", - be->dpcm[stream].state); - - if (--be->dpcm[stream].users != 0) - continue; - - if ((be->dpcm[stream].state != SND_SOC_DPCM_STATE_HW_FREE) && - (be->dpcm[stream].state != SND_SOC_DPCM_STATE_OPEN)) { - soc_pcm_hw_free(be_substream); - be->dpcm[stream].state = SND_SOC_DPCM_STATE_HW_FREE; - } - - dev_dbg(be->dev, "ASoC: close BE %s\n", - be->dai_link->name); - - soc_pcm_close(be_substream); - be_substream->runtime = NULL; - - be->dpcm[stream].state = SND_SOC_DPCM_STATE_CLOSE; - } - return 0; -} - static int dpcm_fe_dai_shutdown(struct snd_pcm_substream *substream) { struct snd_soc_pcm_runtime *fe = asoc_substream_to_rtd(substream); @@ -2371,9 +2319,7 @@ static int dpcm_run_update_shutdown(struct snd_soc_pcm_runtime *fe, int stream) if (err < 0) dev_err(fe->dev,"ASoC: hw_free FE failed %d\n", err); - err = dpcm_be_dai_shutdown(fe, stream); - if (err < 0) - dev_err(fe->dev,"ASoC: shutdown FE failed %d\n", err); + dpcm_be_dai_shutdown(fe, stream); /* run the stream event for each BE */ dpcm_dapm_stream_event(fe, stream, SND_SOC_DAPM_STREAM_NOP); From 2e5e57f085a3243aae7e4af88dc2c40e5ff4d3be Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Wed, 10 Mar 2021 18:49:01 -0600 Subject: [PATCH 204/587] ASoC: mediatek: mtk-btcvsd: remove useless assignment cppcheck warning: sound/soc/mediatek/common/mtk-btcvsd.c:783:34: style: Variable 'avail' is assigned a value that is never used. [unreadVariable] int written_size = count, avail = 0, cur_write_idx, write_size, cont; ^ Signed-off-by: Pierre-Louis Bossart Link: https://lore.kernel.org/r/20210311004904.121205-2-pierre-louis.bossart@linux.intel.com Signed-off-by: Mark Brown --- sound/soc/mediatek/common/mtk-btcvsd.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sound/soc/mediatek/common/mtk-btcvsd.c b/sound/soc/mediatek/common/mtk-btcvsd.c index a554c57b6460..f85b5ea180ec 100644 --- a/sound/soc/mediatek/common/mtk-btcvsd.c +++ b/sound/soc/mediatek/common/mtk-btcvsd.c @@ -780,7 +780,7 @@ static ssize_t mtk_btcvsd_snd_write(struct mtk_btcvsd_snd *bt, char __user *buf, size_t count) { - int written_size = count, avail = 0, cur_write_idx, write_size, cont; + int written_size = count, avail, cur_write_idx, write_size, cont; unsigned int cur_buf_ofs = 0; unsigned long flags; unsigned int packet_size = bt->tx->packet_size; From 57f1379e77a7432759e2f35b720c71863e2d83bc Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Wed, 10 Mar 2021 18:49:02 -0600 Subject: [PATCH 205/587] ASoC: mediatek: mt2701: align function prototype cppcheck warnings: sound/soc/mediatek/mt2701/mt2701-afe-clock-ctrl.c:102:30: style:inconclusive: Function 'mt2701_afe_enable_i2s' argument 2 names different: declaration 'path' definition 'i2s_path'. [funcArgNamesDifferent] struct mt2701_i2s_path *i2s_path, ^ sound/soc/mediatek/mt2701/mt2701-afe-clock-ctrl.h:21:30: note: Function 'mt2701_afe_enable_i2s' argument 2 names different: declaration 'path' definition 'i2s_path'. struct mt2701_i2s_path *path, ^ sound/soc/mediatek/mt2701/mt2701-afe-clock-ctrl.c:102:30: note: Function 'mt2701_afe_enable_i2s' argument 2 names different: declaration 'path' definition 'i2s_path'. struct mt2701_i2s_path *i2s_path, ^ sound/soc/mediatek/mt2701/mt2701-afe-clock-ctrl.c:128:32: style:inconclusive: Function 'mt2701_afe_disable_i2s' argument 2 names different: declaration 'path' definition 'i2s_path'. [funcArgNamesDifferent] struct mt2701_i2s_path *i2s_path, ^ sound/soc/mediatek/mt2701/mt2701-afe-clock-ctrl.h:24:32: note: Function 'mt2701_afe_disable_i2s' argument 2 names different: declaration 'path' definition 'i2s_path'. struct mt2701_i2s_path *path, ^ sound/soc/mediatek/mt2701/mt2701-afe-clock-ctrl.c:128:32: note: Function 'mt2701_afe_disable_i2s' argument 2 names different: declaration 'path' definition 'i2s_path'. struct mt2701_i2s_path *i2s_path, ^ Signed-off-by: Pierre-Louis Bossart Link: https://lore.kernel.org/r/20210311004904.121205-3-pierre-louis.bossart@linux.intel.com Signed-off-by: Mark Brown --- sound/soc/mediatek/mt2701/mt2701-afe-clock-ctrl.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/sound/soc/mediatek/mt2701/mt2701-afe-clock-ctrl.h b/sound/soc/mediatek/mt2701/mt2701-afe-clock-ctrl.h index 580fead2ab05..0bd82fbda176 100644 --- a/sound/soc/mediatek/mt2701/mt2701-afe-clock-ctrl.h +++ b/sound/soc/mediatek/mt2701/mt2701-afe-clock-ctrl.h @@ -18,10 +18,10 @@ int mt2701_afe_enable_clock(struct mtk_base_afe *afe); int mt2701_afe_disable_clock(struct mtk_base_afe *afe); int mt2701_afe_enable_i2s(struct mtk_base_afe *afe, - struct mt2701_i2s_path *path, + struct mt2701_i2s_path *i2s_path, int dir); void mt2701_afe_disable_i2s(struct mtk_base_afe *afe, - struct mt2701_i2s_path *path, + struct mt2701_i2s_path *i2s_path, int dir); int mt2701_afe_enable_mclk(struct mtk_base_afe *afe, int id); void mt2701_afe_disable_mclk(struct mtk_base_afe *afe, int id); From d9cdc1335622866c52a463325b3aaea9844cff1b Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Wed, 10 Mar 2021 18:49:03 -0600 Subject: [PATCH 206/587] ASoC: mediatek: mt2701: rename shadowed array cppcheck warning: sound/soc/mediatek/mt2701/mt2701-afe-pcm.c:406:36: style: Local variable 'memif_data' shadows outer variable [shadowVariable] const struct mtk_base_memif_data *memif_data; ^ sound/soc/mediatek/mt2701/mt2701-afe-pcm.c:977:41: note: Shadowed declaration static const struct mtk_base_memif_data memif_data[MT2701_MEMIF_NUM] = { ^ sound/soc/mediatek/mt2701/mt2701-afe-pcm.c:406:36: note: Shadow variable const struct mtk_base_memif_data *memif_data; ^ sound/soc/mediatek/mt2701/mt2701-afe-pcm.c:431:36: style: Local variable 'memif_data' shadows outer variable [shadowVariable] const struct mtk_base_memif_data *memif_data; ^ sound/soc/mediatek/mt2701/mt2701-afe-pcm.c:977:41: note: Shadowed declaration static const struct mtk_base_memif_data memif_data[MT2701_MEMIF_NUM] = { ^ sound/soc/mediatek/mt2701/mt2701-afe-pcm.c:431:36: note: Shadow variable const struct mtk_base_memif_data *memif_data; ^ Signed-off-by: Pierre-Louis Bossart Link: https://lore.kernel.org/r/20210311004904.121205-4-pierre-louis.bossart@linux.intel.com Signed-off-by: Mark Brown --- sound/soc/mediatek/mt2701/mt2701-afe-pcm.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/sound/soc/mediatek/mt2701/mt2701-afe-pcm.c b/sound/soc/mediatek/mt2701/mt2701-afe-pcm.c index d5cffe7a7e15..bc3d0466472b 100644 --- a/sound/soc/mediatek/mt2701/mt2701-afe-pcm.c +++ b/sound/soc/mediatek/mt2701/mt2701-afe-pcm.c @@ -974,7 +974,7 @@ static const struct snd_soc_component_driver mt2701_afe_pcm_dai_component = { .resume = mtk_afe_resume, }; -static const struct mtk_base_memif_data memif_data[MT2701_MEMIF_NUM] = { +static const struct mtk_base_memif_data memif_data_array[MT2701_MEMIF_NUM] = { { .name = "DL1", .id = MT2701_MEMIF_DL1, @@ -1366,7 +1366,7 @@ static int mt2701_afe_pcm_dev_probe(struct platform_device *pdev) return -ENOMEM; for (i = 0; i < afe->memif_size; i++) { - afe->memif[i].data = &memif_data[i]; + afe->memif[i].data = &memif_data_array[i]; afe->memif[i].irq_usage = -1; } From 14667403a5631ce2fd2935d90c6d36f7975f61f3 Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Wed, 10 Mar 2021 18:49:04 -0600 Subject: [PATCH 207/587] ASoC: mediatek: mt8173: rename local irq variable cppcheck warning: sound/soc/mediatek/mt8173/mt8173-afe-pcm.c:929:28: style: Local variable 'irq' shadows outer argument [shadowArgument] struct mtk_base_afe_irq *irq; ^ sound/soc/mediatek/mt8173/mt8173-afe-pcm.c:914:47: note: Shadowed declaration static irqreturn_t mt8173_afe_irq_handler(int irq, void *dev_id) ^ sound/soc/mediatek/mt8173/mt8173-afe-pcm.c:929:28: note: Shadow variable struct mtk_base_afe_irq *irq; ^ Not a great idea to have two 'irq' variables in the same function... Signed-off-by: Pierre-Louis Bossart Link: https://lore.kernel.org/r/20210311004904.121205-5-pierre-louis.bossart@linux.intel.com Signed-off-by: Mark Brown --- sound/soc/mediatek/mt8173/mt8173-afe-pcm.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/sound/soc/mediatek/mt8173/mt8173-afe-pcm.c b/sound/soc/mediatek/mt8173/mt8173-afe-pcm.c index 685f4074b4e0..6350390414d4 100644 --- a/sound/soc/mediatek/mt8173/mt8173-afe-pcm.c +++ b/sound/soc/mediatek/mt8173/mt8173-afe-pcm.c @@ -926,14 +926,14 @@ static irqreturn_t mt8173_afe_irq_handler(int irq, void *dev_id) for (i = 0; i < MT8173_AFE_MEMIF_NUM; i++) { struct mtk_base_afe_memif *memif = &afe->memif[i]; - struct mtk_base_afe_irq *irq; + struct mtk_base_afe_irq *irq_p; if (memif->irq_usage < 0) continue; - irq = &afe->irqs[memif->irq_usage]; + irq_p = &afe->irqs[memif->irq_usage]; - if (!(reg_value & (1 << irq->irq_data->irq_clr_shift))) + if (!(reg_value & (1 << irq_p->irq_data->irq_clr_shift))) continue; snd_pcm_period_elapsed(memif->substream); From b7c7203a1f751348f35fc4bcb157572d303f7573 Mon Sep 17 00:00:00 2001 From: Hans de Goede Date: Fri, 12 Mar 2021 12:48:50 +0100 Subject: [PATCH 208/587] ASoC: Intel: bytcr_rt5640: Enable jack-detect support on Asus T100TAF The Asus T100TAF uses the same jack-detect settings as the T100TA, this has been confirmed on actual hardware. Add these settings to the T100TAF quirks to enable jack-detect support on the T100TAF. Signed-off-by: Hans de Goede Acked-by: Pierre-Louis Bossart Link: https://lore.kernel.org/r/20210312114850.13832-1-hdegoede@redhat.com Signed-off-by: Mark Brown --- sound/soc/intel/boards/bytcr_rt5640.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/sound/soc/intel/boards/bytcr_rt5640.c b/sound/soc/intel/boards/bytcr_rt5640.c index 5d48cc359c3d..19faababb78d 100644 --- a/sound/soc/intel/boards/bytcr_rt5640.c +++ b/sound/soc/intel/boards/bytcr_rt5640.c @@ -482,6 +482,9 @@ static const struct dmi_system_id byt_rt5640_quirk_table[] = { DMI_EXACT_MATCH(DMI_PRODUCT_NAME, "T100TAF"), }, .driver_data = (void *)(BYT_RT5640_IN1_MAP | + BYT_RT5640_JD_SRC_JD2_IN4N | + BYT_RT5640_OVCD_TH_2000UA | + BYT_RT5640_OVCD_SF_0P75 | BYT_RT5640_MONO_SPEAKER | BYT_RT5640_DIFF_MIC | BYT_RT5640_SSP0_AIF2 | From 464b489a7885d6a89b0dfa7b7f1f56e2db80700d Mon Sep 17 00:00:00 2001 From: Jack Yu Date: Fri, 12 Mar 2021 02:45:15 +0000 Subject: [PATCH 209/587] ASoC: rt1015p: add acpi device id for rt1015p Add acpi device id for rt1015p. Signed-off-by: Jack Yu Reviewed-by: Pierre-Louis Bossart Link: https://lore.kernel.org/r/949671bd00c14b6d9aa5e85cc14be5d4@realtek.com Signed-off-by: Mark Brown --- sound/soc/codecs/rt1015p.c | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/sound/soc/codecs/rt1015p.c b/sound/soc/codecs/rt1015p.c index 671f2a2130fe..39f4c4ed2ab8 100644 --- a/sound/soc/codecs/rt1015p.c +++ b/sound/soc/codecs/rt1015p.c @@ -4,6 +4,7 @@ // // Copyright 2020 The Linux Foundation. All rights reserved. +#include #include #include #include @@ -130,10 +131,19 @@ static const struct of_device_id rt1015p_device_id[] = { MODULE_DEVICE_TABLE(of, rt1015p_device_id); #endif +#ifdef CONFIG_ACPI +static const struct acpi_device_id rt1015p_acpi_match[] = { + { "RTL1015", 0}, + { }, +}; +MODULE_DEVICE_TABLE(acpi, rt1015p_acpi_match); +#endif + static struct platform_driver rt1015p_platform_driver = { .driver = { .name = "rt1015p", .of_match_table = of_match_ptr(rt1015p_device_id), + .acpi_match_table = ACPI_PTR(rt1015p_acpi_match), }, .probe = rt1015p_platform_probe, }; From d58970da324732686529655c21791cef0ee547c4 Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Fri, 12 Mar 2021 12:02:30 -0600 Subject: [PATCH 210/587] ASoC: samsung: tm2_wm5110: check of of_parse return value cppcheck warning: sound/soc/samsung/tm2_wm5110.c:605:6: style: Variable 'ret' is reassigned a value before the old one has been used. [redundantAssignment] ret = devm_snd_soc_register_component(dev, &tm2_component, ^ sound/soc/samsung/tm2_wm5110.c:554:7: note: ret is assigned ret = of_parse_phandle_with_args(dev->of_node, "i2s-controller", ^ sound/soc/samsung/tm2_wm5110.c:605:6: note: ret is overwritten ret = devm_snd_soc_register_component(dev, &tm2_component, ^ The args is a stack variable, so it could have junk (uninitialized) therefore args.np could have a non-NULL and random value even though property was missing. Later could trigger invalid pointer dereference. There's no need to check for args.np because args.np won't be initialized on errors. Fixes: 8d1513cef51a ("ASoC: samsung: Add support for HDMI audio on TM2 board") Cc: Suggested-by: Krzysztof Kozlowski Reviewed-by: Krzysztof Kozlowski Reviewed-by: Sylwester Nawrocki Signed-off-by: Pierre-Louis Bossart Link: https://lore.kernel.org/r/20210312180231.2741-2-pierre-louis.bossart@linux.intel.com Signed-off-by: Mark Brown --- sound/soc/samsung/tm2_wm5110.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sound/soc/samsung/tm2_wm5110.c b/sound/soc/samsung/tm2_wm5110.c index 9300fef9bf26..125e07f65d2b 100644 --- a/sound/soc/samsung/tm2_wm5110.c +++ b/sound/soc/samsung/tm2_wm5110.c @@ -553,7 +553,7 @@ static int tm2_probe(struct platform_device *pdev) ret = of_parse_phandle_with_args(dev->of_node, "i2s-controller", cells_name, i, &args); - if (!args.np) { + if (ret) { dev_err(dev, "i2s-controller property parse error: %d\n", i); ret = -EINVAL; goto dai_node_put; From f7b61287cf17486dd09438115a993d699db2ab3b Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Fri, 12 Mar 2021 12:02:31 -0600 Subject: [PATCH 211/587] ASoC: samsung: tm2_wm5110: remove shadowed variable cppcheck warning: sound/soc/samsung/tm2_wm5110.c:552:26: style: Local variable 'args' shadows outer variable [shadowVariable] struct of_phandle_args args; ^ sound/soc/samsung/tm2_wm5110.c:504:25: note: Shadowed declaration struct of_phandle_args args; ^ sound/soc/samsung/tm2_wm5110.c:552:26: note: Shadow variable struct of_phandle_args args; ^ Move the top-level variable to the lower scope where it's needed. Signed-off-by: Pierre-Louis Bossart Reviewed-by: Krzysztof Kozlowski Link: https://lore.kernel.org/r/20210312180231.2741-3-pierre-louis.bossart@linux.intel.com Signed-off-by: Mark Brown --- sound/soc/samsung/tm2_wm5110.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/sound/soc/samsung/tm2_wm5110.c b/sound/soc/samsung/tm2_wm5110.c index 125e07f65d2b..84c2c63d5a87 100644 --- a/sound/soc/samsung/tm2_wm5110.c +++ b/sound/soc/samsung/tm2_wm5110.c @@ -501,7 +501,6 @@ static int tm2_probe(struct platform_device *pdev) struct device *dev = &pdev->dev; struct snd_soc_card *card = &tm2_card; struct tm2_machine_priv *priv; - struct of_phandle_args args; struct snd_soc_dai_link *dai_link; int num_codecs, ret, i; @@ -585,6 +584,8 @@ static int tm2_probe(struct platform_device *pdev) } if (num_codecs > 1) { + struct of_phandle_args args; + /* HDMI DAI link (I2S1) */ i = card->num_links - 1; From 40e4046913a34dd187c94f66c0f43facbff0f430 Mon Sep 17 00:00:00 2001 From: Hans de Goede Date: Sun, 7 Mar 2021 16:05:02 +0100 Subject: [PATCH 212/587] ASoC: rt5640: Rename 'Mono DAC Playback Volume' to 'DAC2 Playback Volume' Rename 'Mono DAC Playback Volume' to 'DAC2 Playback Volume' and move it from rt5640_specific_snd_controls[] to rt5640_snd_controls[]. The RT5640_DAC2_DIG_VOL register controlled by this mixer-element has nothing to do with the Mono (Amplified) output which is only available on the ALC5640 chip and not on the ALC5642 chip. The RT5640_DAC2_DIG_VOL volume-control is the main volume control for audio coming from the I2S2 / AIF2 input of the chip and as such is also available on the ALC5642. This commit results in the following userspace visible changes: 1. On devices with an ACL5640 codec, the 'Mono DAC Playback Volume' control is renamed to 'DAC2 Playback Volume' allowing the alsa-lib mixer code to properly group it with the 'DAC2 Playback Switch' which is controlling the mute bits in the RT5640_DAC2_DIG_VOL register. Note the removal of the 'Mono DAC Playback Volume' is not an issue for userspace because the UCM profiles do not use it (the UCM profiles are shared betweent the 5640 and 5642 and only the 5640 had this control). 2. On devices with an ACL5642 codec, there now will be a new 'DAC2 Playback Volume', grouped with the 'DAC2 Playback Switch' Having a complete 'DAC2 Playback Volume' / 'DAC2 Playback Switch' pair on both variants will allow enabling hardware-volume control by setting the UCM PlaybackMasterElem to "DAC2" on devices where the I2S2/AIF2 interface of the codec is used. Signed-off-by: Hans de Goede Link: https://lore.kernel.org/r/20210307150503.34906-2-hdegoede@redhat.com Signed-off-by: Mark Brown --- sound/soc/codecs/rt5640.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/sound/soc/codecs/rt5640.c b/sound/soc/codecs/rt5640.c index 8c1766954b92..9523f4b5c800 100644 --- a/sound/soc/codecs/rt5640.c +++ b/sound/soc/codecs/rt5640.c @@ -400,6 +400,9 @@ static const struct snd_kcontrol_new rt5640_snd_controls[] = { /* DAC Digital Volume */ SOC_DOUBLE("DAC2 Playback Switch", RT5640_DAC2_CTRL, RT5640_M_DAC_L2_VOL_SFT, RT5640_M_DAC_R2_VOL_SFT, 1, 1), + SOC_DOUBLE_TLV("DAC2 Playback Volume", RT5640_DAC2_DIG_VOL, + RT5640_L_VOL_SFT, RT5640_R_VOL_SFT, + 175, 0, dac_vol_tlv), SOC_DOUBLE_TLV("DAC1 Playback Volume", RT5640_DAC1_DIG_VOL, RT5640_L_VOL_SFT, RT5640_R_VOL_SFT, 175, 0, dac_vol_tlv), @@ -443,9 +446,6 @@ static const struct snd_kcontrol_new rt5640_specific_snd_controls[] = { /* MONO Output Control */ SOC_SINGLE("Mono Playback Switch", RT5640_MONO_OUT, RT5640_L_MUTE_SFT, 1, 1), - - SOC_DOUBLE_TLV("Mono DAC Playback Volume", RT5640_DAC2_DIG_VOL, - RT5640_L_VOL_SFT, RT5640_R_VOL_SFT, 175, 0, dac_vol_tlv), }; /** From 9f47c9c8bddc79e770ed19366840b9c2ab280ac1 Mon Sep 17 00:00:00 2001 From: Hans de Goede Date: Sun, 7 Mar 2021 16:05:03 +0100 Subject: [PATCH 213/587] ASoC: Intel: bytcr_rt5640: Add used AIF to the components string Depending on which AIF is used the UCM profile needs to setup a different path through the rt5640's "Digital Mixer Path" graph. ATM the UCM profiles solve this by just enabling paths to the outputs / from the input from both AIF1 and AIF2 and then relying on the DAPM framework to power-down the parts of the graph connected to the unused AIF. But in order to be able to use hardware-volumecontrol and to use the hardware mute controls, which are necessary for mute LED control, the UCM profiles need to know which AIF is actually being used. Add a new "aif:1" or "aif:2" part to the component string to provide info about the used AIF to userspace / to the UCM profiles. Note the size of byt_rt5640_components is not increased because the size of 32 chars already is big enough. Signed-off-by: Hans de Goede Link: https://lore.kernel.org/r/20210307150503.34906-3-hdegoede@redhat.com Signed-off-by: Mark Brown --- sound/soc/intel/boards/bytcr_rt5640.c | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/sound/soc/intel/boards/bytcr_rt5640.c b/sound/soc/intel/boards/bytcr_rt5640.c index 19faababb78d..59d6d47c8d82 100644 --- a/sound/soc/intel/boards/bytcr_rt5640.c +++ b/sound/soc/intel/boards/bytcr_rt5640.c @@ -1255,6 +1255,7 @@ static int snd_byt_rt5640_mc_probe(struct platform_device *pdev) int ret_val = 0; int dai_index = 0; int i, cfg_spk; + int aif; is_bytcr = false; priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL); @@ -1366,8 +1367,12 @@ static int snd_byt_rt5640_mc_probe(struct platform_device *pdev) log_quirks(&pdev->dev); if ((byt_rt5640_quirk & BYT_RT5640_SSP2_AIF2) || - (byt_rt5640_quirk & BYT_RT5640_SSP0_AIF2)) + (byt_rt5640_quirk & BYT_RT5640_SSP0_AIF2)) { byt_rt5640_dais[dai_index].codecs->dai_name = "rt5640-aif2"; + aif = 2; + } else { + aif = 1; + } if ((byt_rt5640_quirk & BYT_RT5640_SSP0_AIF1) || (byt_rt5640_quirk & BYT_RT5640_SSP0_AIF2)) @@ -1405,8 +1410,8 @@ static int snd_byt_rt5640_mc_probe(struct platform_device *pdev) } snprintf(byt_rt5640_components, sizeof(byt_rt5640_components), - "cfg-spk:%d cfg-mic:%s", cfg_spk, - map_name[BYT_RT5640_MAP(byt_rt5640_quirk)]); + "cfg-spk:%d cfg-mic:%s aif:%d", cfg_spk, + map_name[BYT_RT5640_MAP(byt_rt5640_quirk)], aif); byt_rt5640_card.components = byt_rt5640_components; #if !IS_ENABLED(CONFIG_SND_SOC_INTEL_USER_FRIENDLY_LONG_NAMES) snprintf(byt_rt5640_long_name, sizeof(byt_rt5640_long_name), From ee427ea4f12672e5d7874abaa634ddee0ff2bb97 Mon Sep 17 00:00:00 2001 From: Robin Gong Date: Fri, 5 Mar 2021 17:19:37 +0800 Subject: [PATCH 214/587] ASoC: fsl_asrc_dma: request dma channel from specific controller Request dma channel from specific dma controller instead of generic dma controller list, otherwise, may get the wrong dma controller if there are multi dma controllers such as i.MX8MP. Signed-off-by: Robin Gong Signed-off-by: Shengjiu Wang Link: https://lore.kernel.org/r/1614935977-21638-1-git-send-email-shengjiu.wang@nxp.com Signed-off-by: Mark Brown --- sound/soc/fsl/fsl_asrc_dma.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/sound/soc/fsl/fsl_asrc_dma.c b/sound/soc/fsl/fsl_asrc_dma.c index 29f91cdecbc3..c313a26c8f95 100644 --- a/sound/soc/fsl/fsl_asrc_dma.c +++ b/sound/soc/fsl/fsl_asrc_dma.c @@ -141,6 +141,7 @@ static int fsl_asrc_dma_hw_params(struct snd_soc_component *component, struct dma_slave_config config_fe, config_be; enum asrc_pair_index index = pair->index; struct device *dev = component->dev; + struct device_node *of_dma_node; int stream = substream->stream; struct imx_dma_data *tmp_data; struct snd_soc_dpcm *dpcm; @@ -231,8 +232,10 @@ static int fsl_asrc_dma_hw_params(struct snd_soc_component *component, pair->dma_data.priority = tmp_data->priority; dma_release_channel(tmp_chan); + of_dma_node = pair->dma_chan[!dir]->device->dev->of_node; pair->dma_chan[dir] = - dma_request_channel(mask, filter, &pair->dma_data); + __dma_request_channel(&mask, filter, &pair->dma_data, + of_dma_node); pair->req_dma_chan = true; } else { pair->dma_chan[dir] = tmp_chan; From fb3447d5842b71ec960da1b8a3ca5ee5f46a5327 Mon Sep 17 00:00:00 2001 From: Stefan Binding Date: Mon, 15 Mar 2021 19:07:13 +0000 Subject: [PATCH 215/587] ALSA: hda/cirrus: Add error handling into CS8409 I2C functions Also removing 2 redundant cs8409_i2c_read() calls, as we already did read them in a code above. Tested on DELL Inspiron-3505, DELL Inspiron-3501, DELL Inspiron-3500 Signed-off-by: Stefan Binding Signed-off-by: Vitaly Rodionov Link: https://lore.kernel.org/r/20210315190716.47686-2-vitalyr@opensource.cirrus.com Signed-off-by: Takashi Iwai --- sound/pci/hda/patch_cirrus.c | 136 +++++++++++++++++++++++------------ 1 file changed, 91 insertions(+), 45 deletions(-) diff --git a/sound/pci/hda/patch_cirrus.c b/sound/pci/hda/patch_cirrus.c index 6a9e5c803977..d95478ea2fb2 100644 --- a/sound/pci/hda/patch_cirrus.c +++ b/sound/pci/hda/patch_cirrus.c @@ -1493,22 +1493,34 @@ static const struct cs8409_cir_param cs8409_cs42l42_hw_cfg[] = { {} /* Terminator */ }; -/* Enable I2C clocks */ -static void cs8409_enable_i2c_clock(struct hda_codec *codec, unsigned int flag) +/** + * cs8409_enable_i2c_clock - Enable I2C clocks + * @codec: the codec instance + * @enable: Enable or disable I2C clocks + * + * Enable or Disable I2C clocks. + */ +static void cs8409_enable_i2c_clock(struct hda_codec *codec, unsigned int enable) { unsigned int retval = 0; unsigned int newval = 0; retval = cs_vendor_coef_get(codec, 0x0); - newval = (flag) ? (retval | 0x8) : (retval & 0xfffffff7); + newval = (enable) ? (retval | 0x8) : (retval & 0xfffffff7); cs_vendor_coef_set(codec, 0x0, newval); } -/* Wait I2C transaction */ +/** + * cs8409_i2c_wait_complete - Wait for I2C transaction + * @codec: the codec instance + * + * Wait for I2C transaction to complete. + * Return -1 if transaction wait times out. + */ static int cs8409_i2c_wait_complete(struct hda_codec *codec) { int repeat = 5; - unsigned int retval = 0; + unsigned int retval; do { retval = cs_vendor_coef_get(codec, CIR_I2C_STATUS); @@ -1516,82 +1528,103 @@ static int cs8409_i2c_wait_complete(struct hda_codec *codec) usleep_range(2000, 4000); --repeat; } else - break; + return 0; } while (repeat); - return repeat > 0 ? 0 : -1; + return -1; } -/* CS8409 slave i2cRead */ -static unsigned int cs8409_i2c_read(struct hda_codec *codec, +/** + * cs8409_i2c_read - CS8409 I2C Read. + * @codec: the codec instance + * @i2c_address: I2C Address + * @i2c_reg: Register to read + * @paged: Is a paged transaction + * + * CS8409 I2C Read. + * Returns negative on error, otherwise returns read value in bits 0-7. + */ +static int cs8409_i2c_read(struct hda_codec *codec, unsigned int i2c_address, unsigned int i2c_reg, unsigned int paged) { unsigned int i2c_reg_data; - unsigned int retval = 0; + unsigned int read_data; cs8409_enable_i2c_clock(codec, 1); cs_vendor_coef_set(codec, CIR_I2C_ADDR, i2c_address); if (paged) { cs_vendor_coef_set(codec, CIR_I2C_QWRITE, i2c_reg >> 8); - if (cs8409_i2c_wait_complete(codec) == -1) { + if (cs8409_i2c_wait_complete(codec) < 0) { codec_err(codec, - "%s() Paged Transaction Failed 0x%02x : 0x%04x = 0x%02x\n", - __func__, i2c_address, i2c_reg, retval); + "%s() Paged Transaction Failed 0x%02x : 0x%04x\n", + __func__, i2c_address, i2c_reg); + return -EIO; } } i2c_reg_data = (i2c_reg << 8) & 0x0ffff; cs_vendor_coef_set(codec, CIR_I2C_QREAD, i2c_reg_data); - if (cs8409_i2c_wait_complete(codec) == -1) { - codec_err(codec, "%s() Transaction Failed 0x%02x : 0x%04x = 0x%02x\n", - __func__, i2c_address, i2c_reg, retval); + if (cs8409_i2c_wait_complete(codec) < 0) { + codec_err(codec, "%s() Transaction Failed 0x%02x : 0x%04x\n", + __func__, i2c_address, i2c_reg); + return -EIO; } /* Register in bits 15-8 and the data in 7-0 */ - retval = cs_vendor_coef_get(codec, CIR_I2C_QREAD); - retval &= 0x0ff; + read_data = cs_vendor_coef_get(codec, CIR_I2C_QREAD); cs8409_enable_i2c_clock(codec, 0); - return retval; + return read_data & 0x0ff; } -/* CS8409 slave i2cWrite */ -static unsigned int cs8409_i2c_write(struct hda_codec *codec, +/** + * cs8409_i2c_write - CS8409 I2C Write. + * @codec: the codec instance + * @i2c_address: I2C Address + * @i2c_reg: Register to write to + * @i2c_data: Data to write + * @paged: Is a paged transaction + * + * CS8409 I2C Write. + * Returns negative on error, otherwise returns 0. + */ +static int cs8409_i2c_write(struct hda_codec *codec, unsigned int i2c_address, unsigned int i2c_reg, unsigned int i2c_data, unsigned int paged) { - unsigned int retval = 0; - unsigned int i2c_reg_data = 0; + unsigned int i2c_reg_data; cs8409_enable_i2c_clock(codec, 1); cs_vendor_coef_set(codec, CIR_I2C_ADDR, i2c_address); if (paged) { cs_vendor_coef_set(codec, CIR_I2C_QWRITE, i2c_reg >> 8); - if (cs8409_i2c_wait_complete(codec) == -1) { + if (cs8409_i2c_wait_complete(codec) < 0) { codec_err(codec, - "%s() Paged Transaction Failed 0x%02x : 0x%04x = 0x%02x\n", - __func__, i2c_address, i2c_reg, retval); + "%s() Paged Transaction Failed 0x%02x : 0x%04x\n", + __func__, i2c_address, i2c_reg); + return -EIO; } } i2c_reg_data = ((i2c_reg << 8) & 0x0ff00) | (i2c_data & 0x0ff); cs_vendor_coef_set(codec, CIR_I2C_QWRITE, i2c_reg_data); - if (cs8409_i2c_wait_complete(codec) == -1) { - codec_err(codec, "%s() Transaction Failed 0x%02x : 0x%04x = 0x%02x\n", - __func__, i2c_address, i2c_reg, retval); + if (cs8409_i2c_wait_complete(codec) < 0) { + codec_err(codec, "%s() Transaction Failed 0x%02x : 0x%04x\n", + __func__, i2c_address, i2c_reg); + return -EIO; } cs8409_enable_i2c_clock(codec, 0); - return retval; + return 0; } static int cs8409_cs42l42_volume_info(struct snd_kcontrol *kcontrol, @@ -1624,14 +1657,27 @@ static int cs8409_cs42l42_volume_info(struct snd_kcontrol *kcontrol, static void cs8409_cs42l42_update_volume(struct hda_codec *codec) { struct cs_spec *spec = codec->spec; + int data; mutex_lock(&spec->cs8409_i2c_mux); - spec->cs42l42_hp_volume[0] = -(cs8409_i2c_read(codec, CS42L42_I2C_ADDR, - CS8409_CS42L42_REG_HS_VOLUME_CHA, 1)); - spec->cs42l42_hp_volume[1] = -(cs8409_i2c_read(codec, CS42L42_I2C_ADDR, - CS8409_CS42L42_REG_HS_VOLUME_CHB, 1)); - spec->cs42l42_hs_mic_volume[0] = -(cs8409_i2c_read(codec, CS42L42_I2C_ADDR, - CS8409_CS42L42_REG_AMIC_VOLUME, 1)); + data = cs8409_i2c_read(codec, CS42L42_I2C_ADDR, + CS8409_CS42L42_REG_HS_VOLUME_CHA, 1); + if (data >= 0) + spec->cs42l42_hp_volume[0] = -data; + else + spec->cs42l42_hp_volume[0] = CS8409_CS42L42_HP_VOL_REAL_MIN; + data = cs8409_i2c_read(codec, CS42L42_I2C_ADDR, + CS8409_CS42L42_REG_HS_VOLUME_CHB, 1); + if (data >= 0) + spec->cs42l42_hp_volume[1] = -data; + else + spec->cs42l42_hp_volume[1] = CS8409_CS42L42_HP_VOL_REAL_MIN; + data = cs8409_i2c_read(codec, CS42L42_I2C_ADDR, + CS8409_CS42L42_REG_AMIC_VOLUME, 1); + if (data >= 0) + spec->cs42l42_hs_mic_volume[0] = -data; + else + spec->cs42l42_hs_mic_volume[0] = CS8409_CS42L42_AMIC_VOL_REAL_MIN; mutex_unlock(&spec->cs8409_i2c_mux); spec->cs42l42_volume_init = 1; } @@ -1782,7 +1828,7 @@ static void cs8409_cs42l42_reset(struct hda_codec *codec) } /* Configure CS42L42 slave codec for jack autodetect */ -static int cs8409_cs42l42_enable_jack_detect(struct hda_codec *codec) +static void cs8409_cs42l42_enable_jack_detect(struct hda_codec *codec) { struct cs_spec *spec = codec->spec; @@ -1804,8 +1850,6 @@ static int cs8409_cs42l42_enable_jack_detect(struct hda_codec *codec) cs8409_i2c_write(codec, CS42L42_I2C_ADDR, 0x1b79, 0x00, 1); mutex_unlock(&spec->cs8409_i2c_mux); - - return 0; } /* Enable and run CS42L42 slave codec jack auto detect */ @@ -1860,9 +1904,9 @@ static void cs8409_jack_unsol_event(struct hda_codec *codec, unsigned int res) { struct cs_spec *spec = codec->spec; int status_changed = 0; - unsigned int reg_cdc_status = 0; - unsigned int reg_hs_status = 0; - unsigned int reg_ts_status = 0; + int reg_cdc_status; + int reg_hs_status; + int reg_ts_status; int type = 0; struct hda_jack_tbl *jk; @@ -1881,13 +1925,15 @@ static void cs8409_jack_unsol_event(struct hda_codec *codec, unsigned int res) reg_hs_status = cs8409_i2c_read(codec, CS42L42_I2C_ADDR, 0x1124, 1); reg_ts_status = cs8409_i2c_read(codec, CS42L42_I2C_ADDR, 0x130f, 1); - /* Clear interrupts */ + /* Clear interrupts, by reading interrupt status registers */ cs8409_i2c_read(codec, CS42L42_I2C_ADDR, 0x1b7b, 1); - cs8409_i2c_read(codec, CS42L42_I2C_ADDR, 0x1308, 1); - cs8409_i2c_read(codec, CS42L42_I2C_ADDR, 0x130f, 1); mutex_unlock(&spec->cs8409_i2c_mux); + /* If status values are < 0, read error has occurred. */ + if (reg_cdc_status < 0 || reg_hs_status < 0 || reg_ts_status < 0) + return; + /* HSDET_AUTO_DONE */ if (reg_cdc_status & CS42L42_HSDET_AUTO_DONE) { From 61a9aba19f4482984dc7ec5c04c54bf51166cff2 Mon Sep 17 00:00:00 2001 From: Stefan Binding Date: Mon, 15 Mar 2021 19:07:14 +0000 Subject: [PATCH 216/587] ALSA: hda/cirrus: Cleanup patch_cirrus.c code. Minor changes, clean up code, remove unnecessary initialization of variables, reduced number of warnings from ./scripts/checkpatch.pl from 19 to 0 Tested on DELL Inspiron-3505, DELL Inspiron-3501, DELL Inspiron-3500 Signed-off-by: Stefan Binding Signed-off-by: Vitaly Rodionov Link: https://lore.kernel.org/r/20210315190716.47686-3-vitalyr@opensource.cirrus.com Signed-off-by: Takashi Iwai --- sound/pci/hda/patch_cirrus.c | 147 +++++++++++++++++------------------ 1 file changed, 72 insertions(+), 75 deletions(-) diff --git a/sound/pci/hda/patch_cirrus.c b/sound/pci/hda/patch_cirrus.c index d95478ea2fb2..275bba02cc05 100644 --- a/sound/pci/hda/patch_cirrus.c +++ b/sound/pci/hda/patch_cirrus.c @@ -127,7 +127,7 @@ enum { * 1 DAC => HP(sense) / Speakers, * 1 ADC <= LineIn(sense) / MicIn / DMicIn, * 1 SPDIF OUT => SPDIF Trasmitter(sense) -*/ + */ #define CS4210_DAC_NID 0x02 #define CS4210_ADC_NID 0x03 #define CS4210_VENDOR_NID 0x0B @@ -146,6 +146,7 @@ enum { static inline int cs_vendor_coef_get(struct hda_codec *codec, unsigned int idx) { struct cs_spec *spec = codec->spec; + snd_hda_codec_write(codec, spec->vendor_nid, 0, AC_VERB_SET_COEF_INDEX, idx); return snd_hda_codec_read(codec, spec->vendor_nid, 0, @@ -156,6 +157,7 @@ static inline void cs_vendor_coef_set(struct hda_codec *codec, unsigned int idx, unsigned int coef) { struct cs_spec *spec = codec->spec; + snd_hda_codec_write(codec, spec->vendor_nid, 0, AC_VERB_SET_COEF_INDEX, idx); snd_hda_codec_write(codec, spec->vendor_nid, 0, @@ -192,6 +194,7 @@ static void cs_automute(struct hda_codec *codec) static bool is_active_pin(struct hda_codec *codec, hda_nid_t nid) { unsigned int val; + val = snd_hda_codec_get_pincfg(codec, nid); return (get_defcfg_connect(val) != AC_JACK_PORT_NONE); } @@ -210,7 +213,7 @@ static void init_input_coef(struct hda_codec *codec) coef |= 1 << 3; /* DMIC1 2 chan on, GPIO0 off * No effect if SPDIF_OUT2 is * selected in IDX_SPDIF_CTL. - */ + */ cs_vendor_coef_set(codec, IDX_BEEP_CFG, coef); } @@ -284,13 +287,6 @@ static const struct hda_verb cs_errata_init_verbs[] = { {0x11, AC_VERB_SET_COEF_INDEX, 0x0001}, {0x11, AC_VERB_SET_PROC_COEF, 0x0008}, {0x11, AC_VERB_SET_PROC_STATE, 0x00}, - -#if 0 /* Don't to set to D3 as we are in power-up sequence */ - {0x07, AC_VERB_SET_POWER_STATE, 0x03}, /* S/PDIF Rx: D3 */ - {0x08, AC_VERB_SET_POWER_STATE, 0x03}, /* S/PDIF Tx: D3 */ - /*{0x01, AC_VERB_SET_POWER_STATE, 0x03},*/ /* AFG: D3 This is already handled */ -#endif - {} /* terminator */ }; @@ -378,8 +374,10 @@ static int cs_parse_auto_config(struct hda_codec *codec) /* keep the ADCs powered up when it's dynamically switchable */ if (spec->gen.dyn_adc_switch) { unsigned int done = 0; + for (i = 0; i < spec->gen.input_mux.num_items; i++) { int idx = spec->gen.dyn_adc_idx[i]; + if (done & (1 << idx)) continue; snd_hda_gen_fix_pin_power(codec, @@ -513,6 +511,7 @@ static void cs420x_fixup_gpio_13(struct hda_codec *codec, { if (action == HDA_FIXUP_ACT_PRE_PROBE) { struct cs_spec *spec = codec->spec; + spec->gpio_eapd_hp = 2; /* GPIO1 = headphones */ spec->gpio_eapd_speaker = 8; /* GPIO3 = speakers */ spec->gpio_mask = spec->gpio_dir = @@ -525,6 +524,7 @@ static void cs420x_fixup_gpio_23(struct hda_codec *codec, { if (action == HDA_FIXUP_ACT_PRE_PROBE) { struct cs_spec *spec = codec->spec; + spec->gpio_eapd_hp = 4; /* GPIO2 = headphones */ spec->gpio_eapd_speaker = 8; /* GPIO3 = speakers */ spec->gpio_mask = spec->gpio_dir = @@ -669,6 +669,7 @@ static void cs4208_fixup_gpio0(struct hda_codec *codec, { if (action == HDA_FIXUP_ACT_PRE_PROBE) { struct cs_spec *spec = codec->spec; + spec->gpio_eapd_hp = 0; spec->gpio_eapd_speaker = 1; spec->gpio_mask = spec->gpio_dir = @@ -823,7 +824,7 @@ static int patch_cs4208(struct hda_codec *codec) * 1 DAC => HP(sense) / Speakers, * 1 ADC <= LineIn(sense) / MicIn / DMicIn, * 1 SPDIF OUT => SPDIF Trasmitter(sense) -*/ + */ /* CS4210 board names */ static const struct hda_model_fixup cs421x_models[] = { @@ -866,6 +867,7 @@ static void cs421x_fixup_sense_b(struct hda_codec *codec, const struct hda_fixup *fix, int action) { struct cs_spec *spec = codec->spec; + if (action == HDA_FIXUP_ACT_PRE_PROBE) spec->sense_b = 1; } @@ -891,9 +893,9 @@ static const struct hda_verb cs421x_coef_init_verbs[] = { {0x0B, AC_VERB_SET_PROC_STATE, 1}, {0x0B, AC_VERB_SET_COEF_INDEX, CS421X_IDX_DEV_CFG}, /* - Disable Coefficient Index Auto-Increment(DAI)=1, - PDREF=0 - */ + * Disable Coefficient Index Auto-Increment(DAI)=1, + * PDREF=0 + */ {0x0B, AC_VERB_SET_PROC_COEF, 0x0001 }, {0x0B, AC_VERB_SET_COEF_INDEX, CS421X_IDX_ADC_CFG}, @@ -980,12 +982,12 @@ static int cs421x_boost_vol_put(struct snd_kcontrol *kcontrol, coef &= ~0x0003; coef |= (vol & 0x0003); - if (original_coef == coef) - return 0; - else { + if (original_coef != coef) { cs_vendor_coef_set(codec, CS421X_IDX_SPK_CTL, coef); return 1; } + + return 0; } static const struct snd_kcontrol_new cs421x_speaker_boost_ctl = { @@ -1024,8 +1026,8 @@ static void cs4210_pinmux_init(struct hda_codec *codec) is_active_pin(codec, CS421X_DMIC_PIN_NID)) { /* - GPIO or SENSE_B forced - disconnect the DMIC pin. - */ + * GPIO or SENSE_B forced - disconnect the DMIC pin. + */ def_conf = snd_hda_codec_get_pincfg(codec, CS421X_DMIC_PIN_NID); def_conf &= ~AC_DEFCFG_PORT_CONN; def_conf |= (AC_JACK_PORT_NONE << AC_DEFCFG_PORT_CONN_SHIFT); @@ -1064,6 +1066,7 @@ static void parse_cs421x_digital(struct hda_codec *codec) for (i = 0; i < cfg->dig_outs; i++) { hda_nid_t nid = cfg->dig_out_pins[i]; + if (get_wcaps(codec, nid) & AC_WCAP_UNSOL_CAP) { spec->spdif_detect = 1; snd_hda_jack_detect_enable_callback(codec, nid, @@ -1142,9 +1145,9 @@ static int cs421x_parse_auto_config(struct hda_codec *codec) #ifdef CONFIG_PM /* - Manage PDREF, when transitioning to D3hot - (DAC,ADC) -> D3, PDREF=1, AFG->D3 -*/ + * Manage PDREF, when transitioning to D3hot + * (DAC,ADC) -> D3, PDREF=1, AFG->D3 + */ static int cs421x_suspend(struct hda_codec *codec) { struct cs_spec *spec = codec->spec; @@ -1195,10 +1198,10 @@ static int patch_cs4210(struct hda_codec *codec) snd_hda_apply_fixup(codec, HDA_FIXUP_ACT_PRE_PROBE); /* - Update the GPIO/DMIC/SENSE_B pinmux before the configuration - is auto-parsed. If GPIO or SENSE_B is forced, DMIC input - is disabled. - */ + * Update the GPIO/DMIC/SENSE_B pinmux before the configuration + * is auto-parsed. If GPIO or SENSE_B is forced, DMIC input + * is disabled. + */ cs4210_pinmux_init(codec); err = cs421x_parse_auto_config(codec); @@ -1502,8 +1505,8 @@ static const struct cs8409_cir_param cs8409_cs42l42_hw_cfg[] = { */ static void cs8409_enable_i2c_clock(struct hda_codec *codec, unsigned int enable) { - unsigned int retval = 0; - unsigned int newval = 0; + unsigned int retval; + unsigned int newval; retval = cs_vendor_coef_get(codec, 0x0); newval = (enable) ? (retval | 0x8) : (retval & 0xfffffff7); @@ -1698,13 +1701,13 @@ static int cs8409_cs42l42_volume_get(struct snd_kcontrol *kcontrol, } switch (nid) { case CS8409_CS42L42_HP_PIN_NID: - if (chs & 1) + if (chs & BIT(0)) *valp++ = spec->cs42l42_hp_volume[0]; - if (chs & 2) + if (chs & BIT(1)) *valp++ = spec->cs42l42_hp_volume[1]; break; case CS8409_CS42L42_AMIC_PIN_NID: - if (chs & 1) + if (chs & BIT(0)) *valp++ = spec->cs42l42_hs_mic_volume[0]; break; default: @@ -1722,19 +1725,19 @@ static int cs8409_cs42l42_volume_put(struct snd_kcontrol *kcontrol, int chs = get_amp_channels(kcontrol); long *valp = ucontrol->value.integer.value; int change = 0; - char vol = 0; + char vol; snd_hda_power_up(codec); switch (nid) { case CS8409_CS42L42_HP_PIN_NID: mutex_lock(&spec->cs8409_i2c_mux); - if (chs & 1) { + if (chs & BIT(0)) { vol = -(*valp); change = cs8409_i2c_write(codec, CS42L42_I2C_ADDR, CS8409_CS42L42_REG_HS_VOLUME_CHA, vol, 1); valp++; } - if (chs & 2) { + if (chs & BIT(1)) { vol = -(*valp); change |= cs8409_i2c_write(codec, CS42L42_I2C_ADDR, CS8409_CS42L42_REG_HS_VOLUME_CHB, vol, 1); @@ -1743,7 +1746,7 @@ static int cs8409_cs42l42_volume_put(struct snd_kcontrol *kcontrol, break; case CS8409_CS42L42_AMIC_PIN_NID: mutex_lock(&spec->cs8409_i2c_mux); - if (chs & 1) { + if (chs & BIT(0)) { change = cs8409_i2c_write( codec, CS42L42_I2C_ADDR, CS8409_CS42L42_REG_AMIC_VOLUME, (char)*valp, 1); @@ -1907,7 +1910,7 @@ static void cs8409_jack_unsol_event(struct hda_codec *codec, unsigned int res) int reg_cdc_status; int reg_hs_status; int reg_ts_status; - int type = 0; + int type; struct hda_jack_tbl *jk; /* jack_unsol_event() will be called every time gpio line changing state. @@ -1984,7 +1987,7 @@ static void cs8409_jack_unsol_event(struct hda_codec *codec, unsigned int res) if (status_changed) { snd_hda_set_pin_ctl(codec, CS8409_CS42L42_SPK_PIN_NID, - (spec->cs42l42_hp_jack_in)?0 : PIN_OUT); + spec->cs42l42_hp_jack_in ? 0 : PIN_OUT); /* Report jack*/ jk = snd_hda_jack_tbl_get_mst(codec, CS8409_CS42L42_HP_PIN_NID, 0); @@ -2072,18 +2075,18 @@ static void cs8409_enable_ur(struct hda_codec *codec, int flag) /* GPIO4 INT# and GPIO3 WAKE# */ snd_hda_codec_write(codec, codec->core.afg, 0, AC_VERB_SET_GPIO_UNSOLICITED_RSP_MASK, - flag?(GPIO3_INT | GPIO4_INT) : 0); + flag ? (GPIO3_INT | GPIO4_INT) : 0); snd_hda_codec_write(codec, codec->core.afg, 0, AC_VERB_SET_UNSOLICITED_ENABLE, - flag?AC_UNSOL_ENABLED : 0); + flag ? AC_UNSOL_ENABLED : 0); } /* Vendor specific HW configuration * PLL, ASP, I2C, SPI, GPIOs, DMIC etc... */ -static int cs8409_cs42l42_hw_init(struct hda_codec *codec) +static void cs8409_cs42l42_hw_init(struct hda_codec *codec) { const struct cs8409_cir_param *seq = cs8409_cs42l42_hw_cfg; struct cs_spec *spec = codec->spec; @@ -2123,14 +2126,16 @@ static int cs8409_cs42l42_hw_init(struct hda_codec *codec) if (spec->cs42l42_volume_init) { mutex_lock(&spec->cs8409_i2c_mux); cs8409_i2c_write(codec, CS42L42_I2C_ADDR, - CS8409_CS42L42_REG_HS_VOLUME_CHA, -spec->cs42l42_hp_volume[0], + CS8409_CS42L42_REG_HS_VOLUME_CHA, + -spec->cs42l42_hp_volume[0], 1); cs8409_i2c_write(codec, CS42L42_I2C_ADDR, - CS8409_CS42L42_REG_HS_VOLUME_CHB, -spec->cs42l42_hp_volume[1], + CS8409_CS42L42_REG_HS_VOLUME_CHB, + -spec->cs42l42_hp_volume[1], 1); - cs8409_i2c_write( - codec, CS42L42_I2C_ADDR, - CS8409_CS42L42_REG_AMIC_VOLUME, spec->cs42l42_hs_mic_volume[0], + cs8409_i2c_write(codec, CS42L42_I2C_ADDR, + CS8409_CS42L42_REG_AMIC_VOLUME, + spec->cs42l42_hs_mic_volume[0], 1); mutex_unlock(&spec->cs8409_i2c_mux); } @@ -2141,15 +2146,11 @@ static int cs8409_cs42l42_hw_init(struct hda_codec *codec) /* Enable Unsolicited Response */ cs8409_enable_ur(codec, 1); - - return 1; } static int cs8409_cs42l42_init(struct hda_codec *codec) { - int ret = 0; - - ret = snd_hda_gen_init(codec); + int ret = snd_hda_gen_init(codec); if (!ret) { /* On Dell platforms with suspend D3 mode support we @@ -2181,9 +2182,9 @@ static const struct hda_codec_ops cs8409_cs42l42_patch_ops = { static int cs8409_cs42l42_fixup(struct hda_codec *codec) { - int err = 0; + int err; struct cs_spec *spec = codec->spec; - unsigned int pincap = 0; + int caps; /* Basic initial sequence for specific hw configuration */ snd_hda_sequence_write(codec, cs8409_cs42l42_init_verbs); @@ -2198,25 +2199,25 @@ static int cs8409_cs42l42_fixup(struct hda_codec *codec) * capabilities. We have to override pin capabilities, * otherwise they will not be created as input devices. */ - _snd_hdac_read_parm(&codec->core, - CS8409_CS42L42_HP_PIN_NID, AC_PAR_PIN_CAP, &pincap); - - snd_hdac_override_parm(&codec->core, + caps = snd_hdac_read_parm(&codec->core, CS8409_CS42L42_HP_PIN_NID, + AC_PAR_PIN_CAP); + if (caps >= 0) + snd_hdac_override_parm(&codec->core, CS8409_CS42L42_HP_PIN_NID, AC_PAR_PIN_CAP, - (pincap | (AC_PINCAP_IMP_SENSE | AC_PINCAP_PRES_DETECT))); + (caps | (AC_PINCAP_IMP_SENSE | AC_PINCAP_PRES_DETECT))); - _snd_hdac_read_parm(&codec->core, CS8409_CS42L42_AMIC_PIN_NID, - AC_PAR_PIN_CAP, &pincap); - - snd_hdac_override_parm(&codec->core, + caps = snd_hdac_read_parm(&codec->core, CS8409_CS42L42_AMIC_PIN_NID, + AC_PAR_PIN_CAP); + if (caps >= 0) + snd_hdac_override_parm(&codec->core, CS8409_CS42L42_AMIC_PIN_NID, AC_PAR_PIN_CAP, - (pincap | (AC_PINCAP_IMP_SENSE | AC_PINCAP_PRES_DETECT))); + (caps | (AC_PINCAP_IMP_SENSE | AC_PINCAP_PRES_DETECT))); snd_hda_override_wcaps(codec, CS8409_CS42L42_HP_PIN_NID, - (get_wcaps(codec, CS8409_CS42L42_HP_PIN_NID) | AC_WCAP_UNSOL_CAP)); + (get_wcaps(codec, CS8409_CS42L42_HP_PIN_NID) | AC_WCAP_UNSOL_CAP)); snd_hda_override_wcaps(codec, CS8409_CS42L42_AMIC_PIN_NID, - (get_wcaps(codec, CS8409_CS42L42_AMIC_PIN_NID) | AC_WCAP_UNSOL_CAP)); + (get_wcaps(codec, CS8409_CS42L42_AMIC_PIN_NID) | AC_WCAP_UNSOL_CAP)); snd_hda_apply_fixup(codec, HDA_FIXUP_ACT_PRE_PROBE); @@ -2238,7 +2239,7 @@ static int cs8409_cs42l42_fixup(struct hda_codec *codec) snd_hda_apply_fixup(codec, HDA_FIXUP_ACT_PROBE); - return err; + return 0; } static int cs8409_cs42l42_exec_verb(struct hdac_device *dev, @@ -2247,11 +2248,8 @@ static int cs8409_cs42l42_exec_verb(struct hdac_device *dev, struct hda_codec *codec = container_of(dev, struct hda_codec, core); struct cs_spec *spec = codec->spec; - unsigned int nid = 0; - unsigned int verb = 0; - - nid = ((cmd >> 20) & 0x07f); - verb = ((cmd >> 8) & 0x0fff); + unsigned int nid = ((cmd >> 20) & 0x07f); + unsigned int verb = ((cmd >> 8) & 0x0fff); /* CS8409 pins have no AC_PINSENSE_PRESENCE * capabilities. We have to intercept 2 calls for pins 0x24 and 0x34 @@ -2327,9 +2325,6 @@ static int patch_cs8409(struct hda_codec *codec) spec->cs42l42_mic_jack_in = 0; err = cs8409_cs42l42_fixup(codec); - - if (err > 0) - err = cs8409_cs42l42_hw_init(codec); break; default: @@ -2338,10 +2333,12 @@ static int patch_cs8409(struct hda_codec *codec) codec->bus->pci->subsystem_device); break; } - if (err < 0) - cs_free(codec); - else + + if (!err) { + cs8409_cs42l42_hw_init(codec); snd_hda_codec_set_name(codec, "CS8409/CS42L42"); + } else + cs_free(codec); return err; } From 9f8de3b7d789693008b65a4849bc444e81fcfe5a Mon Sep 17 00:00:00 2001 From: Stefan Binding Date: Mon, 15 Mar 2021 19:07:15 +0000 Subject: [PATCH 217/587] ALSA: hda/cirrus: Fix CS42L42 Headset Mic volume control name Existing name "Headset Mic Volume Control" causes multiple Microphone entries to appear in UI. Using name "Mic Volume Control" ensures only a single Microphone entry exists when the Headset is connected. Tested on DELL Inspiron-3505, DELL Inspiron-3501, DELL Inspiron-3500 Signed-off-by: Stefan Binding Signed-off-by: Vitaly Rodionov BugLink: https://bugs.launchpad.net/bugs/1918378 Reported-and-tested-by: You-Sheng Yang Link: https://lore.kernel.org/r/20210315190716.47686-4-vitalyr@opensource.cirrus.com Signed-off-by: Takashi Iwai --- sound/pci/hda/patch_cirrus.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sound/pci/hda/patch_cirrus.c b/sound/pci/hda/patch_cirrus.c index 275bba02cc05..c99ec5e485af 100644 --- a/sound/pci/hda/patch_cirrus.c +++ b/sound/pci/hda/patch_cirrus.c @@ -1789,7 +1789,7 @@ static const struct snd_kcontrol_new cs8409_cs42l42_hp_volume_mixer = { static const struct snd_kcontrol_new cs8409_cs42l42_amic_volume_mixer = { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .index = 0, - .name = "Headset Mic Capture Volume", + .name = "Mic Capture Volume", .subdevice = (HDA_SUBDEV_AMP_FLAG | HDA_SUBDEV_NID_FLAG), .access = (SNDRV_CTL_ELEM_ACCESS_READWRITE | SNDRV_CTL_ELEM_ACCESS_TLV_READ), From 7a114444af813ee35dbe0ef6d26ffb56b309549b Mon Sep 17 00:00:00 2001 From: Stefan Binding Date: Mon, 15 Mar 2021 19:07:16 +0000 Subject: [PATCH 218/587] ALSA: hda/cirrus: Make CS8409 driver more generic by using fixups. CS8409/CS42L42 Driver currently does most of the platform specific setup inside the main body of the code, however, this setup can be moved into fixup functions, to make the driver more generic. Making the driver more generic, allows the driver to use the cs_parse_auto_config function in the patch function. This function forces all of the ADCs to be permanently powered, which means the cap_sync_hook function is no longer needed to restart the stream, when the jack has been ejected. Since the codec is re-initialized on every init/resume, there is no need to add specific verbs to be run on init, and instead these can be combined with the initialization verbs, which are run on init. In addition, the extra fixup verbs are no longer required, since this is taken care of elsewhere. Tested on DELL Inspiron-3505, DELL Inspiron-3501, DELL Inspiron-3500 [ Use fallthrough macro instead of comment -- tiwai ] Signed-off-by: Stefan Binding Signed-off-by: Vitaly Rodionov Link: https://lore.kernel.org/r/20210315190716.47686-5-vitalyr@opensource.cirrus.com Signed-off-by: Takashi Iwai --- sound/pci/hda/patch_cirrus.c | 274 ++++++++++++----------------------- 1 file changed, 95 insertions(+), 179 deletions(-) diff --git a/sound/pci/hda/patch_cirrus.c b/sound/pci/hda/patch_cirrus.c index c99ec5e485af..5d57096b3a95 100644 --- a/sound/pci/hda/patch_cirrus.c +++ b/sound/pci/hda/patch_cirrus.c @@ -1292,9 +1292,14 @@ enum { CS8409_BULLSEYE, CS8409_WARLOCK, CS8409_CYBORG, - CS8409_VERBS, + CS8409_FIXUPS, }; +static void cs8409_cs42l42_fixups(struct hda_codec *codec, + const struct hda_fixup *fix, int action); +static int cs8409_cs42l42_exec_verb(struct hdac_device *dev, + unsigned int cmd, unsigned int flags, unsigned int *res); + /* Dell Inspiron models with cs8409/cs42l42 */ static const struct hda_model_fixup cs8409_models[] = { { .id = CS8409_BULLSEYE, .name = "bullseye" }, @@ -1368,48 +1373,28 @@ static const struct hda_pintbl cs8409_cs42l42_pincfgs[] = { {} /* terminator */ }; -static const struct hda_verb cs8409_cs42l42_add_verbs[] = { - { 0x24, 0x71c, 0xF0 }, /* Widget node ASP-1-TX */ - { 0x24, 0x71d, 0x20 }, - { 0x24, 0x71e, 0x21 }, - { 0x24, 0x71f, 0x04 }, - { 0x34, 0x71c, 0x50 }, /* Widget node ASP-1-RX0 */ - { 0x34, 0x71d, 0x20 }, - { 0x34, 0x71e, 0xa1 }, - { 0x34, 0x71f, 0x04 }, - { 0x2C, 0x71c, 0xF0 }, /* Widget node ASP-2-TX */ - { 0x2C, 0x71d, 0x00 }, - { 0x2C, 0x71e, 0x10 }, - { 0x2C, 0x71f, 0x90 }, - { 0x44, 0x71c, 0x90 }, /* Widget node DMIC-1 */ - { 0x44, 0x71d, 0x00 }, - { 0x44, 0x71e, 0xA0 }, - { 0x44, 0x71f, 0x90 }, - {} /* terminator */ -}; - static const struct hda_fixup cs8409_fixups[] = { [CS8409_BULLSEYE] = { .type = HDA_FIXUP_PINS, .v.pins = cs8409_cs42l42_pincfgs, .chained = true, - .chain_id = CS8409_VERBS, + .chain_id = CS8409_FIXUPS, }, [CS8409_WARLOCK] = { .type = HDA_FIXUP_PINS, .v.pins = cs8409_cs42l42_pincfgs, .chained = true, - .chain_id = CS8409_VERBS, + .chain_id = CS8409_FIXUPS, }, [CS8409_CYBORG] = { .type = HDA_FIXUP_PINS, .v.pins = cs8409_cs42l42_pincfgs, .chained = true, - .chain_id = CS8409_VERBS, + .chain_id = CS8409_FIXUPS, }, - [CS8409_VERBS] = { - .type = HDA_FIXUP_VERBS, - .v.verbs = cs8409_cs42l42_add_verbs, + [CS8409_FIXUPS] = { + .type = HDA_FIXUP_FUNC, + .v.func = cs8409_cs42l42_fixups, }, }; @@ -2004,26 +1989,6 @@ static void cs8409_jack_unsol_event(struct hda_codec *codec, unsigned int res) } } -static int cs8409_cs42l42_build_controls(struct hda_codec *codec) -{ - int err; - - err = snd_hda_gen_build_controls(codec); - if (err < 0) - return err; - - snd_hda_apply_fixup(codec, HDA_FIXUP_ACT_BUILD); - - /* Run jack auto detect first time on boot - * after controls have been added, to check if jack has - * been already plugged in - */ - cs8409_cs42l42_run_jack_detect(codec); - usleep_range(100000, 150000); - - return 0; -} - #ifdef CONFIG_PM /* Manage PDREF, when transition to D3hot */ static int cs8409_suspend(struct hda_codec *codec) @@ -2044,31 +2009,6 @@ static int cs8409_suspend(struct hda_codec *codec) } #endif -static void cs8409_cs42l42_cap_sync_hook(struct hda_codec *codec, - struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_value *ucontrol) -{ - struct cs_spec *spec = codec->spec; - unsigned int curval, expval; - /* CS8409 DMIC Pin only allows the setting of the Stream Parameters in - * Power State D0. When a headset is unplugged, and the path is switched to - * the DMIC, the Stream is restarted with the new ADC, but this is done in - * Power State D3. Restart the Stream now DMIC is in D0. - */ - if (spec->gen.cur_adc == CS8409_CS42L42_DMIC_ADC_PIN_NID) { - curval = snd_hda_codec_read(codec, spec->gen.cur_adc, - 0, AC_VERB_GET_CONV, 0); - expval = (spec->gen.cur_adc_stream_tag << 4) | 0; - if (curval != expval) { - codec_dbg(codec, "%s Restarting Stream after DMIC switch\n", __func__); - __snd_hda_codec_cleanup_stream(codec, spec->gen.cur_adc, 1); - snd_hda_codec_setup_stream(codec, spec->gen.cur_adc, - spec->gen.cur_adc_stream_tag, 0, - spec->gen.cur_adc_format); - } - } -} - /* Enable/Disable Unsolicited Response for gpio(s) 3,4 */ static void cs8409_enable_ur(struct hda_codec *codec, int flag) { @@ -2152,25 +2092,14 @@ static int cs8409_cs42l42_init(struct hda_codec *codec) { int ret = snd_hda_gen_init(codec); - if (!ret) { - /* On Dell platforms with suspend D3 mode support we - * have to re-initialise cs8409 bridge and companion - * cs42l42 codec - */ - snd_hda_sequence_write(codec, cs8409_cs42l42_init_verbs); - snd_hda_sequence_write(codec, cs8409_cs42l42_add_verbs); - - cs8409_cs42l42_hw_init(codec); - - cs8409_cs42l42_run_jack_detect(codec); - usleep_range(100000, 150000); - } + if (!ret) + snd_hda_apply_fixup(codec, HDA_FIXUP_ACT_INIT); return ret; } static const struct hda_codec_ops cs8409_cs42l42_patch_ops = { - .build_controls = cs8409_cs42l42_build_controls, + .build_controls = cs_build_controls, .build_pcms = snd_hda_gen_build_pcms, .init = cs8409_cs42l42_init, .free = cs_free, @@ -2180,66 +2109,91 @@ static const struct hda_codec_ops cs8409_cs42l42_patch_ops = { #endif }; -static int cs8409_cs42l42_fixup(struct hda_codec *codec) +static void cs8409_cs42l42_fixups(struct hda_codec *codec, + const struct hda_fixup *fix, int action) { - int err; struct cs_spec *spec = codec->spec; int caps; - /* Basic initial sequence for specific hw configuration */ - snd_hda_sequence_write(codec, cs8409_cs42l42_init_verbs); + switch (action) { + case HDA_FIXUP_ACT_PRE_PROBE: + snd_hda_add_verbs(codec, cs8409_cs42l42_init_verbs); + /* verb exec op override */ + spec->exec_verb = codec->core.exec_verb; + codec->core.exec_verb = cs8409_cs42l42_exec_verb; - /* CS8409 is simple HDA bridge and intended to be used with a remote - * companion codec. Most of input/output PIN(s) have only basic - * capabilities. NID(s) 0x24 and 0x34 have only OUTC and INC - * capabilities and no presence detect capable (PDC) and call to - * snd_hda_gen_build_controls() will mark them as non detectable - * phantom jacks. However, in this configuration companion codec - * CS42L42 is connected to these pins and it has jack detect - * capabilities. We have to override pin capabilities, - * otherwise they will not be created as input devices. - */ - caps = snd_hdac_read_parm(&codec->core, CS8409_CS42L42_HP_PIN_NID, - AC_PAR_PIN_CAP); - if (caps >= 0) - snd_hdac_override_parm(&codec->core, - CS8409_CS42L42_HP_PIN_NID, AC_PAR_PIN_CAP, - (caps | (AC_PINCAP_IMP_SENSE | AC_PINCAP_PRES_DETECT))); + mutex_init(&spec->cs8409_i2c_mux); - caps = snd_hdac_read_parm(&codec->core, CS8409_CS42L42_AMIC_PIN_NID, - AC_PAR_PIN_CAP); - if (caps >= 0) - snd_hdac_override_parm(&codec->core, - CS8409_CS42L42_AMIC_PIN_NID, AC_PAR_PIN_CAP, - (caps | (AC_PINCAP_IMP_SENSE | AC_PINCAP_PRES_DETECT))); + codec->patch_ops = cs8409_cs42l42_patch_ops; - snd_hda_override_wcaps(codec, CS8409_CS42L42_HP_PIN_NID, - (get_wcaps(codec, CS8409_CS42L42_HP_PIN_NID) | AC_WCAP_UNSOL_CAP)); + spec->gen.suppress_auto_mute = 1; + spec->gen.no_primary_hp = 1; + spec->gen.suppress_vmaster = 1; - snd_hda_override_wcaps(codec, CS8409_CS42L42_AMIC_PIN_NID, - (get_wcaps(codec, CS8409_CS42L42_AMIC_PIN_NID) | AC_WCAP_UNSOL_CAP)); + /* GPIO 5 out, 3,4 in */ + spec->gpio_dir = GPIO5_INT; + spec->gpio_data = 0; + spec->gpio_mask = 0x03f; - snd_hda_apply_fixup(codec, HDA_FIXUP_ACT_PRE_PROBE); + spec->cs42l42_hp_jack_in = 0; + spec->cs42l42_mic_jack_in = 0; - err = snd_hda_parse_pin_defcfg(codec, &spec->gen.autocfg, 0, 0); - if (err < 0) - return err; + /* Basic initial sequence for specific hw configuration */ + snd_hda_sequence_write(codec, cs8409_cs42l42_init_verbs); - err = snd_hda_gen_parse_auto_config(codec, &spec->gen.autocfg); - if (err < 0) - return err; + /* CS8409 is simple HDA bridge and intended to be used with a remote + * companion codec. Most of input/output PIN(s) have only basic + * capabilities. NID(s) 0x24 and 0x34 have only OUTC and INC + * capabilities and no presence detect capable (PDC) and call to + * snd_hda_gen_build_controls() will mark them as non detectable + * phantom jacks. However, in this configuration companion codec + * CS42L42 is connected to these pins and it has jack detect + * capabilities. We have to override pin capabilities, + * otherwise they will not be created as input devices. + */ + caps = snd_hdac_read_parm(&codec->core, CS8409_CS42L42_HP_PIN_NID, + AC_PAR_PIN_CAP); + if (caps >= 0) + snd_hdac_override_parm(&codec->core, + CS8409_CS42L42_HP_PIN_NID, AC_PAR_PIN_CAP, + (caps | (AC_PINCAP_IMP_SENSE | AC_PINCAP_PRES_DETECT))); - if (!snd_hda_gen_add_kctl( - &spec->gen, NULL, &cs8409_cs42l42_hp_volume_mixer)) - return -1; + caps = snd_hdac_read_parm(&codec->core, CS8409_CS42L42_AMIC_PIN_NID, + AC_PAR_PIN_CAP); + if (caps >= 0) + snd_hdac_override_parm(&codec->core, + CS8409_CS42L42_AMIC_PIN_NID, AC_PAR_PIN_CAP, + (caps | (AC_PINCAP_IMP_SENSE | AC_PINCAP_PRES_DETECT))); - if (!snd_hda_gen_add_kctl( - &spec->gen, NULL, &cs8409_cs42l42_amic_volume_mixer)) - return -1; + snd_hda_override_wcaps(codec, CS8409_CS42L42_HP_PIN_NID, + (get_wcaps(codec, CS8409_CS42L42_HP_PIN_NID) | AC_WCAP_UNSOL_CAP)); - snd_hda_apply_fixup(codec, HDA_FIXUP_ACT_PROBE); - - return 0; + snd_hda_override_wcaps(codec, CS8409_CS42L42_AMIC_PIN_NID, + (get_wcaps(codec, CS8409_CS42L42_AMIC_PIN_NID) | AC_WCAP_UNSOL_CAP)); + break; + case HDA_FIXUP_ACT_PROBE: + snd_hda_gen_add_kctl(&spec->gen, + NULL, &cs8409_cs42l42_hp_volume_mixer); + snd_hda_gen_add_kctl(&spec->gen, + NULL, &cs8409_cs42l42_amic_volume_mixer); + cs8409_cs42l42_hw_init(codec); + snd_hda_codec_set_name(codec, "CS8409/CS42L42"); + break; + case HDA_FIXUP_ACT_INIT: + cs8409_cs42l42_hw_init(codec); + fallthrough; + case HDA_FIXUP_ACT_BUILD: + /* Run jack auto detect first time on boot + * after controls have been added, to check if jack has + * been already plugged in. + * Run immediately after init. + */ + cs8409_cs42l42_run_jack_detect(codec); + usleep_range(100000, 150000); + break; + default: + break; + } } static int cs8409_cs42l42_exec_verb(struct hdac_device *dev, @@ -2280,11 +2234,9 @@ static int cs8409_cs42l42_exec_verb(struct hdac_device *dev, static int patch_cs8409(struct hda_codec *codec) { - struct cs_spec *spec; - int err = -EINVAL; + int err; - spec = cs_alloc_spec(codec, CS8409_VENDOR_NID); - if (!spec) + if (!cs_alloc_spec(codec, CS8409_VENDOR_NID)) return -ENOMEM; snd_hda_pick_fixup(codec, @@ -2295,52 +2247,16 @@ static int patch_cs8409(struct hda_codec *codec) codec->bus->pci->subsystem_vendor, codec->bus->pci->subsystem_device); - switch (codec->fixup_id) { - /* Dell platforms with CS42L42 companion codec */ - case CS8409_BULLSEYE: - case CS8409_WARLOCK: - case CS8409_CYBORG: + snd_hda_apply_fixup(codec, HDA_FIXUP_ACT_PRE_PROBE); - snd_hda_add_verbs(codec, cs8409_cs42l42_add_verbs); - - /* verb exec op override */ - spec->exec_verb = codec->core.exec_verb; - codec->core.exec_verb = cs8409_cs42l42_exec_verb; - - mutex_init(&spec->cs8409_i2c_mux); - - codec->patch_ops = cs8409_cs42l42_patch_ops; - - spec->gen.cap_sync_hook = cs8409_cs42l42_cap_sync_hook; - - spec->gen.suppress_auto_mute = 1; - spec->gen.no_primary_hp = 1; - spec->gen.suppress_vmaster = 1; - /* GPIO 5 out, 3,4 in */ - spec->gpio_dir = GPIO5_INT; - spec->gpio_data = 0; - spec->gpio_mask = 0x03f; - - spec->cs42l42_hp_jack_in = 0; - spec->cs42l42_mic_jack_in = 0; - - err = cs8409_cs42l42_fixup(codec); - break; - - default: - codec_err(codec, "VID=%08x, DEV=%08x not supported\n", - codec->bus->pci->subsystem_vendor, - codec->bus->pci->subsystem_device); - break; + err = cs_parse_auto_config(codec); + if (err < 0) { + cs_free(codec); + return err; } - if (!err) { - cs8409_cs42l42_hw_init(codec); - snd_hda_codec_set_name(codec, "CS8409/CS42L42"); - } else - cs_free(codec); - - return err; + snd_hda_apply_fixup(codec, HDA_FIXUP_ACT_PROBE); + return 0; } /* From 11fd6d8e097b5b179ea445e0206aaefc47e62845 Mon Sep 17 00:00:00 2001 From: Guennadi Liakhovetski Date: Mon, 15 Mar 2021 11:39:30 -0500 Subject: [PATCH 219/587] ASoC: SOF: fix debugfs initialisation error handling If debugfs initialisation fails partially in sof_probe_continue() some debugfs files and the root directory might have been created successfully. They have to be cleaned up if some of them failed too. Reviewed-by: Ranjani Sridharan Reviewed-by: Xiuli Pan Signed-off-by: Guennadi Liakhovetski Signed-off-by: Pierre-Louis Bossart Link: https://lore.kernel.org/r/20210315163932.18663-2-pierre-louis.bossart@linux.intel.com Signed-off-by: Mark Brown --- sound/soc/sof/core.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/sound/soc/sof/core.c b/sound/soc/sof/core.c index 6d8f7d9fd192..495295a34c3a 100644 --- a/sound/soc/sof/core.c +++ b/sound/soc/sof/core.c @@ -154,7 +154,7 @@ static int sof_probe_continue(struct snd_sof_dev *sdev) if (ret < 0) { dev_err(sdev->dev, "error: failed to get machine info %d\n", ret); - goto dbg_err; + goto dsp_err; } /* set up platform component driver */ @@ -257,8 +257,9 @@ fw_run_err: fw_load_err: snd_sof_ipc_free(sdev); ipc_err: - snd_sof_free_debug(sdev); dbg_err: + snd_sof_free_debug(sdev); +dsp_err: snd_sof_remove(sdev); /* all resources freed, update state to match */ From 72c35856b5edc3f734be5699e9f6737190a1d897 Mon Sep 17 00:00:00 2001 From: Guennadi Liakhovetski Date: Mon, 15 Mar 2021 11:39:31 -0500 Subject: [PATCH 220/587] ASoC: SOF: only allocate debugfs cache buffers for IPC flood entries snd_sof_debugfs_buf_item() is an exported function and is called from different locations to initialise different debugfs entries. However .cache_buf is only needed for IPC flood entries. Limit allocations respectively. Reviewed-by: Ranjani Sridharan Reviewed-by: Xiuli Pan Signed-off-by: Guennadi Liakhovetski Signed-off-by: Pierre-Louis Bossart Link: https://lore.kernel.org/r/20210315163932.18663-3-pierre-louis.bossart@linux.intel.com Signed-off-by: Mark Brown --- sound/soc/sof/debug.c | 18 ++++++++++-------- 1 file changed, 10 insertions(+), 8 deletions(-) diff --git a/sound/soc/sof/debug.c b/sound/soc/sof/debug.c index 715a374b33cf..778c7d028493 100644 --- a/sound/soc/sof/debug.c +++ b/sound/soc/sof/debug.c @@ -609,14 +609,16 @@ int snd_sof_debugfs_buf_item(struct snd_sof_dev *sdev, dfse->sdev = sdev; #if IS_ENABLED(CONFIG_SND_SOC_SOF_DEBUG_IPC_FLOOD_TEST) - /* - * cache_buf is unused for SOF_DFSENTRY_TYPE_BUF debugfs entries. - * So, use it to save the results of the last IPC flood test. - */ - dfse->cache_buf = devm_kzalloc(sdev->dev, IPC_FLOOD_TEST_RESULT_LEN, - GFP_KERNEL); - if (!dfse->cache_buf) - return -ENOMEM; + if (!strncmp(name, "ipc_flood", strlen("ipc_flood"))) { + /* + * cache_buf is unused for SOF_DFSENTRY_TYPE_BUF debugfs entries. + * So, use it to save the results of the last IPC flood test. + */ + dfse->cache_buf = devm_kzalloc(sdev->dev, IPC_FLOOD_TEST_RESULT_LEN, + GFP_KERNEL); + if (!dfse->cache_buf) + return -ENOMEM; + } #endif debugfs_create_file(name, mode, sdev->debugfs_root, dfse, From 97f53046d746bef513d5fbaac53eedb011968407 Mon Sep 17 00:00:00 2001 From: Guennadi Liakhovetski Date: Mon, 15 Mar 2021 11:39:32 -0500 Subject: [PATCH 221/587] ASoC: SOF: remove superfluous NULL check in debugfs read MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit When reading from IPC flood debugfs entries no need to check whether .cache_buf is NULL - it's impossible since otherwise the initialisation would have failed. This also fixes a klocwork reported issue: passed to function and may be dereferenced there by passing argument 2 to function 'memcpy' at line 510. sound/soc/sof/debug.c:510 | sof_dfsentry_read() Reported-by: Keqiao Zhang Reviewed-by: Ranjani Sridharan Reviewed-by: Xiuli Pan Signed-off-by: Guennadi Liakhovetski Signed-off-by: Pierre-Louis Bossart Link: https://lore.kernel.org/r/20210315163932.18663-4-pierre-louis.bossart@linux.intel.com Signed-off-by: Mark Brown --- sound/soc/sof/debug.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/sound/soc/sof/debug.c b/sound/soc/sof/debug.c index 778c7d028493..a51a928ea40a 100644 --- a/sound/soc/sof/debug.c +++ b/sound/soc/sof/debug.c @@ -451,8 +451,7 @@ static ssize_t sof_dfsentry_read(struct file *file, char __user *buffer, dentry = file->f_path.dentry; if ((!strcmp(dentry->d_name.name, "ipc_flood_count") || - !strcmp(dentry->d_name.name, "ipc_flood_duration_ms")) && - dfse->cache_buf) { + !strcmp(dentry->d_name.name, "ipc_flood_duration_ms"))) { if (*ppos) return 0; From 6ad864ed6ac50f11a6d8575fda79991cca8f245c Mon Sep 17 00:00:00 2001 From: Viorel Suman Date: Tue, 16 Mar 2021 17:42:16 +0800 Subject: [PATCH 222/587] ASoC: fsl_spdif: use snd_ctl_boolean_mono_info Remove redundant code and use snd_ctl_boolean_mono_info instead. Signed-off-by: Viorel Suman Signed-off-by: Shengjiu Wang Link: https://lore.kernel.org/r/1615887736-31217-1-git-send-email-shengjiu.wang@nxp.com Signed-off-by: Mark Brown --- sound/soc/fsl/fsl_spdif.c | 30 +++--------------------------- 1 file changed, 3 insertions(+), 27 deletions(-) diff --git a/sound/soc/fsl/fsl_spdif.c b/sound/soc/fsl/fsl_spdif.c index 174e558224d8..1cd3441d1c03 100644 --- a/sound/soc/fsl/fsl_spdif.c +++ b/sound/soc/fsl/fsl_spdif.c @@ -801,18 +801,6 @@ static int fsl_spdif_qget(struct snd_kcontrol *kcontrol, return ret; } -/* Valid bit information */ -static int fsl_spdif_vbit_info(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_info *uinfo) -{ - uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN; - uinfo->count = 1; - uinfo->value.integer.min = 0; - uinfo->value.integer.max = 1; - - return 0; -} - /* Get valid good bit from interrupt status register */ static int fsl_spdif_rx_vbit_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) @@ -925,18 +913,6 @@ static int fsl_spdif_rxrate_get(struct snd_kcontrol *kcontrol, return 0; } -/* User bit sync mode info */ -static int fsl_spdif_usync_info(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_info *uinfo) -{ - uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN; - uinfo->count = 1; - uinfo->value.integer.min = 0; - uinfo->value.integer.max = 1; - - return 0; -} - /* * User bit sync mode: * 1 CD User channel subcode @@ -1018,7 +994,7 @@ static struct snd_kcontrol_new fsl_spdif_ctrls[] = { .name = "IEC958 RX V-Bit Errors", .access = SNDRV_CTL_ELEM_ACCESS_READ | SNDRV_CTL_ELEM_ACCESS_VOLATILE, - .info = fsl_spdif_vbit_info, + .info = snd_ctl_boolean_mono_info, .get = fsl_spdif_rx_vbit_get, }, { @@ -1027,7 +1003,7 @@ static struct snd_kcontrol_new fsl_spdif_ctrls[] = { .access = SNDRV_CTL_ELEM_ACCESS_READ | SNDRV_CTL_ELEM_ACCESS_WRITE | SNDRV_CTL_ELEM_ACCESS_VOLATILE, - .info = fsl_spdif_vbit_info, + .info = snd_ctl_boolean_mono_info, .get = fsl_spdif_tx_vbit_get, .put = fsl_spdif_tx_vbit_put, }, @@ -1047,7 +1023,7 @@ static struct snd_kcontrol_new fsl_spdif_ctrls[] = { .access = SNDRV_CTL_ELEM_ACCESS_READ | SNDRV_CTL_ELEM_ACCESS_WRITE | SNDRV_CTL_ELEM_ACCESS_VOLATILE, - .info = fsl_spdif_usync_info, + .info = snd_ctl_boolean_mono_info, .get = fsl_spdif_usync_get, .put = fsl_spdif_usync_put, }, From 1d49439c04792a4a3d8299a32b7673ab7ba13b77 Mon Sep 17 00:00:00 2001 From: Fabio Estevam Date: Mon, 15 Mar 2021 16:38:42 -0300 Subject: [PATCH 223/587] ASoC: mx27vis: Remove unused file i.MX has been converted to a devicetree-only platform and asoc-mx27vis.h is no longer used. Get rid of this unused file. Signed-off-by: Fabio Estevam Link: https://lore.kernel.org/r/20210315193842.183042-1-festevam@gmail.com Signed-off-by: Mark Brown --- include/linux/platform_data/asoc-mx27vis.h | 12 ------------ 1 file changed, 12 deletions(-) delete mode 100644 include/linux/platform_data/asoc-mx27vis.h diff --git a/include/linux/platform_data/asoc-mx27vis.h b/include/linux/platform_data/asoc-mx27vis.h deleted file mode 100644 index 2107d0d992dd..000000000000 --- a/include/linux/platform_data/asoc-mx27vis.h +++ /dev/null @@ -1,12 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0 */ -#ifndef __PLATFORM_DATA_ASOC_MX27VIS_H -#define __PLATFORM_DATA_ASOC_MX27VIS_H - -struct snd_mx27vis_platform_data { - int amp_gain0_gpio; - int amp_gain1_gpio; - int amp_mutel_gpio; - int amp_muter_gpio; -}; - -#endif /* __PLATFORM_DATA_ASOC_MX27VIS_H */ From 19c6a63ced5e07e40f3a5255cb1f0fe0d3be7b14 Mon Sep 17 00:00:00 2001 From: Mikhail Durnev Date: Tue, 16 Mar 2021 14:47:35 +1000 Subject: [PATCH 224/587] ASoC: rsnd: core: Check convert rate in rsnd_hw_params snd_pcm_hw_params_set_rate_near can return incorrect sample rate in some cases, e.g. when the backend output rate is set to some value higher than 48000 Hz and the input rate is 8000 Hz. So passing the value returned by snd_pcm_hw_params_set_rate_near to snd_pcm_hw_params will result in "FSO/FSI ratio error" and playing no audio at all while the userland is not properly notified about the issue. If SRC is unable to convert the requested sample rate to the sample rate the backend is using, then the requested sample rate should be adjusted in rsnd_hw_params. The userland will be notified about that change in the returned hw_params structure. Signed-off-by: Mikhail Durnev Link: https://lore.kernel.org/r/1615870055-13954-1-git-send-email-mikhail_durnev@mentor.com Signed-off-by: Mark Brown --- sound/soc/sh/rcar/core.c | 69 +++++++++++++++++++++++++++++++++++++++- 1 file changed, 68 insertions(+), 1 deletion(-) diff --git a/sound/soc/sh/rcar/core.c b/sound/soc/sh/rcar/core.c index d1612d35f0ee..8696a993c478 100644 --- a/sound/soc/sh/rcar/core.c +++ b/sound/soc/sh/rcar/core.c @@ -1424,8 +1424,75 @@ static int rsnd_hw_params(struct snd_soc_component *component, } if (io->converted_chan) dev_dbg(dev, "convert channels = %d\n", io->converted_chan); - if (io->converted_rate) + if (io->converted_rate) { + /* + * SRC supports convert rates from params_rate(hw_params)/k_down + * to params_rate(hw_params)*k_up, where k_up is always 6, and + * k_down depends on number of channels and SRC unit. + * So all SRC units can upsample audio up to 6 times regardless + * its number of channels. And all SRC units can downsample + * 2 channel audio up to 6 times too. + */ + int k_up = 6; + int k_down = 6; + int channel; + struct rsnd_mod *src_mod = rsnd_io_to_mod_src(io); + dev_dbg(dev, "convert rate = %d\n", io->converted_rate); + + channel = io->converted_chan ? io->converted_chan : + params_channels(hw_params); + + switch (rsnd_mod_id(src_mod)) { + /* + * SRC0 can downsample 4, 6 and 8 channel audio up to 4 times. + * SRC1, SRC3 and SRC4 can downsample 4 channel audio + * up to 4 times. + * SRC1, SRC3 and SRC4 can downsample 6 and 8 channel audio + * no more than twice. + */ + case 1: + case 3: + case 4: + if (channel > 4) { + k_down = 2; + break; + } + fallthrough; + case 0: + if (channel > 2) + k_down = 4; + break; + + /* Other SRC units do not support more than 2 channels */ + default: + if (channel > 2) + return -EINVAL; + } + + if (params_rate(hw_params) > io->converted_rate * k_down) { + hw_param_interval(hw_params, SNDRV_PCM_HW_PARAM_RATE)->min = + io->converted_rate * k_down; + hw_param_interval(hw_params, SNDRV_PCM_HW_PARAM_RATE)->max = + io->converted_rate * k_down; + hw_params->cmask |= SNDRV_PCM_HW_PARAM_RATE; + } else if (params_rate(hw_params) * k_up < io->converted_rate) { + hw_param_interval(hw_params, SNDRV_PCM_HW_PARAM_RATE)->min = + (io->converted_rate + k_up - 1) / k_up; + hw_param_interval(hw_params, SNDRV_PCM_HW_PARAM_RATE)->max = + (io->converted_rate + k_up - 1) / k_up; + hw_params->cmask |= SNDRV_PCM_HW_PARAM_RATE; + } + + /* + * TBD: Max SRC input and output rates also depend on number + * of channels and SRC unit: + * SRC1, SRC3 and SRC4 do not support more than 128kHz + * for 6 channel and 96kHz for 8 channel audio. + * Perhaps this function should return EINVAL if the input or + * the output rate exceeds the limitation. + */ + } } return rsnd_dai_call(hw_params, io, substream, hw_params); From 2e2bf6d479616a15c54c4e668558f61caffa4db4 Mon Sep 17 00:00:00 2001 From: Yang Li Date: Thu, 4 Mar 2021 17:08:01 +0800 Subject: [PATCH 225/587] ASoC: imx-hdmi: fix platform_no_drv_owner.cocci warnings ./sound/soc/fsl/imx-hdmi.c:226:3-8: No need to set .owner here. The core will do it. Remove .owner field if calls are used which set it automatically Reported-by: Abaci Robot Signed-off-by: Yang Li Reviewed-by: Fabio Estevam Link: https://lore.kernel.org/r/1614848881-29637-1-git-send-email-yang.lee@linux.alibaba.com Signed-off-by: Mark Brown --- sound/soc/fsl/imx-hdmi.c | 1 - 1 file changed, 1 deletion(-) diff --git a/sound/soc/fsl/imx-hdmi.c b/sound/soc/fsl/imx-hdmi.c index 1ebcb9a2336b..34a0dceae621 100644 --- a/sound/soc/fsl/imx-hdmi.c +++ b/sound/soc/fsl/imx-hdmi.c @@ -219,7 +219,6 @@ MODULE_DEVICE_TABLE(of, imx_hdmi_dt_ids); static struct platform_driver imx_hdmi_driver = { .driver = { .name = "imx-hdmi", - .owner = THIS_MODULE, .pm = &snd_soc_pm_ops, .of_match_table = imx_hdmi_dt_ids, }, From c00f4f2598d334470b49385f811ca8f5c966a63e Mon Sep 17 00:00:00 2001 From: Bhaskar Chowdhury Date: Wed, 17 Mar 2021 13:50:42 +0530 Subject: [PATCH 226/587] ASoC: ti: Fix a typo in the file ams-delta.c s/functonality/functionality/ Signed-off-by: Bhaskar Chowdhury Link: https://lore.kernel.org/r/20210317082042.3670745-1-unixbhaskar@gmail.com Signed-off-by: Mark Brown --- sound/soc/ti/ams-delta.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sound/soc/ti/ams-delta.c b/sound/soc/ti/ams-delta.c index 57feb473a579..31462587f922 100644 --- a/sound/soc/ti/ams-delta.c +++ b/sound/soc/ti/ams-delta.c @@ -408,7 +408,7 @@ static struct tty_ldisc_ops cx81801_ops = { /* * Even if not very useful, the sound card can still work without any of the - * above functonality activated. You can still control its audio input/output + * above functionality activated. You can still control its audio input/output * constellation and speakerphone gain from userspace by issuing AT commands * over the modem port. */ From cbdce7a3620c7daff6b8a2cb27b41bb0a2e6f78d Mon Sep 17 00:00:00 2001 From: Aditya Srivastava Date: Thu, 18 Mar 2021 01:51:44 +0530 Subject: [PATCH 227/587] ALSA: asihpi: fix comment syntax in file headers The opening comment mark '/**' is used for highlighting the beginning of kernel-doc comments. There are files in sound/pci/asihpi which follow this syntax in their file headers, i.e. start with '/**' like comments, which causes unexpected warnings from kernel-doc. E.g., running scripts/kernel-doc -none on sound/pci/asihpi/hpidspcd.h causes this warning: "warning: Cannot understand on line 4 - I thought it was a doc line" Provide a simple fix by replacing the kernel-doc like comment syntax with general format, i.e. "/*", to prevent kernel-doc from parsing it. Signed-off-by: Aditya Srivastava Acked-by: Randy Dunlap Link: https://lore.kernel.org/r/20210317202144.20290-1-yashsri421@gmail.com Signed-off-by: Takashi Iwai --- sound/pci/asihpi/hpicmn.h | 2 +- sound/pci/asihpi/hpidspcd.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/sound/pci/asihpi/hpicmn.h b/sound/pci/asihpi/hpicmn.h index de3bedd29d94..8ec656cf8848 100644 --- a/sound/pci/asihpi/hpicmn.h +++ b/sound/pci/asihpi/hpicmn.h @@ -1,5 +1,5 @@ /* SPDX-License-Identifier: GPL-2.0-only */ -/** +/* AudioScience HPI driver Copyright (C) 1997-2014 AudioScience Inc. diff --git a/sound/pci/asihpi/hpidspcd.h b/sound/pci/asihpi/hpidspcd.h index a01e8c6092bd..9f1468ed7096 100644 --- a/sound/pci/asihpi/hpidspcd.h +++ b/sound/pci/asihpi/hpidspcd.h @@ -1,6 +1,6 @@ /* SPDX-License-Identifier: GPL-2.0-only */ /***********************************************************************/ -/** +/* AudioScience HPI driver Copyright (C) 1997-2011 AudioScience Inc. From a08b9f2f2267421092bf4b882a9461858216ed47 Mon Sep 17 00:00:00 2001 From: Aditya Srivastava Date: Thu, 18 Mar 2021 02:09:32 +0530 Subject: [PATCH 228/587] ALSA: ctxfi: fix comment syntax in file headers The opening comment mark '/**' is used for highlighting the beginning of kernel-doc comments. There are files in sound/pci/ctxfi which follow this syntax in their file headers, i.e. start with '/**' like comments, which causes unexpected warnings from kernel-doc. E.g., running scripts/kernel-doc -none on sound/pci/ctxfi/ctresource.c causes this warning: "warning: wrong kernel-doc identifier on line: * Copyright (C) 2008, Creative Technology Ltd. All Rights Reserved." Similarly for other files too. Provide a simple fix by replacing the kernel-doc like comment syntax with general format, i.e. "/*", to prevent kernel-doc from parsing it. Signed-off-by: Aditya Srivastava Acked-by: Randy Dunlap Link: https://lore.kernel.org/r/20210317203932.23993-1-yashsri421@gmail.com Signed-off-by: Takashi Iwai --- sound/pci/ctxfi/ct20k1reg.h | 2 +- sound/pci/ctxfi/ct20k2reg.h | 2 +- sound/pci/ctxfi/ctamixer.c | 2 +- sound/pci/ctxfi/ctamixer.h | 2 +- sound/pci/ctxfi/ctatc.c | 2 +- sound/pci/ctxfi/ctatc.h | 2 +- sound/pci/ctxfi/ctdaio.c | 2 +- sound/pci/ctxfi/ctdaio.h | 2 +- sound/pci/ctxfi/cthardware.h | 2 +- sound/pci/ctxfi/cthw20k1.h | 2 +- sound/pci/ctxfi/cthw20k2.h | 2 +- sound/pci/ctxfi/ctimap.h | 2 +- sound/pci/ctxfi/ctmixer.h | 2 +- sound/pci/ctxfi/ctpcm.h | 2 +- sound/pci/ctxfi/ctresource.c | 2 +- sound/pci/ctxfi/ctresource.h | 2 +- sound/pci/ctxfi/ctsrc.c | 2 +- sound/pci/ctxfi/ctsrc.h | 2 +- sound/pci/ctxfi/ctvmem.c | 2 +- sound/pci/ctxfi/ctvmem.h | 2 +- 20 files changed, 20 insertions(+), 20 deletions(-) diff --git a/sound/pci/ctxfi/ct20k1reg.h b/sound/pci/ctxfi/ct20k1reg.h index d4bfee499fb1..05bb006c0f4c 100644 --- a/sound/pci/ctxfi/ct20k1reg.h +++ b/sound/pci/ctxfi/ct20k1reg.h @@ -1,5 +1,5 @@ /* SPDX-License-Identifier: GPL-2.0-only */ -/** +/* * Copyright (C) 2008, Creative Technology Ltd. All Rights Reserved. */ diff --git a/sound/pci/ctxfi/ct20k2reg.h b/sound/pci/ctxfi/ct20k2reg.h index af94ea66fdda..02f67828eabe 100644 --- a/sound/pci/ctxfi/ct20k2reg.h +++ b/sound/pci/ctxfi/ct20k2reg.h @@ -1,5 +1,5 @@ /* SPDX-License-Identifier: GPL-2.0-only */ -/** +/* * Copyright (C) 2008, Creative Technology Ltd. All Rights Reserved. */ diff --git a/sound/pci/ctxfi/ctamixer.c b/sound/pci/ctxfi/ctamixer.c index d4ff377eb3a3..da6e6350ceaf 100644 --- a/sound/pci/ctxfi/ctamixer.c +++ b/sound/pci/ctxfi/ctamixer.c @@ -1,5 +1,5 @@ // SPDX-License-Identifier: GPL-2.0-only -/** +/* * Copyright (C) 2008, Creative Technology Ltd. All Rights Reserved. * * @File ctamixer.c diff --git a/sound/pci/ctxfi/ctamixer.h b/sound/pci/ctxfi/ctamixer.h index 4fafb397abed..4498e6139d0e 100644 --- a/sound/pci/ctxfi/ctamixer.h +++ b/sound/pci/ctxfi/ctamixer.h @@ -1,5 +1,5 @@ /* SPDX-License-Identifier: GPL-2.0-only */ -/** +/* * Copyright (C) 2008, Creative Technology Ltd. All Rights Reserved. * * @File ctamixer.h diff --git a/sound/pci/ctxfi/ctatc.c b/sound/pci/ctxfi/ctatc.c index f8ac96cf38a4..78f35e88aed6 100644 --- a/sound/pci/ctxfi/ctatc.c +++ b/sound/pci/ctxfi/ctatc.c @@ -1,5 +1,5 @@ // SPDX-License-Identifier: GPL-2.0-only -/** +/* * Copyright (C) 2008, Creative Technology Ltd. All Rights Reserved. * * @File ctatc.c diff --git a/sound/pci/ctxfi/ctatc.h b/sound/pci/ctxfi/ctatc.h index ac31b32b277b..0bc7b71d910b 100644 --- a/sound/pci/ctxfi/ctatc.h +++ b/sound/pci/ctxfi/ctatc.h @@ -1,5 +1,5 @@ /* SPDX-License-Identifier: GPL-2.0-only */ -/** +/* * Copyright (C) 2008, Creative Technology Ltd. All Rights Reserved. * * @File ctatc.h diff --git a/sound/pci/ctxfi/ctdaio.c b/sound/pci/ctxfi/ctdaio.c index 4cb47b5a792c..f589da045342 100644 --- a/sound/pci/ctxfi/ctdaio.c +++ b/sound/pci/ctxfi/ctdaio.c @@ -1,5 +1,5 @@ // SPDX-License-Identifier: GPL-2.0-only -/** +/* * Copyright (C) 2008, Creative Technology Ltd. All Rights Reserved. * * @File ctdaio.c diff --git a/sound/pci/ctxfi/ctdaio.h b/sound/pci/ctxfi/ctdaio.h index 431583bb0a3e..bd6310f48013 100644 --- a/sound/pci/ctxfi/ctdaio.h +++ b/sound/pci/ctxfi/ctdaio.h @@ -1,5 +1,5 @@ /* SPDX-License-Identifier: GPL-2.0-only */ -/** +/* * Copyright (C) 2008, Creative Technology Ltd. All Rights Reserved. * * @File ctdaio.h diff --git a/sound/pci/ctxfi/cthardware.h b/sound/pci/ctxfi/cthardware.h index 9e6b83bd432d..f406b626a28c 100644 --- a/sound/pci/ctxfi/cthardware.h +++ b/sound/pci/ctxfi/cthardware.h @@ -1,5 +1,5 @@ /* SPDX-License-Identifier: GPL-2.0-only */ -/** +/* * Copyright (C) 2008, Creative Technology Ltd. All Rights Reserved. * * @File cthardware.h diff --git a/sound/pci/ctxfi/cthw20k1.h b/sound/pci/ctxfi/cthw20k1.h index b7cbe82d71bd..ffb019abf651 100644 --- a/sound/pci/ctxfi/cthw20k1.h +++ b/sound/pci/ctxfi/cthw20k1.h @@ -1,5 +1,5 @@ /* SPDX-License-Identifier: GPL-2.0-only */ -/** +/* * Copyright (C) 2008, Creative Technology Ltd. All Rights Reserved. * * @File cthw20k1.h diff --git a/sound/pci/ctxfi/cthw20k2.h b/sound/pci/ctxfi/cthw20k2.h index 797b13dcd84c..6993a3d5277a 100644 --- a/sound/pci/ctxfi/cthw20k2.h +++ b/sound/pci/ctxfi/cthw20k2.h @@ -1,5 +1,5 @@ /* SPDX-License-Identifier: GPL-2.0-only */ -/** +/* * Copyright (C) 2008, Creative Technology Ltd. All Rights Reserved. * * @File cthw20k2.h diff --git a/sound/pci/ctxfi/ctimap.h b/sound/pci/ctxfi/ctimap.h index 79bc94bce4d5..49b1bb831410 100644 --- a/sound/pci/ctxfi/ctimap.h +++ b/sound/pci/ctxfi/ctimap.h @@ -1,5 +1,5 @@ /* SPDX-License-Identifier: GPL-2.0-only */ -/** +/* * Copyright (C) 2008, Creative Technology Ltd. All Rights Reserved. * * @File ctimap.h diff --git a/sound/pci/ctxfi/ctmixer.h b/sound/pci/ctxfi/ctmixer.h index 770dc18a85e8..e812f6c93b41 100644 --- a/sound/pci/ctxfi/ctmixer.h +++ b/sound/pci/ctxfi/ctmixer.h @@ -1,5 +1,5 @@ /* SPDX-License-Identifier: GPL-2.0-only */ -/** +/* * Copyright (C) 2008, Creative Technology Ltd. All Rights Reserved. * * @File ctmixer.h diff --git a/sound/pci/ctxfi/ctpcm.h b/sound/pci/ctxfi/ctpcm.h index dfa1c62f7d1e..8b39bdd262b4 100644 --- a/sound/pci/ctxfi/ctpcm.h +++ b/sound/pci/ctxfi/ctpcm.h @@ -1,5 +1,5 @@ /* SPDX-License-Identifier: GPL-2.0-only */ -/** +/* * Copyright (C) 2008, Creative Technology Ltd. All Rights Reserved. * * @File ctpcm.h diff --git a/sound/pci/ctxfi/ctresource.c b/sound/pci/ctxfi/ctresource.c index 6d0a01b189e1..81ad26934518 100644 --- a/sound/pci/ctxfi/ctresource.c +++ b/sound/pci/ctxfi/ctresource.c @@ -1,5 +1,5 @@ // SPDX-License-Identifier: GPL-2.0-only -/** +/* * Copyright (C) 2008, Creative Technology Ltd. All Rights Reserved. * * @File ctresource.c diff --git a/sound/pci/ctxfi/ctresource.h b/sound/pci/ctxfi/ctresource.h index 93e47488a1c1..fdbfd808816d 100644 --- a/sound/pci/ctxfi/ctresource.h +++ b/sound/pci/ctxfi/ctresource.h @@ -1,5 +1,5 @@ /* SPDX-License-Identifier: GPL-2.0-only */ -/** +/* * Copyright (C) 2008, Creative Technology Ltd. All Rights Reserved. * * @File ctresource.h diff --git a/sound/pci/ctxfi/ctsrc.c b/sound/pci/ctxfi/ctsrc.c index 37c18ce84974..bd4697b44233 100644 --- a/sound/pci/ctxfi/ctsrc.c +++ b/sound/pci/ctxfi/ctsrc.c @@ -1,5 +1,5 @@ // SPDX-License-Identifier: GPL-2.0-only -/** +/* * Copyright (C) 2008, Creative Technology Ltd. All Rights Reserved. * * @File ctsrc.c diff --git a/sound/pci/ctxfi/ctsrc.h b/sound/pci/ctxfi/ctsrc.h index 1204962280c8..1124daf50c9b 100644 --- a/sound/pci/ctxfi/ctsrc.h +++ b/sound/pci/ctxfi/ctsrc.h @@ -1,5 +1,5 @@ /* SPDX-License-Identifier: GPL-2.0-only */ -/** +/* * Copyright (C) 2008, Creative Technology Ltd. All Rights Reserved. * * @File ctsrc.h diff --git a/sound/pci/ctxfi/ctvmem.c b/sound/pci/ctxfi/ctvmem.c index bde28aa9e139..7a805c4a58e1 100644 --- a/sound/pci/ctxfi/ctvmem.c +++ b/sound/pci/ctxfi/ctvmem.c @@ -1,5 +1,5 @@ // SPDX-License-Identifier: GPL-2.0-only -/** +/* * Copyright (C) 2008, Creative Technology Ltd. All Rights Reserved. * * @File ctvmem.c diff --git a/sound/pci/ctxfi/ctvmem.h b/sound/pci/ctxfi/ctvmem.h index 54818a3c245d..da54cbcdb0be 100644 --- a/sound/pci/ctxfi/ctvmem.h +++ b/sound/pci/ctxfi/ctvmem.h @@ -1,5 +1,5 @@ /* SPDX-License-Identifier: GPL-2.0-only */ -/** +/* * Copyright (C) 2008, Creative Technology Ltd. All Rights Reserved. * * @File ctvmem.h From a46b78247b852345ae4458711a4aec6744a7838c Mon Sep 17 00:00:00 2001 From: Dmitry Osipenko Date: Sun, 14 Mar 2021 18:44:43 +0300 Subject: [PATCH 229/587] ASoC: tegra20: ac97: Add reset control Tegra20 AC97 driver doesn't manage the AC97 controller reset, relying on implicit deassertion of the reset by tegra-clk driver, which needs to be fixed since this behaviour is unacceptable by other Tegra drivers. Add explicit reset control to the Tegra20 AC97 driver. Note that AC97 reset was always specified in Tegra20 device-tree, hence DTB ABI changes aren't required. Signed-off-by: Dmitry Osipenko Link: https://lore.kernel.org/r/20210314154459.15375-2-digetx@gmail.com Signed-off-by: Mark Brown --- sound/soc/tegra/tegra20_ac97.c | 21 +++++++++++++++++++++ sound/soc/tegra/tegra20_ac97.h | 1 + 2 files changed, 22 insertions(+) diff --git a/sound/soc/tegra/tegra20_ac97.c b/sound/soc/tegra/tegra20_ac97.c index 06c728ae17ed..c454a34c15c4 100644 --- a/sound/soc/tegra/tegra20_ac97.c +++ b/sound/soc/tegra/tegra20_ac97.c @@ -21,6 +21,7 @@ #include #include #include +#include #include #include #include @@ -313,6 +314,12 @@ static int tegra20_ac97_platform_probe(struct platform_device *pdev) } dev_set_drvdata(&pdev->dev, ac97); + ac97->reset = devm_reset_control_get_exclusive(&pdev->dev, "ac97"); + if (IS_ERR(ac97->reset)) { + dev_err(&pdev->dev, "Can't retrieve ac97 reset\n"); + return PTR_ERR(ac97->reset); + } + ac97->clk_ac97 = devm_clk_get(&pdev->dev, NULL); if (IS_ERR(ac97->clk_ac97)) { dev_err(&pdev->dev, "Can't retrieve ac97 clock\n"); @@ -364,12 +371,26 @@ static int tegra20_ac97_platform_probe(struct platform_device *pdev) ac97->playback_dma_data.addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES; ac97->playback_dma_data.maxburst = 4; + ret = reset_control_assert(ac97->reset); + if (ret) { + dev_err(&pdev->dev, "Failed to assert AC'97 reset: %d\n", ret); + goto err_clk_put; + } + ret = clk_prepare_enable(ac97->clk_ac97); if (ret) { dev_err(&pdev->dev, "clk_enable failed: %d\n", ret); goto err_clk_put; } + usleep_range(10, 100); + + ret = reset_control_deassert(ac97->reset); + if (ret) { + dev_err(&pdev->dev, "Failed to deassert AC'97 reset: %d\n", ret); + goto err_clk_disable_unprepare; + } + ret = snd_soc_set_ac97_ops(&tegra20_ac97_ops); if (ret) { dev_err(&pdev->dev, "Failed to set AC'97 ops: %d\n", ret); diff --git a/sound/soc/tegra/tegra20_ac97.h b/sound/soc/tegra/tegra20_ac97.h index e467cd1ff2ca..870ea09ff301 100644 --- a/sound/soc/tegra/tegra20_ac97.h +++ b/sound/soc/tegra/tegra20_ac97.h @@ -78,6 +78,7 @@ struct tegra20_ac97 { struct clk *clk_ac97; struct snd_dmaengine_dai_dma_data capture_dma_data; struct snd_dmaengine_dai_dma_data playback_dma_data; + struct reset_control *reset; struct regmap *regmap; int reset_gpio; int sync_gpio; From 9c648ef82d7d4696e80b286d37dae07b67a9a32d Mon Sep 17 00:00:00 2001 From: Dmitry Osipenko Date: Sun, 14 Mar 2021 18:44:44 +0300 Subject: [PATCH 230/587] ASoC: tegra20: i2s: Add reset control The I2S reset may be asserted at a boot time, in particular this is the case on Tegra20 AC100 netbook. Tegra20 I2S driver doesn't manage the reset control and currently it happens to work because reset is implicitly deasserted by the tegra-clk driver when I2S clock is enabled. The I2S permanently stays in a reset once tegra-clk is fixed to not touch the resets, which it shouldn't be doing. Add reset control to the Tegra20 I2S driver. Note that I2S reset was always specified in Tegra20 device-tree, hence DTB ABI changes aren't required. Tested-by: Paul Fertser # T20 AC100 Reported-by: Paul Fertser Signed-off-by: Dmitry Osipenko Link: https://lore.kernel.org/r/20210314154459.15375-3-digetx@gmail.com Signed-off-by: Mark Brown --- sound/soc/tegra/tegra20_i2s.c | 31 +++++++++++++++++++++++++++++++ sound/soc/tegra/tegra20_i2s.h | 1 + 2 files changed, 32 insertions(+) diff --git a/sound/soc/tegra/tegra20_i2s.c b/sound/soc/tegra/tegra20_i2s.c index d7a3d046c8f8..c0af5352b483 100644 --- a/sound/soc/tegra/tegra20_i2s.c +++ b/sound/soc/tegra/tegra20_i2s.c @@ -22,6 +22,7 @@ #include #include #include +#include #include #include #include @@ -37,6 +38,8 @@ static int tegra20_i2s_runtime_suspend(struct device *dev) { struct tegra20_i2s *i2s = dev_get_drvdata(dev); + regcache_cache_only(i2s->regmap, true); + clk_disable_unprepare(i2s->clk_i2s); return 0; @@ -47,13 +50,35 @@ static int tegra20_i2s_runtime_resume(struct device *dev) struct tegra20_i2s *i2s = dev_get_drvdata(dev); int ret; + ret = reset_control_assert(i2s->reset); + if (ret) + return ret; + ret = clk_prepare_enable(i2s->clk_i2s); if (ret) { dev_err(dev, "clk_enable failed: %d\n", ret); return ret; } + usleep_range(10, 100); + + ret = reset_control_deassert(i2s->reset); + if (ret) + goto disable_clocks; + + regcache_cache_only(i2s->regmap, false); + regcache_mark_dirty(i2s->regmap); + + ret = regcache_sync(i2s->regmap); + if (ret) + goto disable_clocks; + return 0; + +disable_clocks: + clk_disable_unprepare(i2s->clk_i2s); + + return ret; } static int tegra20_i2s_set_fmt(struct snd_soc_dai *dai, @@ -339,6 +364,12 @@ static int tegra20_i2s_platform_probe(struct platform_device *pdev) i2s->dai = tegra20_i2s_dai_template; i2s->dai.name = dev_name(&pdev->dev); + i2s->reset = devm_reset_control_get_exclusive(&pdev->dev, "i2s"); + if (IS_ERR(i2s->reset)) { + dev_err(&pdev->dev, "Can't retrieve i2s reset\n"); + return PTR_ERR(i2s->reset); + } + i2s->clk_i2s = clk_get(&pdev->dev, NULL); if (IS_ERR(i2s->clk_i2s)) { dev_err(&pdev->dev, "Can't retrieve i2s clock\n"); diff --git a/sound/soc/tegra/tegra20_i2s.h b/sound/soc/tegra/tegra20_i2s.h index 628d3ca09f42..8233e5fa2eff 100644 --- a/sound/soc/tegra/tegra20_i2s.h +++ b/sound/soc/tegra/tegra20_i2s.h @@ -144,6 +144,7 @@ struct tegra20_i2s { struct snd_dmaengine_dai_dma_data capture_dma_data; struct snd_dmaengine_dai_dma_data playback_dma_data; struct regmap *regmap; + struct reset_control *reset; }; #endif From 0bbcecaaab15a74ba69f93df46c753f2a64eadca Mon Sep 17 00:00:00 2001 From: Dmitry Osipenko Date: Sun, 14 Mar 2021 18:44:45 +0300 Subject: [PATCH 231/587] ASoC: tegra30: i2s: Restore hardware state on runtime PM resume Tegra30 I2S driver syncs regmap cache only on resume from system suspend, but hardware is reset across the runtime suspend because RPM of the parent AHUB driver resets the I2S hardware, hence h/w state is lost after each RPM resume. The problem isn't visible because hardware happens to be fully reprogrammed after each RPM resume. Move hardware syncing to RPM resume in order to restore h/w state properly. Fixes: ed9ce1ed2239 ("ASoC: tegra: ahub: Reset hardware properly") Signed-off-by: Dmitry Osipenko Link: https://lore.kernel.org/r/20210314154459.15375-4-digetx@gmail.com Signed-off-by: Mark Brown --- sound/soc/tegra/tegra30_i2s.c | 40 +++++++++++------------------------ 1 file changed, 12 insertions(+), 28 deletions(-) diff --git a/sound/soc/tegra/tegra30_i2s.c b/sound/soc/tegra/tegra30_i2s.c index 6740df541508..3d22c1be6f3d 100644 --- a/sound/soc/tegra/tegra30_i2s.c +++ b/sound/soc/tegra/tegra30_i2s.c @@ -58,8 +58,18 @@ static int tegra30_i2s_runtime_resume(struct device *dev) } regcache_cache_only(i2s->regmap, false); + regcache_mark_dirty(i2s->regmap); + + ret = regcache_sync(i2s->regmap); + if (ret) + goto disable_clocks; return 0; + +disable_clocks: + clk_disable_unprepare(i2s->clk_i2s); + + return ret; } static int tegra30_i2s_set_fmt(struct snd_soc_dai *dai, @@ -551,37 +561,11 @@ static int tegra30_i2s_platform_remove(struct platform_device *pdev) return 0; } -#ifdef CONFIG_PM_SLEEP -static int tegra30_i2s_suspend(struct device *dev) -{ - struct tegra30_i2s *i2s = dev_get_drvdata(dev); - - regcache_mark_dirty(i2s->regmap); - - return 0; -} - -static int tegra30_i2s_resume(struct device *dev) -{ - struct tegra30_i2s *i2s = dev_get_drvdata(dev); - int ret; - - ret = pm_runtime_get_sync(dev); - if (ret < 0) { - pm_runtime_put(dev); - return ret; - } - ret = regcache_sync(i2s->regmap); - pm_runtime_put(dev); - - return ret; -} -#endif - static const struct dev_pm_ops tegra30_i2s_pm_ops = { SET_RUNTIME_PM_OPS(tegra30_i2s_runtime_suspend, tegra30_i2s_runtime_resume, NULL) - SET_SYSTEM_SLEEP_PM_OPS(tegra30_i2s_suspend, tegra30_i2s_resume) + SET_SYSTEM_SLEEP_PM_OPS(pm_runtime_force_suspend, + pm_runtime_force_resume) }; static struct platform_driver tegra30_i2s_driver = { From 48d71395896d54eec989179dd265e569fcecb15a Mon Sep 17 00:00:00 2001 From: Philipp Zabel Date: Sun, 14 Mar 2021 18:44:46 +0300 Subject: [PATCH 232/587] reset: Add reset_control_bulk API Follow the clock and regulator subsystems' lead and add a bulk API for reset controls. Signed-off-by: Philipp Zabel Tested-by: Dmitry Osipenko Signed-off-by: Dmitry Osipenko Link: https://lore.kernel.org/r/20210314154459.15375-5-digetx@gmail.com Signed-off-by: Mark Brown --- drivers/reset/core.c | 215 ++++++++++++++++++++++++++++ include/linux/reset.h | 315 ++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 530 insertions(+) diff --git a/drivers/reset/core.c b/drivers/reset/core.c index dbf881b586d9..71c1c8264b2d 100644 --- a/drivers/reset/core.c +++ b/drivers/reset/core.c @@ -358,6 +358,30 @@ int reset_control_reset(struct reset_control *rstc) } EXPORT_SYMBOL_GPL(reset_control_reset); +/** + * reset_control_bulk_reset - reset the controlled devices in order + * @num_rstcs: number of entries in rstcs array + * @rstcs: array of struct reset_control_bulk_data with reset controls set + * + * Issue a reset on all provided reset controls, in order. + * + * See also: reset_control_reset() + */ +int reset_control_bulk_reset(int num_rstcs, + struct reset_control_bulk_data *rstcs) +{ + int ret, i; + + for (i = 0; i < num_rstcs; i++) { + ret = reset_control_reset(rstcs[i].rstc); + if (ret) + return ret; + } + + return 0; +} +EXPORT_SYMBOL_GPL(reset_control_bulk_reset); + /** * reset_control_rearm - allow shared reset line to be re-triggered" * @rstc: reset controller @@ -461,6 +485,36 @@ int reset_control_assert(struct reset_control *rstc) } EXPORT_SYMBOL_GPL(reset_control_assert); +/** + * reset_control_bulk_assert - asserts the reset lines in order + * @num_rstcs: number of entries in rstcs array + * @rstcs: array of struct reset_control_bulk_data with reset controls set + * + * Assert the reset lines for all provided reset controls, in order. + * If an assertion fails, already asserted resets are deasserted again. + * + * See also: reset_control_assert() + */ +int reset_control_bulk_assert(int num_rstcs, + struct reset_control_bulk_data *rstcs) +{ + int ret, i; + + for (i = 0; i < num_rstcs; i++) { + ret = reset_control_assert(rstcs[i].rstc); + if (ret) + goto err; + } + + return 0; + +err: + while (i--) + reset_control_deassert(rstcs[i].rstc); + return ret; +} +EXPORT_SYMBOL_GPL(reset_control_bulk_assert); + /** * reset_control_deassert - deasserts the reset line * @rstc: reset controller @@ -511,6 +565,36 @@ int reset_control_deassert(struct reset_control *rstc) } EXPORT_SYMBOL_GPL(reset_control_deassert); +/** + * reset_control_bulk_deassert - deasserts the reset lines in reverse order + * @num_rstcs: number of entries in rstcs array + * @rstcs: array of struct reset_control_bulk_data with reset controls set + * + * Deassert the reset lines for all provided reset controls, in reverse order. + * If a deassertion fails, already deasserted resets are asserted again. + * + * See also: reset_control_deassert() + */ +int reset_control_bulk_deassert(int num_rstcs, + struct reset_control_bulk_data *rstcs) +{ + int ret, i; + + for (i = num_rstcs - 1; i >= 0; i--) { + ret = reset_control_deassert(rstcs[i].rstc); + if (ret) + goto err; + } + + return 0; + +err: + while (i < num_rstcs) + reset_control_assert(rstcs[i++].rstc); + return ret; +} +EXPORT_SYMBOL_GPL(reset_control_bulk_deassert); + /** * reset_control_status - returns a negative errno if not supported, a * positive value if the reset line is asserted, or zero if the reset @@ -588,6 +672,36 @@ int reset_control_acquire(struct reset_control *rstc) } EXPORT_SYMBOL_GPL(reset_control_acquire); +/** + * reset_control_bulk_acquire - acquires reset controls for exclusive use + * @num_rstcs: number of entries in rstcs array + * @rstcs: array of struct reset_control_bulk_data with reset controls set + * + * This is used to explicitly acquire reset controls requested with + * reset_control_bulk_get_exclusive_release() for temporary exclusive use. + * + * See also: reset_control_acquire(), reset_control_bulk_release() + */ +int reset_control_bulk_acquire(int num_rstcs, + struct reset_control_bulk_data *rstcs) +{ + int ret, i; + + for (i = 0; i < num_rstcs; i++) { + ret = reset_control_acquire(rstcs[i].rstc); + if (ret) + goto err; + } + + return 0; + +err: + while (i--) + reset_control_release(rstcs[i].rstc); + return ret; +} +EXPORT_SYMBOL_GPL(reset_control_bulk_acquire); + /** * reset_control_release() - releases exclusive access to a reset control * @rstc: reset control @@ -610,6 +724,26 @@ void reset_control_release(struct reset_control *rstc) } EXPORT_SYMBOL_GPL(reset_control_release); +/** + * reset_control_bulk_release() - releases exclusive access to reset controls + * @num_rstcs: number of entries in rstcs array + * @rstcs: array of struct reset_control_bulk_data with reset controls set + * + * Releases exclusive access right to reset controls previously obtained by a + * call to reset_control_bulk_acquire(). + * + * See also: reset_control_release(), reset_control_bulk_acquire() + */ +void reset_control_bulk_release(int num_rstcs, + struct reset_control_bulk_data *rstcs) +{ + int i; + + for (i = 0; i < num_rstcs; i++) + reset_control_release(rstcs[i].rstc); +} +EXPORT_SYMBOL_GPL(reset_control_bulk_release); + static struct reset_control *__reset_control_get_internal( struct reset_controller_dev *rcdev, unsigned int index, bool shared, bool acquired) @@ -814,6 +948,32 @@ struct reset_control *__reset_control_get(struct device *dev, const char *id, } EXPORT_SYMBOL_GPL(__reset_control_get); +int __reset_control_bulk_get(struct device *dev, int num_rstcs, + struct reset_control_bulk_data *rstcs, + bool shared, bool optional, bool acquired) +{ + int ret, i; + + for (i = 0; i < num_rstcs; i++) { + rstcs[i].rstc = __reset_control_get(dev, rstcs[i].id, 0, + shared, optional, acquired); + if (IS_ERR(rstcs[i].rstc)) { + ret = PTR_ERR(rstcs[i].rstc); + goto err; + } + } + + return 0; + +err: + mutex_lock(&reset_list_mutex); + while (i--) + __reset_control_put_internal(rstcs[i].rstc); + mutex_unlock(&reset_list_mutex); + return ret; +} +EXPORT_SYMBOL_GPL(__reset_control_bulk_get); + static void reset_control_array_put(struct reset_control_array *resets) { int i; @@ -845,6 +1005,23 @@ void reset_control_put(struct reset_control *rstc) } EXPORT_SYMBOL_GPL(reset_control_put); +/** + * reset_control_bulk_put - free the reset controllers + * @num_rstcs: number of entries in rstcs array + * @rstcs: array of struct reset_control_bulk_data with reset controls set + */ +void reset_control_bulk_put(int num_rstcs, struct reset_control_bulk_data *rstcs) +{ + mutex_lock(&reset_list_mutex); + while (num_rstcs--) { + if (IS_ERR_OR_NULL(rstcs[num_rstcs].rstc)) + continue; + __reset_control_put_internal(rstcs[num_rstcs].rstc); + } + mutex_unlock(&reset_list_mutex); +} +EXPORT_SYMBOL_GPL(reset_control_bulk_put); + static void devm_reset_control_release(struct device *dev, void *res) { reset_control_put(*(struct reset_control **)res); @@ -874,6 +1051,44 @@ struct reset_control *__devm_reset_control_get(struct device *dev, } EXPORT_SYMBOL_GPL(__devm_reset_control_get); +struct reset_control_bulk_devres { + int num_rstcs; + struct reset_control_bulk_data *rstcs; +}; + +static void devm_reset_control_bulk_release(struct device *dev, void *res) +{ + struct reset_control_bulk_devres *devres = res; + + reset_control_bulk_put(devres->num_rstcs, devres->rstcs); +} + +int __devm_reset_control_bulk_get(struct device *dev, int num_rstcs, + struct reset_control_bulk_data *rstcs, + bool shared, bool optional, bool acquired) +{ + struct reset_control_bulk_devres *ptr; + int ret; + + ptr = devres_alloc(devm_reset_control_bulk_release, sizeof(*ptr), + GFP_KERNEL); + if (!ptr) + return -ENOMEM; + + ret = __reset_control_bulk_get(dev, num_rstcs, rstcs, shared, optional, acquired); + if (ret < 0) { + devres_free(ptr); + return ret; + } + + ptr->num_rstcs = num_rstcs; + ptr->rstcs = rstcs; + devres_add(dev, ptr); + + return 0; +} +EXPORT_SYMBOL_GPL(__devm_reset_control_bulk_get); + /** * __device_reset - find reset controller associated with the device * and perform reset diff --git a/include/linux/reset.h b/include/linux/reset.h index b9109efa2a5c..46e6372cb431 100644 --- a/include/linux/reset.h +++ b/include/linux/reset.h @@ -10,6 +10,21 @@ struct device; struct device_node; struct reset_control; +/** + * struct reset_control_bulk_data - Data used for bulk reset control operations. + * + * @id: reset control consumer ID + * @rstc: struct reset_control * to store the associated reset control + * + * The reset APIs provide a series of reset_control_bulk_*() API calls as + * a convenience to consumers which require multiple reset controls. + * This structure is used to manage data for these calls. + */ +struct reset_control_bulk_data { + const char *id; + struct reset_control *rstc; +}; + #ifdef CONFIG_RESET_CONTROLLER int reset_control_reset(struct reset_control *rstc); @@ -20,6 +35,12 @@ int reset_control_status(struct reset_control *rstc); int reset_control_acquire(struct reset_control *rstc); void reset_control_release(struct reset_control *rstc); +int reset_control_bulk_reset(int num_rstcs, struct reset_control_bulk_data *rstcs); +int reset_control_bulk_assert(int num_rstcs, struct reset_control_bulk_data *rstcs); +int reset_control_bulk_deassert(int num_rstcs, struct reset_control_bulk_data *rstcs); +int reset_control_bulk_acquire(int num_rstcs, struct reset_control_bulk_data *rstcs); +void reset_control_bulk_release(int num_rstcs, struct reset_control_bulk_data *rstcs); + struct reset_control *__of_reset_control_get(struct device_node *node, const char *id, int index, bool shared, bool optional, bool acquired); @@ -27,10 +48,18 @@ struct reset_control *__reset_control_get(struct device *dev, const char *id, int index, bool shared, bool optional, bool acquired); void reset_control_put(struct reset_control *rstc); +int __reset_control_bulk_get(struct device *dev, int num_rstcs, + struct reset_control_bulk_data *rstcs, + bool shared, bool optional, bool acquired); +void reset_control_bulk_put(int num_rstcs, struct reset_control_bulk_data *rstcs); + int __device_reset(struct device *dev, bool optional); struct reset_control *__devm_reset_control_get(struct device *dev, const char *id, int index, bool shared, bool optional, bool acquired); +int __devm_reset_control_bulk_get(struct device *dev, int num_rstcs, + struct reset_control_bulk_data *rstcs, + bool shared, bool optional, bool acquired); struct reset_control *devm_reset_control_array_get(struct device *dev, bool shared, bool optional); @@ -96,6 +125,48 @@ static inline struct reset_control *__reset_control_get( return optional ? NULL : ERR_PTR(-ENOTSUPP); } +static inline int +reset_control_bulk_reset(int num_rstcs, struct reset_control_bulk_data *rstcs) +{ + return 0; +} + +static inline int +reset_control_bulk_assert(int num_rstcs, struct reset_control_bulk_data *rstcs) +{ + return 0; +} + +static inline int +reset_control_bulk_deassert(int num_rstcs, struct reset_control_bulk_data *rstcs) +{ + return 0; +} + +static inline int +reset_control_bulk_acquire(int num_rstcs, struct reset_control_bulk_data *rstcs) +{ + return 0; +} + +static inline void +reset_control_bulk_release(int num_rstcs, struct reset_control_bulk_data *rstcs) +{ +} + +static inline int +__reset_control_bulk_get(struct device *dev, int num_rstcs, + struct reset_control_bulk_data *rstcs, + bool shared, bool optional, bool acquired) +{ + return optional ? 0 : -EOPNOTSUPP; +} + +static inline void +reset_control_bulk_put(int num_rstcs, struct reset_control_bulk_data *rstcs) +{ +} + static inline struct reset_control *__devm_reset_control_get( struct device *dev, const char *id, int index, bool shared, bool optional, @@ -104,6 +175,14 @@ static inline struct reset_control *__devm_reset_control_get( return optional ? NULL : ERR_PTR(-ENOTSUPP); } +static inline int +__devm_reset_control_bulk_get(struct device *dev, int num_rstcs, + struct reset_control_bulk_data *rstcs, + bool shared, bool optional, bool acquired) +{ + return optional ? 0 : -EOPNOTSUPP; +} + static inline struct reset_control * devm_reset_control_array_get(struct device *dev, bool shared, bool optional) { @@ -155,6 +234,23 @@ __must_check reset_control_get_exclusive(struct device *dev, const char *id) return __reset_control_get(dev, id, 0, false, false, true); } +/** + * reset_control_bulk_get_exclusive - Lookup and obtain exclusive references to + * multiple reset controllers. + * @dev: device to be reset by the controller + * @num_rstcs: number of entries in rstcs array + * @rstcs: array of struct reset_control_bulk_data with reset line names set + * + * Fills the rstcs array with pointers to exclusive reset controls and + * returns 0, or an IS_ERR() condition containing errno. + */ +static inline int __must_check +reset_control_bulk_get_exclusive(struct device *dev, int num_rstcs, + struct reset_control_bulk_data *rstcs) +{ + return __reset_control_bulk_get(dev, num_rstcs, rstcs, false, false, true); +} + /** * reset_control_get_exclusive_released - Lookup and obtain a temoprarily * exclusive reference to a reset @@ -176,6 +272,48 @@ __must_check reset_control_get_exclusive_released(struct device *dev, return __reset_control_get(dev, id, 0, false, false, false); } +/** + * reset_control_bulk_get_exclusive_released - Lookup and obtain temporarily + * exclusive references to multiple reset + * controllers. + * @dev: device to be reset by the controller + * @num_rstcs: number of entries in rstcs array + * @rstcs: array of struct reset_control_bulk_data with reset line names set + * + * Fills the rstcs array with pointers to exclusive reset controls and + * returns 0, or an IS_ERR() condition containing errno. + * reset-controls returned by this function must be acquired via + * reset_control_bulk_acquire() before they can be used and should be released + * via reset_control_bulk_release() afterwards. + */ +static inline int __must_check +reset_control_bulk_get_exclusive_released(struct device *dev, int num_rstcs, + struct reset_control_bulk_data *rstcs) +{ + return __reset_control_bulk_get(dev, num_rstcs, rstcs, false, false, false); +} + +/** + * reset_control_bulk_get_optional_exclusive_released - Lookup and obtain optional + * temporarily exclusive references to multiple + * reset controllers. + * @dev: device to be reset by the controller + * @num_rstcs: number of entries in rstcs array + * @rstcs: array of struct reset_control_bulk_data with reset line names set + * + * Optional variant of reset_control_bulk_get_exclusive_released(). If the + * requested reset is not specified in the device tree, this function returns 0 + * instead of an error and missing rtsc is set to NULL. + * + * See reset_control_bulk_get_exclusive_released() for more information. + */ +static inline int __must_check +reset_control_bulk_get_optional_exclusive_released(struct device *dev, int num_rstcs, + struct reset_control_bulk_data *rstcs) +{ + return __reset_control_bulk_get(dev, num_rstcs, rstcs, false, true, false); +} + /** * reset_control_get_shared - Lookup and obtain a shared reference to a * reset controller. @@ -204,6 +342,23 @@ static inline struct reset_control *reset_control_get_shared( return __reset_control_get(dev, id, 0, true, false, false); } +/** + * reset_control_bulk_get_shared - Lookup and obtain shared references to + * multiple reset controllers. + * @dev: device to be reset by the controller + * @num_rstcs: number of entries in rstcs array + * @rstcs: array of struct reset_control_bulk_data with reset line names set + * + * Fills the rstcs array with pointers to shared reset controls and + * returns 0, or an IS_ERR() condition containing errno. + */ +static inline int __must_check +reset_control_bulk_get_shared(struct device *dev, int num_rstcs, + struct reset_control_bulk_data *rstcs) +{ + return __reset_control_bulk_get(dev, num_rstcs, rstcs, true, false, false); +} + /** * reset_control_get_optional_exclusive - optional reset_control_get_exclusive() * @dev: device to be reset by the controller @@ -221,6 +376,26 @@ static inline struct reset_control *reset_control_get_optional_exclusive( return __reset_control_get(dev, id, 0, false, true, true); } +/** + * reset_control_bulk_get_optional_exclusive - optional + * reset_control_bulk_get_exclusive() + * @dev: device to be reset by the controller + * @num_rstcs: number of entries in rstcs array + * @rstcs: array of struct reset_control_bulk_data with reset line names set + * + * Optional variant of reset_control_bulk_get_exclusive(). If any of the + * requested resets are not specified in the device tree, this function sets + * them to NULL instead of returning an error. + * + * See reset_control_bulk_get_exclusive() for more information. + */ +static inline int __must_check +reset_control_bulk_get_optional_exclusive(struct device *dev, int num_rstcs, + struct reset_control_bulk_data *rstcs) +{ + return __reset_control_bulk_get(dev, num_rstcs, rstcs, false, true, true); +} + /** * reset_control_get_optional_shared - optional reset_control_get_shared() * @dev: device to be reset by the controller @@ -238,6 +413,26 @@ static inline struct reset_control *reset_control_get_optional_shared( return __reset_control_get(dev, id, 0, true, true, false); } +/** + * reset_control_bulk_get_optional_shared - optional + * reset_control_bulk_get_shared() + * @dev: device to be reset by the controller + * @num_rstcs: number of entries in rstcs array + * @rstcs: array of struct reset_control_bulk_data with reset line names set + * + * Optional variant of reset_control_bulk_get_shared(). If the requested resets + * are not specified in the device tree, this function sets them to NULL + * instead of returning an error. + * + * See reset_control_bulk_get_shared() for more information. + */ +static inline int __must_check +reset_control_bulk_get_optional_shared(struct device *dev, int num_rstcs, + struct reset_control_bulk_data *rstcs) +{ + return __reset_control_bulk_get(dev, num_rstcs, rstcs, true, true, false); +} + /** * of_reset_control_get_exclusive - Lookup and obtain an exclusive reference * to a reset controller. @@ -343,6 +538,26 @@ __must_check devm_reset_control_get_exclusive(struct device *dev, return __devm_reset_control_get(dev, id, 0, false, false, true); } +/** + * devm_reset_control_bulk_get_exclusive - resource managed + * reset_control_bulk_get_exclusive() + * @dev: device to be reset by the controller + * @num_rstcs: number of entries in rstcs array + * @rstcs: array of struct reset_control_bulk_data with reset line names set + * + * Managed reset_control_bulk_get_exclusive(). For reset controllers returned + * from this function, reset_control_put() is called automatically on driver + * detach. + * + * See reset_control_bulk_get_exclusive() for more information. + */ +static inline int __must_check +devm_reset_control_bulk_get_exclusive(struct device *dev, int num_rstcs, + struct reset_control_bulk_data *rstcs) +{ + return __devm_reset_control_bulk_get(dev, num_rstcs, rstcs, false, false, true); +} + /** * devm_reset_control_get_exclusive_released - resource managed * reset_control_get_exclusive_released() @@ -362,6 +577,26 @@ __must_check devm_reset_control_get_exclusive_released(struct device *dev, return __devm_reset_control_get(dev, id, 0, false, false, false); } +/** + * devm_reset_control_bulk_get_exclusive_released - resource managed + * reset_control_bulk_get_exclusive_released() + * @dev: device to be reset by the controller + * @num_rstcs: number of entries in rstcs array + * @rstcs: array of struct reset_control_bulk_data with reset line names set + * + * Managed reset_control_bulk_get_exclusive_released(). For reset controllers + * returned from this function, reset_control_put() is called automatically on + * driver detach. + * + * See reset_control_bulk_get_exclusive_released() for more information. + */ +static inline int __must_check +devm_reset_control_bulk_get_exclusive_released(struct device *dev, int num_rstcs, + struct reset_control_bulk_data *rstcs) +{ + return __devm_reset_control_bulk_get(dev, num_rstcs, rstcs, false, false, false); +} + /** * devm_reset_control_get_optional_exclusive_released - resource managed * reset_control_get_optional_exclusive_released() @@ -381,6 +616,26 @@ __must_check devm_reset_control_get_optional_exclusive_released(struct device *d return __devm_reset_control_get(dev, id, 0, false, true, false); } +/** + * devm_reset_control_bulk_get_optional_exclusive_released - resource managed + * reset_control_bulk_optional_get_exclusive_released() + * @dev: device to be reset by the controller + * @num_rstcs: number of entries in rstcs array + * @rstcs: array of struct reset_control_bulk_data with reset line names set + * + * Managed reset_control_bulk_optional_get_exclusive_released(). For reset + * controllers returned from this function, reset_control_put() is called + * automatically on driver detach. + * + * See reset_control_bulk_optional_get_exclusive_released() for more information. + */ +static inline int __must_check +devm_reset_control_bulk_get_optional_exclusive_released(struct device *dev, int num_rstcs, + struct reset_control_bulk_data *rstcs) +{ + return __devm_reset_control_bulk_get(dev, num_rstcs, rstcs, false, true, false); +} + /** * devm_reset_control_get_shared - resource managed reset_control_get_shared() * @dev: device to be reset by the controller @@ -396,6 +651,26 @@ static inline struct reset_control *devm_reset_control_get_shared( return __devm_reset_control_get(dev, id, 0, true, false, false); } +/** + * devm_reset_control_bulk_get_shared - resource managed + * reset_control_bulk_get_shared() + * @dev: device to be reset by the controller + * @num_rstcs: number of entries in rstcs array + * @rstcs: array of struct reset_control_bulk_data with reset line names set + * + * Managed reset_control_bulk_get_shared(). For reset controllers returned + * from this function, reset_control_put() is called automatically on driver + * detach. + * + * See reset_control_bulk_get_shared() for more information. + */ +static inline int __must_check +devm_reset_control_bulk_get_shared(struct device *dev, int num_rstcs, + struct reset_control_bulk_data *rstcs) +{ + return __devm_reset_control_bulk_get(dev, num_rstcs, rstcs, true, false, false); +} + /** * devm_reset_control_get_optional_exclusive - resource managed * reset_control_get_optional_exclusive() @@ -414,6 +689,26 @@ static inline struct reset_control *devm_reset_control_get_optional_exclusive( return __devm_reset_control_get(dev, id, 0, false, true, true); } +/** + * devm_reset_control_bulk_get_optional_exclusive - resource managed + * reset_control_bulk_get_optional_exclusive() + * @dev: device to be reset by the controller + * @num_rstcs: number of entries in rstcs array + * @rstcs: array of struct reset_control_bulk_data with reset line names set + * + * Managed reset_control_bulk_get_optional_exclusive(). For reset controllers + * returned from this function, reset_control_put() is called automatically on + * driver detach. + * + * See reset_control_bulk_get_optional_exclusive() for more information. + */ +static inline int __must_check +devm_reset_control_bulk_get_optional_exclusive(struct device *dev, int num_rstcs, + struct reset_control_bulk_data *rstcs) +{ + return __devm_reset_control_bulk_get(dev, num_rstcs, rstcs, true, false, true); +} + /** * devm_reset_control_get_optional_shared - resource managed * reset_control_get_optional_shared() @@ -432,6 +727,26 @@ static inline struct reset_control *devm_reset_control_get_optional_shared( return __devm_reset_control_get(dev, id, 0, true, true, false); } +/** + * devm_reset_control_bulk_get_optional_shared - resource managed + * reset_control_bulk_get_optional_shared() + * @dev: device to be reset by the controller + * @num_rstcs: number of entries in rstcs array + * @rstcs: array of struct reset_control_bulk_data with reset line names set + * + * Managed reset_control_bulk_get_optional_shared(). For reset controllers + * returned from this function, reset_control_put() is called automatically on + * driver detach. + * + * See reset_control_bulk_get_optional_shared() for more information. + */ +static inline int __must_check +devm_reset_control_bulk_get_optional_shared(struct device *dev, int num_rstcs, + struct reset_control_bulk_data *rstcs) +{ + return __devm_reset_control_bulk_get(dev, num_rstcs, rstcs, true, true, false); +} + /** * devm_reset_control_get_exclusive_by_index - resource managed * reset_control_get_exclusive() From 050086eb6dc945207b1db1d15cd81e9366dfd2f1 Mon Sep 17 00:00:00 2001 From: Dmitry Osipenko Date: Sun, 14 Mar 2021 18:44:47 +0300 Subject: [PATCH 233/587] ASoC: tegra30: ahub: Switch to use reset-bulk API Switch to use reset-bulk API in order to make code cleaner. Signed-off-by: Dmitry Osipenko Link: https://lore.kernel.org/r/20210314154459.15375-6-digetx@gmail.com Signed-off-by: Mark Brown --- sound/soc/tegra/tegra30_ahub.c | 104 ++++++++++++--------------------- sound/soc/tegra/tegra30_ahub.h | 5 +- sound/soc/tegra/tegra30_i2s.c | 1 + 3 files changed, 40 insertions(+), 70 deletions(-) diff --git a/sound/soc/tegra/tegra30_ahub.c b/sound/soc/tegra/tegra30_ahub.c index 9ef05ca4f6c4..d24c26f4960d 100644 --- a/sound/soc/tegra/tegra30_ahub.c +++ b/sound/soc/tegra/tegra30_ahub.c @@ -65,7 +65,7 @@ static int tegra30_ahub_runtime_resume(struct device *dev) { int ret; - ret = reset_control_assert(ahub->reset); + ret = reset_control_bulk_assert(ahub->nresets, ahub->resets); if (ret) return ret; @@ -75,7 +75,7 @@ static int tegra30_ahub_runtime_resume(struct device *dev) usleep_range(10, 100); - ret = reset_control_deassert(ahub->reset); + ret = reset_control_bulk_deassert(ahub->nresets, ahub->resets); if (ret) goto disable_clocks; @@ -339,41 +339,28 @@ int tegra30_ahub_unset_rx_cif_source(enum tegra30_ahub_rxcif rxcif) } EXPORT_SYMBOL_GPL(tegra30_ahub_unset_rx_cif_source); -#define MOD_LIST_MASK_TEGRA30 BIT(0) -#define MOD_LIST_MASK_TEGRA114 BIT(1) -#define MOD_LIST_MASK_TEGRA124 BIT(2) - -#define MOD_LIST_MASK_TEGRA30_OR_LATER \ - (MOD_LIST_MASK_TEGRA30 | MOD_LIST_MASK_TEGRA114 | \ - MOD_LIST_MASK_TEGRA124) -#define MOD_LIST_MASK_TEGRA114_OR_LATER \ - (MOD_LIST_MASK_TEGRA114 | MOD_LIST_MASK_TEGRA124) - -static const struct { - const char *rst_name; - u32 mod_list_mask; -} configlink_mods[] = { - { "d_audio", MOD_LIST_MASK_TEGRA30_OR_LATER }, - { "apbif", MOD_LIST_MASK_TEGRA30_OR_LATER }, - { "i2s0", MOD_LIST_MASK_TEGRA30_OR_LATER }, - { "i2s1", MOD_LIST_MASK_TEGRA30_OR_LATER }, - { "i2s2", MOD_LIST_MASK_TEGRA30_OR_LATER }, - { "i2s3", MOD_LIST_MASK_TEGRA30_OR_LATER }, - { "i2s4", MOD_LIST_MASK_TEGRA30_OR_LATER }, - { "dam0", MOD_LIST_MASK_TEGRA30_OR_LATER }, - { "dam1", MOD_LIST_MASK_TEGRA30_OR_LATER }, - { "dam2", MOD_LIST_MASK_TEGRA30_OR_LATER }, - { "spdif", MOD_LIST_MASK_TEGRA30_OR_LATER }, - { "amx", MOD_LIST_MASK_TEGRA114_OR_LATER }, - { "adx", MOD_LIST_MASK_TEGRA114_OR_LATER }, - { "amx1", MOD_LIST_MASK_TEGRA124 }, - { "adx1", MOD_LIST_MASK_TEGRA124 }, - { "afc0", MOD_LIST_MASK_TEGRA124 }, - { "afc1", MOD_LIST_MASK_TEGRA124 }, - { "afc2", MOD_LIST_MASK_TEGRA124 }, - { "afc3", MOD_LIST_MASK_TEGRA124 }, - { "afc4", MOD_LIST_MASK_TEGRA124 }, - { "afc5", MOD_LIST_MASK_TEGRA124 }, +static const struct reset_control_bulk_data tegra30_ahub_resets_data[] = { + { "d_audio" }, + { "apbif" }, + { "i2s0" }, + { "i2s1" }, + { "i2s2" }, + { "i2s3" }, + { "i2s4" }, + { "dam0" }, + { "dam1" }, + { "dam2" }, + { "spdif" }, + { "amx" }, /* Tegra114+ */ + { "adx" }, /* Tegra114+ */ + { "amx1" }, /* Tegra124 */ + { "adx1" }, /* Tegra124 */ + { "afc0" }, /* Tegra124 */ + { "afc1" }, /* Tegra124 */ + { "afc2" }, /* Tegra124 */ + { "afc3" }, /* Tegra124 */ + { "afc4" }, /* Tegra124 */ + { "afc5" }, /* Tegra124 */ }; #define LAST_REG(name) \ @@ -502,17 +489,17 @@ static const struct regmap_config tegra30_ahub_ahub_regmap_config = { }; static struct tegra30_ahub_soc_data soc_data_tegra30 = { - .mod_list_mask = MOD_LIST_MASK_TEGRA30, + .num_resets = 11, .set_audio_cif = tegra30_ahub_set_cif, }; static struct tegra30_ahub_soc_data soc_data_tegra114 = { - .mod_list_mask = MOD_LIST_MASK_TEGRA114, + .num_resets = 13, .set_audio_cif = tegra30_ahub_set_cif, }; static struct tegra30_ahub_soc_data soc_data_tegra124 = { - .mod_list_mask = MOD_LIST_MASK_TEGRA124, + .num_resets = 21, .set_audio_cif = tegra124_ahub_set_cif, }; @@ -527,8 +514,6 @@ static int tegra30_ahub_probe(struct platform_device *pdev) { const struct of_device_id *match; const struct tegra30_ahub_soc_data *soc_data; - struct reset_control *rst; - int i; struct resource *res0; void __iomem *regs_apbif, *regs_ahub; int ret = 0; @@ -541,34 +526,16 @@ static int tegra30_ahub_probe(struct platform_device *pdev) return -EINVAL; soc_data = match->data; - /* - * The AHUB hosts a register bus: the "configlink". For this to - * operate correctly, all devices on this bus must be out of reset. - */ - for (i = 0; i < ARRAY_SIZE(configlink_mods); i++) { - if (!(configlink_mods[i].mod_list_mask & - soc_data->mod_list_mask)) - continue; - - rst = reset_control_get_exclusive(&pdev->dev, - configlink_mods[i].rst_name); - if (IS_ERR(rst)) { - dev_err(&pdev->dev, "Can't get reset %s\n", - configlink_mods[i].rst_name); - ret = PTR_ERR(rst); - return ret; - } - - /* just check presence of the reset control in DT */ - reset_control_put(rst); - } - ahub = devm_kzalloc(&pdev->dev, sizeof(struct tegra30_ahub), GFP_KERNEL); if (!ahub) return -ENOMEM; dev_set_drvdata(&pdev->dev, ahub); + BUILD_BUG_ON(sizeof(ahub->resets) != sizeof(tegra30_ahub_resets_data)); + memcpy(ahub->resets, tegra30_ahub_resets_data, sizeof(ahub->resets)); + + ahub->nresets = soc_data->num_resets; ahub->soc_data = soc_data; ahub->dev = &pdev->dev; @@ -579,10 +546,11 @@ static int tegra30_ahub_probe(struct platform_device *pdev) if (ret) return ret; - ahub->reset = devm_reset_control_array_get_exclusive(&pdev->dev); - if (IS_ERR(ahub->reset)) { - dev_err(&pdev->dev, "Can't get resets: %pe\n", ahub->reset); - return PTR_ERR(ahub->reset); + ret = devm_reset_control_bulk_get_exclusive(&pdev->dev, ahub->nresets, + ahub->resets); + if (ret) { + dev_err(&pdev->dev, "Can't get resets: %d\n", ret); + return ret; } res0 = platform_get_resource(pdev, IORESOURCE_MEM, 0); diff --git a/sound/soc/tegra/tegra30_ahub.h b/sound/soc/tegra/tegra30_ahub.h index 3b85244f87f1..c9eaf4ec8f6e 100644 --- a/sound/soc/tegra/tegra30_ahub.h +++ b/sound/soc/tegra/tegra30_ahub.h @@ -491,7 +491,7 @@ void tegra124_ahub_set_cif(struct regmap *regmap, unsigned int reg, struct tegra30_ahub_cif_conf *conf); struct tegra30_ahub_soc_data { - u32 mod_list_mask; + unsigned int num_resets; void (*set_audio_cif)(struct regmap *regmap, unsigned int reg, struct tegra30_ahub_cif_conf *conf); @@ -511,7 +511,8 @@ struct tegra30_ahub_soc_data { struct tegra30_ahub { const struct tegra30_ahub_soc_data *soc_data; struct device *dev; - struct reset_control *reset; + struct reset_control_bulk_data resets[21]; + unsigned int nresets; struct clk_bulk_data clocks[2]; unsigned int nclocks; resource_size_t apbif_addr; diff --git a/sound/soc/tegra/tegra30_i2s.c b/sound/soc/tegra/tegra30_i2s.c index 3d22c1be6f3d..614b67be1dd9 100644 --- a/sound/soc/tegra/tegra30_i2s.c +++ b/sound/soc/tegra/tegra30_i2s.c @@ -23,6 +23,7 @@ #include #include #include +#include #include #include #include From 0911f154a2ae264ee2a7c868c1267a102396d016 Mon Sep 17 00:00:00 2001 From: Dmitry Osipenko Date: Sun, 14 Mar 2021 18:44:48 +0300 Subject: [PATCH 234/587] ASoC: tegra20: spdif: Correct driver removal order Tegra20 SPDIF driver has a wrong driver removal order, which should be opposite to the registration order, but it's not. In particular the runtime PM is disabled in a wrong order. Fix the order. Signed-off-by: Dmitry Osipenko Link: https://lore.kernel.org/r/20210314154459.15375-7-digetx@gmail.com Signed-off-by: Mark Brown --- sound/soc/tegra/tegra20_spdif.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/sound/soc/tegra/tegra20_spdif.c b/sound/soc/tegra/tegra20_spdif.c index 5839833e23a0..e48d332506a0 100644 --- a/sound/soc/tegra/tegra20_spdif.c +++ b/sound/soc/tegra/tegra20_spdif.c @@ -329,13 +329,13 @@ err_pm_disable: static int tegra20_spdif_platform_remove(struct platform_device *pdev) { + tegra_pcm_platform_unregister(&pdev->dev); + snd_soc_unregister_component(&pdev->dev); + pm_runtime_disable(&pdev->dev); if (!pm_runtime_status_suspended(&pdev->dev)) tegra20_spdif_runtime_suspend(&pdev->dev); - tegra_pcm_platform_unregister(&pdev->dev); - snd_soc_unregister_component(&pdev->dev); - return 0; } From c53b396f0dd49a626ea2b1fc0a8b9e0a0bf95d4d Mon Sep 17 00:00:00 2001 From: Dmitry Osipenko Date: Sun, 14 Mar 2021 18:44:49 +0300 Subject: [PATCH 235/587] ASoC: tegra20: spdif: Remove handing of disabled runtime PM Runtime PM is always available on Tegra since commit 40b2bb1b132a ("ARM: tegra: enforce PM requirement"), hence there is no need to handle the case of a disabled RPM by Tegra drivers. Remove handing of a disabled runtime PM from Tegra20 SPDIF driver. Signed-off-by: Dmitry Osipenko Link: https://lore.kernel.org/r/20210314154459.15375-8-digetx@gmail.com Signed-off-by: Mark Brown --- sound/soc/tegra/tegra20_spdif.c | 12 +----------- 1 file changed, 1 insertion(+), 11 deletions(-) diff --git a/sound/soc/tegra/tegra20_spdif.c b/sound/soc/tegra/tegra20_spdif.c index e48d332506a0..7b597ee63cb5 100644 --- a/sound/soc/tegra/tegra20_spdif.c +++ b/sound/soc/tegra/tegra20_spdif.c @@ -294,18 +294,13 @@ static int tegra20_spdif_platform_probe(struct platform_device *pdev) spdif->playback_dma_data.slave_id = dmareq->start; pm_runtime_enable(&pdev->dev); - if (!pm_runtime_enabled(&pdev->dev)) { - ret = tegra20_spdif_runtime_resume(&pdev->dev); - if (ret) - goto err_pm_disable; - } ret = snd_soc_register_component(&pdev->dev, &tegra20_spdif_component, &tegra20_spdif_dai, 1); if (ret) { dev_err(&pdev->dev, "Could not register DAI: %d\n", ret); ret = -ENOMEM; - goto err_suspend; + goto err_pm_disable; } ret = tegra_pcm_platform_register(&pdev->dev); @@ -318,9 +313,6 @@ static int tegra20_spdif_platform_probe(struct platform_device *pdev) err_unregister_component: snd_soc_unregister_component(&pdev->dev); -err_suspend: - if (!pm_runtime_status_suspended(&pdev->dev)) - tegra20_spdif_runtime_suspend(&pdev->dev); err_pm_disable: pm_runtime_disable(&pdev->dev); @@ -333,8 +325,6 @@ static int tegra20_spdif_platform_remove(struct platform_device *pdev) snd_soc_unregister_component(&pdev->dev); pm_runtime_disable(&pdev->dev); - if (!pm_runtime_status_suspended(&pdev->dev)) - tegra20_spdif_runtime_suspend(&pdev->dev); return 0; } From e33fdd9bee12be35d080bfd4acc9d1e3a0d04001 Mon Sep 17 00:00:00 2001 From: Dmitry Osipenko Date: Sun, 14 Mar 2021 18:44:50 +0300 Subject: [PATCH 236/587] ASoC: tegra20: i2s: Add system level suspend-resume callbacks Add system level suspend-resume callbacks in order to ensure that I2S is gated before system is suspended. This puts Tegra20 I2S driver on par with the Tegra30 I2S driver. Signed-off-by: Dmitry Osipenko Link: https://lore.kernel.org/r/20210314154459.15375-9-digetx@gmail.com Signed-off-by: Mark Brown --- sound/soc/tegra/tegra20_i2s.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/sound/soc/tegra/tegra20_i2s.c b/sound/soc/tegra/tegra20_i2s.c index c0af5352b483..267517446d27 100644 --- a/sound/soc/tegra/tegra20_i2s.c +++ b/sound/soc/tegra/tegra20_i2s.c @@ -460,6 +460,8 @@ static const struct of_device_id tegra20_i2s_of_match[] = { static const struct dev_pm_ops tegra20_i2s_pm_ops = { SET_RUNTIME_PM_OPS(tegra20_i2s_runtime_suspend, tegra20_i2s_runtime_resume, NULL) + SET_SYSTEM_SLEEP_PM_OPS(pm_runtime_force_suspend, + pm_runtime_force_resume) }; static struct platform_driver tegra20_i2s_driver = { From ca6e960ed6b10ba9236da8b3614574bb4524c65e Mon Sep 17 00:00:00 2001 From: Dmitry Osipenko Date: Sun, 14 Mar 2021 18:44:51 +0300 Subject: [PATCH 237/587] ASoC: tegra20: i2s: Correct driver removal order Tegra20 I2S driver has a wrong driver removal order, which should be opposite to the registration order, but it's not. In particular the runtime PM is disabled in a wrong order. Fix the order. Signed-off-by: Dmitry Osipenko Link: https://lore.kernel.org/r/20210314154459.15375-10-digetx@gmail.com Signed-off-by: Mark Brown --- sound/soc/tegra/tegra20_i2s.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/sound/soc/tegra/tegra20_i2s.c b/sound/soc/tegra/tegra20_i2s.c index 267517446d27..0f2bdc2e8598 100644 --- a/sound/soc/tegra/tegra20_i2s.c +++ b/sound/soc/tegra/tegra20_i2s.c @@ -440,13 +440,13 @@ static int tegra20_i2s_platform_remove(struct platform_device *pdev) { struct tegra20_i2s *i2s = dev_get_drvdata(&pdev->dev); + tegra_pcm_platform_unregister(&pdev->dev); + snd_soc_unregister_component(&pdev->dev); + pm_runtime_disable(&pdev->dev); if (!pm_runtime_status_suspended(&pdev->dev)) tegra20_i2s_runtime_suspend(&pdev->dev); - tegra_pcm_platform_unregister(&pdev->dev); - snd_soc_unregister_component(&pdev->dev); - clk_put(i2s->clk_i2s); return 0; From d3c6ef98dadd1e500445e4c5a9d684cbf3182c7d Mon Sep 17 00:00:00 2001 From: Dmitry Osipenko Date: Sun, 14 Mar 2021 18:44:52 +0300 Subject: [PATCH 238/587] ASoC: tegra20: i2s: Use devm_clk_get() Use resource-managed variant of clk_get() to simplify code. Signed-off-by: Dmitry Osipenko Link: https://lore.kernel.org/r/20210314154459.15375-11-digetx@gmail.com Signed-off-by: Mark Brown --- sound/soc/tegra/tegra20_i2s.c | 12 +++--------- 1 file changed, 3 insertions(+), 9 deletions(-) diff --git a/sound/soc/tegra/tegra20_i2s.c b/sound/soc/tegra/tegra20_i2s.c index 0f2bdc2e8598..fe569198b17a 100644 --- a/sound/soc/tegra/tegra20_i2s.c +++ b/sound/soc/tegra/tegra20_i2s.c @@ -370,7 +370,7 @@ static int tegra20_i2s_platform_probe(struct platform_device *pdev) return PTR_ERR(i2s->reset); } - i2s->clk_i2s = clk_get(&pdev->dev, NULL); + i2s->clk_i2s = devm_clk_get(&pdev->dev, NULL); if (IS_ERR(i2s->clk_i2s)) { dev_err(&pdev->dev, "Can't retrieve i2s clock\n"); ret = PTR_ERR(i2s->clk_i2s); @@ -381,7 +381,7 @@ static int tegra20_i2s_platform_probe(struct platform_device *pdev) regs = devm_ioremap_resource(&pdev->dev, mem); if (IS_ERR(regs)) { ret = PTR_ERR(regs); - goto err_clk_put; + goto err; } i2s->regmap = devm_regmap_init_mmio(&pdev->dev, regs, @@ -389,7 +389,7 @@ static int tegra20_i2s_platform_probe(struct platform_device *pdev) if (IS_ERR(i2s->regmap)) { dev_err(&pdev->dev, "regmap init failed\n"); ret = PTR_ERR(i2s->regmap); - goto err_clk_put; + goto err; } i2s->capture_dma_data.addr = mem->start + TEGRA20_I2S_FIFO2; @@ -430,16 +430,12 @@ err_suspend: tegra20_i2s_runtime_suspend(&pdev->dev); err_pm_disable: pm_runtime_disable(&pdev->dev); -err_clk_put: - clk_put(i2s->clk_i2s); err: return ret; } static int tegra20_i2s_platform_remove(struct platform_device *pdev) { - struct tegra20_i2s *i2s = dev_get_drvdata(&pdev->dev); - tegra_pcm_platform_unregister(&pdev->dev); snd_soc_unregister_component(&pdev->dev); @@ -447,8 +443,6 @@ static int tegra20_i2s_platform_remove(struct platform_device *pdev) if (!pm_runtime_status_suspended(&pdev->dev)) tegra20_i2s_runtime_suspend(&pdev->dev); - clk_put(i2s->clk_i2s); - return 0; } From 80ec4a4cb36d3f8bb56b5aa89faceb1145ef7aea Mon Sep 17 00:00:00 2001 From: Dmitry Osipenko Date: Sun, 14 Mar 2021 18:44:53 +0300 Subject: [PATCH 239/587] ASoC: tegra20: i2s: Remove handing of disabled runtime PM Runtime PM is always available on Tegra since commit 40b2bb1b132a ("ARM: tegra: enforce PM requirement"), hence there is no need to handle the case of a disabled RPM by Tegra drivers. Remove handing of a disabled runtime PM from Tegra20 I2S driver. Signed-off-by: Dmitry Osipenko Link: https://lore.kernel.org/r/20210314154459.15375-12-digetx@gmail.com Signed-off-by: Mark Brown --- sound/soc/tegra/tegra20_i2s.c | 13 +------------ 1 file changed, 1 insertion(+), 12 deletions(-) diff --git a/sound/soc/tegra/tegra20_i2s.c b/sound/soc/tegra/tegra20_i2s.c index fe569198b17a..1b27f81c10fe 100644 --- a/sound/soc/tegra/tegra20_i2s.c +++ b/sound/soc/tegra/tegra20_i2s.c @@ -401,18 +401,13 @@ static int tegra20_i2s_platform_probe(struct platform_device *pdev) i2s->playback_dma_data.maxburst = 4; pm_runtime_enable(&pdev->dev); - if (!pm_runtime_enabled(&pdev->dev)) { - ret = tegra20_i2s_runtime_resume(&pdev->dev); - if (ret) - goto err_pm_disable; - } ret = snd_soc_register_component(&pdev->dev, &tegra20_i2s_component, &i2s->dai, 1); if (ret) { dev_err(&pdev->dev, "Could not register DAI: %d\n", ret); ret = -ENOMEM; - goto err_suspend; + goto err_pm_disable; } ret = tegra_pcm_platform_register(&pdev->dev); @@ -425,9 +420,6 @@ static int tegra20_i2s_platform_probe(struct platform_device *pdev) err_unregister_component: snd_soc_unregister_component(&pdev->dev); -err_suspend: - if (!pm_runtime_status_suspended(&pdev->dev)) - tegra20_i2s_runtime_suspend(&pdev->dev); err_pm_disable: pm_runtime_disable(&pdev->dev); err: @@ -438,10 +430,7 @@ static int tegra20_i2s_platform_remove(struct platform_device *pdev) { tegra_pcm_platform_unregister(&pdev->dev); snd_soc_unregister_component(&pdev->dev); - pm_runtime_disable(&pdev->dev); - if (!pm_runtime_status_suspended(&pdev->dev)) - tegra20_i2s_runtime_suspend(&pdev->dev); return 0; } From f852e1e4acf4ebde4c960bab6f89407fa18ca489 Mon Sep 17 00:00:00 2001 From: Dmitry Osipenko Date: Sun, 14 Mar 2021 18:44:54 +0300 Subject: [PATCH 240/587] ASoC: tegra30: i2s: Correct driver removal order Tegra30 I2S driver has a wrong driver removal order, which should be opposite to the registration order, but it's not. In particular the runtime PM is disabled in a wrong order. Fix the order. Signed-off-by: Dmitry Osipenko Link: https://lore.kernel.org/r/20210314154459.15375-13-digetx@gmail.com Signed-off-by: Mark Brown --- sound/soc/tegra/tegra30_i2s.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/sound/soc/tegra/tegra30_i2s.c b/sound/soc/tegra/tegra30_i2s.c index 614b67be1dd9..31e08c5c1405 100644 --- a/sound/soc/tegra/tegra30_i2s.c +++ b/sound/soc/tegra/tegra30_i2s.c @@ -544,10 +544,6 @@ static int tegra30_i2s_platform_remove(struct platform_device *pdev) { struct tegra30_i2s *i2s = dev_get_drvdata(&pdev->dev); - pm_runtime_disable(&pdev->dev); - if (!pm_runtime_status_suspended(&pdev->dev)) - tegra30_i2s_runtime_suspend(&pdev->dev); - tegra_pcm_platform_unregister(&pdev->dev); snd_soc_unregister_component(&pdev->dev); @@ -557,6 +553,10 @@ static int tegra30_i2s_platform_remove(struct platform_device *pdev) tegra30_ahub_unset_rx_cif_source(i2s->playback_i2s_cif); tegra30_ahub_free_tx_fifo(i2s->playback_fifo_cif); + pm_runtime_disable(&pdev->dev); + if (!pm_runtime_status_suspended(&pdev->dev)) + tegra30_i2s_runtime_suspend(&pdev->dev); + clk_put(i2s->clk_i2s); return 0; From 52674aef9eb678f30d99f77fd53f6c564d5e2d92 Mon Sep 17 00:00:00 2001 From: Dmitry Osipenko Date: Sun, 14 Mar 2021 18:44:55 +0300 Subject: [PATCH 241/587] ASoC: tegra30: i2s: Use devm_clk_get() Use resource-managed variant of clk_get() to simplify code. Signed-off-by: Dmitry Osipenko Link: https://lore.kernel.org/r/20210314154459.15375-14-digetx@gmail.com Signed-off-by: Mark Brown --- sound/soc/tegra/tegra30_i2s.c | 10 +++------- 1 file changed, 3 insertions(+), 7 deletions(-) diff --git a/sound/soc/tegra/tegra30_i2s.c b/sound/soc/tegra/tegra30_i2s.c index 31e08c5c1405..0ed982548ce4 100644 --- a/sound/soc/tegra/tegra30_i2s.c +++ b/sound/soc/tegra/tegra30_i2s.c @@ -438,7 +438,7 @@ static int tegra30_i2s_platform_probe(struct platform_device *pdev) i2s->playback_i2s_cif = cif_ids[0]; i2s->capture_i2s_cif = cif_ids[1]; - i2s->clk_i2s = clk_get(&pdev->dev, NULL); + i2s->clk_i2s = devm_clk_get(&pdev->dev, NULL); if (IS_ERR(i2s->clk_i2s)) { dev_err(&pdev->dev, "Can't retrieve i2s clock\n"); ret = PTR_ERR(i2s->clk_i2s); @@ -448,7 +448,7 @@ static int tegra30_i2s_platform_probe(struct platform_device *pdev) regs = devm_platform_ioremap_resource(pdev, 0); if (IS_ERR(regs)) { ret = PTR_ERR(regs); - goto err_clk_put; + goto err; } i2s->regmap = devm_regmap_init_mmio(&pdev->dev, regs, @@ -456,7 +456,7 @@ static int tegra30_i2s_platform_probe(struct platform_device *pdev) if (IS_ERR(i2s->regmap)) { dev_err(&pdev->dev, "regmap init failed\n"); ret = PTR_ERR(i2s->regmap); - goto err_clk_put; + goto err; } regcache_cache_only(i2s->regmap, true); @@ -534,8 +534,6 @@ err_suspend: tegra30_i2s_runtime_suspend(&pdev->dev); err_pm_disable: pm_runtime_disable(&pdev->dev); -err_clk_put: - clk_put(i2s->clk_i2s); err: return ret; } @@ -557,8 +555,6 @@ static int tegra30_i2s_platform_remove(struct platform_device *pdev) if (!pm_runtime_status_suspended(&pdev->dev)) tegra30_i2s_runtime_suspend(&pdev->dev); - clk_put(i2s->clk_i2s); - return 0; } From b5f6f781fcb27b3ae5a2f04312a190115b5cbbd1 Mon Sep 17 00:00:00 2001 From: Dmitry Osipenko Date: Sun, 14 Mar 2021 18:44:56 +0300 Subject: [PATCH 242/587] ASoC: tegra30: i2s: Remove handing of disabled runtime PM Runtime PM is always available on Tegra since commit 40b2bb1b132a ("ARM: tegra: enforce PM requirement"), hence there is no need to handle the case of a disabled RPM by Tegra drivers. Remove handing of a disabled runtime PM from Tegra30 I2S driver. Signed-off-by: Dmitry Osipenko Link: https://lore.kernel.org/r/20210314154459.15375-15-digetx@gmail.com Signed-off-by: Mark Brown --- sound/soc/tegra/tegra30_i2s.c | 12 +----------- 1 file changed, 1 insertion(+), 11 deletions(-) diff --git a/sound/soc/tegra/tegra30_i2s.c b/sound/soc/tegra/tegra30_i2s.c index 0ed982548ce4..8730ffa0f691 100644 --- a/sound/soc/tegra/tegra30_i2s.c +++ b/sound/soc/tegra/tegra30_i2s.c @@ -461,11 +461,6 @@ static int tegra30_i2s_platform_probe(struct platform_device *pdev) regcache_cache_only(i2s->regmap, true); pm_runtime_enable(&pdev->dev); - if (!pm_runtime_enabled(&pdev->dev)) { - ret = tegra30_i2s_runtime_resume(&pdev->dev); - if (ret) - goto err_pm_disable; - } i2s->playback_dma_data.addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES; i2s->playback_dma_data.maxburst = 4; @@ -475,7 +470,7 @@ static int tegra30_i2s_platform_probe(struct platform_device *pdev) &i2s->playback_dma_data.addr); if (ret) { dev_err(&pdev->dev, "Could not alloc TX FIFO: %d\n", ret); - goto err_suspend; + goto err_pm_disable; } ret = tegra30_ahub_set_rx_cif_source(i2s->playback_i2s_cif, i2s->playback_fifo_cif); @@ -529,9 +524,6 @@ err_unroute_tx_fifo: tegra30_ahub_unset_rx_cif_source(i2s->playback_i2s_cif); err_free_tx_fifo: tegra30_ahub_free_tx_fifo(i2s->playback_fifo_cif); -err_suspend: - if (!pm_runtime_status_suspended(&pdev->dev)) - tegra30_i2s_runtime_suspend(&pdev->dev); err_pm_disable: pm_runtime_disable(&pdev->dev); err: @@ -552,8 +544,6 @@ static int tegra30_i2s_platform_remove(struct platform_device *pdev) tegra30_ahub_free_tx_fifo(i2s->playback_fifo_cif); pm_runtime_disable(&pdev->dev); - if (!pm_runtime_status_suspended(&pdev->dev)) - tegra30_i2s_runtime_suspend(&pdev->dev); return 0; } From 5d956e3cb806870012c443bc265e6ac6188d3c36 Mon Sep 17 00:00:00 2001 From: Dmitry Osipenko Date: Sun, 14 Mar 2021 18:44:57 +0300 Subject: [PATCH 243/587] ASoC: tegra30: ahub: Reset global variable Tegra30 AHUB uses global variable that is never reset by the driver on a probe failure and on driver removal, meaning that driver will never try to re-probe and can't be unbound. Make driver to reset the variable. Signed-off-by: Dmitry Osipenko Link: https://lore.kernel.org/r/20210314154459.15375-16-digetx@gmail.com Signed-off-by: Mark Brown --- sound/soc/tegra/tegra30_ahub.c | 30 ++++++++++++++++-------------- 1 file changed, 16 insertions(+), 14 deletions(-) diff --git a/sound/soc/tegra/tegra30_ahub.c b/sound/soc/tegra/tegra30_ahub.c index d24c26f4960d..409a259e6343 100644 --- a/sound/soc/tegra/tegra30_ahub.c +++ b/sound/soc/tegra/tegra30_ahub.c @@ -518,9 +518,6 @@ static int tegra30_ahub_probe(struct platform_device *pdev) void __iomem *regs_apbif, *regs_ahub; int ret = 0; - if (ahub) - return -ENODEV; - match = of_match_device(tegra30_ahub_of_match, &pdev->dev); if (!match) return -EINVAL; @@ -544,19 +541,21 @@ static int tegra30_ahub_probe(struct platform_device *pdev) ret = devm_clk_bulk_get(&pdev->dev, ahub->nclocks, ahub->clocks); if (ret) - return ret; + goto err_unset_ahub; ret = devm_reset_control_bulk_get_exclusive(&pdev->dev, ahub->nresets, ahub->resets); if (ret) { dev_err(&pdev->dev, "Can't get resets: %d\n", ret); - return ret; + goto err_unset_ahub; } res0 = platform_get_resource(pdev, IORESOURCE_MEM, 0); regs_apbif = devm_ioremap_resource(&pdev->dev, res0); - if (IS_ERR(regs_apbif)) - return PTR_ERR(regs_apbif); + if (IS_ERR(regs_apbif)) { + ret = PTR_ERR(regs_apbif); + goto err_unset_ahub; + } ahub->apbif_addr = res0->start; @@ -565,20 +564,22 @@ static int tegra30_ahub_probe(struct platform_device *pdev) if (IS_ERR(ahub->regmap_apbif)) { dev_err(&pdev->dev, "apbif regmap init failed\n"); ret = PTR_ERR(ahub->regmap_apbif); - return ret; + goto err_unset_ahub; } regcache_cache_only(ahub->regmap_apbif, true); regs_ahub = devm_platform_ioremap_resource(pdev, 1); - if (IS_ERR(regs_ahub)) - return PTR_ERR(regs_ahub); + if (IS_ERR(regs_ahub)) { + ret = PTR_ERR(regs_ahub); + goto err_unset_ahub; + } ahub->regmap_ahub = devm_regmap_init_mmio(&pdev->dev, regs_ahub, &tegra30_ahub_ahub_regmap_config); if (IS_ERR(ahub->regmap_ahub)) { dev_err(&pdev->dev, "ahub regmap init failed\n"); ret = PTR_ERR(ahub->regmap_ahub); - return ret; + goto err_unset_ahub; } regcache_cache_only(ahub->regmap_ahub, true); @@ -595,19 +596,20 @@ static int tegra30_ahub_probe(struct platform_device *pdev) err_pm_disable: pm_runtime_disable(&pdev->dev); +err_unset_ahub: + ahub = NULL; return ret; } static int tegra30_ahub_remove(struct platform_device *pdev) { - if (!ahub) - return -ENODEV; - pm_runtime_disable(&pdev->dev); if (!pm_runtime_status_suspended(&pdev->dev)) tegra30_ahub_runtime_suspend(&pdev->dev); + ahub = NULL; + return 0; } From e2965c2ca139e780dc353cef1474103bb037136e Mon Sep 17 00:00:00 2001 From: Dmitry Osipenko Date: Sun, 14 Mar 2021 18:44:58 +0300 Subject: [PATCH 244/587] ASoC: tegra30: ahub: Correct suspend-resume callbacks Tegra30 AHUB driver always syncs hardware state on a runtime PM resume, hence there is no needed to re-sync the state on system resume. Replace the suspend-resume callbacks with a generic helpers which ensure that AHUB is suspended using RPM callbacks across system suspend-resume. Signed-off-by: Dmitry Osipenko Link: https://lore.kernel.org/r/20210314154459.15375-17-digetx@gmail.com Signed-off-by: Mark Brown --- sound/soc/tegra/tegra30_ahub.c | 29 ++--------------------------- 1 file changed, 2 insertions(+), 27 deletions(-) diff --git a/sound/soc/tegra/tegra30_ahub.c b/sound/soc/tegra/tegra30_ahub.c index 409a259e6343..e64b41bc5fdf 100644 --- a/sound/soc/tegra/tegra30_ahub.c +++ b/sound/soc/tegra/tegra30_ahub.c @@ -613,36 +613,11 @@ static int tegra30_ahub_remove(struct platform_device *pdev) return 0; } -#ifdef CONFIG_PM_SLEEP -static int tegra30_ahub_suspend(struct device *dev) -{ - regcache_mark_dirty(ahub->regmap_ahub); - regcache_mark_dirty(ahub->regmap_apbif); - - return 0; -} - -static int tegra30_ahub_resume(struct device *dev) -{ - int ret; - - ret = pm_runtime_get_sync(dev); - if (ret < 0) { - pm_runtime_put(dev); - return ret; - } - ret = regcache_sync(ahub->regmap_ahub); - ret |= regcache_sync(ahub->regmap_apbif); - pm_runtime_put(dev); - - return ret; -} -#endif - static const struct dev_pm_ops tegra30_ahub_pm_ops = { SET_RUNTIME_PM_OPS(tegra30_ahub_runtime_suspend, tegra30_ahub_runtime_resume, NULL) - SET_SYSTEM_SLEEP_PM_OPS(tegra30_ahub_suspend, tegra30_ahub_resume) + SET_SYSTEM_SLEEP_PM_OPS(pm_runtime_force_suspend, + pm_runtime_force_resume) }; static struct platform_driver tegra30_ahub_driver = { From b5571449e6186bd37e8da16e7bce53f621c05e72 Mon Sep 17 00:00:00 2001 From: Dmitry Osipenko Date: Sun, 14 Mar 2021 18:44:59 +0300 Subject: [PATCH 245/587] ASoC: tegra30: ahub: Remove handing of disabled runtime PM Runtime PM is always available on Tegra since commit 40b2bb1b132a ("ARM: tegra: enforce PM requirement"), hence there is no need to handle the case of a disabled RPM by Tegra drivers. Remove handing of a disabled runtime PM from Tegra30 AHUB driver. Signed-off-by: Dmitry Osipenko Link: https://lore.kernel.org/r/20210314154459.15375-18-digetx@gmail.com Signed-off-by: Mark Brown --- sound/soc/tegra/tegra30_ahub.c | 9 --------- 1 file changed, 9 deletions(-) diff --git a/sound/soc/tegra/tegra30_ahub.c b/sound/soc/tegra/tegra30_ahub.c index e64b41bc5fdf..d1718f3af3cd 100644 --- a/sound/soc/tegra/tegra30_ahub.c +++ b/sound/soc/tegra/tegra30_ahub.c @@ -584,18 +584,11 @@ static int tegra30_ahub_probe(struct platform_device *pdev) regcache_cache_only(ahub->regmap_ahub, true); pm_runtime_enable(&pdev->dev); - if (!pm_runtime_enabled(&pdev->dev)) { - ret = tegra30_ahub_runtime_resume(&pdev->dev); - if (ret) - goto err_pm_disable; - } of_platform_populate(pdev->dev.of_node, NULL, NULL, &pdev->dev); return 0; -err_pm_disable: - pm_runtime_disable(&pdev->dev); err_unset_ahub: ahub = NULL; @@ -605,8 +598,6 @@ err_unset_ahub: static int tegra30_ahub_remove(struct platform_device *pdev) { pm_runtime_disable(&pdev->dev); - if (!pm_runtime_status_suspended(&pdev->dev)) - tegra30_ahub_runtime_suspend(&pdev->dev); ahub = NULL; From 73b4fe4a03db519977a22cdf34303bd0ac21c69d Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Fri, 12 Mar 2021 12:22:24 -0600 Subject: [PATCH 246/587] ASoC: ab8500-codec: remove useless structure Cppcheck warnings: sound/soc/codecs/ab8500-codec.c:117:20: style: struct member 'ab8500_codec_drvdata_dbg::vaud' is never used. [unusedStructMember] struct regulator *vaud; ^ sound/soc/codecs/ab8500-codec.c:118:20: style: struct member 'ab8500_codec_drvdata_dbg::vamic1' is never used. [unusedStructMember] struct regulator *vamic1; ^ sound/soc/codecs/ab8500-codec.c:119:20: style: struct member 'ab8500_codec_drvdata_dbg::vamic2' is never used. [unusedStructMember] struct regulator *vamic2; ^ sound/soc/codecs/ab8500-codec.c:120:20: style: struct member 'ab8500_codec_drvdata_dbg::vdmic' is never used. [unusedStructMember] struct regulator *vdmic; ^ The structure is never used, remove. Signed-off-by: Pierre-Louis Bossart Link: https://lore.kernel.org/r/20210312182246.5153-2-pierre-louis.bossart@linux.intel.com Signed-off-by: Mark Brown --- sound/soc/codecs/ab8500-codec.c | 7 ------- 1 file changed, 7 deletions(-) diff --git a/sound/soc/codecs/ab8500-codec.c b/sound/soc/codecs/ab8500-codec.c index c95f007cede1..5525e1ccab76 100644 --- a/sound/soc/codecs/ab8500-codec.c +++ b/sound/soc/codecs/ab8500-codec.c @@ -113,13 +113,6 @@ enum amic_idx { AMIC_IDX_2 }; -struct ab8500_codec_drvdata_dbg { - struct regulator *vaud; - struct regulator *vamic1; - struct regulator *vamic2; - struct regulator *vdmic; -}; - /* Private data for AB8500 device-driver */ struct ab8500_codec_drvdata { struct regmap *regmap; From ca6b3a6ca047d23b9b2a54af9f7f4d6f41200719 Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Fri, 12 Mar 2021 12:22:25 -0600 Subject: [PATCH 247/587] ASoC: ad1836: remove useless return Cppcheck warning: sound/soc/codecs/ad1836.c:311:9: warning: Identical condition and return expression 'ret', return value is always 0 [identicalConditionAfterEarlyExit] return ret; ^ sound/soc/codecs/ad1836.c:308:6: note: If condition 'ret' is true, the function will return/exit if (ret) ^ sound/soc/codecs/ad1836.c:311:9: note: Returning identical expression 'ret' return ret; ^ Likely copy/paste between adc and dac cases. Signed-off-by: Pierre-Louis Bossart Link: https://lore.kernel.org/r/20210312182246.5153-3-pierre-louis.bossart@linux.intel.com Signed-off-by: Mark Brown --- sound/soc/codecs/ad1836.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/sound/soc/codecs/ad1836.c b/sound/soc/codecs/ad1836.c index a46152560294..08a5651bed9f 100644 --- a/sound/soc/codecs/ad1836.c +++ b/sound/soc/codecs/ad1836.c @@ -305,8 +305,6 @@ static int ad1836_probe(struct snd_soc_component *component) return ret; ret = snd_soc_dapm_add_routes(dapm, ad183x_adc_routes, num_adcs); - if (ret) - return ret; return ret; } From 5b349c8f355ae4bd1de462f1f1b6164d14796b0e Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Fri, 12 Mar 2021 12:22:26 -0600 Subject: [PATCH 248/587] ASoC: adau1977: remove useless return Cppcheck warning: sound/soc/codecs/adau1977.c:242:9: warning: Identical condition and return expression 'ret', return value is always 0 [identicalConditionAfterEarlyExit] return ret; ^ sound/soc/codecs/adau1977.c:239:6: note: If condition 'ret' is true, the function will return/exit if (ret) ^ sound/soc/codecs/adau1977.c:242:9: note: Returning identical expression 'ret' return ret; ^ Signed-off-by: Pierre-Louis Bossart Link: https://lore.kernel.org/r/20210312182246.5153-4-pierre-louis.bossart@linux.intel.com Signed-off-by: Mark Brown --- sound/soc/codecs/adau1977.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/sound/soc/codecs/adau1977.c b/sound/soc/codecs/adau1977.c index 8260f49caa24..e347a48131d1 100644 --- a/sound/soc/codecs/adau1977.c +++ b/sound/soc/codecs/adau1977.c @@ -236,8 +236,6 @@ static int adau1977_reset(struct adau1977 *adau1977) ret = regmap_write(adau1977->regmap, ADAU1977_REG_POWER, ADAU1977_POWER_RESET); regcache_cache_bypass(adau1977->regmap, false); - if (ret) - return ret; return ret; } From 157c4df677569daad6f204c63cfaf226c941bf03 Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Fri, 12 Mar 2021 12:22:27 -0600 Subject: [PATCH 249/587] ASoC: cros_ec_codec: remove null pointer dereference warning Cppcheck complains of a possible issue: sound/soc/codecs/cros_ec_codec.c:98:10: warning: Possible null pointer dereference: in [nullPointer] memcpy(in, msg->data, insize); ^ sound/soc/codecs/cros_ec_codec.c:162:34: note: Calling function 'send_ec_host_command', 5th argument 'NULL' value is 0 (uint8_t *)&p, sizeof(p), NULL, 0); ^ sound/soc/codecs/cros_ec_codec.c:98:10: note: Null pointer dereference memcpy(in, msg->data, insize); ^ In practice the access to the pointer is protected by another argument, but this is likely to fool other static analysis tools. Add a test to avoid doing the memcpy if the pointer is NULL or the size is zero. Signed-off-by: Pierre-Louis Bossart Acked-by: Enric Balletbo i Serra Link: https://lore.kernel.org/r/20210312182246.5153-5-pierre-louis.bossart@linux.intel.com Signed-off-by: Mark Brown --- sound/soc/codecs/cros_ec_codec.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sound/soc/codecs/cros_ec_codec.c b/sound/soc/codecs/cros_ec_codec.c index c4772f82485a..a201d652aca2 100644 --- a/sound/soc/codecs/cros_ec_codec.c +++ b/sound/soc/codecs/cros_ec_codec.c @@ -94,7 +94,7 @@ static int send_ec_host_command(struct cros_ec_device *ec_dev, uint32_t cmd, if (ret < 0) goto error; - if (insize) + if (in && insize) memcpy(in, msg->data, insize); ret = 0; From 4d753b6642ee7304fc56f9fc463bb69ec641a037 Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Fri, 12 Mar 2021 12:22:28 -0600 Subject: [PATCH 250/587] ASoC: cx2070x: remove useless assignment Cppcheck warning: sound/soc/codecs/cx2072x.c:830:26: style: Variable 'reg1.r.rx_data_one_line' is reassigned a value before the old one has been used. [redundantAssignment] reg1.r.rx_data_one_line = 1; ^ sound/soc/codecs/cx2072x.c:782:26: note: reg1.r.rx_data_one_line is assigned reg1.r.rx_data_one_line = 1; ^ sound/soc/codecs/cx2072x.c:830:26: note: reg1.r.rx_data_one_line is overwritten reg1.r.rx_data_one_line = 1; ^ sound/soc/codecs/cx2072x.c:831:26: style: Variable 'reg1.r.tx_data_one_line' is reassigned a value before the old one has been used. [redundantAssignment] reg1.r.tx_data_one_line = 1; ^ sound/soc/codecs/cx2072x.c:783:26: note: reg1.r.tx_data_one_line is assigned reg1.r.tx_data_one_line = 1; ^ sound/soc/codecs/cx2072x.c:831:26: note: reg1.r.tx_data_one_line is overwritten reg1.r.tx_data_one_line = 1; ^ Likely copy/paste. Signed-off-by: Pierre-Louis Bossart Reviewed-by: Takashi Iwai Link: https://lore.kernel.org/r/20210312182246.5153-6-pierre-louis.bossart@linux.intel.com Signed-off-by: Mark Brown --- sound/soc/codecs/cx2072x.c | 3 --- 1 file changed, 3 deletions(-) diff --git a/sound/soc/codecs/cx2072x.c b/sound/soc/codecs/cx2072x.c index 8ab22815c2c9..d2d004654c9b 100644 --- a/sound/soc/codecs/cx2072x.c +++ b/sound/soc/codecs/cx2072x.c @@ -827,9 +827,6 @@ static int cx2072x_config_i2spcm(struct cx2072x_priv *cx2072x) } regdbt2.r.i2s_bclk_invert = is_bclk_inv; - reg1.r.rx_data_one_line = 1; - reg1.r.tx_data_one_line = 1; - /* Configures the BCLK output */ bclk_rate = cx2072x->sample_rate * frame_len; reg5.r.i2s_pcm_clk_div_chan_en = 0; From 8d41c1ab248fa6e6bfd4728a31eec6d3b9e0f924 Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Fri, 12 Mar 2021 12:22:29 -0600 Subject: [PATCH 251/587] ASoC: cx2070x: remove duplicate else branch cppcheck warning: sound/soc/codecs/cx2072x.c:1436:10: style:inconclusive: Found duplicate branches for 'if' and 'else'. [duplicateBranch] } else if (type & 0x4) { ^ sound/soc/codecs/cx2072x.c:1439:5: note: Found duplicate branches for 'if' and 'else'. } else { ^ sound/soc/codecs/cx2072x.c:1436:10: note: Found duplicate branches for 'if' and 'else'. } else if (type & 0x4) { ^ The last two branches do the same thing and can be collapsed together. Signed-off-by: Pierre-Louis Bossart Reviewed-by: Takashi Iwai Link: https://lore.kernel.org/r/20210312182246.5153-7-pierre-louis.bossart@linux.intel.com Signed-off-by: Mark Brown --- sound/soc/codecs/cx2072x.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/sound/soc/codecs/cx2072x.c b/sound/soc/codecs/cx2072x.c index d2d004654c9b..d924e3528029 100644 --- a/sound/soc/codecs/cx2072x.c +++ b/sound/soc/codecs/cx2072x.c @@ -1430,11 +1430,11 @@ static int cx2072x_jack_status_check(void *data) state |= SND_JACK_HEADSET; if (type & 0x2) state |= SND_JACK_BTN_0; - } else if (type & 0x4) { - /* Nokia headset */ - state |= SND_JACK_HEADPHONE; } else { - /* Headphone */ + /* + * Nokia headset (type & 0x4) and + * regular Headphone + */ state |= SND_JACK_HEADPHONE; } } From f8a684a4c2c9a6f922453f0e5dc6d20b1bdb082b Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Fri, 12 Mar 2021 12:22:30 -0600 Subject: [PATCH 252/587] ASoC: da7219-aad: remove useless initialization cppcheck warning: sound/soc/codecs/da7219-aad.c:118:22: style: Variable 'ret' is assigned a value that is never used. [unreadVariable] int report = 0, ret = 0; ^ Signed-off-by: Pierre-Louis Bossart Acked-by: Adam Thomson Link: https://lore.kernel.org/r/20210312182246.5153-8-pierre-louis.bossart@linux.intel.com Signed-off-by: Mark Brown --- sound/soc/codecs/da7219-aad.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sound/soc/codecs/da7219-aad.c b/sound/soc/codecs/da7219-aad.c index 48081d71c22c..7998fdd3b378 100644 --- a/sound/soc/codecs/da7219-aad.c +++ b/sound/soc/codecs/da7219-aad.c @@ -115,7 +115,7 @@ static void da7219_aad_hptest_work(struct work_struct *work) __le16 tonegen_freq_hptest; u8 pll_srm_sts, pll_ctrl, gain_ramp_ctrl, accdet_cfg8; - int report = 0, ret = 0; + int report = 0, ret; /* Lock DAPM, Kcontrols affected by this test and the PLL */ snd_soc_dapm_mutex_lock(dapm); From 426b3bbcee199e1e96ec62b1c1d9cb7019a84efb Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Fri, 12 Mar 2021 12:22:31 -0600 Subject: [PATCH 253/587] ASoC: hdac_hdmi: remove useless initializations Cppcheck complains a lot about possible null pointer dereferences but it's again a case of useless initializations to NULL. Signed-off-by: Pierre-Louis Bossart Link: https://lore.kernel.org/r/20210312182246.5153-9-pierre-louis.bossart@linux.intel.com Signed-off-by: Mark Brown --- sound/soc/codecs/hdac_hdmi.c | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/sound/soc/codecs/hdac_hdmi.c b/sound/soc/codecs/hdac_hdmi.c index 2c1305bf0572..66408a98298b 100644 --- a/sound/soc/codecs/hdac_hdmi.c +++ b/sound/soc/codecs/hdac_hdmi.c @@ -523,7 +523,7 @@ static struct hdac_hdmi_port *hdac_hdmi_get_port_from_cvt( struct hdac_hdmi_cvt *cvt) { struct hdac_hdmi_pcm *pcm; - struct hdac_hdmi_port *port = NULL; + struct hdac_hdmi_port *port; int ret, i; list_for_each_entry(pcm, &hdmi->pcm_list, head) { @@ -713,7 +713,7 @@ static struct hdac_hdmi_pcm *hdac_hdmi_get_pcm(struct hdac_device *hdev, struct hdac_hdmi_port *port) { struct hdac_hdmi_priv *hdmi = hdev_to_hdmi_priv(hdev); - struct hdac_hdmi_pcm *pcm = NULL; + struct hdac_hdmi_pcm *pcm; struct hdac_hdmi_port *p; list_for_each_entry(pcm, &hdmi->pcm_list, head) { @@ -900,7 +900,7 @@ static int hdac_hdmi_set_pin_port_mux(struct snd_kcontrol *kcontrol, struct hdac_hdmi_port *port = w->priv; struct hdac_device *hdev = dev_to_hdac_dev(dapm->dev); struct hdac_hdmi_priv *hdmi = hdev_to_hdmi_priv(hdev); - struct hdac_hdmi_pcm *pcm = NULL; + struct hdac_hdmi_pcm *pcm; const char *cvt_name = e->texts[ucontrol->value.enumerated.item[0]]; ret = snd_soc_dapm_put_enum_double(kcontrol, ucontrol); @@ -1693,7 +1693,7 @@ static void hdac_hdmi_eld_notify_cb(void *aptr, int port, int pipe) { struct hdac_device *hdev = aptr; struct hdac_hdmi_priv *hdmi = hdev_to_hdmi_priv(hdev); - struct hdac_hdmi_pin *pin = NULL; + struct hdac_hdmi_pin *pin; struct hdac_hdmi_port *hport = NULL; struct snd_soc_component *component = hdmi->component; int i; @@ -1958,7 +1958,7 @@ static int hdmi_codec_probe(struct snd_soc_component *component) struct hdac_device *hdev = hdmi->hdev; struct snd_soc_dapm_context *dapm = snd_soc_component_get_dapm(component); - struct hdac_ext_link *hlink = NULL; + struct hdac_ext_link *hlink; int ret; hdmi->component = component; @@ -2227,7 +2227,7 @@ static int hdac_hdmi_runtime_suspend(struct device *dev) { struct hdac_device *hdev = dev_to_hdac_dev(dev); struct hdac_bus *bus = hdev->bus; - struct hdac_ext_link *hlink = NULL; + struct hdac_ext_link *hlink; dev_dbg(dev, "Enter: %s\n", __func__); @@ -2263,7 +2263,7 @@ static int hdac_hdmi_runtime_resume(struct device *dev) { struct hdac_device *hdev = dev_to_hdac_dev(dev); struct hdac_bus *bus = hdev->bus; - struct hdac_ext_link *hlink = NULL; + struct hdac_ext_link *hlink; dev_dbg(dev, "Enter: %s\n", __func__); From 997994d7e6fab713d1c03843c9698919e64cc135 Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Fri, 12 Mar 2021 12:22:32 -0600 Subject: [PATCH 254/587] ASoC: hdac_hdmi: align function arguments cppcheck warning: sound/soc/codecs/hdac_hdmi.c:1882:54: style:inconclusive: Function 'hdac_hdmi_jack_init' argument 2 names different: declaration 'pcm' definition 'device'. [funcArgNamesDifferent] int hdac_hdmi_jack_init(struct snd_soc_dai *dai, int device, ^ sound/soc/codecs/hdac_hdmi.h:5:54: note: Function 'hdac_hdmi_jack_init' argument 2 names different: declaration 'pcm' definition 'device'. int hdac_hdmi_jack_init(struct snd_soc_dai *dai, int pcm, ^ Signed-off-by: Pierre-Louis Bossart Link: https://lore.kernel.org/r/20210312182246.5153-10-pierre-louis.bossart@linux.intel.com Signed-off-by: Mark Brown --- sound/soc/codecs/hdac_hdmi.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sound/soc/codecs/hdac_hdmi.h b/sound/soc/codecs/hdac_hdmi.h index 4fa2fc9ee893..493fa3b4ef75 100644 --- a/sound/soc/codecs/hdac_hdmi.h +++ b/sound/soc/codecs/hdac_hdmi.h @@ -2,7 +2,7 @@ #ifndef __HDAC_HDMI_H__ #define __HDAC_HDMI_H__ -int hdac_hdmi_jack_init(struct snd_soc_dai *dai, int pcm, +int hdac_hdmi_jack_init(struct snd_soc_dai *dai, int device, struct snd_soc_jack *jack); int hdac_hdmi_jack_port_init(struct snd_soc_component *component, From 3c011ef344cddd15be0a9b2256f7886f6b5eeec5 Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Fri, 12 Mar 2021 12:22:33 -0600 Subject: [PATCH 255/587] ASoC: hdmi-codec: remove useless initialization Fix cppcheck warning: sound/soc/codecs/hdmi-codec.c:745:5: style: Redundant initialization for 'cf'. The initialized value is overwritten before it is read. [redundantInitialization] cf = dai->playback_dma_data; ^ sound/soc/codecs/hdmi-codec.c:738:31: note: cf is initialized struct hdmi_codec_daifmt *cf = dai->playback_dma_data; ^ sound/soc/codecs/hdmi-codec.c:745:5: note: cf is overwritten cf = dai->playback_dma_data; ^ Signed-off-by: Pierre-Louis Bossart Link: https://lore.kernel.org/r/20210312182246.5153-11-pierre-louis.bossart@linux.intel.com Signed-off-by: Mark Brown --- sound/soc/codecs/hdmi-codec.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sound/soc/codecs/hdmi-codec.c b/sound/soc/codecs/hdmi-codec.c index 422539f933de..83e74ddccf59 100644 --- a/sound/soc/codecs/hdmi-codec.c +++ b/sound/soc/codecs/hdmi-codec.c @@ -735,7 +735,7 @@ static int hdmi_codec_set_jack(struct snd_soc_component *component, static int hdmi_dai_spdif_probe(struct snd_soc_dai *dai) { - struct hdmi_codec_daifmt *cf = dai->playback_dma_data; + struct hdmi_codec_daifmt *cf; int ret; ret = hdmi_dai_probe(dai); From 9ad869fee5c598d914fa5cf8fb26f5e106e90956 Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Fri, 12 Mar 2021 12:22:34 -0600 Subject: [PATCH 256/587] ASoC: hdmi-codec: remove unused spk_mask member fix cppcheck warning: sound/soc/codecs/hdmi-codec.c:25:16: style: struct member 'hdmi_codec_channel_map_table::spk_mask' is never used. [unusedStructMember] unsigned long spk_mask; /* speaker position bit mask */ ^ Signed-off-by: Pierre-Louis Bossart Link: https://lore.kernel.org/r/20210312182246.5153-12-pierre-louis.bossart@linux.intel.com Signed-off-by: Mark Brown --- sound/soc/codecs/hdmi-codec.c | 1 - 1 file changed, 1 deletion(-) diff --git a/sound/soc/codecs/hdmi-codec.c b/sound/soc/codecs/hdmi-codec.c index 83e74ddccf59..1567ba196ab9 100644 --- a/sound/soc/codecs/hdmi-codec.c +++ b/sound/soc/codecs/hdmi-codec.c @@ -22,7 +22,6 @@ struct hdmi_codec_channel_map_table { unsigned char map; /* ALSA API channel map position */ - unsigned long spk_mask; /* speaker position bit mask */ }; /* From 226a783f3dcf7f565c173627d565135424ee0be9 Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Fri, 12 Mar 2021 12:22:35 -0600 Subject: [PATCH 257/587] ASoC: max98090: remove useless assignment cppcheck warning: sound/soc/codecs/max98090.c:1835:16: style: Variable 'test_diff' is assigned a value that is never used. [unreadVariable] int test_diff = INT_MAX; ^ Signed-off-by: Pierre-Louis Bossart Link: https://lore.kernel.org/r/20210312182246.5153-13-pierre-louis.bossart@linux.intel.com Signed-off-by: Mark Brown --- sound/soc/codecs/max98090.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sound/soc/codecs/max98090.c b/sound/soc/codecs/max98090.c index 06276ff5f8a3..bc30a1dc7530 100644 --- a/sound/soc/codecs/max98090.c +++ b/sound/soc/codecs/max98090.c @@ -1832,7 +1832,7 @@ static const struct dmic_table dmic_table[] = { /* One for each pclk freq. */ static int max98090_find_divisor(int target_freq, int pclk) { int current_diff = INT_MAX; - int test_diff = INT_MAX; + int test_diff; int divisor_index = 0; int i; From 2b5e8cd53ffad8c586d8a9d47087fdb058a21287 Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Fri, 12 Mar 2021 12:22:36 -0600 Subject: [PATCH 258/587] ASoC: mt6358: remove useless initializations cppcheck warnings: sound/soc/codecs/mt6358.c:334:19: style: Variable 'stage' is assigned a value that is never used. [unreadVariable] int i = 0, stage = 0; ^ sound/soc/codecs/mt6358.c:350:19: style: Variable 'stage' is assigned a value that is never used. [unreadVariable] int i = 0, stage = 0; ^ 185/930 files checked 25% done Checking sound/soc/codecs/mt6359.c ... sound/soc/codecs/mt6359.c:274:8: style: Variable 'i' is assigned a value that is never used. [unreadVariable] int i = 0, stage = 0; ^ sound/soc/codecs/mt6359.c:274:19: style: Variable 'stage' is assigned a value that is never used. [unreadVariable] int i = 0, stage = 0; ^ Signed-off-by: Pierre-Louis Bossart Link: https://lore.kernel.org/r/20210312182246.5153-14-pierre-louis.bossart@linux.intel.com Signed-off-by: Mark Brown --- sound/soc/codecs/mt6358.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/sound/soc/codecs/mt6358.c b/sound/soc/codecs/mt6358.c index 1f39d5998cf6..9b263a9a669d 100644 --- a/sound/soc/codecs/mt6358.c +++ b/sound/soc/codecs/mt6358.c @@ -331,7 +331,7 @@ static void hp_zcd_disable(struct mt6358_priv *priv) static void hp_main_output_ramp(struct mt6358_priv *priv, bool up) { - int i = 0, stage = 0; + int i, stage; int target = 7; /* Enable/Reduce HPL/R main output stage step by step */ @@ -347,7 +347,7 @@ static void hp_main_output_ramp(struct mt6358_priv *priv, bool up) static void hp_aux_feedback_loop_gain_ramp(struct mt6358_priv *priv, bool up) { - int i = 0, stage = 0; + int i, stage; /* Reduce HP aux feedback loop gain step by step */ for (i = 0; i <= 0xf; i++) { From d068ab4eab0de3224b32ac37234d4d33452d5b01 Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Fri, 12 Mar 2021 12:22:37 -0600 Subject: [PATCH 259/587] ASoC: mt6359: remove useless assignment cppcheck warning: sound/soc/codecs/mt6359.c:242:19: style: Variable 'stage' is assigned a value that is never used. [unreadVariable] int i = 0, stage = 0; ^ sound/soc/codecs/mt6359.c:260:19: style: Variable 'stage' is assigned a value that is never used. [unreadVariable] int i = 0, stage = 0; ^ sound/soc/codecs/mt6359.c:274:8: style: Variable 'i' is assigned a value that is never used. [unreadVariable] int i = 0, stage = 0; ^ sound/soc/codecs/mt6359.c:274:19: style: Variable 'stage' is assigned a value that is never used. [unreadVariable] int i = 0, stage = 0; ^ Signed-off-by: Pierre-Louis Bossart Link: https://lore.kernel.org/r/20210312182246.5153-15-pierre-louis.bossart@linux.intel.com Signed-off-by: Mark Brown --- sound/soc/codecs/mt6359.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/sound/soc/codecs/mt6359.c b/sound/soc/codecs/mt6359.c index 6f4b1da52082..b909b36582b7 100644 --- a/sound/soc/codecs/mt6359.c +++ b/sound/soc/codecs/mt6359.c @@ -239,7 +239,7 @@ static void zcd_disable(struct mt6359_priv *priv) static void hp_main_output_ramp(struct mt6359_priv *priv, bool up) { - int i = 0, stage = 0; + int i, stage; int target = 7; /* Enable/Reduce HPL/R main output stage step by step */ @@ -257,7 +257,7 @@ static void hp_main_output_ramp(struct mt6359_priv *priv, bool up) static void hp_aux_feedback_loop_gain_ramp(struct mt6359_priv *priv, bool up) { - int i = 0, stage = 0; + int i, stage; int target = 0xf; /* Enable/Reduce HP aux feedback loop gain step by step */ From a3966b254c481ee1890f75d809a52e5aa358c4b1 Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Fri, 12 Mar 2021 12:22:38 -0600 Subject: [PATCH 260/587] ASoC: nau8825: remove useless assignment cppcheck warning: sound/soc/codecs/nau8825.c:2113:10: style: Variable 'ret' is assigned a value that is never used. [unreadVariable] int ret = 0; ^ Signed-off-by: Pierre-Louis Bossart Link: https://lore.kernel.org/r/20210312182246.5153-16-pierre-louis.bossart@linux.intel.com Signed-off-by: Mark Brown --- sound/soc/codecs/nau8825.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sound/soc/codecs/nau8825.c b/sound/soc/codecs/nau8825.c index e19db30c457b..67de0e49ccf4 100644 --- a/sound/soc/codecs/nau8825.c +++ b/sound/soc/codecs/nau8825.c @@ -2111,7 +2111,7 @@ static int nau8825_set_pll(struct snd_soc_component *component, int pll_id, int static int nau8825_mclk_prepare(struct nau8825 *nau8825, unsigned int freq) { - int ret = 0; + int ret; nau8825->mclk = devm_clk_get(nau8825->dev, "mclk"); if (IS_ERR(nau8825->mclk)) { From f10280d5c59b8d83ae9e9e2307075cc7ad32a6b8 Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Fri, 12 Mar 2021 12:22:39 -0600 Subject: [PATCH 261/587] ASoC: pcm1681: remove useless assignment cppcheck warning: sound/soc/codecs/pcm1681.c:87:8: style: Variable 'i' is assigned a value that is never used. [unreadVariable] int i = 0, val = -1, enable = 0; ^ Signed-off-by: Pierre-Louis Bossart Link: https://lore.kernel.org/r/20210312182246.5153-17-pierre-louis.bossart@linux.intel.com Signed-off-by: Mark Brown --- sound/soc/codecs/pcm1681.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sound/soc/codecs/pcm1681.c b/sound/soc/codecs/pcm1681.c index 07ed8fded471..5b78e9299c95 100644 --- a/sound/soc/codecs/pcm1681.c +++ b/sound/soc/codecs/pcm1681.c @@ -84,7 +84,7 @@ static const int pcm1681_deemph[] = { 44100, 48000, 32000 }; static int pcm1681_set_deemph(struct snd_soc_component *component) { struct pcm1681_private *priv = snd_soc_component_get_drvdata(component); - int i = 0, val = -1, enable = 0; + int i, val = -1, enable = 0; if (priv->deemph) { for (i = 0; i < ARRAY_SIZE(pcm1681_deemph); i++) { From 17d74e68e9765d9549acf1c36caa8b7559dc99ce Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Fri, 12 Mar 2021 12:22:40 -0600 Subject: [PATCH 262/587] ASoC: sigmadsp: align function prototype cppcheck warning: sound/soc/codecs/sigmadsp.c:736:60: style:inconclusive: Function 'sigmadsp_setup' argument 2 names different: declaration 'rate' definition 'samplerate'. [funcArgNamesDifferent] int sigmadsp_setup(struct sigmadsp *sigmadsp, unsigned int samplerate) ^ sound/soc/codecs/sigmadsp.h:62:60: note: Function 'sigmadsp_setup' argument 2 names different: declaration 'rate' definition 'samplerate'. int sigmadsp_setup(struct sigmadsp *sigmadsp, unsigned int rate); ^ sound/soc/codecs/sigmadsp.c:736:60: note: Function 'sigmadsp_setup' argument 2 names different: declaration 'rate' definition 'samplerate'. int sigmadsp_setup(struct sigmadsp *sigmadsp, unsigned int samplerate) ^ Signed-off-by: Pierre-Louis Bossart Link: https://lore.kernel.org/r/20210312182246.5153-18-pierre-louis.bossart@linux.intel.com Signed-off-by: Mark Brown --- sound/soc/codecs/sigmadsp.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sound/soc/codecs/sigmadsp.h b/sound/soc/codecs/sigmadsp.h index e3c9656e006d..d63b8c366efb 100644 --- a/sound/soc/codecs/sigmadsp.h +++ b/sound/soc/codecs/sigmadsp.h @@ -59,7 +59,7 @@ struct sigmadsp *devm_sigmadsp_init_i2c(struct i2c_client *client, int sigmadsp_attach(struct sigmadsp *sigmadsp, struct snd_soc_component *component); -int sigmadsp_setup(struct sigmadsp *sigmadsp, unsigned int rate); +int sigmadsp_setup(struct sigmadsp *sigmadsp, unsigned int samplerate); void sigmadsp_reset(struct sigmadsp *sigmadsp); #endif From 02a70d7f26e7a3d87c9a5af39ca399b52a451a1a Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Fri, 12 Mar 2021 12:22:41 -0600 Subject: [PATCH 263/587] ASoC: sti-sas: remove unused struct members cppcheck warnings: sound/soc/codecs/sti-sas.c:54:25: style: struct member 'sti_dac_audio::field' is never used. [unusedStructMember] struct regmap_field **field; ^ sound/soc/codecs/sti-sas.c:55:24: style: struct member 'sti_dac_audio::rst' is never used. [unusedStructMember] struct reset_control *rst; ^ sound/soc/codecs/sti-sas.c:61:25: style: struct member 'sti_spdif_audio::field' is never used. [unusedStructMember] struct regmap_field **field; ^ Signed-off-by: Pierre-Louis Bossart Link: https://lore.kernel.org/r/20210312182246.5153-19-pierre-louis.bossart@linux.intel.com Signed-off-by: Mark Brown --- sound/soc/codecs/sti-sas.c | 3 --- 1 file changed, 3 deletions(-) diff --git a/sound/soc/codecs/sti-sas.c b/sound/soc/codecs/sti-sas.c index ec9933b054ad..ffdf7e559515 100644 --- a/sound/soc/codecs/sti-sas.c +++ b/sound/soc/codecs/sti-sas.c @@ -51,14 +51,11 @@ static const struct reg_default stih407_sas_reg_defaults[] = { struct sti_dac_audio { struct regmap *regmap; struct regmap *virt_regmap; - struct regmap_field **field; - struct reset_control *rst; int mclk; }; struct sti_spdif_audio { struct regmap *regmap; - struct regmap_field **field; int mclk; }; From e83c47861c266f704d2344f51031ee67a93309ab Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Fri, 12 Mar 2021 12:22:42 -0600 Subject: [PATCH 264/587] ASoC: tas2562: remove useless assignment cppcheck throws a warning: sound/soc/codecs/tas2562.c:203:4: style: Assignment of function parameter has no effect outside the function. [uselessAssignmentArg] tx_mask &= ~(1 << right_slot); ^ This assignment seems to come from a copy/paste but the value is indeed not used. Let's remove it. Signed-off-by: Pierre-Louis Bossart Link: https://lore.kernel.org/r/20210312182246.5153-20-pierre-louis.bossart@linux.intel.com Signed-off-by: Mark Brown --- sound/soc/codecs/tas2562.c | 1 - 1 file changed, 1 deletion(-) diff --git a/sound/soc/codecs/tas2562.c b/sound/soc/codecs/tas2562.c index 19965fabe949..ba23f9f07f04 100644 --- a/sound/soc/codecs/tas2562.c +++ b/sound/soc/codecs/tas2562.c @@ -200,7 +200,6 @@ static int tas2562_set_dai_tdm_slot(struct snd_soc_dai *dai, right_slot = left_slot; } else { right_slot = __ffs(tx_mask); - tx_mask &= ~(1 << right_slot); } } From 2e40b21cd4f697a761f1c5e4f08aac1a5c6c6018 Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Fri, 12 Mar 2021 12:22:43 -0600 Subject: [PATCH 265/587] ASoC: tas2562: remove warning on return value cppcheck warning: sound/soc/codecs/tas2562.c:530:9: warning: Identical condition and return expression 'ret', return value is always 0 [identicalConditionAfterEarlyExit] return ret; ^ sound/soc/codecs/tas2562.c:525:6: note: If condition 'ret' is true, the function will return/exit if (ret) ^ sound/soc/codecs/tas2562.c:530:9: note: Returning identical expression 'ret' return ret; ^ Fix with return 0 Signed-off-by: Pierre-Louis Bossart Link: https://lore.kernel.org/r/20210312182246.5153-21-pierre-louis.bossart@linux.intel.com Signed-off-by: Mark Brown --- sound/soc/codecs/tas2562.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sound/soc/codecs/tas2562.c b/sound/soc/codecs/tas2562.c index ba23f9f07f04..10302552195e 100644 --- a/sound/soc/codecs/tas2562.c +++ b/sound/soc/codecs/tas2562.c @@ -526,7 +526,7 @@ static int tas2562_volume_control_put(struct snd_kcontrol *kcontrol, tas2562->volume_lvl = ucontrol->value.integer.value[0]; - return ret; + return 0; } /* Digital Volume Control. From 0 dB to -110 dB in 1 dB steps */ From ffab1215bdbea7358051f8dd87b1240e4c6d56e6 Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Fri, 12 Mar 2021 12:22:44 -0600 Subject: [PATCH 266/587] ASoC: tas2770: remove useless initialization cppcheck warning: sound/soc/codecs/tas2770.c:109:10: style: Variable 'ret' is assigned a value that is never used. [unreadVariable] int ret = 0; ^ Signed-off-by: Pierre-Louis Bossart Link: https://lore.kernel.org/r/20210312182246.5153-22-pierre-louis.bossart@linux.intel.com Signed-off-by: Mark Brown --- sound/soc/codecs/tas2770.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sound/soc/codecs/tas2770.c b/sound/soc/codecs/tas2770.c index 15fca5109e14..781bf9cc4faa 100644 --- a/sound/soc/codecs/tas2770.c +++ b/sound/soc/codecs/tas2770.c @@ -106,7 +106,7 @@ static int tas2770_codec_suspend(struct snd_soc_component *component) static int tas2770_codec_resume(struct snd_soc_component *component) { struct tas2770_priv *tas2770 = snd_soc_component_get_drvdata(component); - int ret = 0; + int ret; if (tas2770->sdz_gpio) { gpiod_set_value_cansleep(tas2770->sdz_gpio, 1); From 39e69cef0aa9f6897161a11ed84362f5805c43fd Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Fri, 12 Mar 2021 12:22:45 -0600 Subject: [PATCH 267/587] ASoC: tlv320dac33: clarify expression cppcheck warning: sound/soc/codecs/tlv320dac33.c:1074:43: style: Clarify calculation precedence for '%' and '?'. [clarifyCalculation] (dac33->alarm_threshold % period_size ? ^ Signed-off-by: Pierre-Louis Bossart Link: https://lore.kernel.org/r/20210312182246.5153-23-pierre-louis.bossart@linux.intel.com Signed-off-by: Mark Brown --- sound/soc/codecs/tlv320dac33.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sound/soc/codecs/tlv320dac33.c b/sound/soc/codecs/tlv320dac33.c index d905e03aaec7..48572d66cb3b 100644 --- a/sound/soc/codecs/tlv320dac33.c +++ b/sound/soc/codecs/tlv320dac33.c @@ -1071,7 +1071,7 @@ static void dac33_calculate_times(struct snd_pcm_substream *substream, */ dac33->nsample = period_size * ((dac33->alarm_threshold / period_size) + - (dac33->alarm_threshold % period_size ? + ((dac33->alarm_threshold % period_size) ? 1 : 0)); else if (period_size > nsample_limit) dac33->nsample = nsample_limit; From a2cc1568dc50020a807c94bd14a053dd54e9c35e Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Fri, 12 Mar 2021 12:22:46 -0600 Subject: [PATCH 268/587] ASoC: tscs454: remove useless test on PLL disable cppcheck warning: sound/soc/codecs/tscs454.c:730:37: style: Same value in both branches of ternary operator. [duplicateValueTernary] val = pll1 ? FV_PLL1CLKEN_DISABLE : FV_PLL2CLKEN_DISABLE; ^ Signed-off-by: Pierre-Louis Bossart Link: https://lore.kernel.org/r/20210312182246.5153-24-pierre-louis.bossart@linux.intel.com Signed-off-by: Mark Brown --- sound/soc/codecs/tscs454.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/sound/soc/codecs/tscs454.c b/sound/soc/codecs/tscs454.c index 1bafc9d1101c..43220bb36701 100644 --- a/sound/soc/codecs/tscs454.c +++ b/sound/soc/codecs/tscs454.c @@ -727,7 +727,12 @@ static int pll_power_event(struct snd_soc_dapm_widget *w, if (enable) val = pll1 ? FV_PLL1CLKEN_ENABLE : FV_PLL2CLKEN_ENABLE; else - val = pll1 ? FV_PLL1CLKEN_DISABLE : FV_PLL2CLKEN_DISABLE; + /* + * FV_PLL1CLKEN_DISABLE and FV_PLL2CLKEN_DISABLE are + * identical zero vzalues, there is no need to test + * the PLL index + */ + val = FV_PLL1CLKEN_DISABLE; ret = snd_soc_component_update_bits(component, R_PLLCTL, msk, val); if (ret < 0) { From bef2897d31b97852d80b38e9376ed5ef3a90b309 Mon Sep 17 00:00:00 2001 From: Nick Desaulniers Date: Sun, 14 Mar 2021 18:39:08 -0700 Subject: [PATCH 269/587] ASoC: Intel: Skylake: skl-topology: fix -frame-larger-than sound/soc/intel/skylake/skl-topology.c:3613:13: warning: stack frame size of 1304 bytes in function 'skl_tplg_complete' [-Wframe-larger-than=] struct snd_ctl_elem_value is 1224 bytes in my configuration. Heap allocate it, then free it within the current frame. Suggested-by: Andy Shevchenko Signed-off-by: Nick Desaulniers Link: https://lore.kernel.org/r/20210315013908.217219-1-nick.desaulniers@gmail.com Signed-off-by: Mark Brown --- sound/soc/intel/skylake/skl-topology.c | 17 +++++++++++------ 1 file changed, 11 insertions(+), 6 deletions(-) diff --git a/sound/soc/intel/skylake/skl-topology.c b/sound/soc/intel/skylake/skl-topology.c index b824086203b9..c0fdab39e7c2 100644 --- a/sound/soc/intel/skylake/skl-topology.c +++ b/sound/soc/intel/skylake/skl-topology.c @@ -3613,10 +3613,15 @@ static int skl_manifest_load(struct snd_soc_component *cmpnt, int index, static void skl_tplg_complete(struct snd_soc_component *component) { struct snd_soc_dobj *dobj; - struct snd_soc_acpi_mach *mach = - dev_get_platdata(component->card->dev); + struct snd_soc_acpi_mach *mach; + struct snd_ctl_elem_value *val; int i; + val = kmalloc(sizeof(*val), GFP_KERNEL); + if (!val) + return; + + mach = dev_get_platdata(component->card->dev); list_for_each_entry(dobj, &component->dobj_list, list) { struct snd_kcontrol *kcontrol = dobj->control.kcontrol; struct soc_enum *se; @@ -3632,14 +3637,14 @@ static void skl_tplg_complete(struct snd_soc_component *component) sprintf(chan_text, "c%d", mach->mach_params.dmic_num); for (i = 0; i < se->items; i++) { - struct snd_ctl_elem_value val = {}; - if (strstr(texts[i], chan_text)) { - val.value.enumerated.item[0] = i; - kcontrol->put(kcontrol, &val); + memset(val, 0, sizeof(*val)); + val->value.enumerated.item[0] = i; + kcontrol->put(kcontrol, val); } } } + kfree(val); } static struct snd_soc_tplg_ops skl_tplg_ops = { From 8dd855334736f275e9de71096d816c8d9da46bf7 Mon Sep 17 00:00:00 2001 From: Bhaskar Chowdhury Date: Sun, 14 Mar 2021 04:48:50 +0530 Subject: [PATCH 270/587] ASoC: Fix a typo in the file rt5682.txt s/drving/driving/ Signed-off-by: Bhaskar Chowdhury Acked-by: Randy Dunlap Link: https://lore.kernel.org/r/20210313231850.17278-1-unixbhaskar@gmail.com Signed-off-by: Mark Brown --- Documentation/devicetree/bindings/sound/rt5682.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Documentation/devicetree/bindings/sound/rt5682.txt b/Documentation/devicetree/bindings/sound/rt5682.txt index 9c5fadb6ac82..cd8c53d8497e 100644 --- a/Documentation/devicetree/bindings/sound/rt5682.txt +++ b/Documentation/devicetree/bindings/sound/rt5682.txt @@ -44,7 +44,7 @@ Optional properties: - realtek,dmic-delay-ms : Set the delay time (ms) for the requirement of the particular DMIC. -- realtek,dmic-clk-driving-high : Set the high drving of the DMIC clock out. +- realtek,dmic-clk-driving-high : Set the high driving of the DMIC clock out. Pins on the device (for linking into audio routes) for RT5682: From 7ec79d3850d0cb6dc52e6aa472886ab3adf15863 Mon Sep 17 00:00:00 2001 From: Jack Yu Date: Thu, 11 Mar 2021 10:58:09 +0800 Subject: [PATCH 271/587] ASoC: rt1019: add rt1019 amplifier driver This is initial amplifier driver for rt1019. Signed-off-by: Jack Yu Link: https://lore.kernel.org/r/20210311025809.31852-1-jack.yu@realtek.com Signed-off-by: Mark Brown --- .../devicetree/bindings/sound/rt1019.yaml | 33 + sound/soc/codecs/Kconfig | 7 + sound/soc/codecs/Makefile | 2 + sound/soc/codecs/rt1019.c | 940 ++++++++++++++++++ sound/soc/codecs/rt1019.h | 320 ++++++ 5 files changed, 1302 insertions(+) create mode 100644 Documentation/devicetree/bindings/sound/rt1019.yaml create mode 100644 sound/soc/codecs/rt1019.c create mode 100644 sound/soc/codecs/rt1019.h diff --git a/Documentation/devicetree/bindings/sound/rt1019.yaml b/Documentation/devicetree/bindings/sound/rt1019.yaml new file mode 100644 index 000000000000..c24c29eafa54 --- /dev/null +++ b/Documentation/devicetree/bindings/sound/rt1019.yaml @@ -0,0 +1,33 @@ +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/sound/rt1019.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: RT1019 Mono Class-D Audio Amplifier + +maintainers: + - jack.yu@realtek.com + +properties: + compatible: + const: realtek,rt1019 + + reg: + maxItems: 1 + description: I2C address of the device. + +required: + - compatible + - reg + +additionalProperties: false + +examples: + - | + i2c { + rt1019: codec@28 { + compatible = "realtek,rt1019"; + reg = <0x28>; + }; + }; diff --git a/sound/soc/codecs/Kconfig b/sound/soc/codecs/Kconfig index 6ce74c99a305..4ab34bca71aa 100644 --- a/sound/soc/codecs/Kconfig +++ b/sound/soc/codecs/Kconfig @@ -161,6 +161,7 @@ config SND_SOC_ALL_CODECS imply SND_SOC_RT1011 imply SND_SOC_RT1015 imply SND_SOC_RT1015P + imply SND_SOC_RT1019 imply SND_SOC_RT1305 imply SND_SOC_RT1308 imply SND_SOC_RT5514 @@ -1079,6 +1080,7 @@ config SND_SOC_RL6231 default y if SND_SOC_RT1011=y default y if SND_SOC_RT1015=y default y if SND_SOC_RT1015P=y + default y if SND_SOC_RT1019=y default y if SND_SOC_RT1305=y default y if SND_SOC_RT1308=y default m if SND_SOC_RT5514=m @@ -1097,6 +1099,7 @@ config SND_SOC_RL6231 default m if SND_SOC_RT1011=m default m if SND_SOC_RT1015=m default m if SND_SOC_RT1015P=m + default m if SND_SOC_RT1019=m default m if SND_SOC_RT1305=m default m if SND_SOC_RT1308=m @@ -1133,6 +1136,10 @@ config SND_SOC_RT1015P tristate depends on GPIOLIB +config SND_SOC_RT1019 + tristate + depends on I2C + config SND_SOC_RT1305 tristate depends on I2C diff --git a/sound/soc/codecs/Makefile b/sound/soc/codecs/Makefile index dcc2f757bb82..edff5c5b92d3 100644 --- a/sound/soc/codecs/Makefile +++ b/sound/soc/codecs/Makefile @@ -170,6 +170,7 @@ snd-soc-rl6347a-objs := rl6347a.o snd-soc-rt1011-objs := rt1011.o snd-soc-rt1015-objs := rt1015.o snd-soc-rt1015p-objs := rt1015p.o +snd-soc-rt1019-objs := rt1019.o snd-soc-rt1305-objs := rt1305.o snd-soc-rt1308-objs := rt1308.o snd-soc-rt1308-sdw-objs := rt1308-sdw.o @@ -487,6 +488,7 @@ obj-$(CONFIG_SND_SOC_RL6347A) += snd-soc-rl6347a.o obj-$(CONFIG_SND_SOC_RT1011) += snd-soc-rt1011.o obj-$(CONFIG_SND_SOC_RT1015) += snd-soc-rt1015.o obj-$(CONFIG_SND_SOC_RT1015P) += snd-soc-rt1015p.o +obj-$(CONFIG_SND_SOC_RT1019) += snd-soc-rt1019.o obj-$(CONFIG_SND_SOC_RT1305) += snd-soc-rt1305.o obj-$(CONFIG_SND_SOC_RT1308) += snd-soc-rt1308.o obj-$(CONFIG_SND_SOC_RT1308_SDW) += snd-soc-rt1308-sdw.o diff --git a/sound/soc/codecs/rt1019.c b/sound/soc/codecs/rt1019.c new file mode 100644 index 000000000000..fb275686a00f --- /dev/null +++ b/sound/soc/codecs/rt1019.c @@ -0,0 +1,940 @@ +// SPDX-License-Identifier: GPL-2.0-only +// +// rt1019.c -- RT1019 ALSA SoC audio amplifier driver +// Author: Jack Yu +// +// Copyright(c) 2021 Realtek Semiconductor Corp. +// +// + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "rl6231.h" +#include "rt1019.h" + +static const struct reg_default rt1019_reg[] = { + { 0x0000, 0x00 }, + { 0x0002, 0x55 }, + { 0x0003, 0x55 }, + { 0x0005, 0x54 }, + { 0x0006, 0x05 }, + { 0x0007, 0x01 }, + { 0x0008, 0x70 }, + { 0x0009, 0x28 }, + { 0x000a, 0x7f }, + { 0x0011, 0x04 }, + { 0x0013, 0x00 }, + { 0x0015, 0x00 }, + { 0x0017, 0x00 }, + { 0x0019, 0x30 }, + { 0x001b, 0x01 }, + { 0x001d, 0x18 }, + { 0x001f, 0x29 }, + { 0x0021, 0x09 }, + { 0x0023, 0x02 }, + { 0x0025, 0x00 }, + { 0x0026, 0x00 }, + { 0x0028, 0x03 }, + { 0x0053, 0x00 }, + { 0x0055, 0x00 }, + { 0x0056, 0x00 }, + { 0x0057, 0x00 }, + { 0x0058, 0x00 }, + { 0x005a, 0x00 }, + { 0x005c, 0x00 }, + { 0x005d, 0x00 }, + { 0x005e, 0x10 }, + { 0x005f, 0xec }, + { 0x0061, 0x10 }, + { 0x0062, 0x19 }, + { 0x0064, 0x00 }, + { 0x0066, 0x08 }, + { 0x0068, 0x00 }, + { 0x006a, 0x00 }, + { 0x006c, 0x00 }, + { 0x006e, 0x00 }, + { 0x0100, 0x80 }, + { 0x0100, 0x51 }, + { 0x0102, 0x23 }, + { 0x0102, 0x0f }, + { 0x0104, 0x6c }, + { 0x0105, 0xec }, + { 0x0106, 0x00 }, + { 0x0107, 0x00 }, + { 0x0108, 0x00 }, + { 0x0200, 0x40 }, + { 0x0201, 0x00 }, + { 0x0202, 0x00 }, + { 0x0203, 0x00 }, + { 0x0301, 0x02 }, + { 0x0302, 0xaa }, + { 0x0303, 0x2a }, + { 0x0304, 0x6a }, + { 0x0306, 0xb0 }, + { 0x0308, 0x48 }, + { 0x030a, 0x0a }, + { 0x030b, 0x4b }, + { 0x030d, 0x7d }, + { 0x030e, 0xef }, + { 0x030f, 0x5a }, + { 0x0311, 0x00 }, + { 0x0312, 0x3e }, + { 0x0313, 0x86 }, + { 0x0315, 0xa8 }, + { 0x0318, 0x1b }, + { 0x031a, 0x3d }, + { 0x031c, 0x40 }, + { 0x031d, 0x40 }, + { 0x031e, 0x30 }, + { 0x031f, 0xbb }, + { 0x0320, 0xa5 }, + { 0x0321, 0xa5 }, + { 0x0323, 0x5a }, + { 0x0324, 0xaa }, + { 0x0325, 0x80 }, + { 0x0326, 0xaa }, + { 0x0327, 0x66 }, + { 0x0328, 0x94 }, + { 0x0329, 0x00 }, + { 0x0330, 0x00 }, + { 0x0331, 0x30 }, + { 0x0332, 0x05 }, + { 0x0400, 0x03 }, + { 0x0401, 0x02 }, + { 0x0402, 0x01 }, + { 0x0403, 0x23 }, + { 0x0404, 0x45 }, + { 0x0405, 0x67 }, + { 0x0500, 0x80 }, + { 0x0501, 0x00 }, + { 0x0502, 0x00 }, + { 0x0503, 0x00 }, + { 0x0504, 0xff }, + { 0x0505, 0x24 }, + { 0x0600, 0x75 }, + { 0x0601, 0x41 }, + { 0x0602, 0x60 }, + { 0x0603, 0x7f }, + { 0x0604, 0x65 }, + { 0x0605, 0x43 }, + { 0x0606, 0x00 }, + { 0x0607, 0x00 }, + { 0x0608, 0x00 }, + { 0x0609, 0x00 }, + { 0x060a, 0x00 }, + { 0x060b, 0x00 }, + { 0x060c, 0x00 }, + { 0x060d, 0x00 }, + { 0x060e, 0x00 }, + { 0x060f, 0x00 }, + { 0x0700, 0x15 }, + { 0x0701, 0xc8 }, + { 0x0704, 0x02 }, + { 0x0705, 0x00 }, + { 0x0706, 0x00 }, + { 0x0707, 0x80 }, + { 0x0708, 0x08 }, + { 0x0709, 0x00 }, + { 0x0800, 0x00 }, + { 0x0801, 0x00 }, + { 0x0802, 0x09 }, + { 0x0803, 0x00 }, + { 0x0900, 0x87 }, + { 0x0a01, 0x99 }, + { 0x0a02, 0x40 }, + { 0x0a03, 0x10 }, + { 0x0b00, 0x50 }, + { 0x0b01, 0xc3 }, + { 0x0c00, 0x84 }, + { 0x0c01, 0x00 }, + { 0x0c02, 0xbb }, + { 0x0c03, 0x80 }, + { 0x0c04, 0x10 }, + { 0x0c05, 0x30 }, + { 0x0c06, 0x00 }, + { 0x0d00, 0x80 }, + { 0x0d01, 0xbb }, + { 0x0d02, 0x80 }, + { 0x0d03, 0x00 }, + { 0x0d04, 0x00 }, + { 0x0d05, 0x00 }, + { 0x0e00, 0x80 }, + { 0x0e01, 0xbb }, + { 0x0e02, 0x80 }, + { 0x0e03, 0x00 }, + { 0x0e04, 0x10 }, + { 0x0e05, 0x30 }, + { 0x0f00, 0x80 }, + { 0x0f01, 0xbb }, + { 0x0f02, 0x80 }, + { 0x0f03, 0x00 }, + { 0x0f04, 0x10 }, + { 0x0f05, 0x30 }, + { 0x0f06, 0x88 }, + { 0x0f07, 0x88 }, + { 0x0f08, 0x00 }, + { 0x0f09, 0x00 }, +}; + +static bool rt1019_volatile_register(struct device *dev, unsigned int reg) +{ + switch (reg) { + case RT1019_PWR_STRP_1: + case RT1019_PWR_STRP_2: + case RT1019_SIL_DET_GAT: + case RT1019_PHASE_SYNC: + case RT1019_STAT_MACH_2: + case RT1019_FS_DET_1: + case RT1019_FS_DET_2: + case RT1019_FS_DET_3: + case RT1019_FS_DET_4: + case RT1019_FS_DET_5: + case RT1019_FS_DET_6: + case RT1019_FS_DET_7: + case RT1019_ANA_READ: + case RT1019_VER_ID: + case RT1019_CUSTOM_ID: + case RT1019_VEND_ID_1: + case RT1019_VEND_ID_2: + case RT1019_DEV_ID_1: + case RT1019_DEV_ID_2: + case RT1019_CAL_TOP_3: + case RT1019_CAL_TOP_7: + case RT1019_CAL_TOP_17: + case RT1019_CAL_TOP_18: + case RT1019_CAL_TOP_19: + case RT1019_CAL_TOP_20: + case RT1019_CAL_TOP_21: + case RT1019_CAL_TOP_22: + case RT1019_MDRE_CTRL_2: + case RT1019_MDRE_CTRL_3: + case RT1019_MDRE_CTRL_4: + case RT1019_SIL_DET_2: + case RT1019_PWM_DC_DET_1: + case RT1019_PMC_8: + case RT1019_PMC_9: + case RT1019_SPKDRC_7: + case RT1019_HALF_FREQ_7: + case RT1019_CUR_CTRL_11: + case RT1019_CUR_CTRL_12: + case RT1019_CUR_CTRL_13: + return true; + + default: + return false; + } +} + +static bool rt1019_readable_register(struct device *dev, unsigned int reg) +{ + switch (reg) { + case RT1019_RESET: + case RT1019_PAD_DRV_1: + case RT1019_PAD_DRV_2: + case RT1019_PAD_PULL_1: + case RT1019_PAD_PULL_2: + case RT1019_PAD_PULL_3: + case RT1019_I2C_CTRL_1: + case RT1019_I2C_CTRL_2: + case RT1019_I2C_CTRL_3: + case RT1019_IDS_CTRL: + case RT1019_ASEL_CTRL: + case RT1019_PLL_RESET: + case RT1019_PWR_STRP_1: + case RT1019_PWR_STRP_2: + case RT1019_BEEP_TONE: + case RT1019_SIL_DET_GAT: + case RT1019_CLASSD_TIME: + case RT1019_CLASSD_OCP: + case RT1019_PHASE_SYNC: + case RT1019_STAT_MACH_1: + case RT1019_STAT_MACH_2: + case RT1019_EFF_CTRL: + case RT1019_FS_DET_1: + case RT1019_FS_DET_2: + case RT1019_FS_DET_3: + case RT1019_FS_DET_4: + case RT1019_FS_DET_5: + case RT1019_FS_DET_6: + case RT1019_FS_DET_7: + case RT1019_ANA_CTRL: + case RT1019_DUMMY_A: + case RT1019_DUMMY_B: + case RT1019_DUMMY_C: + case RT1019_DUMMY_D: + case RT1019_ANA_READ: + case RT1019_VER_ID: + case RT1019_CUSTOM_ID: + case RT1019_VEND_ID_1: + case RT1019_VEND_ID_2: + case RT1019_DEV_ID_1: + case RT1019_DEV_ID_2: + case RT1019_TEST_PAD: + case RT1019_SDB_CTRL: + case RT1019_TEST_CTRL_1: + case RT1019_TEST_CTRL_2: + case RT1019_TEST_CTRL_3: + case RT1019_SCAN_MODE: + case RT1019_CLK_TREE_1: + case RT1019_CLK_TREE_2: + case RT1019_CLK_TREE_3: + case RT1019_CLK_TREE_4: + case RT1019_CLK_TREE_5: + case RT1019_CLK_TREE_6: + case RT1019_CLK_TREE_7: + case RT1019_CLK_TREE_8: + case RT1019_CLK_TREE_9: + case RT1019_ASRC_1: + case RT1019_ASRC_2: + case RT1019_ASRC_3: + case RT1019_ASRC_4: + case RT1019_SYS_CLK: + case RT1019_BIAS_CUR_1: + case RT1019_BIAS_CUR_2: + case RT1019_BIAS_CUR_3: + case RT1019_BIAS_CUR_4: + case RT1019_CHOP_CLK_DAC: + case RT1019_CHOP_CLK_ADC: + case RT1019_LDO_CTRL_1: + case RT1019_LDO_CTRL_2: + case RT1019_PM_ANA_1: + case RT1019_PM_ANA_2: + case RT1019_PM_ANA_3: + case RT1019_PLL_1: + case RT1019_PLL_2: + case RT1019_PLL_3: + case RT1019_PLL_INT_1: + case RT1019_PLL_INT_3: + case RT1019_MIXER: + case RT1019_CLD_OUT_1: + case RT1019_CLD_OUT_2: + case RT1019_CLD_OUT_3: + case RT1019_CLD_OUT_4: + case RT1019_CLD_OUT_5: + case RT1019_CLD_OUT_6: + case RT1019_CLS_INT_REG_1: + case RT1019_CLS_INT_REG_2: + case RT1019_CLS_INT_REG_3: + case RT1019_CLS_INT_REG_4: + case RT1019_CLS_INT_REG_5: + case RT1019_CLS_INT_REG_6: + case RT1019_CLS_INT_REG_7: + case RT1019_CLS_INT_REG_8: + case RT1019_CLS_INT_REG_9: + case RT1019_CLS_INT_REG_10: + case RT1019_TDM_1: + case RT1019_TDM_2: + case RT1019_TDM_3: + case RT1019_TDM_4: + case RT1019_TDM_5: + case RT1019_TDM_6: + case RT1019_DVOL_1: + case RT1019_DVOL_2: + case RT1019_DVOL_3: + case RT1019_DVOL_4: + case RT1019_DMIX_MONO_1: + case RT1019_DMIX_MONO_2: + case RT1019_CAL_TOP_1: + case RT1019_CAL_TOP_2: + case RT1019_CAL_TOP_3: + case RT1019_CAL_TOP_4: + case RT1019_CAL_TOP_5: + case RT1019_CAL_TOP_6: + case RT1019_CAL_TOP_7: + case RT1019_CAL_TOP_8: + case RT1019_CAL_TOP_9: + case RT1019_CAL_TOP_10: + case RT1019_CAL_TOP_11: + case RT1019_CAL_TOP_12: + case RT1019_CAL_TOP_13: + case RT1019_CAL_TOP_14: + case RT1019_CAL_TOP_15: + case RT1019_CAL_TOP_16: + case RT1019_CAL_TOP_17: + case RT1019_CAL_TOP_18: + case RT1019_CAL_TOP_19: + case RT1019_CAL_TOP_20: + case RT1019_CAL_TOP_21: + case RT1019_CAL_TOP_22: + case RT1019_MDRE_CTRL_1: + case RT1019_MDRE_CTRL_2: + case RT1019_MDRE_CTRL_3: + case RT1019_MDRE_CTRL_4: + case RT1019_MDRE_CTRL_5: + case RT1019_MDRE_CTRL_6: + case RT1019_MDRE_CTRL_7: + case RT1019_MDRE_CTRL_8: + case RT1019_MDRE_CTRL_9: + case RT1019_MDRE_CTRL_10: + case RT1019_SCC_CTRL_1: + case RT1019_SCC_CTRL_2: + case RT1019_SCC_CTRL_3: + case RT1019_SCC_DUMMY: + case RT1019_SIL_DET_1: + case RT1019_SIL_DET_2: + case RT1019_PWM_DC_DET_1: + case RT1019_PWM_DC_DET_2: + case RT1019_PWM_DC_DET_3: + case RT1019_PWM_DC_DET_4: + case RT1019_BEEP_1: + case RT1019_BEEP_2: + case RT1019_PMC_1: + case RT1019_PMC_2: + case RT1019_PMC_3: + case RT1019_PMC_4: + case RT1019_PMC_5: + case RT1019_PMC_6: + case RT1019_PMC_7: + case RT1019_PMC_8: + case RT1019_PMC_9: + case RT1019_SPKDRC_1: + case RT1019_SPKDRC_2: + case RT1019_SPKDRC_3: + case RT1019_SPKDRC_4: + case RT1019_SPKDRC_5: + case RT1019_SPKDRC_6: + case RT1019_SPKDRC_7: + case RT1019_HALF_FREQ_1: + case RT1019_HALF_FREQ_2: + case RT1019_HALF_FREQ_3: + case RT1019_HALF_FREQ_4: + case RT1019_HALF_FREQ_5: + case RT1019_HALF_FREQ_6: + case RT1019_HALF_FREQ_7: + case RT1019_CUR_CTRL_1: + case RT1019_CUR_CTRL_2: + case RT1019_CUR_CTRL_3: + case RT1019_CUR_CTRL_4: + case RT1019_CUR_CTRL_5: + case RT1019_CUR_CTRL_6: + case RT1019_CUR_CTRL_7: + case RT1019_CUR_CTRL_8: + case RT1019_CUR_CTRL_9: + case RT1019_CUR_CTRL_10: + case RT1019_CUR_CTRL_11: + case RT1019_CUR_CTRL_12: + case RT1019_CUR_CTRL_13: + return true; + default: + return false; + } +} + +static const DECLARE_TLV_DB_SCALE(dac_vol_tlv, -9525, 75, 0); + +static const char * const rt1019_din_source_select[] = { + "Left", + "Right", + "Left + Right average", +}; + +static SOC_ENUM_SINGLE_DECL(rt1019_mono_lr_sel, RT1019_IDS_CTRL, 0, + rt1019_din_source_select); + +static const struct snd_kcontrol_new rt1019_snd_controls[] = { + SOC_SINGLE_TLV("DAC Playback Volume", RT1019_DMIX_MONO_1, 0, + 127, 0, dac_vol_tlv), + SOC_ENUM("Mono LR Select", rt1019_mono_lr_sel), +}; + +static int r1019_dac_event(struct snd_soc_dapm_widget *w, + struct snd_kcontrol *kcontrol, int event) +{ + struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm); + + switch (event) { + case SND_SOC_DAPM_PRE_PMU: + snd_soc_component_write(component, RT1019_SDB_CTRL, 0xb); + break; + case SND_SOC_DAPM_POST_PMD: + snd_soc_component_write(component, RT1019_SDB_CTRL, 0xa); + break; + default: + break; + } + + return 0; +} + +static const struct snd_soc_dapm_widget rt1019_dapm_widgets[] = { + SND_SOC_DAPM_AIF_IN("AIFRX", "AIF Playback", 0, SND_SOC_NOPM, 0, 0), + SND_SOC_DAPM_DAC_E("DAC", NULL, SND_SOC_NOPM, 0, 0, + r1019_dac_event, SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD), + SND_SOC_DAPM_OUTPUT("SPO"), +}; + +static const struct snd_soc_dapm_route rt1019_dapm_routes[] = { + { "DAC", NULL, "AIFRX" }, + { "SPO", NULL, "DAC" }, +}; + +static int rt1019_hw_params(struct snd_pcm_substream *substream, + struct snd_pcm_hw_params *params, struct snd_soc_dai *dai) +{ + struct snd_soc_component *component = dai->component; + struct rt1019_priv *rt1019 = snd_soc_component_get_drvdata(component); + int pre_div, bclk_ms, frame_size; + unsigned int val_len = 0, sys_div_da_filter = 0; + unsigned int sys_dac_osr = 0, sys_fifo_clk = 0; + unsigned int sys_clk_cal = 0, sys_asrc_in = 0; + + rt1019->lrck = params_rate(params); + pre_div = rl6231_get_clk_info(rt1019->sysclk, rt1019->lrck); + if (pre_div < 0) { + dev_err(component->dev, "Unsupported clock setting\n"); + return -EINVAL; + } + + frame_size = snd_soc_params_to_frame_size(params); + if (frame_size < 0) { + dev_err(component->dev, "Unsupported frame size: %d\n", frame_size); + return -EINVAL; + } + + bclk_ms = frame_size > 32; + rt1019->bclk = rt1019->lrck * (32 << bclk_ms); + + dev_dbg(dai->dev, "bclk is %dHz and lrck is %dHz\n", + rt1019->bclk, rt1019->lrck); + dev_dbg(dai->dev, "bclk_ms is %d and pre_div is %d for iis %d\n", + bclk_ms, pre_div, dai->id); + + switch (pre_div) { + case 0: + sys_div_da_filter = RT1019_SYS_DIV_DA_FIL_DIV1; + sys_dac_osr = RT1019_SYS_DA_OSR_DIV1; + sys_asrc_in = RT1019_ASRC_256FS_DIV1; + sys_fifo_clk = RT1019_SEL_FIFO_DIV1; + sys_clk_cal = RT1019_SEL_CLK_CAL_DIV1; + break; + case 1: + sys_div_da_filter = RT1019_SYS_DIV_DA_FIL_DIV2; + sys_dac_osr = RT1019_SYS_DA_OSR_DIV2; + sys_asrc_in = RT1019_ASRC_256FS_DIV2; + sys_fifo_clk = RT1019_SEL_FIFO_DIV2; + sys_clk_cal = RT1019_SEL_CLK_CAL_DIV2; + break; + case 3: + sys_div_da_filter = RT1019_SYS_DIV_DA_FIL_DIV4; + sys_dac_osr = RT1019_SYS_DA_OSR_DIV4; + sys_asrc_in = RT1019_ASRC_256FS_DIV4; + sys_fifo_clk = RT1019_SEL_FIFO_DIV4; + sys_clk_cal = RT1019_SEL_CLK_CAL_DIV4; + break; + default: + return -EINVAL; + } + + switch (params_width(params)) { + case 16: + break; + case 20: + val_len = RT1019_I2S_DL_20; + break; + case 24: + val_len = RT1019_I2S_DL_24; + break; + case 32: + val_len = RT1019_I2S_DL_32; + break; + case 8: + val_len = RT1019_I2S_DL_8; + break; + default: + return -EINVAL; + } + + snd_soc_component_update_bits(component, RT1019_TDM_2, RT1019_I2S_DL_MASK, + val_len); + snd_soc_component_update_bits(component, RT1019_CLK_TREE_1, + RT1019_SEL_FIFO_MASK, sys_fifo_clk); + snd_soc_component_update_bits(component, RT1019_CLK_TREE_2, + RT1019_SYS_DIV_DA_FIL_MASK | RT1019_SYS_DA_OSR_MASK | + RT1019_ASRC_256FS_MASK, sys_div_da_filter | sys_dac_osr | + sys_asrc_in); + snd_soc_component_update_bits(component, RT1019_CLK_TREE_3, + RT1019_SEL_CLK_CAL_MASK, sys_clk_cal); + + return 0; +} + +static int rt1019_set_dai_fmt(struct snd_soc_dai *dai, unsigned int fmt) +{ + struct snd_soc_component *component = dai->component; + unsigned int reg_val = 0, reg_val2 = 0; + + switch (fmt & SND_SOC_DAIFMT_INV_MASK) { + case SND_SOC_DAIFMT_NB_NF: + break; + case SND_SOC_DAIFMT_IB_NF: + reg_val2 |= RT1019_TDM_BCLK_INV; + break; + default: + return -EINVAL; + } + + switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) { + case SND_SOC_DAIFMT_I2S: + break; + + case SND_SOC_DAIFMT_LEFT_J: + reg_val |= RT1019_I2S_DF_LEFT; + break; + + case SND_SOC_DAIFMT_DSP_A: + reg_val |= RT1019_I2S_DF_PCM_A_R; + break; + + case SND_SOC_DAIFMT_DSP_B: + reg_val |= RT1019_I2S_DF_PCM_B_R; + break; + + default: + return -EINVAL; + } + + snd_soc_component_update_bits(component, RT1019_TDM_2, + RT1019_I2S_DF_MASK, reg_val); + snd_soc_component_update_bits(component, RT1019_TDM_1, + RT1019_TDM_BCLK_MASK, reg_val2); + + return 0; +} + +static int rt1019_set_dai_sysclk(struct snd_soc_dai *dai, + int clk_id, unsigned int freq, int dir) +{ + struct snd_soc_component *component = dai->component; + struct rt1019_priv *rt1019 = snd_soc_component_get_drvdata(component); + unsigned int reg_val = 0; + + if (freq == rt1019->sysclk && clk_id == rt1019->sysclk_src) + return 0; + + switch (clk_id) { + case RT1019_SCLK_S_BCLK: + reg_val |= RT1019_CLK_SYS_PRE_SEL_BCLK; + break; + + case RT1019_SCLK_S_PLL: + reg_val |= RT1019_CLK_SYS_PRE_SEL_PLL; + break; + + default: + dev_err(component->dev, "Invalid clock id (%d)\n", clk_id); + return -EINVAL; + } + + rt1019->sysclk = freq; + rt1019->sysclk_src = clk_id; + + dev_dbg(dai->dev, "Sysclk is %dHz and clock id is %d\n", freq, clk_id); + + snd_soc_component_update_bits(component, RT1019_CLK_TREE_1, + RT1019_CLK_SYS_PRE_SEL_MASK, reg_val); + + return 0; +} + +static int rt1019_set_dai_pll(struct snd_soc_dai *dai, int pll_id, int source, + unsigned int freq_in, unsigned int freq_out) +{ + struct snd_soc_component *component = dai->component; + struct rt1019_priv *rt1019 = snd_soc_component_get_drvdata(component); + struct rl6231_pll_code pll_code; + int ret; + + if (!freq_in || !freq_out) { + dev_dbg(component->dev, "PLL disabled\n"); + rt1019->pll_in = 0; + rt1019->pll_out = 0; + return 0; + } + + if (source == rt1019->pll_src && freq_in == rt1019->pll_in && + freq_out == rt1019->pll_out) + return 0; + + switch (source) { + case RT1019_PLL_S_BCLK: + snd_soc_component_update_bits(component, RT1019_CLK_TREE_1, + RT1019_PLL_SRC_MASK, RT1019_PLL_SRC_SEL_BCLK); + break; + + case RT1019_PLL_S_RC25M: + snd_soc_component_update_bits(component, RT1019_CLK_TREE_1, + RT1019_PLL_SRC_MASK, RT1019_PLL_SRC_SEL_RC); + break; + + default: + dev_err(component->dev, "Unknown PLL source %d\n", source); + return -EINVAL; + } + + ret = rl6231_pll_calc(freq_in, freq_out, &pll_code); + if (ret < 0) { + dev_err(component->dev, "Unsupport input clock %d\n", freq_in); + return ret; + } + + dev_dbg(component->dev, "bypass=%d m=%d n=%d k=%d\n", + pll_code.m_bp, (pll_code.m_bp ? 0 : pll_code.m_code), + pll_code.n_code, pll_code.k_code); + + snd_soc_component_update_bits(component, RT1019_PWR_STRP_2, + RT1019_AUTO_BITS_SEL_MASK | RT1019_AUTO_CLK_SEL_MASK, + RT1019_AUTO_BITS_SEL_MANU | RT1019_AUTO_CLK_SEL_MANU); + snd_soc_component_update_bits(component, RT1019_PLL_1, + RT1019_PLL_M_MASK | RT1019_PLL_M_BP_MASK | RT1019_PLL_Q_8_8_MASK, + (pll_code.m_bp ? 0 : pll_code.m_code) << RT1019_PLL_M_SFT | + pll_code.m_bp << RT1019_PLL_M_BP_SFT | + ((pll_code.n_code >> 8) & RT1019_PLL_Q_8_8_MASK)); + snd_soc_component_update_bits(component, RT1019_PLL_2, + RT1019_PLL_Q_7_0_MASK, pll_code.n_code & RT1019_PLL_Q_7_0_MASK); + snd_soc_component_update_bits(component, RT1019_PLL_3, + RT1019_PLL_K_MASK, pll_code.k_code); + + rt1019->pll_in = freq_in; + rt1019->pll_out = freq_out; + rt1019->pll_src = source; + + return 0; +} + +static int rt1019_set_tdm_slot(struct snd_soc_dai *dai, unsigned int tx_mask, + unsigned int rx_mask, int slots, int slot_width) +{ + struct snd_soc_component *component = dai->component; + unsigned int val = 0, rx_slotnum; + int ret = 0, first_bit; + + switch (slots) { + case 4: + val |= RT1019_I2S_TX_4CH; + break; + case 6: + val |= RT1019_I2S_TX_6CH; + break; + case 8: + val |= RT1019_I2S_TX_8CH; + break; + case 2: + break; + default: + return -EINVAL; + } + + switch (slot_width) { + case 20: + val |= RT1019_I2S_DL_20; + break; + case 24: + val |= RT1019_I2S_DL_24; + break; + case 32: + val |= RT1019_I2S_DL_32; + break; + case 8: + val |= RT1019_I2S_DL_8; + break; + case 16: + break; + default: + return -EINVAL; + } + + /* Rx slot configuration */ + rx_slotnum = hweight_long(rx_mask); + if (rx_slotnum != 1) { + ret = -EINVAL; + dev_err(component->dev, "too many rx slots or zero slot\n"); + goto _set_tdm_err_; + } + /* This is an assumption that the system sends stereo audio to the + * amplifier typically. And the stereo audio is placed in slot 0/2/4/6 + * as the starting slot. The users could select the channel from + * L/R/L+R by "Mono LR Select" control. + */ + first_bit = __ffs(rx_mask); + switch (first_bit) { + case 0: + case 2: + case 4: + case 6: + snd_soc_component_update_bits(component, + RT1019_TDM_3, + RT1019_TDM_I2S_TX_L_DAC1_1_MASK | + RT1019_TDM_I2S_TX_R_DAC1_1_MASK, + (first_bit << RT1019_TDM_I2S_TX_L_DAC1_1_SFT) | + ((first_bit + 1) << RT1019_TDM_I2S_TX_R_DAC1_1_SFT)); + break; + case 1: + case 3: + case 5: + case 7: + snd_soc_component_update_bits(component, + RT1019_TDM_3, + RT1019_TDM_I2S_TX_L_DAC1_1_MASK | + RT1019_TDM_I2S_TX_R_DAC1_1_MASK, + ((first_bit - 1) << RT1019_TDM_I2S_TX_L_DAC1_1_SFT) | + (first_bit << RT1019_TDM_I2S_TX_R_DAC1_1_SFT)); + break; + default: + ret = -EINVAL; + goto _set_tdm_err_; + } + + snd_soc_component_update_bits(component, RT1019_TDM_2, + RT1019_I2S_CH_TX_MASK | RT1019_I2S_DF_MASK, val); + +_set_tdm_err_: + return ret; +} + +static int rt1019_probe(struct snd_soc_component *component) +{ + struct rt1019_priv *rt1019 = snd_soc_component_get_drvdata(component); + + rt1019->component = component; + snd_soc_component_write(component, RT1019_SDB_CTRL, 0xa); + + return 0; +} + +#define RT1019_STEREO_RATES SNDRV_PCM_RATE_8000_192000 +#define RT1019_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S20_3LE | \ + SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S8) + +static struct snd_soc_dai_ops rt1019_aif_dai_ops = { + .hw_params = rt1019_hw_params, + .set_fmt = rt1019_set_dai_fmt, + .set_sysclk = rt1019_set_dai_sysclk, + .set_pll = rt1019_set_dai_pll, + .set_tdm_slot = rt1019_set_tdm_slot, +}; + +static struct snd_soc_dai_driver rt1019_dai[] = { + { + .name = "rt1019-aif", + .id = 0, + .playback = { + .stream_name = "AIF Playback", + .channels_min = 1, + .channels_max = 2, + .rates = RT1019_STEREO_RATES, + .formats = RT1019_FORMATS, + }, + .ops = &rt1019_aif_dai_ops, + } +}; + +static const struct snd_soc_component_driver soc_component_dev_rt1019 = { + .probe = rt1019_probe, + .controls = rt1019_snd_controls, + .num_controls = ARRAY_SIZE(rt1019_snd_controls), + .dapm_widgets = rt1019_dapm_widgets, + .num_dapm_widgets = ARRAY_SIZE(rt1019_dapm_widgets), + .dapm_routes = rt1019_dapm_routes, + .num_dapm_routes = ARRAY_SIZE(rt1019_dapm_routes), +}; + +static const struct regmap_config rt1019_regmap = { + .reg_bits = 16, + .val_bits = 8, + .use_single_read = true, + .use_single_write = true, + .max_register = RT1019_CUR_CTRL_13, + .volatile_reg = rt1019_volatile_register, + .readable_reg = rt1019_readable_register, + .cache_type = REGCACHE_RBTREE, + .reg_defaults = rt1019_reg, + .num_reg_defaults = ARRAY_SIZE(rt1019_reg), +}; + +static const struct i2c_device_id rt1019_i2c_id[] = { + { "rt1019", 0 }, + { } +}; +MODULE_DEVICE_TABLE(i2c, rt1019_i2c_id); + +static const struct of_device_id rt1019_of_match[] = { + { .compatible = "realtek,rt1019", }, + {}, +}; +MODULE_DEVICE_TABLE(of, rt1019_of_match); + +#ifdef CONFIG_ACPI +static const struct acpi_device_id rt1019_acpi_match[] = { + { "10EC1019", 0}, + { }, +}; +MODULE_DEVICE_TABLE(acpi, rt1019_acpi_match); +#endif + +static int rt1019_i2c_probe(struct i2c_client *i2c, + const struct i2c_device_id *id) +{ + struct rt1019_priv *rt1019; + int ret; + unsigned int val, val2, dev_id; + + rt1019 = devm_kzalloc(&i2c->dev, sizeof(struct rt1019_priv), + GFP_KERNEL); + if (!rt1019) + return -ENOMEM; + + i2c_set_clientdata(i2c, rt1019); + + rt1019->regmap = devm_regmap_init_i2c(i2c, &rt1019_regmap); + if (IS_ERR(rt1019->regmap)) { + ret = PTR_ERR(rt1019->regmap); + dev_err(&i2c->dev, "Failed to allocate register map: %d\n", + ret); + return ret; + } + + regmap_read(rt1019->regmap, RT1019_DEV_ID_1, &val); + regmap_read(rt1019->regmap, RT1019_DEV_ID_2, &val2); + dev_id = val << 8 | val2; + if (dev_id != RT1019_DEVICE_ID_VAL && dev_id != RT1019_DEVICE_ID_VAL2) { + dev_err(&i2c->dev, + "Device with ID register 0x%x is not rt1019\n", dev_id); + return -ENODEV; + } + + return devm_snd_soc_register_component(&i2c->dev, + &soc_component_dev_rt1019, rt1019_dai, ARRAY_SIZE(rt1019_dai)); +} + +struct i2c_driver rt1019_i2c_driver = { + .driver = { + .name = "rt1019", + .of_match_table = of_match_ptr(rt1019_of_match), + .acpi_match_table = ACPI_PTR(rt1019_acpi_match), + }, + .probe = rt1019_i2c_probe, + .id_table = rt1019_i2c_id, +}; +module_i2c_driver(rt1019_i2c_driver); + +MODULE_DESCRIPTION("ASoC RT1019 driver"); +MODULE_AUTHOR("Jack Yu "); +MODULE_LICENSE("GPL v2"); diff --git a/sound/soc/codecs/rt1019.h b/sound/soc/codecs/rt1019.h new file mode 100644 index 000000000000..46973e71c963 --- /dev/null +++ b/sound/soc/codecs/rt1019.h @@ -0,0 +1,320 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * rt1019.h -- RT1019 ALSA SoC audio amplifier driver + * + * Copyright(c) 2021 Realtek Semiconductor Corp. + */ + +#ifndef __RT1019_H__ +#define __RT1019_H__ + +#define RT1019_DEVICE_ID_VAL 0x1019 +#define RT1019_DEVICE_ID_VAL2 0x6731 + +#define RT1019_RESET 0x0000 +#define RT1019_PAD_DRV_1 0x0002 +#define RT1019_PAD_DRV_2 0x0003 +#define RT1019_PAD_PULL_1 0x0005 +#define RT1019_PAD_PULL_2 0x0006 +#define RT1019_PAD_PULL_3 0x0007 +#define RT1019_I2C_CTRL_1 0x0008 +#define RT1019_I2C_CTRL_2 0x0009 +#define RT1019_I2C_CTRL_3 0x000a +#define RT1019_IDS_CTRL 0x0011 +#define RT1019_ASEL_CTRL 0x0013 +#define RT1019_PLL_RESET 0x0015 +#define RT1019_PWR_STRP_1 0x0017 +#define RT1019_PWR_STRP_2 0x0019 +#define RT1019_BEEP_TONE 0x001b +#define RT1019_SIL_DET_GAT 0x001d +#define RT1019_CLASSD_TIME 0x001f +#define RT1019_CLASSD_OCP 0x0021 +#define RT1019_PHASE_SYNC 0x0023 +#define RT1019_STAT_MACH_1 0x0025 +#define RT1019_STAT_MACH_2 0x0026 +#define RT1019_EFF_CTRL 0x0028 +#define RT1019_FS_DET_1 0x002a +#define RT1019_FS_DET_2 0x002b +#define RT1019_FS_DET_3 0x002c +#define RT1019_FS_DET_4 0x002d +#define RT1019_FS_DET_5 0x002e +#define RT1019_FS_DET_6 0x002f +#define RT1019_FS_DET_7 0x0030 +#define RT1019_ANA_CTRL 0x0053 +#define RT1019_DUMMY_A 0x0055 +#define RT1019_DUMMY_B 0x0056 +#define RT1019_DUMMY_C 0x0057 +#define RT1019_DUMMY_D 0x0058 +#define RT1019_ANA_READ 0x005a +#define RT1019_VER_ID 0x005c +#define RT1019_CUSTOM_ID 0x005d +#define RT1019_VEND_ID_1 0x005e +#define RT1019_VEND_ID_2 0x005f +#define RT1019_DEV_ID_1 0x0061 +#define RT1019_DEV_ID_2 0x0062 +#define RT1019_TEST_PAD 0x0064 +#define RT1019_SDB_CTRL 0x0066 +#define RT1019_TEST_CTRL_1 0x0068 +#define RT1019_TEST_CTRL_2 0x006a +#define RT1019_TEST_CTRL_3 0x006c +#define RT1019_SCAN_MODE 0x006e +#define RT1019_CLK_TREE_1 0x0100 +#define RT1019_CLK_TREE_2 0x0101 +#define RT1019_CLK_TREE_3 0x0102 +#define RT1019_CLK_TREE_4 0x0103 +#define RT1019_CLK_TREE_5 0x0104 +#define RT1019_CLK_TREE_6 0x0105 +#define RT1019_CLK_TREE_7 0x0106 +#define RT1019_CLK_TREE_8 0x0107 +#define RT1019_CLK_TREE_9 0x0108 +#define RT1019_ASRC_1 0x0200 +#define RT1019_ASRC_2 0x0201 +#define RT1019_ASRC_3 0x0202 +#define RT1019_ASRC_4 0x0203 +#define RT1019_SYS_CLK 0x0300 +#define RT1019_BIAS_CUR_1 0x0301 +#define RT1019_BIAS_CUR_2 0x0302 +#define RT1019_BIAS_CUR_3 0x0303 +#define RT1019_BIAS_CUR_4 0x0304 +#define RT1019_CHOP_CLK_DAC 0x0306 +#define RT1019_CHOP_CLK_ADC 0x0308 +#define RT1019_LDO_CTRL_1 0x030a +#define RT1019_LDO_CTRL_2 0x030b +#define RT1019_PM_ANA_1 0x030d +#define RT1019_PM_ANA_2 0x030e +#define RT1019_PM_ANA_3 0x030f +#define RT1019_PLL_1 0x0311 +#define RT1019_PLL_2 0x0312 +#define RT1019_PLL_3 0x0313 +#define RT1019_PLL_INT_1 0x0315 +#define RT1019_PLL_INT_3 0x0318 +#define RT1019_MIXER 0x031a +#define RT1019_CLD_OUT_1 0x031c +#define RT1019_CLD_OUT_2 0x031d +#define RT1019_CLD_OUT_3 0x031e +#define RT1019_CLD_OUT_4 0x031f +#define RT1019_CLD_OUT_5 0x0320 +#define RT1019_CLD_OUT_6 0x0321 +#define RT1019_CLS_INT_REG_1 0x0323 +#define RT1019_CLS_INT_REG_2 0x0324 +#define RT1019_CLS_INT_REG_3 0x0325 +#define RT1019_CLS_INT_REG_4 0x0326 +#define RT1019_CLS_INT_REG_5 0x0327 +#define RT1019_CLS_INT_REG_6 0x0328 +#define RT1019_CLS_INT_REG_7 0x0329 +#define RT1019_CLS_INT_REG_8 0x0330 +#define RT1019_CLS_INT_REG_9 0x0331 +#define RT1019_CLS_INT_REG_10 0x0332 +#define RT1019_TDM_1 0x0400 +#define RT1019_TDM_2 0x0401 +#define RT1019_TDM_3 0x0402 +#define RT1019_TDM_4 0x0403 +#define RT1019_TDM_5 0x0404 +#define RT1019_TDM_6 0x0405 +#define RT1019_DVOL_1 0x0500 +#define RT1019_DVOL_2 0x0501 +#define RT1019_DVOL_3 0x0502 +#define RT1019_DVOL_4 0x0503 +#define RT1019_DMIX_MONO_1 0x0504 +#define RT1019_DMIX_MONO_2 0x0505 +#define RT1019_CAL_TOP_1 0x0600 +#define RT1019_CAL_TOP_2 0x0601 +#define RT1019_CAL_TOP_3 0x0602 +#define RT1019_CAL_TOP_4 0x0603 +#define RT1019_CAL_TOP_5 0x0604 +#define RT1019_CAL_TOP_6 0x0605 +#define RT1019_CAL_TOP_7 0x0606 +#define RT1019_CAL_TOP_8 0x0607 +#define RT1019_CAL_TOP_9 0x0608 +#define RT1019_CAL_TOP_10 0x0609 +#define RT1019_CAL_TOP_11 0x060a +#define RT1019_CAL_TOP_12 0x060b +#define RT1019_CAL_TOP_13 0x060c +#define RT1019_CAL_TOP_14 0x060d +#define RT1019_CAL_TOP_15 0x060e +#define RT1019_CAL_TOP_16 0x060f +#define RT1019_CAL_TOP_17 0x0610 +#define RT1019_CAL_TOP_18 0x0611 +#define RT1019_CAL_TOP_19 0x0612 +#define RT1019_CAL_TOP_20 0x0613 +#define RT1019_CAL_TOP_21 0x0614 +#define RT1019_CAL_TOP_22 0x0615 +#define RT1019_MDRE_CTRL_1 0x0700 +#define RT1019_MDRE_CTRL_2 0x0701 +#define RT1019_MDRE_CTRL_3 0x0702 +#define RT1019_MDRE_CTRL_4 0x0703 +#define RT1019_MDRE_CTRL_5 0x0704 +#define RT1019_MDRE_CTRL_6 0x0705 +#define RT1019_MDRE_CTRL_7 0x0706 +#define RT1019_MDRE_CTRL_8 0x0707 +#define RT1019_MDRE_CTRL_9 0x0708 +#define RT1019_MDRE_CTRL_10 0x0709 +#define RT1019_SCC_CTRL_1 0x0800 +#define RT1019_SCC_CTRL_2 0x0801 +#define RT1019_SCC_CTRL_3 0x0802 +#define RT1019_SCC_DUMMY 0x0803 +#define RT1019_SIL_DET_1 0x0900 +#define RT1019_SIL_DET_2 0x0901 +#define RT1019_PWM_DC_DET_1 0x0a00 +#define RT1019_PWM_DC_DET_2 0x0a01 +#define RT1019_PWM_DC_DET_3 0x0a02 +#define RT1019_PWM_DC_DET_4 0x0a03 +#define RT1019_BEEP_1 0x0b00 +#define RT1019_BEEP_2 0x0b01 +#define RT1019_PMC_1 0x0c00 +#define RT1019_PMC_2 0x0c01 +#define RT1019_PMC_3 0x0c02 +#define RT1019_PMC_4 0x0c03 +#define RT1019_PMC_5 0x0c04 +#define RT1019_PMC_6 0x0c05 +#define RT1019_PMC_7 0x0c06 +#define RT1019_PMC_8 0x0c07 +#define RT1019_PMC_9 0x0c08 +#define RT1019_SPKDRC_1 0x0d00 +#define RT1019_SPKDRC_2 0x0d01 +#define RT1019_SPKDRC_3 0x0d02 +#define RT1019_SPKDRC_4 0x0d03 +#define RT1019_SPKDRC_5 0x0d04 +#define RT1019_SPKDRC_6 0x0d05 +#define RT1019_SPKDRC_7 0x0d06 +#define RT1019_HALF_FREQ_1 0x0e00 +#define RT1019_HALF_FREQ_2 0x0e01 +#define RT1019_HALF_FREQ_3 0x0e02 +#define RT1019_HALF_FREQ_4 0x0e03 +#define RT1019_HALF_FREQ_5 0x0e04 +#define RT1019_HALF_FREQ_6 0x0e05 +#define RT1019_HALF_FREQ_7 0x0e06 +#define RT1019_CUR_CTRL_1 0x0f00 +#define RT1019_CUR_CTRL_2 0x0f01 +#define RT1019_CUR_CTRL_3 0x0f02 +#define RT1019_CUR_CTRL_4 0x0f03 +#define RT1019_CUR_CTRL_5 0x0f04 +#define RT1019_CUR_CTRL_6 0x0f05 +#define RT1019_CUR_CTRL_7 0x0f06 +#define RT1019_CUR_CTRL_8 0x0f07 +#define RT1019_CUR_CTRL_9 0x0f08 +#define RT1019_CUR_CTRL_10 0x0f09 +#define RT1019_CUR_CTRL_11 0x0f0a +#define RT1019_CUR_CTRL_12 0x0f0b +#define RT1019_CUR_CTRL_13 0x0f0c + +/* 0x0019 Power On Strap Control-2 */ +#define RT1019_AUTO_BITS_SEL_MASK (0x1 << 5) +#define RT1019_AUTO_BITS_SEL_AUTO (0x1 << 5) +#define RT1019_AUTO_BITS_SEL_MANU (0x0 << 5) +#define RT1019_AUTO_CLK_SEL_MASK (0x1 << 4) +#define RT1019_AUTO_CLK_SEL_AUTO (0x1 << 4) +#define RT1019_AUTO_CLK_SEL_MANU (0x0 << 4) + +/* 0x0100 Clock Tree Control-1 */ +#define RT1019_CLK_SYS_PRE_SEL_MASK (0x1 << 7) +#define RT1019_CLK_SYS_PRE_SEL_SFT 7 +#define RT1019_CLK_SYS_PRE_SEL_BCLK (0x0 << 7) +#define RT1019_CLK_SYS_PRE_SEL_PLL (0x1 << 7) +#define RT1019_PLL_SRC_MASK (0x1 << 4) +#define RT1019_PLL_SRC_SFT 4 +#define RT1019_PLL_SRC_SEL_BCLK (0x0 << 4) +#define RT1019_PLL_SRC_SEL_RC (0x1 << 4) +#define RT1019_SEL_FIFO_MASK (0x3 << 2) +#define RT1019_SEL_FIFO_DIV1 (0x0 << 2) +#define RT1019_SEL_FIFO_DIV2 (0x1 << 2) +#define RT1019_SEL_FIFO_DIV4 (0x2 << 2) + +/* 0x0101 clock tree control-2 */ +#define RT1019_SYS_DIV_DA_FIL_MASK (0x7 << 5) +#define RT1019_SYS_DIV_DA_FIL_DIV1 (0x2 << 5) +#define RT1019_SYS_DIV_DA_FIL_DIV2 (0x3 << 5) +#define RT1019_SYS_DIV_DA_FIL_DIV4 (0x4 << 5) +#define RT1019_SYS_DA_OSR_MASK (0x3 << 2) +#define RT1019_SYS_DA_OSR_DIV1 (0x0 << 2) +#define RT1019_SYS_DA_OSR_DIV2 (0x1 << 2) +#define RT1019_SYS_DA_OSR_DIV4 (0x2 << 2) +#define RT1019_ASRC_256FS_MASK 0x3 +#define RT1019_ASRC_256FS_DIV1 0x0 +#define RT1019_ASRC_256FS_DIV2 0x1 +#define RT1019_ASRC_256FS_DIV4 0x2 + +/* 0x0102 clock tree control-3 */ +#define RT1019_SEL_CLK_CAL_MASK (0x3 << 6) +#define RT1019_SEL_CLK_CAL_DIV1 (0x0 << 6) +#define RT1019_SEL_CLK_CAL_DIV2 (0x1 << 6) +#define RT1019_SEL_CLK_CAL_DIV4 (0x2 << 6) + +/* 0x0311 PLL-1 */ +#define RT1019_PLL_M_MASK (0xf << 4) +#define RT1019_PLL_M_SFT 4 +#define RT1019_PLL_M_BP_MASK (0x1 << 1) +#define RT1019_PLL_M_BP_SFT 1 +#define RT1019_PLL_Q_8_8_MASK (0x1) + +/* 0x0312 PLL-2 */ +#define RT1019_PLL_Q_7_0_MASK 0xff + +/* 0x0313 PLL-3 */ +#define RT1019_PLL_K_MASK 0x1f + +/* 0x0400 TDM Control-1 */ +#define RT1019_TDM_BCLK_MASK (0x1 << 6) +#define RT1019_TDM_BCLK_NORM (0x0 << 6) +#define RT1019_TDM_BCLK_INV (0x1 << 6) + +/* 0x0401 TDM Control-2 */ +#define RT1019_I2S_CH_TX_MASK (0x3 << 6) +#define RT1019_I2S_CH_TX_SFT 6 +#define RT1019_I2S_TX_2CH (0x0 << 6) +#define RT1019_I2S_TX_4CH (0x1 << 6) +#define RT1019_I2S_TX_6CH (0x2 << 6) +#define RT1019_I2S_TX_8CH (0x3 << 6) +#define RT1019_I2S_DF_MASK (0x7 << 3) +#define RT1019_I2S_DF_SFT 3 +#define RT1019_I2S_DF_I2S (0x0 << 3) +#define RT1019_I2S_DF_LEFT (0x1 << 3) +#define RT1019_I2S_DF_PCM_A_R (0x2 << 3) +#define RT1019_I2S_DF_PCM_B_R (0x3 << 3) +#define RT1019_I2S_DF_PCM_A_F (0x6 << 3) +#define RT1019_I2S_DF_PCM_B_F (0x7 << 3) +#define RT1019_I2S_DL_MASK 0x7 +#define RT1019_I2S_DL_SFT 0 +#define RT1019_I2S_DL_16 0x0 +#define RT1019_I2S_DL_20 0x1 +#define RT1019_I2S_DL_24 0x2 +#define RT1019_I2S_DL_32 0x3 +#define RT1019_I2S_DL_8 0x4 + +/* TDM1 Control-3 (0x0402) */ +#define RT1019_TDM_I2S_TX_L_DAC1_1_MASK (0x7 << 4) +#define RT1019_TDM_I2S_TX_R_DAC1_1_MASK 0x7 +#define RT1019_TDM_I2S_TX_L_DAC1_1_SFT 4 +#define RT1019_TDM_I2S_TX_R_DAC1_1_SFT 0 + +/* System Clock Source */ +enum { + RT1019_SCLK_S_BCLK, + RT1019_SCLK_S_PLL, +}; + +/* PLL1 Source */ +enum { + RT1019_PLL_S_BCLK, + RT1019_PLL_S_RC25M, +}; + +enum { + RT1019_AIF1, + RT1019_AIFS +}; + +struct rt1019_priv { + struct snd_soc_component *component; + struct regmap *regmap; + int sysclk; + int sysclk_src; + int lrck; + int bclk; + int pll_src; + int pll_in; + int pll_out; + unsigned int bclk_ratio; +}; + +#endif /* __RT1019_H__ */ From ad83b1adc58d6693036fd330d6af95a33564eaae Mon Sep 17 00:00:00 2001 From: Brent Lu Date: Wed, 17 Mar 2021 19:08:24 +0800 Subject: [PATCH 272/587] ASoC: Intel: sof_rt5682: Add ALC1015Q-VB speaker amp support This patch adds jsl_rt5682_rt1015p which supports the RT5682 headset codec and ALC1015Q-VB speaker amplifier combination on JasperLake platform. This driver also supports ALC1015Q-CG if running in auto-mode. Following table shows the audio interface support of the two amplifiers. | ALC1015Q-CG | ALC1015Q-VB ===================================== I2C | Yes | No Auto-mode | 48K, 64fs | 16k, 32fs | 48k, 32fs | 48k, 64fs Signed-off-by: Brent Lu Acked-by: Pierre-Louis Bossart Link: https://lore.kernel.org/r/20210317110824.20814-1-brent.lu@intel.com Signed-off-by: Mark Brown --- sound/soc/intel/boards/Kconfig | 1 + sound/soc/intel/boards/sof_realtek_common.c | 105 ++++++++++++++++++ sound/soc/intel/boards/sof_realtek_common.h | 7 ++ sound/soc/intel/boards/sof_rt5682.c | 19 +++- .../intel/common/soc-acpi-intel-jsl-match.c | 13 +++ 5 files changed, 143 insertions(+), 2 deletions(-) diff --git a/sound/soc/intel/boards/Kconfig b/sound/soc/intel/boards/Kconfig index d1d28129a32b..58379393b8e4 100644 --- a/sound/soc/intel/boards/Kconfig +++ b/sound/soc/intel/boards/Kconfig @@ -457,6 +457,7 @@ config SND_SOC_INTEL_SOF_RT5682_MACH select SND_SOC_MAX98373_I2C select SND_SOC_RT1011 select SND_SOC_RT1015 + select SND_SOC_RT1015P select SND_SOC_RT5682_I2C select SND_SOC_DMIC select SND_SOC_HDAC_HDMI diff --git a/sound/soc/intel/boards/sof_realtek_common.c b/sound/soc/intel/boards/sof_realtek_common.c index f3cf73c620ba..2ec34f8df9e1 100644 --- a/sound/soc/intel/boards/sof_realtek_common.c +++ b/sound/soc/intel/boards/sof_realtek_common.c @@ -7,6 +7,7 @@ #include #include #include +#include #include #include #include @@ -136,3 +137,107 @@ void sof_rt1011_codec_conf(struct snd_soc_card *card) card->codec_conf = rt1011_codec_confs; card->num_configs = ARRAY_SIZE(rt1011_codec_confs); } + +/* + * rt1015: i2c mode driver for ALC1015 and ALC1015Q + * rt1015p: auto-mode driver for ALC1015, ALC1015Q, and ALC1015Q-VB + * + * For stereo output, there are always two amplifiers on the board. + * However, the ACPI implements only one device instance (UID=0) if they + * are sharing the same enable pin. The code will detect the number of + * device instance and use corresponding DAPM structures for + * initialization. + */ +static const struct snd_soc_dapm_route rt1015p_1dev_dapm_routes[] = { + /* speaker */ + { "Left Spk", NULL, "Speaker" }, + { "Right Spk", NULL, "Speaker" }, +}; + +static const struct snd_soc_dapm_route rt1015p_2dev_dapm_routes[] = { + /* speaker */ + { "Left Spk", NULL, "Left Speaker" }, + { "Right Spk", NULL, "Right Speaker" }, +}; + +static struct snd_soc_codec_conf rt1015p_codec_confs[] = { + { + .dlc = COMP_CODEC_CONF(RT1015P_DEV0_NAME), + .name_prefix = "Left", + }, + { + .dlc = COMP_CODEC_CONF(RT1015P_DEV1_NAME), + .name_prefix = "Right", + }, +}; + +static struct snd_soc_dai_link_component rt1015p_dai_link_components[] = { + { + .name = RT1015P_DEV0_NAME, + .dai_name = RT1015P_CODEC_DAI, + }, + { + .name = RT1015P_DEV1_NAME, + .dai_name = RT1015P_CODEC_DAI, + }, +}; + +static int rt1015p_get_num_codecs(void) +{ + static int dev_num; + + if (dev_num) + return dev_num; + + if (!acpi_dev_present("RTL1015", "1", -1)) + dev_num = 1; + else + dev_num = 2; + + return dev_num; +} + +static int rt1015p_hw_params(struct snd_pcm_substream *substream, + struct snd_pcm_hw_params *params) +{ + /* reserved for debugging purpose */ + + return 0; +} + +static const struct snd_soc_ops rt1015p_ops = { + .hw_params = rt1015p_hw_params, +}; + +static int rt1015p_init(struct snd_soc_pcm_runtime *rtd) +{ + struct snd_soc_card *card = rtd->card; + int ret; + + if (rt1015p_get_num_codecs() == 1) + ret = snd_soc_dapm_add_routes(&card->dapm, rt1015p_1dev_dapm_routes, + ARRAY_SIZE(rt1015p_1dev_dapm_routes)); + else + ret = snd_soc_dapm_add_routes(&card->dapm, rt1015p_2dev_dapm_routes, + ARRAY_SIZE(rt1015p_2dev_dapm_routes)); + if (ret) + dev_err(rtd->dev, "Speaker map addition failed: %d\n", ret); + return ret; +} + +void sof_rt1015p_dai_link(struct snd_soc_dai_link *link) +{ + link->codecs = rt1015p_dai_link_components; + link->num_codecs = rt1015p_get_num_codecs(); + link->init = rt1015p_init; + link->ops = &rt1015p_ops; +} + +void sof_rt1015p_codec_conf(struct snd_soc_card *card) +{ + if (rt1015p_get_num_codecs() == 1) + return; + + card->codec_conf = rt1015p_codec_confs; + card->num_configs = ARRAY_SIZE(rt1015p_codec_confs); +} diff --git a/sound/soc/intel/boards/sof_realtek_common.h b/sound/soc/intel/boards/sof_realtek_common.h index 87cb3812b926..cb0b49b2855c 100644 --- a/sound/soc/intel/boards/sof_realtek_common.h +++ b/sound/soc/intel/boards/sof_realtek_common.h @@ -21,4 +21,11 @@ void sof_rt1011_dai_link(struct snd_soc_dai_link *link); void sof_rt1011_codec_conf(struct snd_soc_card *card); +#define RT1015P_CODEC_DAI "HiFi" +#define RT1015P_DEV0_NAME "RTL1015:00" +#define RT1015P_DEV1_NAME "RTL1015:01" + +void sof_rt1015p_dai_link(struct snd_soc_dai_link *link); +void sof_rt1015p_codec_conf(struct snd_soc_card *card); + #endif /* __SOF_REALTEK_COMMON_H */ diff --git a/sound/soc/intel/boards/sof_rt5682.c b/sound/soc/intel/boards/sof_rt5682.c index 55505e207bc0..f4b898c1719f 100644 --- a/sound/soc/intel/boards/sof_rt5682.c +++ b/sound/soc/intel/boards/sof_rt5682.c @@ -45,8 +45,9 @@ #define SOF_RT1011_SPEAKER_AMP_PRESENT BIT(13) #define SOF_RT1015_SPEAKER_AMP_PRESENT BIT(14) #define SOF_RT1015_SPEAKER_AMP_100FS BIT(15) -#define SOF_MAX98373_SPEAKER_AMP_PRESENT BIT(16) -#define SOF_MAX98360A_SPEAKER_AMP_PRESENT BIT(17) +#define SOF_RT1015P_SPEAKER_AMP_PRESENT BIT(16) +#define SOF_MAX98373_SPEAKER_AMP_PRESENT BIT(17) +#define SOF_MAX98360A_SPEAKER_AMP_PRESENT BIT(18) /* Default: MCLK on, MCLK 19.2M, SSP0 */ static unsigned long sof_rt5682_quirk = SOF_RT5682_MCLK_EN | @@ -723,6 +724,8 @@ static struct snd_soc_dai_link *sof_card_dai_links_create(struct device *dev, links[id].num_codecs = ARRAY_SIZE(rt1015_components); links[id].init = speaker_codec_init_lr; links[id].ops = &sof_rt1015_ops; + } else if (sof_rt5682_quirk & SOF_RT1015P_SPEAKER_AMP_PRESENT) { + sof_rt1015p_dai_link(&links[id]); } else if (sof_rt5682_quirk & SOF_MAX98373_SPEAKER_AMP_PRESENT) { links[id].codecs = max_98373_components; @@ -851,6 +854,8 @@ static int sof_audio_probe(struct platform_device *pdev) sof_max98373_codec_conf(&sof_audio_card_rt5682); else if (sof_rt5682_quirk & SOF_RT1011_SPEAKER_AMP_PRESENT) sof_rt1011_codec_conf(&sof_audio_card_rt5682); + else if (sof_rt5682_quirk & SOF_RT1015P_SPEAKER_AMP_PRESENT) + sof_rt1015p_codec_conf(&sof_audio_card_rt5682); dai_links = sof_card_dai_links_create(&pdev->dev, ssp_codec, ssp_amp, dmic_be_num, hdmi_num); @@ -940,6 +945,15 @@ static const struct platform_device_id board_ids[] = { SOF_RT5682_SSP_AMP(1) | SOF_RT5682_NUM_HDMIDEV(4)), }, + { + .name = "jsl_rt5682_rt1015p", + .driver_data = (kernel_ulong_t)(SOF_RT5682_MCLK_EN | + SOF_RT5682_MCLK_24MHZ | + SOF_RT5682_SSP_CODEC(0) | + SOF_SPEAKER_AMP_PRESENT | + SOF_RT1015P_SPEAKER_AMP_PRESENT | + SOF_RT5682_SSP_AMP(1)), + }, { } }; @@ -966,3 +980,4 @@ MODULE_ALIAS("platform:tgl_max98373_rt5682"); MODULE_ALIAS("platform:jsl_rt5682_max98360a"); MODULE_ALIAS("platform:cml_rt1015_rt5682"); MODULE_ALIAS("platform:tgl_rt1011_rt5682"); +MODULE_ALIAS("platform:jsl_rt5682_rt1015p"); diff --git a/sound/soc/intel/common/soc-acpi-intel-jsl-match.c b/sound/soc/intel/common/soc-acpi-intel-jsl-match.c index 52238db0bcb5..73fe4f89a82d 100644 --- a/sound/soc/intel/common/soc-acpi-intel-jsl-match.c +++ b/sound/soc/intel/common/soc-acpi-intel-jsl-match.c @@ -19,6 +19,11 @@ static struct snd_soc_acpi_codecs rt1015_spk = { .codecs = {"10EC1015"} }; +static struct snd_soc_acpi_codecs rt1015p_spk = { + .num_codecs = 1, + .codecs = {"RTL1015"} +}; + static struct snd_soc_acpi_codecs mx98360a_spk = { .num_codecs = 1, .codecs = {"MX98360A"} @@ -52,6 +57,14 @@ struct snd_soc_acpi_mach snd_soc_acpi_intel_jsl_machines[] = { .quirk_data = &rt1015_spk, .sof_tplg_filename = "sof-jsl-rt5682-rt1015.tplg", }, + { + .id = "10EC5682", + .drv_name = "jsl_rt5682_rt1015p", + .sof_fw_filename = "sof-jsl.ri", + .machine_quirk = snd_soc_acpi_codec_list, + .quirk_data = &rt1015p_spk, + .sof_tplg_filename = "sof-jsl-rt5682-rt1015.tplg", + }, { .id = "10EC5682", .drv_name = "jsl_rt5682_max98360a", From 8518c6486c2b8355e0781f8ee53c3c3f8427d96c Mon Sep 17 00:00:00 2001 From: huangjianghui Date: Fri, 19 Mar 2021 09:38:54 +0800 Subject: [PATCH 273/587] ALSA: hda: Fix spelling mistakes Signed-off-by: huangjianghui Link: https://lore.kernel.org/r/20210319013854.48830-1-huangjianghui@uniontech.com Signed-off-by: Takashi Iwai --- sound/hda/hdac_stream.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sound/hda/hdac_stream.c b/sound/hda/hdac_stream.c index a6ed3dc35f7e..1eb8563db2df 100644 --- a/sound/hda/hdac_stream.c +++ b/sound/hda/hdac_stream.c @@ -618,7 +618,7 @@ void snd_hdac_stream_sync_trigger(struct hdac_stream *azx_dev, bool set, EXPORT_SYMBOL_GPL(snd_hdac_stream_sync_trigger); /** - * snd_hdac_stream_sync - sync with start/strop trigger operation + * snd_hdac_stream_sync - sync with start/stop trigger operation * @azx_dev: HD-audio core stream (master stream) * @start: true = start, false = stop * @streams: bit flags of streams to sync From e4b044f4582366de10b8b28614c24ac4ff22b299 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Mon, 15 Mar 2021 09:57:37 +0900 Subject: [PATCH 274/587] ASoC: soc-pcm: indicate error message at soc_pcm_open() Indicating error message when failed case is very useful for debuging. In many case, its style is like below. int function(...) { ... return ret; } int caller(...) { ... ret = function(...); if (ret < 0) dev_err(...) ... } This is not so bad, but in this style *each caller* needs to indicate duplicate same error message, and some caller is forgetting to do it. And caller can't indicate detail function() error information. If function() indicates error message, we can get same and detail information without forgot. int function(...) { ... if (ret < 0) dev_err(...) return ret; } int caller(...) { ... ret = function(...); ... } This patch follow above style at soc_pcm_open(). By this patch, dpcm_fe/be_dai_startup(...) temporary lacks FE/BE error info, but it will reborn soon. Signed-off-by: Kuninori Morimoto Link: https://lore.kernel.org/r/87r1khutby.wl-kuninori.morimoto.gx@renesas.com Signed-off-by: Mark Brown --- sound/soc/soc-pcm.c | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/sound/soc/soc-pcm.c b/sound/soc/soc-pcm.c index a27385ab7b55..ad4b67bd0306 100644 --- a/sound/soc/soc-pcm.c +++ b/sound/soc/soc-pcm.c @@ -792,8 +792,10 @@ dynamic: err: mutex_unlock(&rtd->card->pcm_mutex); pm_err: - if (ret < 0) + if (ret < 0) { soc_pcm_clean(substream, 1); + dev_err(rtd->dev, "%s() failed (%d)", __func__, ret); + } return ret; } @@ -1504,7 +1506,6 @@ int dpcm_be_dai_startup(struct snd_soc_pcm_runtime *fe, int stream) be_substream->runtime = be->dpcm[stream].runtime; err = soc_pcm_open(be_substream); if (err < 0) { - dev_err(be->dev, "ASoC: BE open failed %d\n", err); be->dpcm[stream].users--; if (be->dpcm[stream].users < 0) dev_err(be->dev, "ASoC: no users %s at unwind %d\n", @@ -1744,10 +1745,8 @@ static int dpcm_fe_dai_startup(struct snd_pcm_substream *fe_substream) /* start the DAI frontend */ ret = soc_pcm_open(fe_substream); - if (ret < 0) { - dev_err(fe->dev,"ASoC: failed to start FE %d\n", ret); + if (ret < 0) goto unwind; - } fe->dpcm[stream].state = SND_SOC_DPCM_STATE_OPEN; From cb11f79b4af65005584880eb408f9748c32661d0 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Mon, 15 Mar 2021 09:57:42 +0900 Subject: [PATCH 275/587] ASoC: soc-pcm: indicate error message at soc_pcm_hw_params() Indicating error message when failed case is very useful for debuging. In many case, its style is like below. int function(...) { ... return ret; } int caller(...) { ... ret = function(...); if (ret < 0) dev_err(...) ... } This is not so bad, but in this style *each caller* needs to indicate duplicate same error message, and some caller is forgetting to do it. And caller can't indicate detail function() error information. If function() indicates error message, we can get same and detail information without forgot. int function(...) { ... if (ret < 0) dev_err(...) return ret; } int caller(...) { ... ret = function(...); ... } This patch follow above style at soc_pcm_hw_params(). By this patch, dpcm_fe/be_dai_hw_params(...) temporary lacks FE/BE error info, but it will reborn soon. Signed-off-by: Kuninori Morimoto Link: https://lore.kernel.org/r/87pn01utbt.wl-kuninori.morimoto.gx@renesas.com Signed-off-by: Mark Brown --- sound/soc/soc-pcm.c | 14 ++++++-------- 1 file changed, 6 insertions(+), 8 deletions(-) diff --git a/sound/soc/soc-pcm.c b/sound/soc/soc-pcm.c index ad4b67bd0306..a956d1852ade 100644 --- a/sound/soc/soc-pcm.c +++ b/sound/soc/soc-pcm.c @@ -1001,8 +1001,10 @@ static int soc_pcm_hw_params(struct snd_pcm_substream *substream, out: mutex_unlock(&rtd->card->pcm_mutex); - if (ret < 0) + if (ret < 0) { soc_pcm_hw_clean(substream, 1); + dev_err(rtd->dev, "ASoC: %s() failed (%d)\n", __func__, ret); + } return ret; } @@ -1905,11 +1907,8 @@ int dpcm_be_dai_hw_params(struct snd_soc_pcm_runtime *fe, int stream) be->dai_link->name); ret = soc_pcm_hw_params(be_substream, &dpcm->hw_params); - if (ret < 0) { - dev_err(dpcm->be->dev, - "ASoC: hw_params BE failed %d\n", ret); + if (ret < 0) goto unwind; - } be->dpcm[stream].state = SND_SOC_DPCM_STATE_HW_PARAMS; } @@ -1964,10 +1963,9 @@ static int dpcm_fe_dai_hw_params(struct snd_pcm_substream *substream, /* call hw_params on the frontend */ ret = soc_pcm_hw_params(substream, params); - if (ret < 0) { - dev_err(fe->dev,"ASoC: hw_params FE failed %d\n", ret); + if (ret < 0) dpcm_be_dai_hw_free(fe, stream); - } else + else fe->dpcm[stream].state = SND_SOC_DPCM_STATE_HW_PARAMS; out: From dab7eeb4045cce074e083be1f3092d7390d6cfb2 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Mon, 15 Mar 2021 09:57:48 +0900 Subject: [PATCH 276/587] ASoC: soc-pcm: indicate error message at soc_pcm_prepare() Indicating error message when failed case is very useful for debuging. In many case, its style is like below. int function(...) { ... return ret; } int caller(...) { ... ret = function(...); if (ret < 0) dev_err(...) ... } This is not so bad, but in this style *each caller* needs to indicate duplicate same error message, and some caller is forgetting to do it. And caller can't indicate detail function() error information. If function() indicates error message, we can get same and detail information without forgot. int function(...) { ... if (ret < 0) dev_err(...) return ret; } int caller(...) { ... ret = function(...); ... } This patch follow above style at soc_pcm_prepare(). By this patch, dpcm_fe/be_dai_prepare(...) temporary lacks FE/BE error info, but it will reborn soon. Signed-off-by: Kuninori Morimoto Link: https://lore.kernel.org/r/87o8flutbn.wl-kuninori.morimoto.gx@renesas.com Signed-off-by: Mark Brown --- sound/soc/soc-pcm.c | 14 ++++++-------- 1 file changed, 6 insertions(+), 8 deletions(-) diff --git a/sound/soc/soc-pcm.c b/sound/soc/soc-pcm.c index a956d1852ade..82daf79f5b3f 100644 --- a/sound/soc/soc-pcm.c +++ b/sound/soc/soc-pcm.c @@ -852,6 +852,10 @@ static int soc_pcm_prepare(struct snd_pcm_substream *substream) out: mutex_unlock(&rtd->card->pcm_mutex); + + if (ret < 0) + dev_err(rtd->dev, "ASoC: %s() failed (%d)\n", __func__, ret); + return ret; } @@ -2234,11 +2238,8 @@ int dpcm_be_dai_prepare(struct snd_soc_pcm_runtime *fe, int stream) be->dai_link->name); ret = soc_pcm_prepare(be_substream); - if (ret < 0) { - dev_err(be->dev, "ASoC: backend prepare failed %d\n", - ret); + if (ret < 0) break; - } be->dpcm[stream].state = SND_SOC_DPCM_STATE_PREPARE; } @@ -2270,11 +2271,8 @@ static int dpcm_fe_dai_prepare(struct snd_pcm_substream *substream) /* call prepare on the frontend */ ret = soc_pcm_prepare(substream); - if (ret < 0) { - dev_err(fe->dev,"ASoC: prepare FE %s failed\n", - fe->dai_link->name); + if (ret < 0) goto out; - } fe->dpcm[stream].state = SND_SOC_DPCM_STATE_PREPARE; From d479f00b795ac62b24ef90f4ec421e65c3178ca7 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Mon, 15 Mar 2021 09:57:52 +0900 Subject: [PATCH 277/587] ASoC: soc-pcm: indicate error message at dpcm_path_get() Indicating error message when failed case is very useful for debuging. In many case, its style is like below. int function(...) { ... return ret; } int caller(...) { ... ret = function(...); if (ret < 0) dev_err(...) ... } This is not so bad, but in this style *each caller* needs to indicate duplicate same error message, and some caller is forgetting to do it. And caller can't indicate detail function() error information. If function() indicates error message, we can get same and detail information without forgot. int function(...) { ... if (ret < 0) dev_err(...) return ret; } int caller(...) { ... ret = function(...); ... } Now, many place uses dpcm_path_get() like below ret = dpcm_path_get(...); if (ret < 0) goto error; (A) else if (ret == 0) dev_dbg(...) But here, (A) part can be indicated at dpcm_path_get() not caller. It is simple and readable code. This patch do it. Small detail behaviors will be exchanged by this patch. 1) indicates debug info (= path numbers) if path > 0 case only (It was *always* indicated). 2) soc_dpcm_fe_runtime_update() is indicating error message for paths < 0 case, but it is already done at dpcm_path_get(). Thus just remove it. but dev_dbg() vs dev_warn() is exchanged. Signed-off-by: Kuninori Morimoto Link: https://lore.kernel.org/r/87mtv5utbj.wl-kuninori.morimoto.gx@renesas.com Signed-off-by: Mark Brown --- sound/soc/soc-compress.c | 4 +--- sound/soc/soc-pcm.c | 19 +++++++------------ 2 files changed, 8 insertions(+), 15 deletions(-) diff --git a/sound/soc/soc-compress.c b/sound/soc/soc-compress.c index 89445ba0e86b..94f1f7a9dd53 100644 --- a/sound/soc/soc-compress.c +++ b/sound/soc/soc-compress.c @@ -115,9 +115,7 @@ static int soc_compr_open_fe(struct snd_compr_stream *cstream) ret = dpcm_path_get(fe, stream, &list); if (ret < 0) goto be_err; - else if (ret == 0) - dev_dbg(fe->dev, "Compress ASoC: %s no valid %s route\n", - fe->dai_link->name, stream ? "capture" : "playback"); + /* calculate valid and active FE <-> BE dpcms */ dpcm_process_paths(fe, stream, &list, 1); fe->dpcm[stream].runtime = fe_substream->runtime; diff --git a/sound/soc/soc-pcm.c b/sound/soc/soc-pcm.c index 82daf79f5b3f..b21c53becd11 100644 --- a/sound/soc/soc-pcm.c +++ b/sound/soc/soc-pcm.c @@ -1290,8 +1290,12 @@ int dpcm_path_get(struct snd_soc_pcm_runtime *fe, fe->card->component_chaining ? NULL : dpcm_end_walk_at_be); - dev_dbg(fe->dev, "ASoC: found %d audio %s paths\n", paths, + if (paths > 0) + dev_dbg(fe->dev, "ASoC: found %d audio %s paths\n", paths, stream ? "capture" : "playback"); + else if (paths == 0) + dev_dbg(fe->dev, "ASoC: %s no valid %s path\n", fe->dai_link->name, + stream ? "capture" : "playback"); return paths; } @@ -2457,13 +2461,8 @@ static int soc_dpcm_fe_runtime_update(struct snd_soc_pcm_runtime *fe, int new) continue; paths = dpcm_path_get(fe, stream, &list); - if (paths < 0) { - dev_warn(fe->dev, "ASoC: %s no valid %s path\n", - fe->dai_link->name, - stream == SNDRV_PCM_STREAM_PLAYBACK ? - "playback" : "capture"); + if (paths < 0) return paths; - } /* update any playback/capture paths */ count = dpcm_process_paths(fe, stream, &list, new); @@ -2556,12 +2555,8 @@ static int dpcm_fe_dai_open(struct snd_pcm_substream *fe_substream) fe->dpcm[stream].runtime = fe_substream->runtime; ret = dpcm_path_get(fe, stream, &list); - if (ret < 0) { + if (ret < 0) goto open_end; - } else if (ret == 0) { - dev_dbg(fe->dev, "ASoC: %s no valid %s route\n", - fe->dai_link->name, stream ? "capture" : "playback"); - } /* calculate valid and active FE <-> BE dpcms */ dpcm_process_paths(fe, stream, &list, 1); From db3aa39c91068424407f71d23b028493eac994a1 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Mon, 15 Mar 2021 09:57:57 +0900 Subject: [PATCH 278/587] ASoC: soc-pcm: indicate error message at dpcm_be_dai_trigger() Indicating error message when failed case is very useful for debuging. In many case, its style is like below. int function(...) { ... return ret; } int caller(...) { ... ret = function(...); if (ret < 0) dev_err(...) ... } This is not so bad, but in this style *each caller* needs to indicate duplicate same error message, and some caller is forgetting to do it. And caller can't indicate detail function() error information. If function() indicates error message, we can get same and detail information without forgot. int function(...) { ... if (ret < 0) dev_err(...) return ret; } int caller(...) { ... ret = function(...); ... } Now, dpcm_be_dai_trigger() user uses it like below. err = dpcm_be_dai_trigger(...); if (err < 0) dev_err(..., "ASoC: trigger FE failed %d\n", err); But we can get more detail information if dpcm_be_dai_trigger() itself had dev_err(). And above error message is confusable, failed is *BE*, not *FE*. This patch indicates error message at dpcm_be_dai_trigger(). Signed-off-by: Kuninori Morimoto Link: https://lore.kernel.org/r/87lfaputbe.wl-kuninori.morimoto.gx@renesas.com Signed-off-by: Mark Brown --- sound/soc/soc-pcm.c | 30 +++++++++++++++--------------- 1 file changed, 15 insertions(+), 15 deletions(-) diff --git a/sound/soc/soc-pcm.c b/sound/soc/soc-pcm.c index b21c53becd11..35c62062b8f8 100644 --- a/sound/soc/soc-pcm.c +++ b/sound/soc/soc-pcm.c @@ -1985,14 +1985,15 @@ out: int dpcm_be_dai_trigger(struct snd_soc_pcm_runtime *fe, int stream, int cmd) { + struct snd_soc_pcm_runtime *be; struct snd_soc_dpcm *dpcm; int ret = 0; for_each_dpcm_be(fe, stream, dpcm) { + struct snd_pcm_substream *be_substream; - struct snd_soc_pcm_runtime *be = dpcm->be; - struct snd_pcm_substream *be_substream = - snd_soc_dpcm_get_substream(be, stream); + be = dpcm->be; + be_substream = snd_soc_dpcm_get_substream(be, stream); /* is this op for this BE ? */ if (!snd_soc_dpcm_be_can_update(fe, be, stream)) @@ -2010,7 +2011,7 @@ int dpcm_be_dai_trigger(struct snd_soc_pcm_runtime *fe, int stream, ret = soc_pcm_trigger(be_substream, cmd); if (ret) - return ret; + goto end; be->dpcm[stream].state = SND_SOC_DPCM_STATE_START; break; @@ -2020,7 +2021,7 @@ int dpcm_be_dai_trigger(struct snd_soc_pcm_runtime *fe, int stream, ret = soc_pcm_trigger(be_substream, cmd); if (ret) - return ret; + goto end; be->dpcm[stream].state = SND_SOC_DPCM_STATE_START; break; @@ -2030,7 +2031,7 @@ int dpcm_be_dai_trigger(struct snd_soc_pcm_runtime *fe, int stream, ret = soc_pcm_trigger(be_substream, cmd); if (ret) - return ret; + goto end; be->dpcm[stream].state = SND_SOC_DPCM_STATE_START; break; @@ -2044,7 +2045,7 @@ int dpcm_be_dai_trigger(struct snd_soc_pcm_runtime *fe, int stream, ret = soc_pcm_trigger(be_substream, cmd); if (ret) - return ret; + goto end; be->dpcm[stream].state = SND_SOC_DPCM_STATE_STOP; break; @@ -2057,7 +2058,7 @@ int dpcm_be_dai_trigger(struct snd_soc_pcm_runtime *fe, int stream, ret = soc_pcm_trigger(be_substream, cmd); if (ret) - return ret; + goto end; be->dpcm[stream].state = SND_SOC_DPCM_STATE_SUSPEND; break; @@ -2070,13 +2071,16 @@ int dpcm_be_dai_trigger(struct snd_soc_pcm_runtime *fe, int stream, ret = soc_pcm_trigger(be_substream, cmd); if (ret) - return ret; + goto end; be->dpcm[stream].state = SND_SOC_DPCM_STATE_PAUSED; break; } } - +end: + if (ret < 0) + dev_err(fe->dev, "ASoC: %s() failed at %s (%d)\n", + __func__, be->dai_link->name, ret); return ret; } EXPORT_SYMBOL_GPL(dpcm_be_dai_trigger); @@ -2310,8 +2314,6 @@ static int dpcm_run_update_shutdown(struct snd_soc_pcm_runtime *fe, int stream) fe->dai_link->name); err = dpcm_be_dai_trigger(fe, stream, SNDRV_PCM_TRIGGER_STOP); - if (err < 0) - dev_err(fe->dev,"ASoC: trigger FE failed %d\n", err); } err = dpcm_be_dai_hw_free(fe, stream); @@ -2393,10 +2395,8 @@ static int dpcm_run_update_startup(struct snd_soc_pcm_runtime *fe, int stream) ret = dpcm_be_dai_trigger(fe, stream, SNDRV_PCM_TRIGGER_START); - if (ret < 0) { - dev_err(fe->dev,"ASoC: trigger FE failed %d\n", ret); + if (ret < 0) goto hw_free; - } } return 0; From bbd2bac8d6ca00ee0b032d3c03100328131425ac Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Mon, 15 Mar 2021 09:58:02 +0900 Subject: [PATCH 279/587] ASoC: soc-pcm: indicate error message at dpcm_apply_symmetry() Indicating error message when failed case is very useful for debuging. In many case, its style is like below. int function(...) { ... return ret; } int caller(...) { ... ret = function(...); if (ret < 0) dev_err(...) ... } This is not so bad, but in this style *each caller* needs to indicate duplicate same error message, and some caller is forgetting to do it. And caller can't indicate detail function() error information. If function() indicates error message, we can get same and detail information without forgot. int function(...) { ... if (ret < 0) dev_err(...) return ret; } int caller(...) { ... ret = function(...); ... } This patch follow above style at dpcm_apply_symmetry(...) Signed-off-by: Kuninori Morimoto Link: https://lore.kernel.org/r/87k0q9utb9.wl-kuninori.morimoto.gx@renesas.com Signed-off-by: Mark Brown --- sound/soc/soc-pcm.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/sound/soc/soc-pcm.c b/sound/soc/soc-pcm.c index 35c62062b8f8..855904c0938d 100644 --- a/sound/soc/soc-pcm.c +++ b/sound/soc/soc-pcm.c @@ -1706,7 +1706,7 @@ static int dpcm_apply_symmetry(struct snd_pcm_substream *fe_substream, /* Symmetry only applies if we've got an active stream. */ err = soc_pcm_apply_symmetry(fe_substream, fe_cpu_dai); if (err < 0) - return err; + goto error; } /* apply symmetry for BE */ @@ -1731,11 +1731,14 @@ static int dpcm_apply_symmetry(struct snd_pcm_substream *fe_substream, for_each_rtd_dais(rtd, i, dai) { err = soc_pcm_apply_symmetry(fe_substream, dai); if (err < 0) - return err; + goto error; } } +error: + if (err < 0) + dev_err(fe->dev, "ASoC: %s failed (%d)\n", __func__, err); - return 0; + return err; } static int dpcm_fe_dai_startup(struct snd_pcm_substream *fe_substream) @@ -1767,9 +1770,6 @@ static int dpcm_fe_dai_startup(struct snd_pcm_substream *fe_substream) dpcm_runtime_setup_be_rate(fe_substream); ret = dpcm_apply_symmetry(fe_substream, stream); - if (ret < 0) - dev_err(fe->dev, "ASoC: failed to apply dpcm symmetry %d\n", - ret); unwind: if (ret < 0) From 81c82a9edbddc4cd97e4d974dfd7f2689ee63474 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Mon, 15 Mar 2021 09:58:08 +0900 Subject: [PATCH 280/587] ASoC: soc-pcm: indicate error message at dpcm_run_update_startup/shutdown() Indicating error message when failed case is very useful for debuging. In many case, its style is like below. int function(...) { ... return ret; } int caller(...) { ... ret = function(...); if (ret < 0) dev_err(...) ... } This is not so bad, but in this style *each caller* needs to indicate duplicate same error message, and some caller is forgetting to do it. And caller can't indicate detail function() error information. If function() indicates error message, we can get same and detail information without forgot. int function(...) { ... if (ret < 0) dev_err(...) return ret; } int caller(...) { ... ret = function(...); ... } This patch also do below to dpcm_run_update_startup() 1) remove duplicated ret = -EINVAL 2) remove blank line do below to dpcm_run_update_shutdown() 1) remove unused ret Signed-off-by: Kuninori Morimoto Link: https://lore.kernel.org/r/87im5tutb3.wl-kuninori.morimoto.gx@renesas.com Signed-off-by: Mark Brown --- sound/soc/soc-pcm.c | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/sound/soc/soc-pcm.c b/sound/soc/soc-pcm.c index 855904c0938d..a34b1fb9967a 100644 --- a/sound/soc/soc-pcm.c +++ b/sound/soc/soc-pcm.c @@ -2325,7 +2325,10 @@ static int dpcm_run_update_shutdown(struct snd_soc_pcm_runtime *fe, int stream) /* run the stream event for each BE */ dpcm_dapm_stream_event(fe, stream, SND_SOC_DAPM_STREAM_NOP); - return 0; + if (err < 0) + dev_err(fe->dev, "ASoC: %s() failed (%d)\n", __func__, err); + + return err; } static int dpcm_run_update_startup(struct snd_soc_pcm_runtime *fe, int stream) @@ -2366,7 +2369,6 @@ static int dpcm_run_update_startup(struct snd_soc_pcm_runtime *fe, int stream) if (fe->dpcm[stream].state == SND_SOC_DPCM_STATE_HW_PARAMS) return 0; - ret = dpcm_be_dai_prepare(fe, stream); if (ret < 0) goto hw_free; @@ -2421,6 +2423,9 @@ disconnect: } spin_unlock_irqrestore(&fe->card->dpcm_lock, flags); + if (ret < 0) + dev_err(fe->dev, "ASoC: %s() failed (%d)\n", __func__, ret); + return ret; } @@ -2429,7 +2434,6 @@ static int soc_dpcm_fe_runtime_update(struct snd_soc_pcm_runtime *fe, int new) struct snd_soc_dapm_widget_list *list; int stream; int count, paths; - int ret; if (!fe->dai_link->dynamic) return 0; @@ -2469,11 +2473,9 @@ static int soc_dpcm_fe_runtime_update(struct snd_soc_pcm_runtime *fe, int new) if (count) { dpcm_set_fe_update_state(fe, stream, SND_SOC_DPCM_UPDATE_BE); if (new) - ret = dpcm_run_update_startup(fe, stream); + dpcm_run_update_startup(fe, stream); else - ret = dpcm_run_update_shutdown(fe, stream); - if (ret < 0) - dev_err(fe->dev, "ASoC: failed to shutdown some BEs\n"); + dpcm_run_update_shutdown(fe, stream); dpcm_set_fe_update_state(fe, stream, SND_SOC_DPCM_UPDATE_NO); dpcm_clear_pending_state(fe, stream); From 06aaeb874256a10fe5b84f511da3c65f548a43b9 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Mon, 15 Mar 2021 09:58:13 +0900 Subject: [PATCH 281/587] ASoC: soc-pcm: indicate error message at dpcm_fe/be_dai_startup() Indicating error message when failed case is very useful for debuging. In many case, its style is like below. int function(...) { ... return ret; } int caller(...) { ... ret = function(...); if (ret < 0) dev_err(...) ... } This is not so bad, but in this style *each caller* needs to indicate duplicate same error message, and some caller is forgetting to do it. And caller can't indicate detail function() error information. If function() indicates error message, we can get same and detail information without forgot. int function(...) { ... if (ret < 0) dev_err(...) return ret; } int caller(...) { ... ret = function(...); ... } This patch follow above style at dpcm_fe/be_dai_startup(). Signed-off-by: Kuninori Morimoto Link: https://lore.kernel.org/r/87h7ldutay.wl-kuninori.morimoto.gx@renesas.com Signed-off-by: Mark Brown --- sound/soc/soc-pcm.c | 18 ++++++++++++------ 1 file changed, 12 insertions(+), 6 deletions(-) diff --git a/sound/soc/soc-pcm.c b/sound/soc/soc-pcm.c index a34b1fb9967a..9e3ecf788a74 100644 --- a/sound/soc/soc-pcm.c +++ b/sound/soc/soc-pcm.c @@ -1475,15 +1475,16 @@ void dpcm_be_dai_stop(struct snd_soc_pcm_runtime *fe, int stream, int dpcm_be_dai_startup(struct snd_soc_pcm_runtime *fe, int stream) { + struct snd_soc_pcm_runtime *be; struct snd_soc_dpcm *dpcm; int err, count = 0; /* only startup BE DAIs that are either sinks or sources to this FE DAI */ for_each_dpcm_be(fe, stream, dpcm) { + struct snd_pcm_substream *be_substream; - struct snd_soc_pcm_runtime *be = dpcm->be; - struct snd_pcm_substream *be_substream = - snd_soc_dpcm_get_substream(be, stream); + be = dpcm->be; + be_substream = snd_soc_dpcm_get_substream(be, stream); if (!be_substream) { dev_err(be->dev, "ASoC: no backend %s stream\n", @@ -1535,6 +1536,9 @@ int dpcm_be_dai_startup(struct snd_soc_pcm_runtime *fe, int stream) unwind: dpcm_be_dai_startup_rollback(fe, stream, dpcm); + dev_err(fe->dev, "ASoC: %s() failed at %s (%d)\n", + __func__, be->dai_link->name, err); + return err; } @@ -1749,10 +1753,8 @@ static int dpcm_fe_dai_startup(struct snd_pcm_substream *fe_substream) dpcm_set_fe_update_state(fe, stream, SND_SOC_DPCM_UPDATE_FE); ret = dpcm_be_dai_startup(fe, stream); - if (ret < 0) { - dev_err(fe->dev,"ASoC: failed to start some BEs %d\n", ret); + if (ret < 0) goto be_err; - } dev_dbg(fe->dev, "ASoC: open FE %s\n", fe->dai_link->name); @@ -1776,6 +1778,10 @@ unwind: dpcm_be_dai_startup_unwind(fe, stream); be_err: dpcm_set_fe_update_state(fe, stream, SND_SOC_DPCM_UPDATE_NO); + + if (ret < 0) + dev_err(fe->dev, "%s() failed (%d)\n", __func__, ret); + return ret; } From 33b6b94f55ec60517ce71ca2bc9c03a6d337c805 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Mon, 15 Mar 2021 09:58:18 +0900 Subject: [PATCH 282/587] ASoC: soc-pcm: indicate error message at dpcm_fe/be_dai_hw_params() Indicating error message when failed case is very useful for debuging. In many case, its style is like below. int function(...) { ... return ret; } int caller(...) { ... ret = function(...); if (ret < 0) dev_err(...) ... } This is not so bad, but in this style *each caller* needs to indicate duplicate same error message, and some caller is forgetting to do it. And caller can't indicate detail function() error information. If function() indicates error message, we can get same and detail information without forgot. int function(...) { ... if (ret < 0) dev_err(...) return ret; } int caller(...) { ... ret = function(...); ... } This patch follow above style at dpcm_fe/be_dai_hw_params() Signed-off-by: Kuninori Morimoto Link: https://lore.kernel.org/r/87ft0xutat.wl-kuninori.morimoto.gx@renesas.com Signed-off-by: Mark Brown --- sound/soc/soc-pcm.c | 24 ++++++++++++++---------- 1 file changed, 14 insertions(+), 10 deletions(-) diff --git a/sound/soc/soc-pcm.c b/sound/soc/soc-pcm.c index 9e3ecf788a74..e141d0658279 100644 --- a/sound/soc/soc-pcm.c +++ b/sound/soc/soc-pcm.c @@ -1882,14 +1882,14 @@ static int dpcm_fe_dai_hw_free(struct snd_pcm_substream *substream) int dpcm_be_dai_hw_params(struct snd_soc_pcm_runtime *fe, int stream) { + struct snd_soc_pcm_runtime *be; + struct snd_pcm_substream *be_substream; struct snd_soc_dpcm *dpcm; int ret; for_each_dpcm_be(fe, stream, dpcm) { - - struct snd_soc_pcm_runtime *be = dpcm->be; - struct snd_pcm_substream *be_substream = - snd_soc_dpcm_get_substream(be, stream); + be = dpcm->be; + be_substream = snd_soc_dpcm_get_substream(be, stream); /* is this op for this BE ? */ if (!snd_soc_dpcm_be_can_update(fe, be, stream)) @@ -1929,11 +1929,13 @@ int dpcm_be_dai_hw_params(struct snd_soc_pcm_runtime *fe, int stream) return 0; unwind: + dev_dbg(fe->dev, "ASoC: %s() failed at %s (%d)\n", + __func__, be->dai_link->name, ret); + /* disable any enabled and non active backends */ for_each_dpcm_be_rollback(fe, stream, dpcm) { - struct snd_soc_pcm_runtime *be = dpcm->be; - struct snd_pcm_substream *be_substream = - snd_soc_dpcm_get_substream(be, stream); + be = dpcm->be; + be_substream = snd_soc_dpcm_get_substream(be, stream); if (!snd_soc_dpcm_be_can_update(fe, be, stream)) continue; @@ -1966,10 +1968,8 @@ static int dpcm_fe_dai_hw_params(struct snd_pcm_substream *substream, memcpy(&fe->dpcm[stream].hw_params, params, sizeof(struct snd_pcm_hw_params)); ret = dpcm_be_dai_hw_params(fe, stream); - if (ret < 0) { - dev_err(fe->dev,"ASoC: hw_params BE failed %d\n", ret); + if (ret < 0) goto out; - } dev_dbg(fe->dev, "ASoC: hw_params FE %s rate %d chan %x fmt %d\n", fe->dai_link->name, params_rate(params), @@ -1985,6 +1985,10 @@ static int dpcm_fe_dai_hw_params(struct snd_pcm_substream *substream, out: dpcm_set_fe_update_state(fe, stream, SND_SOC_DPCM_UPDATE_NO); mutex_unlock(&fe->card->mutex); + + if (ret < 0) + dev_err(fe->dev, "ASoC: %s failed (%d)\n", __func__, ret); + return ret; } From 273db971cf833d62c9e2d9381d190e14b1cd3641 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Mon, 15 Mar 2021 09:58:22 +0900 Subject: [PATCH 283/587] ASoC: soc-pcm: indicate error message at dpcm_fe/be_dai_prepare() Indicating error message when failed case is very useful for debuging. In many case, its style is like below. int function(...) { ... return ret; } int caller(...) { ... ret = function(...); if (ret < 0) dev_err(...) ... } This is not so bad, but in this style *each caller* needs to indicate duplicate same error message, and some caller is forgetting to do it. And caller can't indicate detail function() error information. If function() indicates error message, we can get same and detail information without forgot. int function(...) { ... if (ret < 0) dev_err(...) return ret; } int caller(...) { ... ret = function(...); ... } This patch follow above style at dpcm_fe/be_dai_prepare() Signed-off-by: Kuninori Morimoto Link: https://lore.kernel.org/r/87eeghutap.wl-kuninori.morimoto.gx@renesas.com Signed-off-by: Mark Brown --- sound/soc/soc-pcm.c | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/sound/soc/soc-pcm.c b/sound/soc/soc-pcm.c index e141d0658279..4a01a3925ab6 100644 --- a/sound/soc/soc-pcm.c +++ b/sound/soc/soc-pcm.c @@ -2261,6 +2261,10 @@ int dpcm_be_dai_prepare(struct snd_soc_pcm_runtime *fe, int stream) be->dpcm[stream].state = SND_SOC_DPCM_STATE_PREPARE; } + + if (ret < 0) + dev_err(fe->dev, "ASoC: %s() failed (%d)\n", __func__, ret); + return ret; } @@ -2298,6 +2302,9 @@ out: dpcm_set_fe_update_state(fe, stream, SND_SOC_DPCM_UPDATE_NO); mutex_unlock(&fe->card->mutex); + if (ret < 0) + dev_err(fe->dev, "ASoC: %s() failed (%d)\n", __func__, ret); + return ret; } From e20c9c4f96d79aa48eb3649c57f1f2784f92b838 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Mon, 15 Mar 2021 09:58:28 +0900 Subject: [PATCH 284/587] ASoC: soc-pcm: don't indicate error message for soc_pcm_hw_free() soc_pcm_hw_free() never fail, error message is not needed. We can't use void function for it, because it is used part of struct snd_pcm_ops :: hw_free. Signed-off-by: Kuninori Morimoto Link: https://lore.kernel.org/r/87czw1utaj.wl-kuninori.morimoto.gx@renesas.com Signed-off-by: Mark Brown --- sound/soc/soc-pcm.c | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/sound/soc/soc-pcm.c b/sound/soc/soc-pcm.c index 4a01a3925ab6..eb52f78ca053 100644 --- a/sound/soc/soc-pcm.c +++ b/sound/soc/soc-pcm.c @@ -1862,10 +1862,7 @@ static int dpcm_fe_dai_hw_free(struct snd_pcm_substream *substream) dev_dbg(fe->dev, "ASoC: hw_free FE %s\n", fe->dai_link->name); /* call hw_free on the frontend */ - err = soc_pcm_hw_free(substream); - if (err < 0) - dev_err(fe->dev,"ASoC: hw_free FE %s failed\n", - fe->dai_link->name); + soc_pcm_hw_free(substream); /* only hw_params backends that are either sinks or sources * to this frontend DAI */ From f52366e6831ecb2da133b6ecfc7c69266086660c Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Mon, 15 Mar 2021 09:58:32 +0900 Subject: [PATCH 285/587] ASoC: soc-pcm: don't indicate error message for dpcm_be_dai_hw_free() dpcm_be_dai_hw_free() never fail, error message is not needed. Signed-off-by: Kuninori Morimoto Link: https://lore.kernel.org/r/87blblutaf.wl-kuninori.morimoto.gx@renesas.com Signed-off-by: Mark Brown --- include/sound/soc-dpcm.h | 2 +- sound/soc/soc-compress.c | 5 +---- sound/soc/soc-pcm.c | 14 ++++---------- 3 files changed, 6 insertions(+), 15 deletions(-) diff --git a/include/sound/soc-dpcm.h b/include/sound/soc-dpcm.h index d76cb1eeeaca..e296a3949b18 100644 --- a/include/sound/soc-dpcm.h +++ b/include/sound/soc-dpcm.h @@ -153,7 +153,7 @@ void dpcm_be_dai_stop(struct snd_soc_pcm_runtime *fe, int stream, int do_hw_free, struct snd_soc_dpcm *last); void dpcm_be_disconnect(struct snd_soc_pcm_runtime *fe, int stream); void dpcm_clear_pending_state(struct snd_soc_pcm_runtime *fe, int stream); -int dpcm_be_dai_hw_free(struct snd_soc_pcm_runtime *fe, int stream); +void dpcm_be_dai_hw_free(struct snd_soc_pcm_runtime *fe, int stream); int dpcm_be_dai_hw_params(struct snd_soc_pcm_runtime *fe, int tream); int dpcm_be_dai_trigger(struct snd_soc_pcm_runtime *fe, int stream, int cmd); int dpcm_be_dai_prepare(struct snd_soc_pcm_runtime *fe, int stream); diff --git a/sound/soc/soc-compress.c b/sound/soc/soc-compress.c index 94f1f7a9dd53..83b511f8b8c9 100644 --- a/sound/soc/soc-compress.c +++ b/sound/soc/soc-compress.c @@ -175,7 +175,6 @@ static int soc_compr_free_fe(struct snd_compr_stream *cstream) struct snd_soc_dai *cpu_dai = asoc_rtd_to_cpu(fe, 0); struct snd_soc_dpcm *dpcm; int stream = cstream->direction; /* SND_COMPRESS_xxx is same as SNDRV_PCM_STREAM_xxx */ - int ret; mutex_lock_nested(&fe->card->mutex, SND_SOC_CARD_CLASS_RUNTIME); @@ -183,9 +182,7 @@ static int soc_compr_free_fe(struct snd_compr_stream *cstream) fe->dpcm[stream].runtime_update = SND_SOC_DPCM_UPDATE_FE; - ret = dpcm_be_dai_hw_free(fe, stream); - if (ret < 0) - dev_err(fe->dev, "Compressed ASoC: hw_free failed: %d\n", ret); + dpcm_be_dai_hw_free(fe, stream); dpcm_be_dai_shutdown(fe, stream); diff --git a/sound/soc/soc-pcm.c b/sound/soc/soc-pcm.c index eb52f78ca053..2a126840677c 100644 --- a/sound/soc/soc-pcm.c +++ b/sound/soc/soc-pcm.c @@ -1808,7 +1808,7 @@ static int dpcm_fe_dai_shutdown(struct snd_pcm_substream *substream) return 0; } -int dpcm_be_dai_hw_free(struct snd_soc_pcm_runtime *fe, int stream) +void dpcm_be_dai_hw_free(struct snd_soc_pcm_runtime *fe, int stream) { struct snd_soc_dpcm *dpcm; @@ -1847,14 +1847,12 @@ int dpcm_be_dai_hw_free(struct snd_soc_pcm_runtime *fe, int stream) be->dpcm[stream].state = SND_SOC_DPCM_STATE_HW_FREE; } - - return 0; } static int dpcm_fe_dai_hw_free(struct snd_pcm_substream *substream) { struct snd_soc_pcm_runtime *fe = asoc_substream_to_rtd(substream); - int err, stream = substream->stream; + int stream = substream->stream; mutex_lock_nested(&fe->card->mutex, SND_SOC_CARD_CLASS_RUNTIME); dpcm_set_fe_update_state(fe, stream, SND_SOC_DPCM_UPDATE_FE); @@ -1866,9 +1864,7 @@ static int dpcm_fe_dai_hw_free(struct snd_pcm_substream *substream) /* only hw_params backends that are either sinks or sources * to this frontend DAI */ - err = dpcm_be_dai_hw_free(fe, stream); - if (err < 0) - dev_err(fe->dev, "ASoC: hw_free BE failed %d\n", err); + dpcm_be_dai_hw_free(fe, stream); fe->dpcm[stream].state = SND_SOC_DPCM_STATE_HW_FREE; dpcm_set_fe_update_state(fe, stream, SND_SOC_DPCM_UPDATE_NO); @@ -2330,9 +2326,7 @@ static int dpcm_run_update_shutdown(struct snd_soc_pcm_runtime *fe, int stream) err = dpcm_be_dai_trigger(fe, stream, SNDRV_PCM_TRIGGER_STOP); } - err = dpcm_be_dai_hw_free(fe, stream); - if (err < 0) - dev_err(fe->dev,"ASoC: hw_free FE failed %d\n", err); + dpcm_be_dai_hw_free(fe, stream); dpcm_be_dai_shutdown(fe, stream); From 62462e018220895267450155b188f5804f54c202 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Mon, 15 Mar 2021 09:58:37 +0900 Subject: [PATCH 286/587] ASoC: don't indicate error message for snd_soc_[pcm_]dai_xxx() All snd_soc_dai_xxx() and snd_soc_pcm_dai_xxx() itself indicate error message if failed. Its caller doesn't need to indicate duplicated error message. This patch removes it. Signed-off-by: Kuninori Morimoto Link: https://lore.kernel.org/r/87a6r5utaa.wl-kuninori.morimoto.gx@renesas.com Signed-off-by: Mark Brown --- sound/soc/soc-core.c | 16 +++------------- sound/soc/soc-dapm.c | 24 ++++++------------------ sound/soc/soc-pcm.c | 10 ++-------- 3 files changed, 11 insertions(+), 39 deletions(-) diff --git a/sound/soc/soc-core.c b/sound/soc/soc-core.c index c7e4600b2dd4..f12c763973fa 100644 --- a/sound/soc/soc-core.c +++ b/sound/soc/soc-core.c @@ -1088,12 +1088,8 @@ static int soc_init_pcm_runtime(struct snd_soc_card *card, /* create compress_device if possible */ ret = snd_soc_dai_compress_new(cpu_dai, rtd, num); - if (ret != -ENOTSUPP) { - if (ret < 0) - dev_err(card->dev, "ASoC: can't create compress %s\n", - dai_link->stream_name); + if (ret != -ENOTSUPP) return ret; - } /* create the pcm */ ret = soc_new_pcm(rtd, num); @@ -1422,11 +1418,8 @@ int snd_soc_runtime_set_dai_fmt(struct snd_soc_pcm_runtime *rtd, for_each_rtd_codec_dais(rtd, i, codec_dai) { ret = snd_soc_dai_set_fmt(codec_dai, dai_fmt); - if (ret != 0 && ret != -ENOTSUPP) { - dev_warn(codec_dai->dev, - "ASoC: Failed to set DAI format: %d\n", ret); + if (ret != 0 && ret != -ENOTSUPP) return ret; - } } /* @@ -1455,11 +1448,8 @@ int snd_soc_runtime_set_dai_fmt(struct snd_soc_pcm_runtime *rtd, fmt = inv_dai_fmt; ret = snd_soc_dai_set_fmt(cpu_dai, fmt); - if (ret != 0 && ret != -ENOTSUPP) { - dev_warn(cpu_dai->dev, - "ASoC: Failed to set DAI format: %d\n", ret); + if (ret != 0 && ret != -ENOTSUPP) return ret; - } } return 0; diff --git a/sound/soc/soc-dapm.c b/sound/soc/soc-dapm.c index b005f9eadd71..91bf939d5233 100644 --- a/sound/soc/soc-dapm.c +++ b/sound/soc/soc-dapm.c @@ -3831,11 +3831,9 @@ snd_soc_dai_link_event_pre_pmu(struct snd_soc_dapm_widget *w, source = path->source->priv; ret = snd_soc_dai_startup(source, substream); - if (ret < 0) { - dev_err(source->dev, - "ASoC: startup() failed: %d\n", ret); + if (ret < 0) goto out; - } + snd_soc_dai_activate(source, substream->stream); } @@ -3844,11 +3842,9 @@ snd_soc_dai_link_event_pre_pmu(struct snd_soc_dapm_widget *w, sink = path->sink->priv; ret = snd_soc_dai_startup(sink, substream); - if (ret < 0) { - dev_err(sink->dev, - "ASoC: startup() failed: %d\n", ret); + if (ret < 0) goto out; - } + snd_soc_dai_activate(sink, substream->stream); } @@ -3943,11 +3939,7 @@ static int snd_soc_dai_link_event(struct snd_soc_dapm_widget *w, snd_soc_dapm_widget_for_each_sink_path(w, path) { sink = path->sink->priv; - ret = snd_soc_dai_digital_mute(sink, 0, - SNDRV_PCM_STREAM_PLAYBACK); - if (ret != 0 && ret != -ENOTSUPP) - dev_warn(sink->dev, - "ASoC: Failed to unmute: %d\n", ret); + snd_soc_dai_digital_mute(sink, 0, SNDRV_PCM_STREAM_PLAYBACK); ret = 0; } break; @@ -3956,11 +3948,7 @@ static int snd_soc_dai_link_event(struct snd_soc_dapm_widget *w, snd_soc_dapm_widget_for_each_sink_path(w, path) { sink = path->sink->priv; - ret = snd_soc_dai_digital_mute(sink, 1, - SNDRV_PCM_STREAM_PLAYBACK); - if (ret != 0 && ret != -ENOTSUPP) - dev_warn(sink->dev, - "ASoC: Failed to mute: %d\n", ret); + snd_soc_dai_digital_mute(sink, 1, SNDRV_PCM_STREAM_PLAYBACK); ret = 0; } diff --git a/sound/soc/soc-pcm.c b/sound/soc/soc-pcm.c index 2a126840677c..ecf2bfa9640b 100644 --- a/sound/soc/soc-pcm.c +++ b/sound/soc/soc-pcm.c @@ -832,10 +832,8 @@ static int soc_pcm_prepare(struct snd_pcm_substream *substream) goto out; ret = snd_soc_pcm_dai_prepare(substream); - if (ret < 0) { - dev_err(rtd->dev, "ASoC: DAI prepare error: %d\n", ret); + if (ret < 0) goto out; - } /* cancel any delayed stream shutdown that is pending */ if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK && @@ -2317,8 +2315,6 @@ static int dpcm_run_update_shutdown(struct snd_soc_pcm_runtime *fe, int stream) fe->dai_link->name); err = snd_soc_pcm_dai_bespoke_trigger(substream, SNDRV_PCM_TRIGGER_STOP); - if (err < 0) - dev_err(fe->dev,"ASoC: trigger FE failed %d\n", err); } else { dev_dbg(fe->dev, "ASoC: trigger FE %s cmd stop\n", fe->dai_link->name); @@ -2395,10 +2391,8 @@ static int dpcm_run_update_startup(struct snd_soc_pcm_runtime *fe, int stream) fe->dai_link->name); ret = snd_soc_pcm_dai_bespoke_trigger(substream, SNDRV_PCM_TRIGGER_START); - if (ret < 0) { - dev_err(fe->dev,"ASoC: bespoke trigger FE failed %d\n", ret); + if (ret < 0) goto hw_free; - } } else { dev_dbg(fe->dev, "ASoC: trigger FE %s cmd start\n", fe->dai_link->name); From 60adbd8fbf486214f4ae1946e61df69c3867e20b Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Mon, 15 Mar 2021 09:58:41 +0900 Subject: [PATCH 287/587] ASoC: don't indicate error message for snd_soc_[pcm_]component_xxx() All snd_soc_component_xxx() and snd_soc_pcm_component_xxx() itself indicate error message if failed. Its caller doesn't need to indicate duplicated error message. This patch removes it. All snd_soc_component_xxx() indicate error message if failed. Its caller doesn't need to indicate duplicated error message. This patch removes it. Signed-off-by: Kuninori Morimoto Link: https://lore.kernel.org/r/878s6puta6.wl-kuninori.morimoto.gx@renesas.com Signed-off-by: Mark Brown --- sound/soc/soc-core.c | 6 ++---- sound/soc/soc-pcm.c | 5 +---- 2 files changed, 3 insertions(+), 8 deletions(-) diff --git a/sound/soc/soc-core.c b/sound/soc/soc-core.c index f12c763973fa..522bae73640a 100644 --- a/sound/soc/soc-core.c +++ b/sound/soc/soc-core.c @@ -1203,11 +1203,9 @@ static int soc_probe_component(struct snd_soc_card *card, } ret = snd_soc_component_probe(component); - if (ret < 0) { - dev_err(component->dev, - "ASoC: failed to probe component %d\n", ret); + if (ret < 0) goto err_probe; - } + WARN(dapm->idle_bias_off && dapm->bias_level != SND_SOC_BIAS_OFF, "codec %s can not start from non-off bias with idle_bias_off==1\n", diff --git a/sound/soc/soc-pcm.c b/sound/soc/soc-pcm.c index ecf2bfa9640b..2df70ab851ea 100644 --- a/sound/soc/soc-pcm.c +++ b/sound/soc/soc-pcm.c @@ -2781,11 +2781,8 @@ int soc_new_pcm(struct snd_soc_pcm_runtime *rtd, int num) snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, &rtd->ops); ret = snd_soc_pcm_component_new(rtd); - if (ret < 0) { - dev_err(rtd->dev, "ASoC: pcm constructor failed for dailink %s: %d\n", - rtd->dai_link->name, ret); + if (ret < 0) return ret; - } pcm->no_device_suspend = true; out: From e6d8af6687fa7730885d5c8d8f62e75e8dff29f0 Mon Sep 17 00:00:00 2001 From: Wei Yongjun Date: Fri, 19 Mar 2021 09:41:02 +0000 Subject: [PATCH 288/587] ASoC: rt1019: make symbol 'rt1019_i2c_driver' static The sparse tool complains as follows: sound/soc/codecs/rt1019.c:927:19: warning: symbol 'rt1019_i2c_driver' was not declared. Should it be static? This symbol is not used outside of rt1019.c, so this commit marks it static. Fixes: 7ec79d3850d0 ("ASoC: rt1019: add rt1019 amplifier driver") Reported-by: Hulk Robot Signed-off-by: Wei Yongjun Link: https://lore.kernel.org/r/20210319094102.4185096-1-weiyongjun1@huawei.com Signed-off-by: Mark Brown --- sound/soc/codecs/rt1019.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sound/soc/codecs/rt1019.c b/sound/soc/codecs/rt1019.c index fb275686a00f..5138f028d9f2 100644 --- a/sound/soc/codecs/rt1019.c +++ b/sound/soc/codecs/rt1019.c @@ -924,7 +924,7 @@ static int rt1019_i2c_probe(struct i2c_client *i2c, &soc_component_dev_rt1019, rt1019_dai, ARRAY_SIZE(rt1019_dai)); } -struct i2c_driver rt1019_i2c_driver = { +static struct i2c_driver rt1019_i2c_driver = { .driver = { .name = "rt1019", .of_match_table = of_match_ptr(rt1019_of_match), From dc85fc9d05d23591ddfde400c817413765611ec7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Amadeusz=20S=C5=82awi=C5=84ski?= Date: Thu, 18 Mar 2021 17:06:16 +0100 Subject: [PATCH 289/587] ALSA: pcm: Add debug print on memory allocation failure MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add debug prints after calls of do_alloc_pages. One simplification would be to move print into do_alloc_pages, however it would cause spam in logs, as preallocate_pcm_pages loops over do_alloc_pages trying lower values in case of failures. Reviewed-by: Cezary Rojewski Signed-off-by: Amadeusz SÅ‚awiÅ„ski Link: https://lore.kernel.org/r/20210318160618.2504068-2-amadeuszx.slawinski@linux.intel.com Signed-off-by: Takashi Iwai --- sound/core/pcm_memory.c | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/sound/core/pcm_memory.c b/sound/core/pcm_memory.c index 289dd1fd8fe7..2878c4c23583 100644 --- a/sound/core/pcm_memory.c +++ b/sound/core/pcm_memory.c @@ -176,6 +176,10 @@ static void snd_pcm_lib_preallocate_proc_write(struct snd_info_entry *entry, substream->dma_buffer.dev.dev, size, &new_dmab) < 0) { buffer->error = -ENOMEM; + pr_debug("ALSA pcmC%dD%d%c,%d:%s: cannot preallocate for size %zu\n", + substream->pcm->card->number, substream->pcm->device, + substream->stream ? 'c' : 'p', substream->number, + substream->pcm->name, size); return; } substream->buffer_bytes_max = size; @@ -400,6 +404,10 @@ int snd_pcm_lib_malloc_pages(struct snd_pcm_substream *substream, size_t size) substream->dma_buffer.dev.dev, size, dmab) < 0) { kfree(dmab); + pr_debug("ALSA pcmC%dD%d%c,%d:%s: cannot preallocate for size %zu\n", + substream->pcm->card->number, substream->pcm->device, + substream->stream ? 'c' : 'p', substream->number, + substream->pcm->name, size); return -ENOMEM; } } From 12b2b508300d08206674bfb3f53bb84f69cf2555 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Amadeusz=20S=C5=82awi=C5=84ski?= Date: Thu, 18 Mar 2021 17:06:17 +0100 Subject: [PATCH 290/587] ALSA: hda: Change AZX_MAX_BUF_SIZE from 1GB to 4MB MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit When SND_HDA_PREALLOC_SIZE is set to 0, applications can request as much memory as there is allowed. With value of AZX_MAX_BUF_SIZE it is 1GB per stream, which is not realistic use case. Change it 4MB. Bug: https://bugzilla.kernel.org/show_bug.cgi?id=201251#c322 Suggested-by: Takashi Iwai Reviewed-by: Cezary Rojewski Signed-off-by: Amadeusz SÅ‚awiÅ„ski Link: https://lore.kernel.org/r/20210318160618.2504068-3-amadeuszx.slawinski@linux.intel.com Signed-off-by: Takashi Iwai --- include/sound/hda_register.h | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/include/sound/hda_register.h b/include/sound/hda_register.h index 4f987b1f32f7..ad8b71b1dbb6 100644 --- a/include/sound/hda_register.h +++ b/include/sound/hda_register.h @@ -140,8 +140,12 @@ enum { SDI0, SDI1, SDI2, SDI3, SDO0, SDO1, SDO2, SDO3 }; #define BDL_SIZE 4096 #define AZX_MAX_BDL_ENTRIES (BDL_SIZE / 16) #define AZX_MAX_FRAG 32 -/* max buffer size - no h/w limit, you can increase as you like */ -#define AZX_MAX_BUF_SIZE (1024*1024*1024) +/* + * max buffer size - artificial 4MB limit per stream to avoid big allocations + * In theory it can be really big, but as it is per stream on systems with many streams memory could + * be quickly saturated if userspace requests maximum buffer size for each of them. + */ +#define AZX_MAX_BUF_SIZE (4*1024*1024) /* RIRB int mask: overrun[2], response[0] */ #define RIRB_INT_RESPONSE 0x01 From f4b4bdf29ace71475b18aae9377402a534f09a72 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Amadeusz=20S=C5=82awi=C5=84ski?= Date: Thu, 18 Mar 2021 17:06:18 +0100 Subject: [PATCH 291/587] ALSA: hda: Revert "ALSA: hda: Allow setting preallocation again for x86" MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This reverts commit f8e4ae10de43 ("ALSA: hda: Allow setting preallocation again for x86"). The reverted commit itself is a revert of c31427d0d21e ("ALSA: hda: No preallocation on x86 platforms"). It was needed because HDA allowed very big allocations, up to 1GB per stream. However as previous commit in this series changes maximum allowed allocation per stream to 4MB, we can safely revert it back. On systems where there are a lot of FrontEnds, when CONFIG_SND_HDA_PREALLOC_SIZE != 0 ALSA core allocates memory for each FE, which may cause out of memory problems due to per card limit. Force config to 0 on X86, so memory will be allocated on as needed basis. Bug: https://bugzilla.kernel.org/show_bug.cgi?id=201251#c322 Suggested-by: Takashi Iwai Reviewed-by: Cezary Rojewski Signed-off-by: Amadeusz SÅ‚awiÅ„ski Link: https://lore.kernel.org/r/20210318160618.2504068-4-amadeuszx.slawinski@linux.intel.com Signed-off-by: Takashi Iwai --- sound/hda/Kconfig | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/sound/hda/Kconfig b/sound/hda/Kconfig index 57595f1552c9..741179ccbd4e 100644 --- a/sound/hda/Kconfig +++ b/sound/hda/Kconfig @@ -21,17 +21,16 @@ config SND_HDA_EXT_CORE select SND_HDA_CORE config SND_HDA_PREALLOC_SIZE - int "Pre-allocated buffer size for HD-audio driver" + int "Pre-allocated buffer size for HD-audio driver" if !SND_DMA_SGBUF range 0 32768 - default 2048 if SND_DMA_SGBUF + default 0 if SND_DMA_SGBUF default 64 if !SND_DMA_SGBUF help Specifies the default pre-allocated buffer-size in kB for the HD-audio driver. A larger buffer (e.g. 2048) is preferred for systems using PulseAudio. The default 64 is chosen just for compatibility reasons. - On x86 systems, the default is 2048 as a reasonable value for - most of modern systems. + On x86 systems, the default is zero as we need no preallocation. Note that the pre-allocation size can be changed dynamically via a proc file (/proc/asound/card*/pcm*/sub*/prealloc), too. From 507cdb9adba006a7798c358456426e1aea3d9c4f Mon Sep 17 00:00:00 2001 From: Tong Zhang Date: Sun, 21 Mar 2021 11:38:38 -0400 Subject: [PATCH 292/587] ALSA: hdsp: don't disable if not enabled hdsp wants to disable a not enabled pci device, which makes kernel throw a warning. Make sure the device is enabled before calling disable. [ 1.758292] snd_hdsp 0000:00:03.0: disabling already-disabled device [ 1.758327] WARNING: CPU: 0 PID: 180 at drivers/pci/pci.c:2146 pci_disable_device+0x91/0xb0 [ 1.766985] Call Trace: [ 1.767121] snd_hdsp_card_free+0x94/0xf0 [snd_hdsp] [ 1.767388] release_card_device+0x4b/0x80 [snd] [ 1.767639] device_release+0x3b/0xa0 [ 1.767838] kobject_put+0x94/0x1b0 [ 1.768027] put_device+0x13/0x20 [ 1.768207] snd_card_free+0x61/0x90 [snd] [ 1.768430] snd_hdsp_probe+0x524/0x5e0 [snd_hdsp] Suggested-by: Takashi Iwai Signed-off-by: Tong Zhang Link: https://lore.kernel.org/r/20210321153840.378226-2-ztong0001@gmail.com Signed-off-by: Takashi Iwai --- sound/pci/rme9652/hdsp.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/sound/pci/rme9652/hdsp.c b/sound/pci/rme9652/hdsp.c index 6d9029333a12..ab9a32a2f5bb 100644 --- a/sound/pci/rme9652/hdsp.c +++ b/sound/pci/rme9652/hdsp.c @@ -5393,7 +5393,8 @@ static int snd_hdsp_free(struct hdsp *hdsp) if (hdsp->port) pci_release_regions(hdsp->pci); - pci_disable_device(hdsp->pci); + if (pci_is_enabled(hdsp->pci)) + pci_disable_device(hdsp->pci); return 0; } From 790f5719b85e12e10c41753b864e74249585ed08 Mon Sep 17 00:00:00 2001 From: Tong Zhang Date: Sun, 21 Mar 2021 11:38:39 -0400 Subject: [PATCH 293/587] ALSA: hdspm: don't disable if not enabled hdspm wants to disable a not enabled pci device, which makes kernel throw a warning. Make sure the device is enabled before calling disable. [ 1.786391] snd_hdspm 0000:00:03.0: disabling already-disabled device [ 1.786400] WARNING: CPU: 0 PID: 182 at drivers/pci/pci.c:2146 pci_disable_device+0x91/0xb0 [ 1.795181] Call Trace: [ 1.795320] snd_hdspm_card_free+0x58/0xa0 [snd_hdspm] [ 1.795595] release_card_device+0x4b/0x80 [snd] [ 1.795860] device_release+0x3b/0xa0 [ 1.796072] kobject_put+0x94/0x1b0 [ 1.796260] put_device+0x13/0x20 [ 1.796438] snd_card_free+0x61/0x90 [snd] [ 1.796659] snd_hdspm_probe+0x97b/0x1440 [snd_hdspm] Suggested-by: Takashi Iwai Signed-off-by: Tong Zhang Link: https://lore.kernel.org/r/20210321153840.378226-3-ztong0001@gmail.com Signed-off-by: Takashi Iwai --- sound/pci/rme9652/hdspm.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/sound/pci/rme9652/hdspm.c b/sound/pci/rme9652/hdspm.c index b66711574b1a..6edc31b44b22 100644 --- a/sound/pci/rme9652/hdspm.c +++ b/sound/pci/rme9652/hdspm.c @@ -6884,7 +6884,8 @@ static int snd_hdspm_free(struct hdspm * hdspm) if (hdspm->port) pci_release_regions(hdspm->pci); - pci_disable_device(hdspm->pci); + if (pci_is_enabled(hdspm->pci)) + pci_disable_device(hdspm->pci); return 0; } From f57a741874bb6995089020e97a1dcdf9b165dcbe Mon Sep 17 00:00:00 2001 From: Tong Zhang Date: Sun, 21 Mar 2021 11:38:40 -0400 Subject: [PATCH 294/587] ALSA: rme9652: don't disable if not enabled rme9652 wants to disable a not enabled pci device, which makes kernel throw a warning. Make sure the device is enabled before calling disable. [ 1.751595] snd_rme9652 0000:00:03.0: disabling already-disabled device [ 1.751605] WARNING: CPU: 0 PID: 174 at drivers/pci/pci.c:2146 pci_disable_device+0x91/0xb0 [ 1.759968] Call Trace: [ 1.760145] snd_rme9652_card_free+0x76/0xa0 [snd_rme9652] [ 1.760434] release_card_device+0x4b/0x80 [snd] [ 1.760679] device_release+0x3b/0xa0 [ 1.760874] kobject_put+0x94/0x1b0 [ 1.761059] put_device+0x13/0x20 [ 1.761235] snd_card_free+0x61/0x90 [snd] [ 1.761454] snd_rme9652_probe+0x3be/0x700 [snd_rme9652] Suggested-by: Takashi Iwai Signed-off-by: Tong Zhang Link: https://lore.kernel.org/r/20210321153840.378226-4-ztong0001@gmail.com Signed-off-by: Takashi Iwai --- sound/pci/rme9652/rme9652.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/sound/pci/rme9652/rme9652.c b/sound/pci/rme9652/rme9652.c index 012fbec5e6a7..0f4ab86a29f6 100644 --- a/sound/pci/rme9652/rme9652.c +++ b/sound/pci/rme9652/rme9652.c @@ -1733,7 +1733,8 @@ static int snd_rme9652_free(struct snd_rme9652 *rme9652) if (rme9652->port) pci_release_regions(rme9652->pci); - pci_disable_device(rme9652->pci); + if (pci_is_enabled(rme9652->pci)) + pci_disable_device(rme9652->pci); return 0; } From caa271510687f3ce3eed3a120cd2a6f71bc49223 Mon Sep 17 00:00:00 2001 From: Takashi Sakamoto Date: Sun, 21 Mar 2021 12:28:29 +0900 Subject: [PATCH 295/587] ALSA: bebob: code refactoring for stream format detection ALSA bebob driver scans supported formats of packet for each direction when probing the target device. Some helper functions are used for the scanning, however its implementation is not necessarily irredundant. This commit refactors the helper functions to remove redundant codes. Signed-off-by: Takashi Sakamoto Link: https://lore.kernel.org/r/20210321032831.340278-2-o-takashi@sakamocchi.jp Signed-off-by: Takashi Iwai --- sound/firewire/bebob/bebob_stream.c | 68 ++++++++++------------------- 1 file changed, 24 insertions(+), 44 deletions(-) diff --git a/sound/firewire/bebob/bebob_stream.c b/sound/firewire/bebob/bebob_stream.c index bbae04793c50..d96d2feb15a8 100644 --- a/sound/firewire/bebob/bebob_stream.c +++ b/sound/firewire/bebob/bebob_stream.c @@ -796,42 +796,42 @@ parse_stream_formation(u8 *buf, unsigned int len, return 0; } -static int -fill_stream_formations(struct snd_bebob *bebob, enum avc_bridgeco_plug_dir dir, - unsigned short pid) +static int fill_stream_formations(struct snd_bebob *bebob, u8 addr[AVC_BRIDGECO_ADDR_BYTES], + enum avc_bridgeco_plug_dir plug_dir, unsigned int plug_id, + struct snd_bebob_stream_formation *formations) { + enum avc_bridgeco_plug_type plug_type; u8 *buf; - struct snd_bebob_stream_formation *formations; unsigned int len, eid; - u8 addr[AVC_BRIDGECO_ADDR_BYTES]; int err; + avc_bridgeco_fill_unit_addr(addr, plug_dir, AVC_BRIDGECO_PLUG_UNIT_ISOC, plug_id); + + err = avc_bridgeco_get_plug_type(bebob->unit, addr, &plug_type); + if (err < 0) { + dev_err(&bebob->unit->device, + "Fail to get type for isoc %d plug 0: %d\n", plug_dir, err); + return err; + } else if (plug_type != AVC_BRIDGECO_PLUG_TYPE_ISOC) + return -ENXIO; + buf = kmalloc(FORMAT_MAXIMUM_LENGTH, GFP_KERNEL); if (buf == NULL) return -ENOMEM; - if (dir == AVC_BRIDGECO_PLUG_DIR_IN) - formations = bebob->rx_stream_formations; - else - formations = bebob->tx_stream_formations; + for (eid = 0; eid < SND_BEBOB_STRM_FMT_ENTRIES; ++eid) { + avc_bridgeco_fill_unit_addr(addr, plug_dir, AVC_BRIDGECO_PLUG_UNIT_ISOC, plug_id); - for (eid = 0; eid < SND_BEBOB_STRM_FMT_ENTRIES; eid++) { len = FORMAT_MAXIMUM_LENGTH; - avc_bridgeco_fill_unit_addr(addr, dir, - AVC_BRIDGECO_PLUG_UNIT_ISOC, pid); - err = avc_bridgeco_get_plug_strm_fmt(bebob->unit, addr, buf, - &len, eid); - /* No entries remained. */ + err = avc_bridgeco_get_plug_strm_fmt(bebob->unit, addr, buf, &len, eid); + // No entries remained. if (err == -EINVAL && eid > 0) { err = 0; break; } else if (err < 0) { dev_err(&bebob->unit->device, - "fail to get stream format %d for isoc %s plug %d:%d\n", - eid, - (dir == AVC_BRIDGECO_PLUG_DIR_IN) ? "in" : - "out", - pid, err); + "fail to get stream format %d for isoc %d plug %d:%d\n", + eid, plug_dir, plug_id, err); break; } @@ -908,33 +908,13 @@ int snd_bebob_stream_discover(struct snd_bebob *bebob) goto end; } - avc_bridgeco_fill_unit_addr(addr, AVC_BRIDGECO_PLUG_DIR_IN, - AVC_BRIDGECO_PLUG_UNIT_ISOC, 0); - err = avc_bridgeco_get_plug_type(bebob->unit, addr, &type); - if (err < 0) { - dev_err(&bebob->unit->device, - "fail to get type for isoc in plug 0: %d\n", err); - goto end; - } else if (type != AVC_BRIDGECO_PLUG_TYPE_ISOC) { - err = -ENOSYS; - goto end; - } - err = fill_stream_formations(bebob, AVC_BRIDGECO_PLUG_DIR_IN, 0); + err = fill_stream_formations(bebob, addr, AVC_BRIDGECO_PLUG_DIR_IN, 0, + bebob->rx_stream_formations); if (err < 0) goto end; - avc_bridgeco_fill_unit_addr(addr, AVC_BRIDGECO_PLUG_DIR_OUT, - AVC_BRIDGECO_PLUG_UNIT_ISOC, 0); - err = avc_bridgeco_get_plug_type(bebob->unit, addr, &type); - if (err < 0) { - dev_err(&bebob->unit->device, - "fail to get type for isoc out plug 0: %d\n", err); - goto end; - } else if (type != AVC_BRIDGECO_PLUG_TYPE_ISOC) { - err = -ENOSYS; - goto end; - } - err = fill_stream_formations(bebob, AVC_BRIDGECO_PLUG_DIR_OUT, 0); + err = fill_stream_formations(bebob, addr, AVC_BRIDGECO_PLUG_DIR_OUT, 0, + bebob->tx_stream_formations); if (err < 0) goto end; From 5c6ea94f2b7c5ce4c012ac8c23fd35588f69c4c7 Mon Sep 17 00:00:00 2001 From: Takashi Sakamoto Date: Sun, 21 Mar 2021 12:28:30 +0900 Subject: [PATCH 296/587] ALSA: bebob: detect the number of available MIDI ports Current implementation counts the number of input/output plugs for MIDI type and uses the count as the number of physical MIDI ports. However, the number of channels of the port represents the count. This commit fixes the bug by additional vendor-specific AVC command extension. Signed-off-by: Takashi Sakamoto Link: https://lore.kernel.org/r/20210321032831.340278-3-o-takashi@sakamocchi.jp Signed-off-by: Takashi Iwai --- sound/firewire/bebob/bebob.h | 2 + sound/firewire/bebob/bebob_command.c | 36 ++++++++++++ sound/firewire/bebob/bebob_stream.c | 83 +++++++++++++++++----------- 3 files changed, 89 insertions(+), 32 deletions(-) diff --git a/sound/firewire/bebob/bebob.h b/sound/firewire/bebob/bebob.h index d1ad9a8451bc..4e0ed84adbee 100644 --- a/sound/firewire/bebob/bebob.h +++ b/sound/firewire/bebob/bebob.h @@ -200,6 +200,8 @@ int avc_bridgeco_get_plug_ch_pos(struct fw_unit *unit, int avc_bridgeco_get_plug_type(struct fw_unit *unit, u8 addr[AVC_BRIDGECO_ADDR_BYTES], enum avc_bridgeco_plug_type *type); +int avc_bridgeco_get_plug_ch_count(struct fw_unit *unit, u8 addr[AVC_BRIDGECO_ADDR_BYTES], + unsigned int *ch_count); int avc_bridgeco_get_plug_section_type(struct fw_unit *unit, u8 addr[AVC_BRIDGECO_ADDR_BYTES], unsigned int id, u8 *type); diff --git a/sound/firewire/bebob/bebob_command.c b/sound/firewire/bebob/bebob_command.c index e276ab8f9006..022df09c68ff 100644 --- a/sound/firewire/bebob/bebob_command.c +++ b/sound/firewire/bebob/bebob_command.c @@ -143,6 +143,42 @@ end: return err; } +int avc_bridgeco_get_plug_ch_count(struct fw_unit *unit, u8 addr[AVC_BRIDGECO_ADDR_BYTES], + unsigned int *ch_count) +{ + u8 *buf; + int err; + + buf = kzalloc(12, GFP_KERNEL); + if (buf == NULL) + return -ENOMEM; + + // Info type is 'plug type'. + avc_bridgeco_fill_plug_info_extension_command(buf, addr, 0x02); + + err = fcp_avc_transaction(unit, buf, 12, buf, 12, + BIT(1) | BIT(2) | BIT(3) | BIT(4) | BIT(5) | + BIT(6) | BIT(7) | BIT(9)); + if (err < 0) + ; + else if (err < 11) + err = -EIO; + else if (buf[0] == 0x08) // NOT IMPLEMENTED + err = -ENOSYS; + else if (buf[0] == 0x0a) // REJECTED + err = -EINVAL; + else if (buf[0] == 0x0b) // IN TRANSITION + err = -EAGAIN; + if (err < 0) + goto end; + + *ch_count = buf[10]; + err = 0; +end: + kfree(buf); + return err; +} + int avc_bridgeco_get_plug_ch_pos(struct fw_unit *unit, u8 addr[AVC_BRIDGECO_ADDR_BYTES], u8 *buf, unsigned int len) diff --git a/sound/firewire/bebob/bebob_stream.c b/sound/firewire/bebob/bebob_stream.c index d96d2feb15a8..23579a73e038 100644 --- a/sound/firewire/bebob/bebob_stream.c +++ b/sound/firewire/bebob/bebob_stream.c @@ -844,6 +844,49 @@ static int fill_stream_formations(struct snd_bebob *bebob, u8 addr[AVC_BRIDGECO_ return err; } +static int detect_midi_ports(struct snd_bebob *bebob, + const struct snd_bebob_stream_formation *formats, + u8 addr[AVC_BRIDGECO_ADDR_BYTES], enum avc_bridgeco_plug_dir plug_dir, + unsigned int plug_count, unsigned int *midi_ports) +{ + int i; + int err = 0; + + *midi_ports = 0; + + /// Detect the number of available MIDI ports when packet has MIDI conformant data channel. + for (i = 0; i < SND_BEBOB_STRM_FMT_ENTRIES; ++i) { + if (formats[i].midi > 0) + break; + } + if (i >= SND_BEBOB_STRM_FMT_ENTRIES) + return 0; + + for (i = 0; i < plug_count; ++i) { + enum avc_bridgeco_plug_type plug_type; + unsigned int ch_count; + + avc_bridgeco_fill_unit_addr(addr, plug_dir, AVC_BRIDGECO_PLUG_UNIT_EXT, i); + + err = avc_bridgeco_get_plug_type(bebob->unit, addr, &plug_type); + if (err < 0) { + dev_err(&bebob->unit->device, + "fail to get type for external %d plug %d: %d\n", + plug_dir, i, err); + break; + } else if (plug_type != AVC_BRIDGECO_PLUG_TYPE_MIDI) { + continue; + } + + err = avc_bridgeco_get_plug_ch_count(bebob->unit, addr, &ch_count); + if (err < 0) + break; + *midi_ports += ch_count; + } + + return err; +} + static int seek_msu_sync_input_plug(struct snd_bebob *bebob) { @@ -886,8 +929,6 @@ int snd_bebob_stream_discover(struct snd_bebob *bebob) { const struct snd_bebob_clock_spec *clk_spec = bebob->spec->clock; u8 plugs[AVC_PLUG_INFO_BUF_BYTES], addr[AVC_BRIDGECO_ADDR_BYTES]; - enum avc_bridgeco_plug_type type; - unsigned int i; int err; /* the number of plugs for isoc in/out, ext in/out */ @@ -918,37 +959,15 @@ int snd_bebob_stream_discover(struct snd_bebob *bebob) if (err < 0) goto end; - /* count external input plugs for MIDI */ - bebob->midi_input_ports = 0; - for (i = 0; i < plugs[2]; i++) { - avc_bridgeco_fill_unit_addr(addr, AVC_BRIDGECO_PLUG_DIR_IN, - AVC_BRIDGECO_PLUG_UNIT_EXT, i); - err = avc_bridgeco_get_plug_type(bebob->unit, addr, &type); - if (err < 0) { - dev_err(&bebob->unit->device, - "fail to get type for external in plug %d: %d\n", - i, err); - goto end; - } else if (type == AVC_BRIDGECO_PLUG_TYPE_MIDI) { - bebob->midi_input_ports++; - } - } + err = detect_midi_ports(bebob, bebob->rx_stream_formations, addr, AVC_BRIDGECO_PLUG_DIR_IN, + plugs[2], &bebob->midi_input_ports); + if (err < 0) + goto end; - /* count external output plugs for MIDI */ - bebob->midi_output_ports = 0; - for (i = 0; i < plugs[3]; i++) { - avc_bridgeco_fill_unit_addr(addr, AVC_BRIDGECO_PLUG_DIR_OUT, - AVC_BRIDGECO_PLUG_UNIT_EXT, i); - err = avc_bridgeco_get_plug_type(bebob->unit, addr, &type); - if (err < 0) { - dev_err(&bebob->unit->device, - "fail to get type for external out plug %d: %d\n", - i, err); - goto end; - } else if (type == AVC_BRIDGECO_PLUG_TYPE_MIDI) { - bebob->midi_output_ports++; - } - } + err = detect_midi_ports(bebob, bebob->tx_stream_formations, addr, AVC_BRIDGECO_PLUG_DIR_OUT, + plugs[3], &bebob->midi_output_ports); + if (err < 0) + goto end; /* for check source of clock later */ if (!clk_spec) From d2b6f15bc18ac8fbce25398290774c21f5b2cd44 Mon Sep 17 00:00:00 2001 From: Takashi Sakamoto Date: Sun, 21 Mar 2021 12:28:31 +0900 Subject: [PATCH 297/587] ALSA: bebob: enable to deliver MIDI messages for multiple ports Current implementation of bebob driver doesn't correctly handle the case that the device has multiple MIDI ports. The cause is the number of MIDI conformant data channels is passed to AM824 data block processing layer. This commit fixes the bug. Signed-off-by: Takashi Sakamoto Link: https://lore.kernel.org/r/20210321032831.340278-4-o-takashi@sakamocchi.jp Signed-off-by: Takashi Iwai --- sound/firewire/bebob/bebob_stream.c | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/sound/firewire/bebob/bebob_stream.c b/sound/firewire/bebob/bebob_stream.c index 23579a73e038..b612ee3e33b6 100644 --- a/sound/firewire/bebob/bebob_stream.c +++ b/sound/firewire/bebob/bebob_stream.c @@ -517,20 +517,22 @@ int snd_bebob_stream_init_duplex(struct snd_bebob *bebob) static int keep_resources(struct snd_bebob *bebob, struct amdtp_stream *stream, unsigned int rate, unsigned int index) { - struct snd_bebob_stream_formation *formation; + unsigned int pcm_channels; + unsigned int midi_ports; struct cmp_connection *conn; int err; if (stream == &bebob->tx_stream) { - formation = bebob->tx_stream_formations + index; + pcm_channels = bebob->tx_stream_formations[index].pcm; + midi_ports = bebob->midi_input_ports; conn = &bebob->out_conn; } else { - formation = bebob->rx_stream_formations + index; + pcm_channels = bebob->rx_stream_formations[index].pcm; + midi_ports = bebob->midi_output_ports; conn = &bebob->in_conn; } - err = amdtp_am824_set_parameters(stream, rate, formation->pcm, - formation->midi, false); + err = amdtp_am824_set_parameters(stream, rate, pcm_channels, midi_ports, false); if (err < 0) return err; From 940ba1f5e18d4411c4e87ef902dc811a10d341d0 Mon Sep 17 00:00:00 2001 From: Arnd Bergmann Date: Mon, 22 Mar 2021 11:31:10 +0100 Subject: [PATCH 298/587] ALSA: core: avoid -Wempty-body warnings Building with 'make W=1' shows some warnings about empty function-style macros: sound/core/pcm_memory.c: In function 'preallocate_pages': sound/core/pcm_memory.c:236:49: error: suggest braces around empty body in an 'if' statement [-Werror=empty-body] 236 | preallocate_info_init(substream); sound/core/seq_device.c: In function 'snd_seq_device_dev_register': sound/core/seq_device.c:163:41: error: suggest braces around empty body in an 'if' statement [-Werror=empty-body] 163 | queue_autoload_drivers(); Change them to empty inline functions, which are more robust here. Signed-off-by: Arnd Bergmann Link: https://lore.kernel.org/r/20210322103128.547199-1-arnd@kernel.org Signed-off-by: Takashi Iwai --- sound/core/oss/pcm_oss.c | 8 ++++++-- sound/core/pcm_memory.c | 4 +++- sound/core/seq_device.c | 15 ++++++++++++--- 3 files changed, 21 insertions(+), 6 deletions(-) diff --git a/sound/core/oss/pcm_oss.c b/sound/core/oss/pcm_oss.c index 142fc751a847..86c39ee01aaa 100644 --- a/sound/core/oss/pcm_oss.c +++ b/sound/core/oss/pcm_oss.c @@ -3069,8 +3069,12 @@ static void snd_pcm_oss_proc_done(struct snd_pcm *pcm) } } #else /* !CONFIG_SND_VERBOSE_PROCFS */ -#define snd_pcm_oss_proc_init(pcm) -#define snd_pcm_oss_proc_done(pcm) +static inline void snd_pcm_oss_proc_init(struct snd_pcm *pcm) +{ +} +static inline void snd_pcm_oss_proc_done(struct snd_pcm *pcm) +{ +} #endif /* CONFIG_SND_VERBOSE_PROCFS */ /* diff --git a/sound/core/pcm_memory.c b/sound/core/pcm_memory.c index 2878c4c23583..542a75babdee 100644 --- a/sound/core/pcm_memory.c +++ b/sound/core/pcm_memory.c @@ -214,7 +214,9 @@ static inline void preallocate_info_init(struct snd_pcm_substream *substream) } #else /* !CONFIG_SND_VERBOSE_PROCFS */ -#define preallocate_info_init(s) +static inline void preallocate_info_init(struct snd_pcm_substream *substream) +{ +} #endif /* CONFIG_SND_VERBOSE_PROCFS */ /* diff --git a/sound/core/seq_device.c b/sound/core/seq_device.c index 7ed13cb32ef8..382275c5b193 100644 --- a/sound/core/seq_device.c +++ b/sound/core/seq_device.c @@ -133,10 +133,19 @@ void snd_seq_device_load_drivers(void) flush_work(&autoload_work); } EXPORT_SYMBOL(snd_seq_device_load_drivers); -#define cancel_autoload_drivers() cancel_work_sync(&autoload_work) + +static inline void cancel_autoload_drivers(void) +{ + cancel_work_sync(&autoload_work); +} #else -#define queue_autoload_drivers() /* NOP */ -#define cancel_autoload_drivers() /* NOP */ +static inline void queue_autoload_drivers(void) +{ +} + +static inline void cancel_autoload_drivers(void) +{ +} #endif /* From 7e71b48f9e27e437ca523432ea285c2585a539dc Mon Sep 17 00:00:00 2001 From: Vijendar Mukunda Date: Fri, 19 Mar 2021 07:10:42 +0530 Subject: [PATCH 299/587] ASoC: amd: Add support for RT5682 codec in machine driver Add support for RT5682 codec in machine driver. Signed-off-by: Vijendar Mukunda Link: https://lore.kernel.org/r/1616118056-5506-1-git-send-email-Vijendar.Mukunda@amd.com Signed-off-by: Mark Brown --- sound/soc/amd/Kconfig | 5 +- sound/soc/amd/acp-da7219-max98357a.c | 355 +++++++++++++++++++++++++-- 2 files changed, 344 insertions(+), 16 deletions(-) diff --git a/sound/soc/amd/Kconfig b/sound/soc/amd/Kconfig index a6ce000fac3f..43f5d29d7c53 100644 --- a/sound/soc/amd/Kconfig +++ b/sound/soc/amd/Kconfig @@ -5,14 +5,15 @@ config SND_SOC_AMD_ACP This option enables ACP DMA support on AMD platform. config SND_SOC_AMD_CZ_DA7219MX98357_MACH - tristate "AMD CZ support for DA7219 and MAX9835" + tristate "AMD CZ support for DA7219, RT5682 and MAX9835" select SND_SOC_DA7219 + select SND_SOC_RT5682_I2C select SND_SOC_MAX98357A select SND_SOC_ADAU7002 select REGULATOR depends on SND_SOC_AMD_ACP && I2C && GPIOLIB help - This option enables machine driver for DA7219 and MAX9835. + This option enables machine driver for DA7219, RT5682 and MAX9835. config SND_SOC_AMD_CZ_RT5645_MACH tristate "AMD CZ support for RT5645" diff --git a/sound/soc/amd/acp-da7219-max98357a.c b/sound/soc/amd/acp-da7219-max98357a.c index 849288d01c6b..e65e007fc604 100644 --- a/sound/soc/amd/acp-da7219-max98357a.c +++ b/sound/soc/amd/acp-da7219-max98357a.c @@ -41,14 +41,19 @@ #include "acp.h" #include "../codecs/da7219.h" #include "../codecs/da7219-aad.h" +#include "../codecs/rt5682.h" #define CZ_PLAT_CLK 48000000 #define DUAL_CHANNEL 2 +#define RT5682_PLL_FREQ (48000 * 512) static struct snd_soc_jack cz_jack; static struct clk *da7219_dai_wclk; static struct clk *da7219_dai_bclk; +static struct clk *rt5682_dai_wclk; +static struct clk *rt5682_dai_bclk; extern bool bt_uart_enable; +void *acp_soc_is_rltk_max(struct device *dev); static int cz_da7219_init(struct snd_soc_pcm_runtime *rtd) { @@ -128,6 +133,96 @@ static void da7219_clk_disable(void) clk_disable_unprepare(da7219_dai_bclk); } +static int cz_rt5682_init(struct snd_soc_pcm_runtime *rtd) +{ + int ret; + struct snd_soc_card *card = rtd->card; + struct snd_soc_dai *codec_dai = asoc_rtd_to_codec(rtd, 0); + struct snd_soc_component *component = codec_dai->component; + + dev_info(codec_dai->dev, "codec dai name = %s\n", codec_dai->name); + + /* Set codec sysclk */ + ret = snd_soc_dai_set_sysclk(codec_dai, RT5682_SCLK_S_PLL2, + RT5682_PLL_FREQ, SND_SOC_CLOCK_IN); + if (ret < 0) { + dev_err(codec_dai->dev, + "Failed to set rt5682 SYSCLK: %d\n", ret); + return ret; + } + /* set codec PLL */ + ret = snd_soc_dai_set_pll(codec_dai, RT5682_PLL2, RT5682_PLL2_S_MCLK, + CZ_PLAT_CLK, RT5682_PLL_FREQ); + if (ret < 0) { + dev_err(codec_dai->dev, "can't set rt5682 PLL: %d\n", ret); + return ret; + } + + rt5682_dai_wclk = devm_clk_get(component->dev, "rt5682-dai-wclk"); + if (IS_ERR(rt5682_dai_wclk)) + return PTR_ERR(rt5682_dai_wclk); + + rt5682_dai_bclk = devm_clk_get(component->dev, "rt5682-dai-bclk"); + if (IS_ERR(rt5682_dai_bclk)) + return PTR_ERR(rt5682_dai_bclk); + + ret = snd_soc_card_jack_new(card, "Headset Jack", + SND_JACK_HEADSET | SND_JACK_LINEOUT | + SND_JACK_BTN_0 | SND_JACK_BTN_1 | + SND_JACK_BTN_2 | SND_JACK_BTN_3, + &cz_jack, NULL, 0); + if (ret) { + dev_err(card->dev, "HP jack creation failed %d\n", ret); + return ret; + } + + snd_jack_set_key(cz_jack.jack, SND_JACK_BTN_0, KEY_PLAYPAUSE); + snd_jack_set_key(cz_jack.jack, SND_JACK_BTN_1, KEY_VOLUMEUP); + snd_jack_set_key(cz_jack.jack, SND_JACK_BTN_2, KEY_VOLUMEDOWN); + snd_jack_set_key(cz_jack.jack, SND_JACK_BTN_3, KEY_VOICECOMMAND); + + ret = snd_soc_component_set_jack(component, &cz_jack, NULL); + if (ret) { + dev_err(rtd->dev, "Headset Jack call-back failed: %d\n", ret); + return ret; + } + return 0; +} + +static int rt5682_clk_enable(struct snd_pcm_substream *substream) +{ + int ret; + struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream); + + /* + * Set wclk to 48000 because the rate constraint of this driver is + * 48000. ADAU7002 spec: "The ADAU7002 requires a BCLK rate that is + * minimum of 64x the LRCLK sample rate." RT5682 is the only clk + * source so for all codecs we have to limit bclk to 64X lrclk. + */ + ret = clk_set_rate(rt5682_dai_wclk, 48000); + if (ret) { + dev_err(rtd->dev, "Error setting wclk rate: %d\n", ret); + return ret; + } + ret = clk_set_rate(rt5682_dai_bclk, 48000 * 64); + if (ret) { + dev_err(rtd->dev, "Error setting bclk rate: %d\n", ret); + return ret; + } + ret = clk_prepare_enable(rt5682_dai_wclk); + if (ret < 0) { + dev_err(rtd->dev, "can't enable wclk %d\n", ret); + return ret; + } + return ret; +} + +static void rt5682_clk_disable(void) +{ + clk_disable_unprepare(rt5682_dai_wclk); +} + static const unsigned int channels[] = { DUAL_CHANNEL, }; @@ -260,6 +355,118 @@ static void cz_da7219_shutdown(struct snd_pcm_substream *substream) da7219_clk_disable(); } +static int cz_rt5682_play_startup(struct snd_pcm_substream *substream) +{ + struct snd_pcm_runtime *runtime = substream->runtime; + struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream); + struct snd_soc_card *card = rtd->card; + struct acp_platform_info *machine = snd_soc_card_get_drvdata(card); + + /* + * On this platform for PCM device we support stereo + */ + + runtime->hw.channels_max = DUAL_CHANNEL; + snd_pcm_hw_constraint_list(runtime, 0, SNDRV_PCM_HW_PARAM_CHANNELS, + &constraints_channels); + snd_pcm_hw_constraint_list(runtime, 0, SNDRV_PCM_HW_PARAM_RATE, + &constraints_rates); + + machine->play_i2s_instance = I2S_SP_INSTANCE; + return rt5682_clk_enable(substream); +} + +static int cz_rt5682_cap_startup(struct snd_pcm_substream *substream) +{ + struct snd_pcm_runtime *runtime = substream->runtime; + struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream); + struct snd_soc_card *card = rtd->card; + struct acp_platform_info *machine = snd_soc_card_get_drvdata(card); + + /* + * On this platform for PCM device we support stereo + */ + + runtime->hw.channels_max = DUAL_CHANNEL; + snd_pcm_hw_constraint_list(runtime, 0, SNDRV_PCM_HW_PARAM_CHANNELS, + &constraints_channels); + snd_pcm_hw_constraint_list(runtime, 0, SNDRV_PCM_HW_PARAM_RATE, + &constraints_rates); + + machine->cap_i2s_instance = I2S_SP_INSTANCE; + machine->capture_channel = CAP_CHANNEL1; + return rt5682_clk_enable(substream); +} + +static int cz_rt5682_max_startup(struct snd_pcm_substream *substream) +{ + struct snd_pcm_runtime *runtime = substream->runtime; + struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream); + struct snd_soc_card *card = rtd->card; + struct acp_platform_info *machine = snd_soc_card_get_drvdata(card); + + /* + * On this platform for PCM device we support stereo + */ + + runtime->hw.channels_max = DUAL_CHANNEL; + snd_pcm_hw_constraint_list(runtime, 0, SNDRV_PCM_HW_PARAM_CHANNELS, + &constraints_channels); + snd_pcm_hw_constraint_list(runtime, 0, SNDRV_PCM_HW_PARAM_RATE, + &constraints_rates); + + machine->play_i2s_instance = I2S_BT_INSTANCE; + return rt5682_clk_enable(substream); +} + +static int cz_rt5682_dmic0_startup(struct snd_pcm_substream *substream) +{ + struct snd_pcm_runtime *runtime = substream->runtime; + struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream); + struct snd_soc_card *card = rtd->card; + struct acp_platform_info *machine = snd_soc_card_get_drvdata(card); + + /* + * On this platform for PCM device we support stereo + */ + + runtime->hw.channels_max = DUAL_CHANNEL; + snd_pcm_hw_constraint_list(runtime, 0, SNDRV_PCM_HW_PARAM_CHANNELS, + &constraints_channels); + snd_pcm_hw_constraint_list(runtime, 0, SNDRV_PCM_HW_PARAM_RATE, + &constraints_rates); + + machine->cap_i2s_instance = I2S_BT_INSTANCE; + return rt5682_clk_enable(substream); +} + +static int cz_rt5682_dmic1_startup(struct snd_pcm_substream *substream) +{ + struct snd_pcm_runtime *runtime = substream->runtime; + struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream); + struct snd_soc_card *card = rtd->card; + struct acp_platform_info *machine = snd_soc_card_get_drvdata(card); + + /* + * On this platform for PCM device we support stereo + */ + + runtime->hw.channels_max = DUAL_CHANNEL; + snd_pcm_hw_constraint_list(runtime, 0, SNDRV_PCM_HW_PARAM_CHANNELS, + &constraints_channels); + snd_pcm_hw_constraint_list(runtime, 0, SNDRV_PCM_HW_PARAM_RATE, + &constraints_rates); + + machine->cap_i2s_instance = I2S_SP_INSTANCE; + machine->capture_channel = CAP_CHANNEL0; + return rt5682_clk_enable(substream); +} + +static void cz_rt5682_shutdown(struct snd_pcm_substream *substream) +{ + rt5682_clk_disable(); +} + static const struct snd_soc_ops cz_da7219_play_ops = { .startup = cz_da7219_play_startup, .shutdown = cz_da7219_shutdown, @@ -285,6 +492,31 @@ static const struct snd_soc_ops cz_dmic1_cap_ops = { .shutdown = cz_da7219_shutdown, }; +static const struct snd_soc_ops cz_rt5682_play_ops = { + .startup = cz_rt5682_play_startup, + .shutdown = cz_rt5682_shutdown, +}; + +static const struct snd_soc_ops cz_rt5682_cap_ops = { + .startup = cz_rt5682_cap_startup, + .shutdown = cz_rt5682_shutdown, +}; + +static const struct snd_soc_ops cz_rt5682_max_play_ops = { + .startup = cz_rt5682_max_startup, + .shutdown = cz_rt5682_shutdown, +}; + +static const struct snd_soc_ops cz_rt5682_dmic0_cap_ops = { + .startup = cz_rt5682_dmic0_startup, + .shutdown = cz_rt5682_shutdown, +}; + +static const struct snd_soc_ops cz_rt5682_dmic1_cap_ops = { + .startup = cz_rt5682_dmic1_startup, + .shutdown = cz_rt5682_shutdown, +}; + SND_SOC_DAILINK_DEF(designware1, DAILINK_COMP_ARRAY(COMP_CPU("designware-i2s.1.auto"))); SND_SOC_DAILINK_DEF(designware2, @@ -294,6 +526,8 @@ SND_SOC_DAILINK_DEF(designware3, SND_SOC_DAILINK_DEF(dlgs, DAILINK_COMP_ARRAY(COMP_CODEC("i2c-DLGS7219:00", "da7219-hifi"))); +SND_SOC_DAILINK_DEF(rt5682, + DAILINK_COMP_ARRAY(COMP_CODEC("i2c-10EC5682:00", "rt5682-aif1"))); SND_SOC_DAILINK_DEF(mx, DAILINK_COMP_ARRAY(COMP_CODEC("MX98357A:00", "HiFi"))); SND_SOC_DAILINK_DEF(adau, @@ -353,6 +587,57 @@ static struct snd_soc_dai_link cz_dai_7219_98357[] = { }, }; +static struct snd_soc_dai_link cz_dai_5682_98357[] = { + { + .name = "amd-rt5682-play", + .stream_name = "Playback", + .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF + | SND_SOC_DAIFMT_CBM_CFM, + .init = cz_rt5682_init, + .dpcm_playback = 1, + .ops = &cz_rt5682_play_ops, + SND_SOC_DAILINK_REG(designware1, rt5682, platform), + }, + { + .name = "amd-rt5682-cap", + .stream_name = "Capture", + .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF + | SND_SOC_DAIFMT_CBM_CFM, + .dpcm_capture = 1, + .ops = &cz_rt5682_cap_ops, + SND_SOC_DAILINK_REG(designware2, rt5682, platform), + }, + { + .name = "amd-max98357-play", + .stream_name = "HiFi Playback", + .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF + | SND_SOC_DAIFMT_CBM_CFM, + .dpcm_playback = 1, + .ops = &cz_rt5682_max_play_ops, + SND_SOC_DAILINK_REG(designware3, mx, platform), + }, + { + /* C panel DMIC */ + .name = "dmic0", + .stream_name = "DMIC0 Capture", + .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF + | SND_SOC_DAIFMT_CBM_CFM, + .dpcm_capture = 1, + .ops = &cz_rt5682_dmic0_cap_ops, + SND_SOC_DAILINK_REG(designware3, adau, platform), + }, + { + /* A/B panel DMIC */ + .name = "dmic1", + .stream_name = "DMIC1 Capture", + .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF + | SND_SOC_DAIFMT_CBM_CFM, + .dpcm_capture = 1, + .ops = &cz_rt5682_dmic1_cap_ops, + SND_SOC_DAILINK_REG(designware2, adau, platform), + }, +}; + static const struct snd_soc_dapm_widget cz_widgets[] = { SND_SOC_DAPM_HP("Headphones", NULL), SND_SOC_DAPM_SPK("Speakers", NULL), @@ -368,6 +653,14 @@ static const struct snd_soc_dapm_route cz_audio_route[] = { {"PDM_DAT", NULL, "Int Mic"}, }; +static const struct snd_soc_dapm_route cz_rt5682_audio_route[] = { + {"Headphones", NULL, "HPOL"}, + {"Headphones", NULL, "HPOR"}, + {"IN1P", NULL, "Headset Mic"}, + {"Speakers", NULL, "Speaker"}, + {"PDM_DAT", NULL, "Int Mic"}, +}; + static const struct snd_kcontrol_new cz_mc_controls[] = { SOC_DAPM_PIN_SWITCH("Headphones"), SOC_DAPM_PIN_SWITCH("Speakers"), @@ -388,6 +681,28 @@ static struct snd_soc_card cz_card = { .num_controls = ARRAY_SIZE(cz_mc_controls), }; +static struct snd_soc_card cz_rt5682_card = { + .name = "acpr5682m98357", + .owner = THIS_MODULE, + .dai_link = cz_dai_5682_98357, + .num_links = ARRAY_SIZE(cz_dai_5682_98357), + .dapm_widgets = cz_widgets, + .num_dapm_widgets = ARRAY_SIZE(cz_widgets), + .dapm_routes = cz_rt5682_audio_route, + .controls = cz_mc_controls, + .num_controls = ARRAY_SIZE(cz_mc_controls), +}; + +void *acp_soc_is_rltk_max(struct device *dev) +{ + const struct acpi_device_id *match; + + match = acpi_match_device(dev->driver->acpi_match_table, dev); + if (!match) + return NULL; + return (void *)match->driver_data; +} + static struct regulator_consumer_supply acp_da7219_supplies[] = { REGULATOR_SUPPLY("VDD", "i2c-DLGS7219:00"), REGULATOR_SUPPLY("VDDMIC", "i2c-DLGS7219:00"), @@ -425,29 +740,39 @@ static int cz_probe(struct platform_device *pdev) struct snd_soc_card *card; struct acp_platform_info *machine; struct regulator_dev *rdev; + struct device *dev = &pdev->dev; - acp_da7219_cfg.dev = &pdev->dev; - rdev = devm_regulator_register(&pdev->dev, &acp_da7219_desc, - &acp_da7219_cfg); - if (IS_ERR(rdev)) { - dev_err(&pdev->dev, "Failed to register regulator: %d\n", - (int)PTR_ERR(rdev)); - return -EINVAL; + card = (struct snd_soc_card *)acp_soc_is_rltk_max(dev); + if (!card) + return -ENODEV; + if (!strcmp(card->name, "acpd7219m98357")) { + acp_da7219_cfg.dev = &pdev->dev; + rdev = devm_regulator_register(&pdev->dev, &acp_da7219_desc, + &acp_da7219_cfg); + if (IS_ERR(rdev)) { + dev_err(&pdev->dev, "Failed to register regulator: %d\n", + (int)PTR_ERR(rdev)); + return -EINVAL; + } } machine = devm_kzalloc(&pdev->dev, sizeof(struct acp_platform_info), GFP_KERNEL); if (!machine) return -ENOMEM; - card = &cz_card; - cz_card.dev = &pdev->dev; + card->dev = &pdev->dev; platform_set_drvdata(pdev, card); snd_soc_card_set_drvdata(card, machine); - ret = devm_snd_soc_register_card(&pdev->dev, &cz_card); + ret = devm_snd_soc_register_card(&pdev->dev, card); if (ret) { - dev_err(&pdev->dev, + if (ret != -EPROBE_DEFER) + dev_err(&pdev->dev, "devm_snd_soc_register_card(%s) failed: %d\n", - cz_card.name, ret); + card->name, ret); + else + dev_dbg(&pdev->dev, + "devm_snd_soc_register_card(%s) probe deferred: %d\n", + card->name, ret); return ret; } bt_uart_enable = !device_property_read_bool(&pdev->dev, @@ -457,7 +782,8 @@ static int cz_probe(struct platform_device *pdev) #ifdef CONFIG_ACPI static const struct acpi_device_id cz_audio_acpi_match[] = { - { "AMD7219", 0 }, + { "AMD7219", (unsigned long)&cz_card }, + { "AMDI5682", (unsigned long)&cz_rt5682_card}, {}, }; MODULE_DEVICE_TABLE(acpi, cz_audio_acpi_match); @@ -475,5 +801,6 @@ static struct platform_driver cz_pcm_driver = { module_platform_driver(cz_pcm_driver); MODULE_AUTHOR("akshu.agrawal@amd.com"); -MODULE_DESCRIPTION("DA7219 & MAX98357A audio support"); +MODULE_AUTHOR("Vijendar.Mukunda@amd.com"); +MODULE_DESCRIPTION("DA7219, RT5682 & MAX98357A audio support"); MODULE_LICENSE("GPL v2"); From 2277e7e36b4b8c27eb8d2fb33a20440bc800c2d7 Mon Sep 17 00:00:00 2001 From: Shengjiu Wang Date: Fri, 19 Mar 2021 16:06:43 +0800 Subject: [PATCH 300/587] ASoC: fsl_sai: Don't use devm_regmap_init_mmio_clk When there is power domain bind with bus clock, The call flow: devm_regmap_init_mmio_clk - clk_prepare() - clk_pm_runtime_get() cause the power domain of clock always be enabled after regmap_init(). which impact the power consumption. So use devm_regmap_init_mmio instead of devm_regmap_init_mmio_clk, then explicitly enable clock when using by pm_runtime_get(), if CONFIG_PM=n, then fsl_sai_runtime_resume will be explicitly called. Signed-off-by: Shengjiu Wang Signed-off-by: Viorel Suman Link: https://lore.kernel.org/r/1616141203-13344-1-git-send-email-shengjiu.wang@nxp.com Signed-off-by: Mark Brown --- sound/soc/fsl/fsl_sai.c | 48 +++++++++++++++++++++++++++-------------- 1 file changed, 32 insertions(+), 16 deletions(-) diff --git a/sound/soc/fsl/fsl_sai.c b/sound/soc/fsl/fsl_sai.c index 6ef2ce348232..407a45e48eee 100644 --- a/sound/soc/fsl/fsl_sai.c +++ b/sound/soc/fsl/fsl_sai.c @@ -994,6 +994,9 @@ static int fsl_sai_check_version(struct device *dev) return 0; } +static int fsl_sai_runtime_suspend(struct device *dev); +static int fsl_sai_runtime_resume(struct device *dev); + static int fsl_sai_probe(struct platform_device *pdev) { struct device_node *np = pdev->dev.of_node; @@ -1026,24 +1029,21 @@ static int fsl_sai_probe(struct platform_device *pdev) ARRAY_SIZE(fsl_sai_reg_defaults_ofs8); } - sai->regmap = devm_regmap_init_mmio_clk(&pdev->dev, - "bus", base, &fsl_sai_regmap_config); - - /* Compatible with old DTB cases */ - if (IS_ERR(sai->regmap) && PTR_ERR(sai->regmap) != -EPROBE_DEFER) - sai->regmap = devm_regmap_init_mmio_clk(&pdev->dev, - "sai", base, &fsl_sai_regmap_config); + sai->regmap = devm_regmap_init_mmio(&pdev->dev, base, &fsl_sai_regmap_config); if (IS_ERR(sai->regmap)) { dev_err(&pdev->dev, "regmap init failed\n"); return PTR_ERR(sai->regmap); } - /* No error out for old DTB cases but only mark the clock NULL */ sai->bus_clk = devm_clk_get(&pdev->dev, "bus"); + /* Compatible with old DTB cases */ + if (IS_ERR(sai->bus_clk) && PTR_ERR(sai->bus_clk) != -EPROBE_DEFER) + sai->bus_clk = devm_clk_get(&pdev->dev, "sai"); if (IS_ERR(sai->bus_clk)) { dev_err(&pdev->dev, "failed to get bus clock: %ld\n", PTR_ERR(sai->bus_clk)); - sai->bus_clk = NULL; + /* -EPROBE_DEFER */ + return PTR_ERR(sai->bus_clk); } for (i = 1; i < FSL_SAI_MCLK_MAX; i++) { @@ -1124,6 +1124,18 @@ static int fsl_sai_probe(struct platform_device *pdev) sai->dma_params_tx.maxburst = FSL_SAI_MAXBURST_TX; platform_set_drvdata(pdev, sai); + pm_runtime_enable(&pdev->dev); + if (!pm_runtime_enabled(&pdev->dev)) { + ret = fsl_sai_runtime_resume(&pdev->dev); + if (ret) + goto err_pm_disable; + } + + ret = pm_runtime_get_sync(&pdev->dev); + if (ret < 0) { + pm_runtime_put_noidle(&pdev->dev); + goto err_pm_get_sync; + } /* Get sai version */ ret = fsl_sai_check_version(&pdev->dev); @@ -1137,26 +1149,30 @@ static int fsl_sai_probe(struct platform_device *pdev) FSL_SAI_MCTL_MCLK_EN, FSL_SAI_MCTL_MCLK_EN); } - pm_runtime_enable(&pdev->dev); - regcache_cache_only(sai->regmap, true); + ret = pm_runtime_put_sync(&pdev->dev); + if (ret < 0) + goto err_pm_get_sync; ret = devm_snd_soc_register_component(&pdev->dev, &fsl_component, &sai->cpu_dai_drv, 1); if (ret) - goto err_pm_disable; + goto err_pm_get_sync; if (sai->soc_data->use_imx_pcm) { ret = imx_pcm_dma_init(pdev, IMX_SAI_DMABUF_SIZE); if (ret) - goto err_pm_disable; + goto err_pm_get_sync; } else { ret = devm_snd_dmaengine_pcm_register(&pdev->dev, NULL, 0); if (ret) - goto err_pm_disable; + goto err_pm_get_sync; } return ret; +err_pm_get_sync: + if (!pm_runtime_status_suspended(&pdev->dev)) + fsl_sai_runtime_suspend(&pdev->dev); err_pm_disable: pm_runtime_disable(&pdev->dev); @@ -1166,6 +1182,8 @@ err_pm_disable: static int fsl_sai_remove(struct platform_device *pdev) { pm_runtime_disable(&pdev->dev); + if (!pm_runtime_status_suspended(&pdev->dev)) + fsl_sai_runtime_suspend(&pdev->dev); return 0; } @@ -1226,7 +1244,6 @@ static const struct of_device_id fsl_sai_ids[] = { }; MODULE_DEVICE_TABLE(of, fsl_sai_ids); -#ifdef CONFIG_PM static int fsl_sai_runtime_suspend(struct device *dev) { struct fsl_sai *sai = dev_get_drvdata(dev); @@ -1299,7 +1316,6 @@ disable_bus_clk: return ret; } -#endif /* CONFIG_PM */ static const struct dev_pm_ops fsl_sai_pm_ops = { SET_RUNTIME_PM_OPS(fsl_sai_runtime_suspend, From b951b51e2ca4d37dc9781e14d8a49d2f2b7e715b Mon Sep 17 00:00:00 2001 From: Keyon Jie Date: Fri, 19 Mar 2021 14:49:49 +0200 Subject: [PATCH 301/587] ASoC: SOF: add a helper to get topology configured mclk Add helper sof_dai_ssp_mclk to get the topology configured MCLK from a pcm_runtime, return 0 if it is not available, and error if the dai type is not SSP at the moment. Export the helper for external use, e.g. from machine drivers. Signed-off-by: Keyon Jie Reviewed-by: Guennadi Liakhovetski Reviewed-by: Daniel Baluta Signed-off-by: Kai Vehmanen Link: https://lore.kernel.org/r/20210319124950.3853994-1-kai.vehmanen@linux.intel.com Signed-off-by: Mark Brown --- include/sound/sof.h | 1 + sound/soc/sof/sof-audio.c | 27 +++++++++++++++++++++++++++ 2 files changed, 28 insertions(+) diff --git a/include/sound/sof.h b/include/sound/sof.h index 646a655c3c6b..b93bb8038080 100644 --- a/include/sound/sof.h +++ b/include/sound/sof.h @@ -103,5 +103,6 @@ struct sof_dev_desc { int sof_nocodec_setup(struct device *dev, const struct snd_sof_dsp_ops *ops, int (*pcm_dai_link_fixup)(struct snd_soc_pcm_runtime *rtd, struct snd_pcm_hw_params *params)); +int sof_dai_get_mclk(struct snd_soc_pcm_runtime *rtd); #endif diff --git a/sound/soc/sof/sof-audio.c b/sound/soc/sof/sof-audio.c index 3277489fee5e..928d7a46d820 100644 --- a/sound/soc/sof/sof-audio.c +++ b/sound/soc/sof/sof-audio.c @@ -433,6 +433,33 @@ struct snd_sof_dai *snd_sof_find_dai(struct snd_soc_component *scomp, return NULL; } +/* + * Helper to get SSP MCLK from a pcm_runtime. + * Return 0 if not exist. + */ +int sof_dai_get_mclk(struct snd_soc_pcm_runtime *rtd) +{ + struct snd_soc_component *component = + snd_soc_rtdcom_lookup(rtd, SOF_AUDIO_PCM_DRV_NAME); + struct snd_sof_dai *dai = + snd_sof_find_dai(component, (char *)rtd->dai_link->name); + + /* use the tplg configured mclk if existed */ + if (!dai || !dai->dai_config) + return 0; + + switch (dai->dai_config->type) { + case SOF_DAI_INTEL_SSP: + return dai->dai_config->ssp.mclk_rate; + default: + /* not yet implemented for platforms other than the above */ + dev_err(rtd->dev, "mclk for dai_config->type %d not supported yet!\n", + dai->dai_config->type); + return -EINVAL; + } +} +EXPORT_SYMBOL(sof_dai_get_mclk); + /* * SOF Driver enumeration. */ From bf939446c357242b3306e88c5f48976940d29679 Mon Sep 17 00:00:00 2001 From: Keyon Jie Date: Fri, 19 Mar 2021 14:49:50 +0200 Subject: [PATCH 302/587] ASoC: intel: sof_rt5682: use the topology mclk We should use the topology configured mclk if it existed, which can make sure we are aligned with the FW side about the mclk usage. Signed-off-by: Keyon Jie Reviewed-by: Guennadi Liakhovetski Reviewed-by: Daniel Baluta Signed-off-by: Kai Vehmanen Link: https://lore.kernel.org/r/20210319124950.3853994-2-kai.vehmanen@linux.intel.com Signed-off-by: Mark Brown --- sound/soc/intel/boards/sof_rt5682.c | 16 ++++++++++++++-- 1 file changed, 14 insertions(+), 2 deletions(-) diff --git a/sound/soc/intel/boards/sof_rt5682.c b/sound/soc/intel/boards/sof_rt5682.c index f4b898c1719f..58548ea0d915 100644 --- a/sound/soc/intel/boards/sof_rt5682.c +++ b/sound/soc/intel/boards/sof_rt5682.c @@ -16,6 +16,7 @@ #include #include #include +#include #include #include #include "../../codecs/rt1015.h" @@ -268,10 +269,21 @@ static int sof_rt5682_hw_params(struct snd_pcm_substream *substream, } clk_id = RT5682_PLL1_S_MCLK; - if (sof_rt5682_quirk & SOF_RT5682_MCLK_24MHZ) + + /* get the tplg configured mclk. */ + clk_freq = sof_dai_get_mclk(rtd); + + /* mclk from the quirk is the first choice */ + if (sof_rt5682_quirk & SOF_RT5682_MCLK_24MHZ) { + if (clk_freq != 24000000) + dev_warn(rtd->dev, "configure wrong mclk in tplg, please use 24MHz.\n"); clk_freq = 24000000; - else + } else if (clk_freq == 0) { + /* use default mclk if not specified correct in topology */ clk_freq = 19200000; + } else if (clk_freq < 0) { + return clk_freq; + } } else { clk_id = RT5682_PLL1_S_BCLK1; clk_freq = params_rate(params) * 50; From dfb81e3b5f47aa0ea5e4832eeb720bc22f07d0c1 Mon Sep 17 00:00:00 2001 From: Kai Vehmanen Date: Mon, 22 Mar 2021 16:38:30 +0200 Subject: [PATCH 303/587] ASoC: SOF: Intel: hda: drop display power on/off in D0i3 flows Controller needs to ensure display power is enabled only for HDA controller reset. Drop the display power-up/down calls from D0i3 entry/exit paths. This was previously not possible as codec drivers could not resume the links, and instead controller kept the reference to display power. The state of display power had be maintained in the D0i3 entry/exit code. With commit 87fc20e4a0cb ("ASoC: SOF: Intel: hda: use hdac_ext fine-grained link management"), this is no longer needed and the code can be cleaned up. Signed-off-by: Kai Vehmanen Reviewed-by: Ranjani Sridharan Reviewed-by: Keyon Jie Link: https://lore.kernel.org/r/20210322143830.3880293-1-kai.vehmanen@linux.intel.com Signed-off-by: Mark Brown --- sound/soc/sof/intel/hda-dsp.c | 5 ----- 1 file changed, 5 deletions(-) diff --git a/sound/soc/sof/intel/hda-dsp.c b/sound/soc/sof/intel/hda-dsp.c index 6e24e1cb13f9..df4cb29b9a1b 100644 --- a/sound/soc/sof/intel/hda-dsp.c +++ b/sound/soc/sof/intel/hda-dsp.c @@ -727,8 +727,6 @@ int hda_dsp_resume(struct snd_sof_dev *sdev) /* resume from D0I3 */ if (sdev->dsp_power_state.state == SOF_DSP_PM_D0) { - hda_codec_i915_display_power(sdev, true); - #if IS_ENABLED(CONFIG_SND_SOC_SOF_HDA) /* power up links that were active before suspend */ list_for_each_entry(hlink, &bus->hlink_list, list) { @@ -839,9 +837,6 @@ int hda_dsp_suspend(struct snd_sof_dev *sdev, u32 target_state) cancel_delayed_work_sync(&hda->d0i3_work); if (target_state == SOF_DSP_PM_D0) { - /* we can't keep a wakeref to display driver at suspend */ - hda_codec_i915_display_power(sdev, false); - /* Set DSP power state */ ret = snd_sof_dsp_set_power_state(sdev, &target_dsp_state); if (ret < 0) { From 203773e39347922b3923df6094324d430664466e Mon Sep 17 00:00:00 2001 From: Shengjiu Wang Date: Wed, 24 Mar 2021 17:58:43 +0800 Subject: [PATCH 304/587] ASoC: fsl_esai: Don't use devm_regmap_init_mmio_clk When there is power domain bind with bus clock, The call flow: devm_regmap_init_mmio_clk - clk_prepare() - clk_pm_runtime_get() cause the power domain of clock always be enabled after regmap_init(). which impact the power consumption. So use devm_regmap_init_mmio instead of devm_regmap_init_mmio_clk,but explicitly enable clock when it is used. Signed-off-by: Shengjiu Wang Link: https://lore.kernel.org/r/1616579928-22428-2-git-send-email-shengjiu.wang@nxp.com Signed-off-by: Mark Brown --- sound/soc/fsl/fsl_esai.c | 48 ++++++++++++++++++++++++++++++---------- 1 file changed, 36 insertions(+), 12 deletions(-) diff --git a/sound/soc/fsl/fsl_esai.c b/sound/soc/fsl/fsl_esai.c index 41b154417b92..c0d4f3c5dbb1 100644 --- a/sound/soc/fsl/fsl_esai.c +++ b/sound/soc/fsl/fsl_esai.c @@ -945,6 +945,9 @@ static const struct regmap_config fsl_esai_regmap_config = { .cache_type = REGCACHE_FLAT, }; +static int fsl_esai_runtime_resume(struct device *dev); +static int fsl_esai_runtime_suspend(struct device *dev); + static int fsl_esai_probe(struct platform_device *pdev) { struct device_node *np = pdev->dev.of_node; @@ -969,8 +972,7 @@ static int fsl_esai_probe(struct platform_device *pdev) if (IS_ERR(regs)) return PTR_ERR(regs); - esai_priv->regmap = devm_regmap_init_mmio_clk(&pdev->dev, - "core", regs, &fsl_esai_regmap_config); + esai_priv->regmap = devm_regmap_init_mmio(&pdev->dev, regs, &fsl_esai_regmap_config); if (IS_ERR(esai_priv->regmap)) { dev_err(&pdev->dev, "failed to init regmap: %ld\n", PTR_ERR(esai_priv->regmap)); @@ -1039,11 +1041,23 @@ static int fsl_esai_probe(struct platform_device *pdev) } dev_set_drvdata(&pdev->dev, esai_priv); - spin_lock_init(&esai_priv->lock); + pm_runtime_enable(&pdev->dev); + if (!pm_runtime_enabled(&pdev->dev)) { + ret = fsl_esai_runtime_resume(&pdev->dev); + if (ret) + goto err_pm_disable; + } + + ret = pm_runtime_get_sync(&pdev->dev); + if (ret < 0) { + pm_runtime_put_noidle(&pdev->dev); + goto err_pm_get_sync; + } + ret = fsl_esai_hw_init(esai_priv); if (ret) - return ret; + goto err_pm_get_sync; esai_priv->tx_mask = 0xFFFFFFFF; esai_priv->rx_mask = 0xFFFFFFFF; @@ -1054,24 +1068,33 @@ static int fsl_esai_probe(struct platform_device *pdev) regmap_write(esai_priv->regmap, REG_ESAI_RSMA, 0); regmap_write(esai_priv->regmap, REG_ESAI_RSMB, 0); + ret = pm_runtime_put_sync(&pdev->dev); + if (ret < 0) + goto err_pm_get_sync; + ret = devm_snd_soc_register_component(&pdev->dev, &fsl_esai_component, &fsl_esai_dai, 1); if (ret) { dev_err(&pdev->dev, "failed to register DAI: %d\n", ret); - return ret; + goto err_pm_get_sync; } INIT_WORK(&esai_priv->work, fsl_esai_hw_reset); - pm_runtime_enable(&pdev->dev); - - regcache_cache_only(esai_priv->regmap, true); - ret = imx_pcm_dma_init(pdev, IMX_ESAI_DMABUF_SIZE); - if (ret) + if (ret) { dev_err(&pdev->dev, "failed to init imx pcm dma: %d\n", ret); + goto err_pm_get_sync; + } return ret; + +err_pm_get_sync: + if (!pm_runtime_status_suspended(&pdev->dev)) + fsl_esai_runtime_suspend(&pdev->dev); +err_pm_disable: + pm_runtime_disable(&pdev->dev); + return ret; } static int fsl_esai_remove(struct platform_device *pdev) @@ -1079,6 +1102,9 @@ static int fsl_esai_remove(struct platform_device *pdev) struct fsl_esai *esai_priv = platform_get_drvdata(pdev); pm_runtime_disable(&pdev->dev); + if (!pm_runtime_status_suspended(&pdev->dev)) + fsl_esai_runtime_suspend(&pdev->dev); + cancel_work_sync(&esai_priv->work); return 0; @@ -1092,7 +1118,6 @@ static const struct of_device_id fsl_esai_dt_ids[] = { }; MODULE_DEVICE_TABLE(of, fsl_esai_dt_ids); -#ifdef CONFIG_PM static int fsl_esai_runtime_resume(struct device *dev) { struct fsl_esai *esai = dev_get_drvdata(dev); @@ -1160,7 +1185,6 @@ static int fsl_esai_runtime_suspend(struct device *dev) return 0; } -#endif /* CONFIG_PM */ static const struct dev_pm_ops fsl_esai_pm_ops = { SET_RUNTIME_PM_OPS(fsl_esai_runtime_suspend, From c2562572467a74fd637d2d22fb773b052512528c Mon Sep 17 00:00:00 2001 From: Shengjiu Wang Date: Wed, 24 Mar 2021 17:58:44 +0800 Subject: [PATCH 305/587] ASoC: fsl_spdif: Don't use devm_regmap_init_mmio_clk When there is power domain bind with core clock, The call flow: devm_regmap_init_mmio_clk - clk_prepare() - clk_pm_runtime_get() cause the power domain of clock always be enabled after regmap_init(). which impact the power consumption. So use devm_regmap_init_mmio instead of devm_regmap_init_mmio_clk,but explicitly enable clock when it is used. Signed-off-by: Shengjiu Wang Link: https://lore.kernel.org/r/1616579928-22428-3-git-send-email-shengjiu.wang@nxp.com Signed-off-by: Mark Brown --- sound/soc/fsl/fsl_spdif.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/sound/soc/fsl/fsl_spdif.c b/sound/soc/fsl/fsl_spdif.c index 1cd3441d1c03..c631de325a6e 100644 --- a/sound/soc/fsl/fsl_spdif.c +++ b/sound/soc/fsl/fsl_spdif.c @@ -1294,8 +1294,7 @@ static int fsl_spdif_probe(struct platform_device *pdev) if (IS_ERR(regs)) return PTR_ERR(regs); - spdif_priv->regmap = devm_regmap_init_mmio_clk(&pdev->dev, - "core", regs, &fsl_spdif_regmap_config); + spdif_priv->regmap = devm_regmap_init_mmio(&pdev->dev, regs, &fsl_spdif_regmap_config); if (IS_ERR(spdif_priv->regmap)) { dev_err(&pdev->dev, "regmap init failed\n"); return PTR_ERR(spdif_priv->regmap); From cab04ab5900fea6655f2a49d1f94c37200b63a59 Mon Sep 17 00:00:00 2001 From: Shengjiu Wang Date: Wed, 24 Mar 2021 17:58:45 +0800 Subject: [PATCH 306/587] ASoC: fsl_asrc: Don't use devm_regmap_init_mmio_clk When there is power domain bind with mem clock, The call flow: devm_regmap_init_mmio_clk - clk_prepare() - clk_pm_runtime_get() cause the power domain of clock always be enabled after regmap_init(). which impact the power consumption. So use devm_regmap_init_mmio instead of devm_regmap_init_mmio_clk,but explicitly enable clock when it is used. Signed-off-by: Shengjiu Wang Link: https://lore.kernel.org/r/1616579928-22428-4-git-send-email-shengjiu.wang@nxp.com Signed-off-by: Mark Brown --- sound/soc/fsl/fsl_asrc.c | 57 +++++++++++++++++++++++++++++++--------- 1 file changed, 44 insertions(+), 13 deletions(-) diff --git a/sound/soc/fsl/fsl_asrc.c b/sound/soc/fsl/fsl_asrc.c index 63d236ef5c4d..0e1ad8efebd3 100644 --- a/sound/soc/fsl/fsl_asrc.c +++ b/sound/soc/fsl/fsl_asrc.c @@ -1008,6 +1008,9 @@ static int fsl_asrc_get_fifo_addr(u8 dir, enum asrc_pair_index index) return REG_ASRDx(dir, index); } +static int fsl_asrc_runtime_resume(struct device *dev); +static int fsl_asrc_runtime_suspend(struct device *dev); + static int fsl_asrc_probe(struct platform_device *pdev) { struct device_node *np = pdev->dev.of_node; @@ -1039,8 +1042,7 @@ static int fsl_asrc_probe(struct platform_device *pdev) asrc->paddr = res->start; - asrc->regmap = devm_regmap_init_mmio_clk(&pdev->dev, "mem", regs, - &fsl_asrc_regmap_config); + asrc->regmap = devm_regmap_init_mmio(&pdev->dev, regs, &fsl_asrc_regmap_config); if (IS_ERR(asrc->regmap)) { dev_err(&pdev->dev, "failed to init regmap\n"); return PTR_ERR(asrc->regmap); @@ -1117,12 +1119,6 @@ static int fsl_asrc_probe(struct platform_device *pdev) } } - ret = fsl_asrc_init(asrc); - if (ret) { - dev_err(&pdev->dev, "failed to init asrc %d\n", ret); - return ret; - } - asrc->channel_avail = 10; ret = of_property_read_u32(np, "fsl,asrc-rate", @@ -1161,21 +1157,56 @@ static int fsl_asrc_probe(struct platform_device *pdev) } platform_set_drvdata(pdev, asrc); - pm_runtime_enable(&pdev->dev); spin_lock_init(&asrc->lock); - regcache_cache_only(asrc->regmap, true); + pm_runtime_enable(&pdev->dev); + if (!pm_runtime_enabled(&pdev->dev)) { + ret = fsl_asrc_runtime_resume(&pdev->dev); + if (ret) + goto err_pm_disable; + } + + ret = pm_runtime_get_sync(&pdev->dev); + if (ret < 0) { + pm_runtime_put_noidle(&pdev->dev); + goto err_pm_get_sync; + } + + ret = fsl_asrc_init(asrc); + if (ret) { + dev_err(&pdev->dev, "failed to init asrc %d\n", ret); + goto err_pm_get_sync; + } + + ret = pm_runtime_put_sync(&pdev->dev); + if (ret < 0) + goto err_pm_get_sync; ret = devm_snd_soc_register_component(&pdev->dev, &fsl_asrc_component, &fsl_asrc_dai, 1); if (ret) { dev_err(&pdev->dev, "failed to register ASoC DAI\n"); - return ret; + goto err_pm_get_sync; } return 0; + +err_pm_get_sync: + if (!pm_runtime_status_suspended(&pdev->dev)) + fsl_asrc_runtime_suspend(&pdev->dev); +err_pm_disable: + pm_runtime_disable(&pdev->dev); + return ret; +} + +static int fsl_asrc_remove(struct platform_device *pdev) +{ + pm_runtime_disable(&pdev->dev); + if (!pm_runtime_status_suspended(&pdev->dev)) + fsl_asrc_runtime_suspend(&pdev->dev); + + return 0; } -#ifdef CONFIG_PM static int fsl_asrc_runtime_resume(struct device *dev) { struct fsl_asrc *asrc = dev_get_drvdata(dev); @@ -1252,7 +1283,6 @@ static int fsl_asrc_runtime_suspend(struct device *dev) return 0; } -#endif /* CONFIG_PM */ static const struct dev_pm_ops fsl_asrc_pm = { SET_RUNTIME_PM_OPS(fsl_asrc_runtime_suspend, fsl_asrc_runtime_resume, NULL) @@ -1291,6 +1321,7 @@ MODULE_DEVICE_TABLE(of, fsl_asrc_ids); static struct platform_driver fsl_asrc_driver = { .probe = fsl_asrc_probe, + .remove = fsl_asrc_remove, .driver = { .name = "fsl-asrc", .of_match_table = fsl_asrc_ids, From 069b24f22eb9dba2e0886b40ea3feaa98e3f4f9b Mon Sep 17 00:00:00 2001 From: Shengjiu Wang Date: Wed, 24 Mar 2021 17:58:46 +0800 Subject: [PATCH 307/587] ASoC: fsl_easrc: Don't use devm_regmap_init_mmio_clk When there is power domain bind with mem clock, The call flow: devm_regmap_init_mmio_clk - clk_prepare() - clk_pm_runtime_get() cause the power domain of clock always be enabled after regmap_init(). which impact the power consumption. So use devm_regmap_init_mmio instead of devm_regmap_init_mmio_clk,but explicitly enable clock when it is used. Signed-off-by: Shengjiu Wang Link: https://lore.kernel.org/r/1616579928-22428-5-git-send-email-shengjiu.wang@nxp.com Signed-off-by: Mark Brown --- sound/soc/fsl/fsl_easrc.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/sound/soc/fsl/fsl_easrc.c b/sound/soc/fsl/fsl_easrc.c index 600e0d670ca6..5e33afe87c4a 100644 --- a/sound/soc/fsl/fsl_easrc.c +++ b/sound/soc/fsl/fsl_easrc.c @@ -1896,8 +1896,7 @@ static int fsl_easrc_probe(struct platform_device *pdev) easrc->paddr = res->start; - easrc->regmap = devm_regmap_init_mmio_clk(dev, "mem", regs, - &fsl_easrc_regmap_config); + easrc->regmap = devm_regmap_init_mmio(dev, regs, &fsl_easrc_regmap_config); if (IS_ERR(easrc->regmap)) { dev_err(dev, "failed to init regmap"); return PTR_ERR(easrc->regmap); From 3feaba79d8f701a774815483aa0e7f4edb15c880 Mon Sep 17 00:00:00 2001 From: Shengjiu Wang Date: Wed, 24 Mar 2021 17:58:47 +0800 Subject: [PATCH 308/587] ASoC: fsl_audmix: Don't use devm_regmap_init_mmio_clk When there is power domain bind with ipg clock, The call flow: devm_regmap_init_mmio_clk - clk_prepare() - clk_pm_runtime_get() cause the power domain of clock always be enabled after regmap_init(). which impact the power consumption. So use devm_regmap_init_mmio instead of devm_regmap_init_mmio_clk,but explicitly enable clock when it is used. Signed-off-by: Shengjiu Wang Link: https://lore.kernel.org/r/1616579928-22428-6-git-send-email-shengjiu.wang@nxp.com Signed-off-by: Mark Brown --- sound/soc/fsl/fsl_audmix.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/sound/soc/fsl/fsl_audmix.c b/sound/soc/fsl/fsl_audmix.c index 8dc44dec7956..f931288e256c 100644 --- a/sound/soc/fsl/fsl_audmix.c +++ b/sound/soc/fsl/fsl_audmix.c @@ -476,8 +476,7 @@ static int fsl_audmix_probe(struct platform_device *pdev) if (IS_ERR(regs)) return PTR_ERR(regs); - priv->regmap = devm_regmap_init_mmio_clk(dev, "ipg", regs, - &fsl_audmix_regmap_config); + priv->regmap = devm_regmap_init_mmio(dev, regs, &fsl_audmix_regmap_config); if (IS_ERR(priv->regmap)) { dev_err(dev, "failed to init regmap\n"); return PTR_ERR(priv->regmap); From b5cf28f7a890f3554ca15a43edbbb86dd1b9663c Mon Sep 17 00:00:00 2001 From: Shengjiu Wang Date: Wed, 24 Mar 2021 17:58:48 +0800 Subject: [PATCH 309/587] ASoC: fsl_micfil: Don't use devm_regmap_init_mmio_clk When there is power domain bind with ipg_clk clock, The call flow: devm_regmap_init_mmio_clk - clk_prepare() - clk_pm_runtime_get() cause the power domain of clock always be enabled after regmap_init(). which impact the power consumption. So use devm_regmap_init_mmio instead of devm_regmap_init_mmio_clk,but explicitly enable clock when it is used. Signed-off-by: Shengjiu Wang Reviewed-by: Viorel Suman Link: https://lore.kernel.org/r/1616579928-22428-7-git-send-email-shengjiu.wang@nxp.com Signed-off-by: Mark Brown --- sound/soc/fsl/fsl_micfil.c | 25 ++++++++++++++++++++----- 1 file changed, 20 insertions(+), 5 deletions(-) diff --git a/sound/soc/fsl/fsl_micfil.c b/sound/soc/fsl/fsl_micfil.c index 2b9edd4bb94d..3cf789ed6cbe 100644 --- a/sound/soc/fsl/fsl_micfil.c +++ b/sound/soc/fsl/fsl_micfil.c @@ -31,6 +31,7 @@ struct fsl_micfil { struct platform_device *pdev; struct regmap *regmap; const struct fsl_micfil_soc_data *soc; + struct clk *busclk; struct clk *mclk; struct snd_dmaengine_dai_dma_data dma_params_rx; unsigned int dataline; @@ -660,16 +661,22 @@ static int fsl_micfil_probe(struct platform_device *pdev) return PTR_ERR(micfil->mclk); } + micfil->busclk = devm_clk_get(&pdev->dev, "ipg_clk"); + if (IS_ERR(micfil->busclk)) { + dev_err(&pdev->dev, "failed to get ipg clock: %ld\n", + PTR_ERR(micfil->busclk)); + return PTR_ERR(micfil->busclk); + } + /* init regmap */ res = platform_get_resource(pdev, IORESOURCE_MEM, 0); regs = devm_ioremap_resource(&pdev->dev, res); if (IS_ERR(regs)) return PTR_ERR(regs); - micfil->regmap = devm_regmap_init_mmio_clk(&pdev->dev, - "ipg_clk", - regs, - &fsl_micfil_regmap_config); + micfil->regmap = devm_regmap_init_mmio(&pdev->dev, + regs, + &fsl_micfil_regmap_config); if (IS_ERR(micfil->regmap)) { dev_err(&pdev->dev, "failed to init MICFIL regmap: %ld\n", PTR_ERR(micfil->regmap)); @@ -729,6 +736,7 @@ static int fsl_micfil_probe(struct platform_device *pdev) platform_set_drvdata(pdev, micfil); pm_runtime_enable(&pdev->dev); + regcache_cache_only(micfil->regmap, true); ret = devm_snd_soc_register_component(&pdev->dev, &fsl_micfil_component, &fsl_micfil_dai, 1); @@ -752,6 +760,7 @@ static int __maybe_unused fsl_micfil_runtime_suspend(struct device *dev) regcache_cache_only(micfil->regmap, true); clk_disable_unprepare(micfil->mclk); + clk_disable_unprepare(micfil->busclk); return 0; } @@ -761,10 +770,16 @@ static int __maybe_unused fsl_micfil_runtime_resume(struct device *dev) struct fsl_micfil *micfil = dev_get_drvdata(dev); int ret; - ret = clk_prepare_enable(micfil->mclk); + ret = clk_prepare_enable(micfil->busclk); if (ret < 0) return ret; + ret = clk_prepare_enable(micfil->mclk); + if (ret < 0) { + clk_disable_unprepare(micfil->busclk); + return ret; + } + regcache_cache_only(micfil->regmap, false); regcache_mark_dirty(micfil->regmap); regcache_sync(micfil->regmap); From bcda8cc4b868782c1a39d722d24f7d2598978389 Mon Sep 17 00:00:00 2001 From: Hans de Goede Date: Sun, 7 Mar 2021 16:18:01 +0100 Subject: [PATCH 310/587] ASoC: arizona-jack: Move jack-detect variables to struct arizona_priv Move all the jack-detect variables from struct arizona_extcon_info to struct arizona_priv. This is part of a patch series converting the arizona extcon driver into a helper library for letting the arizona codec-drivers directly report jack state through the standard sound/soc/soc-jack.c functions. Reviewed-by: Andy Shevchenko Acked-by: Charles Keepax Tested-by: Charles Keepax Signed-off-by: Hans de Goede Link: https://lore.kernel.org/r/20210307151807.35201-8-hdegoede@redhat.com Signed-off-by: Mark Brown --- sound/soc/codecs/arizona-jack.c | 97 ++++++++++----------------------- sound/soc/codecs/arizona.h | 36 ++++++++++++ 2 files changed, 65 insertions(+), 68 deletions(-) diff --git a/sound/soc/codecs/arizona-jack.c b/sound/soc/codecs/arizona-jack.c index 56d2ce05de50..5b40316d0d75 100644 --- a/sound/soc/codecs/arizona-jack.c +++ b/sound/soc/codecs/arizona-jack.c @@ -27,6 +27,8 @@ #include #include +#include "arizona.h" + #define ARIZONA_MAX_MICD_RANGE 8 #define ARIZONA_MICD_CLAMP_MODE_JDL 0x4 @@ -61,47 +63,6 @@ #define MICD_LVL_0_TO_8 (MICD_LVL_0_TO_7 | ARIZONA_MICD_LVL_8) -struct arizona_extcon_info { - struct device *dev; - struct arizona *arizona; - struct mutex lock; - struct regulator *micvdd; - struct input_dev *input; - - u16 last_jackdet; - - int micd_mode; - const struct arizona_micd_config *micd_modes; - int micd_num_modes; - - const struct arizona_micd_range *micd_ranges; - int num_micd_ranges; - - bool micd_reva; - bool micd_clamp; - - struct delayed_work hpdet_work; - struct delayed_work micd_detect_work; - struct delayed_work micd_timeout_work; - - bool hpdet_active; - bool hpdet_done; - bool hpdet_retried; - - int num_hpdet_res; - unsigned int hpdet_res[3]; - - bool mic; - bool detecting; - int jack_flips; - - int hpdet_ip_version; - - struct extcon_dev *edev; - - struct gpio_desc *micd_pol_gpio; -}; - static const struct arizona_micd_config micd_default_modes[] = { { ARIZONA_ACCDET_SRC, 1, 0 }, { 0, 2, 1 }, @@ -135,9 +96,9 @@ static const unsigned int arizona_cable[] = { EXTCON_NONE, }; -static void arizona_start_hpdet_acc_id(struct arizona_extcon_info *info); +static void arizona_start_hpdet_acc_id(struct arizona_priv *info); -static void arizona_extcon_hp_clamp(struct arizona_extcon_info *info, +static void arizona_extcon_hp_clamp(struct arizona_priv *info, bool clamp) { struct arizona *arizona = info->arizona; @@ -222,7 +183,7 @@ static void arizona_extcon_hp_clamp(struct arizona_extcon_info *info, snd_soc_dapm_mutex_unlock(arizona->dapm); } -static void arizona_extcon_set_mode(struct arizona_extcon_info *info, int mode) +static void arizona_extcon_set_mode(struct arizona_priv *info, int mode) { struct arizona *arizona = info->arizona; @@ -243,7 +204,7 @@ static void arizona_extcon_set_mode(struct arizona_extcon_info *info, int mode) dev_dbg(arizona->dev, "Set jack polarity to %d\n", mode); } -static const char *arizona_extcon_get_micbias(struct arizona_extcon_info *info) +static const char *arizona_extcon_get_micbias(struct arizona_priv *info) { switch (info->micd_modes[0].bias) { case 1: @@ -257,7 +218,7 @@ static const char *arizona_extcon_get_micbias(struct arizona_extcon_info *info) } } -static void arizona_extcon_pulse_micbias(struct arizona_extcon_info *info) +static void arizona_extcon_pulse_micbias(struct arizona_priv *info) { struct arizona *arizona = info->arizona; const char *widget = arizona_extcon_get_micbias(info); @@ -282,7 +243,7 @@ static void arizona_extcon_pulse_micbias(struct arizona_extcon_info *info) } } -static void arizona_start_mic(struct arizona_extcon_info *info) +static void arizona_start_mic(struct arizona_priv *info) { struct arizona *arizona = info->arizona; bool change; @@ -339,7 +300,7 @@ static void arizona_start_mic(struct arizona_extcon_info *info) } } -static void arizona_stop_mic(struct arizona_extcon_info *info) +static void arizona_stop_mic(struct arizona_priv *info) { struct arizona *arizona = info->arizona; const char *widget = arizona_extcon_get_micbias(info); @@ -407,7 +368,7 @@ static struct { { 1000, 10000 }, }; -static int arizona_hpdet_read(struct arizona_extcon_info *info) +static int arizona_hpdet_read(struct arizona_priv *info) { struct arizona *arizona = info->arizona; unsigned int val, range; @@ -527,7 +488,7 @@ static int arizona_hpdet_read(struct arizona_extcon_info *info) return val; } -static int arizona_hpdet_do_id(struct arizona_extcon_info *info, int *reading, +static int arizona_hpdet_do_id(struct arizona_priv *info, int *reading, bool *mic) { struct arizona *arizona = info->arizona; @@ -597,7 +558,7 @@ static int arizona_hpdet_do_id(struct arizona_extcon_info *info, int *reading, static irqreturn_t arizona_hpdet_irq(int irq, void *data) { - struct arizona_extcon_info *info = data; + struct arizona_priv *info = data; struct arizona *arizona = info->arizona; int id_gpio = arizona->pdata.hpdet_id_gpio; unsigned int report = EXTCON_JACK_HEADPHONE; @@ -684,7 +645,7 @@ out: return IRQ_HANDLED; } -static void arizona_identify_headphone(struct arizona_extcon_info *info) +static void arizona_identify_headphone(struct arizona_priv *info) { struct arizona *arizona = info->arizona; int ret; @@ -737,7 +698,7 @@ err: info->hpdet_active = false; } -static void arizona_start_hpdet_acc_id(struct arizona_extcon_info *info) +static void arizona_start_hpdet_acc_id(struct arizona_priv *info) { struct arizona *arizona = info->arizona; int hp_reading = 32; @@ -790,8 +751,8 @@ err: static void arizona_micd_timeout_work(struct work_struct *work) { - struct arizona_extcon_info *info = container_of(work, - struct arizona_extcon_info, + struct arizona_priv *info = container_of(work, + struct arizona_priv, micd_timeout_work.work); mutex_lock(&info->lock); @@ -805,7 +766,7 @@ static void arizona_micd_timeout_work(struct work_struct *work) mutex_unlock(&info->lock); } -static int arizona_micd_adc_read(struct arizona_extcon_info *info) +static int arizona_micd_adc_read(struct arizona_priv *info) { struct arizona *arizona = info->arizona; unsigned int val; @@ -842,7 +803,7 @@ static int arizona_micd_adc_read(struct arizona_extcon_info *info) return val; } -static int arizona_micd_read(struct arizona_extcon_info *info) +static int arizona_micd_read(struct arizona_priv *info) { struct arizona *arizona = info->arizona; unsigned int val = 0; @@ -875,7 +836,7 @@ static int arizona_micd_read(struct arizona_extcon_info *info) static int arizona_micdet_reading(void *priv) { - struct arizona_extcon_info *info = priv; + struct arizona_priv *info = priv; struct arizona *arizona = info->arizona; int ret, val; @@ -969,7 +930,7 @@ static int arizona_micdet_reading(void *priv) static int arizona_button_reading(void *priv) { - struct arizona_extcon_info *info = priv; + struct arizona_priv *info = priv; struct arizona *arizona = info->arizona; int val, key, lvl, i; @@ -1017,8 +978,8 @@ static int arizona_button_reading(void *priv) static void arizona_micd_detect(struct work_struct *work) { - struct arizona_extcon_info *info = container_of(work, - struct arizona_extcon_info, + struct arizona_priv *info = container_of(work, + struct arizona_priv, micd_detect_work.work); struct arizona *arizona = info->arizona; int ret; @@ -1051,7 +1012,7 @@ static void arizona_micd_detect(struct work_struct *work) static irqreturn_t arizona_micdet(int irq, void *data) { - struct arizona_extcon_info *info = data; + struct arizona_priv *info = data; struct arizona *arizona = info->arizona; int debounce = arizona->pdata.micd_detect_debounce; @@ -1075,8 +1036,8 @@ static irqreturn_t arizona_micdet(int irq, void *data) static void arizona_hpdet_work(struct work_struct *work) { - struct arizona_extcon_info *info = container_of(work, - struct arizona_extcon_info, + struct arizona_priv *info = container_of(work, + struct arizona_priv, hpdet_work.work); mutex_lock(&info->lock); @@ -1084,7 +1045,7 @@ static void arizona_hpdet_work(struct work_struct *work) mutex_unlock(&info->lock); } -static int arizona_hpdet_wait(struct arizona_extcon_info *info) +static int arizona_hpdet_wait(struct arizona_priv *info) { struct arizona *arizona = info->arizona; unsigned int val; @@ -1120,7 +1081,7 @@ static int arizona_hpdet_wait(struct arizona_extcon_info *info) static irqreturn_t arizona_jackdet(int irq, void *data) { - struct arizona_extcon_info *info = data; + struct arizona_priv *info = data; struct arizona *arizona = info->arizona; unsigned int val, present, mask; bool cancelled_hp, cancelled_mic; @@ -1380,7 +1341,7 @@ static int arizona_extcon_probe(struct platform_device *pdev) { struct arizona *arizona = dev_get_drvdata(pdev->dev.parent); struct arizona_pdata *pdata = &arizona->pdata; - struct arizona_extcon_info *info; + struct arizona_priv *info; unsigned int val; unsigned int clamp_mode; int jack_irq_fall, jack_irq_rise; @@ -1754,7 +1715,7 @@ err_gpio: static int arizona_extcon_remove(struct platform_device *pdev) { - struct arizona_extcon_info *info = platform_get_drvdata(pdev); + struct arizona_priv *info = platform_get_drvdata(pdev); struct arizona *arizona = info->arizona; int jack_irq_rise, jack_irq_fall; bool change; diff --git a/sound/soc/codecs/arizona.h b/sound/soc/codecs/arizona.h index b3abbe80f11d..fdd19dd9896d 100644 --- a/sound/soc/codecs/arizona.h +++ b/sound/soc/codecs/arizona.h @@ -91,6 +91,42 @@ struct arizona_priv { unsigned int dvfs_reqs; struct mutex dvfs_lock; bool dvfs_cached; + + /* Variables used by arizona-jack.c code */ + struct device *dev; + struct mutex lock; + struct delayed_work hpdet_work; + struct delayed_work micd_detect_work; + struct delayed_work micd_timeout_work; + struct regulator *micvdd; + struct input_dev *input; + struct extcon_dev *edev; + struct gpio_desc *micd_pol_gpio; + + u16 last_jackdet; + + int micd_mode; + const struct arizona_micd_config *micd_modes; + int micd_num_modes; + + const struct arizona_micd_range *micd_ranges; + int num_micd_ranges; + + bool micd_reva; + bool micd_clamp; + + bool hpdet_active; + bool hpdet_done; + bool hpdet_retried; + + bool mic; + bool detecting; + + int num_hpdet_res; + unsigned int hpdet_res[3]; + + int jack_flips; + int hpdet_ip_version; }; struct arizona_voice_trigger_info { From 688c8461a425623ca6f679e6ba8965719a98def5 Mon Sep 17 00:00:00 2001 From: Hans de Goede Date: Sun, 7 Mar 2021 16:18:02 +0100 Subject: [PATCH 311/587] ASoC: arizona-jack: Use arizona->dev for runtime-pm Drivers for MFD child-devices such as the arizona codec drivers and the arizona-extcon driver can choose to either make runtime_pm_get/_put calls on their own child-device, which will then be propagated to their parent; or they can make them directly on their MFD parent-device. The arizona-extcon code was using runtime_pm_get/_put calls on its own child-device where as the codec drivers are using runtime_pm_get/_put calls on their parent. The arizona-extcon MFD cell/child-device has been removed and this commit is part of refactoring the arizona-extcon code into a library to be used directly from the codec drivers. Specifically this commit moves the code over to make runtime_pm_get/_put calls on the parent device (on arizona->dev) bringing the code inline with how the codec drivers do this. Note this also removes the pm_runtime_enable/_disable calls as pm_runtime support has already been enabled on the parent-device by the arizona MFD driver. This is part of a patch series converting the arizona extcon driver into a helper library for letting the arizona codec-drivers directly report jack state through the standard sound/soc/soc-jack.c functions. Reviewed-by: Andy Shevchenko Acked-by: Charles Keepax Tested-by: Charles Keepax Signed-off-by: Hans de Goede Link: https://lore.kernel.org/r/20210307151807.35201-9-hdegoede@redhat.com Signed-off-by: Mark Brown --- sound/soc/codecs/arizona-jack.c | 42 ++++++++++++++------------------- sound/soc/codecs/arizona.h | 1 - 2 files changed, 18 insertions(+), 25 deletions(-) diff --git a/sound/soc/codecs/arizona-jack.c b/sound/soc/codecs/arizona-jack.c index 5b40316d0d75..a6e8071f84ab 100644 --- a/sound/soc/codecs/arizona-jack.c +++ b/sound/soc/codecs/arizona-jack.c @@ -251,7 +251,7 @@ static void arizona_start_mic(struct arizona_priv *info) unsigned int mode; /* Microphone detection can't use idle mode */ - pm_runtime_get_sync(info->dev); + pm_runtime_get_sync(arizona->dev); if (info->detecting) { ret = regulator_allow_bypass(info->micvdd, false); @@ -296,7 +296,7 @@ static void arizona_start_mic(struct arizona_priv *info) dev_err(arizona->dev, "Failed to enable micd: %d\n", ret); } else if (!change) { regulator_disable(info->micvdd); - pm_runtime_put_autosuspend(info->dev); + pm_runtime_put_autosuspend(arizona->dev); } } @@ -341,8 +341,8 @@ static void arizona_stop_mic(struct arizona_priv *info) if (change) { regulator_disable(info->micvdd); - pm_runtime_mark_last_busy(info->dev); - pm_runtime_put_autosuspend(info->dev); + pm_runtime_mark_last_busy(arizona->dev); + pm_runtime_put_autosuspend(arizona->dev); } } @@ -534,7 +534,7 @@ static int arizona_hpdet_do_id(struct arizona_priv *info, int *reading, info->num_hpdet_res = 0; info->hpdet_retried = true; arizona_start_hpdet_acc_id(info); - pm_runtime_put(info->dev); + pm_runtime_put(arizona->dev); return -EAGAIN; } @@ -631,7 +631,7 @@ done: arizona_start_mic(info); if (info->hpdet_active) { - pm_runtime_put_autosuspend(info->dev); + pm_runtime_put_autosuspend(arizona->dev); info->hpdet_active = false; } @@ -656,7 +656,7 @@ static void arizona_identify_headphone(struct arizona_priv *info) dev_dbg(arizona->dev, "Starting HPDET\n"); /* Make sure we keep the device enabled during the measurement */ - pm_runtime_get_sync(info->dev); + pm_runtime_get_sync(arizona->dev); info->hpdet_active = true; @@ -685,7 +685,7 @@ static void arizona_identify_headphone(struct arizona_priv *info) err: arizona_extcon_hp_clamp(info, false); - pm_runtime_put_autosuspend(info->dev); + pm_runtime_put_autosuspend(arizona->dev); /* Just report headphone */ ret = extcon_set_state_sync(info->edev, EXTCON_JACK_HEADPHONE, true); @@ -708,7 +708,7 @@ static void arizona_start_hpdet_acc_id(struct arizona_priv *info) dev_dbg(arizona->dev, "Starting identification via HPDET\n"); /* Make sure we keep the device enabled during the measurement */ - pm_runtime_get_sync(info->dev); + pm_runtime_get_sync(arizona->dev); info->hpdet_active = true; @@ -1006,7 +1006,7 @@ static void arizona_micd_detect(struct work_struct *work) else arizona_button_reading(info); - pm_runtime_mark_last_busy(info->dev); + pm_runtime_mark_last_busy(arizona->dev); mutex_unlock(&info->lock); } @@ -1090,7 +1090,7 @@ static irqreturn_t arizona_jackdet(int irq, void *data) cancelled_hp = cancel_delayed_work_sync(&info->hpdet_work); cancelled_mic = cancel_delayed_work_sync(&info->micd_timeout_work); - pm_runtime_get_sync(info->dev); + pm_runtime_get_sync(arizona->dev); mutex_lock(&info->lock); @@ -1110,7 +1110,7 @@ static irqreturn_t arizona_jackdet(int irq, void *data) dev_err(arizona->dev, "Failed to read jackdet status: %d\n", ret); mutex_unlock(&info->lock); - pm_runtime_put_autosuspend(info->dev); + pm_runtime_put_autosuspend(arizona->dev); return IRQ_NONE; } @@ -1210,8 +1210,8 @@ out: mutex_unlock(&info->lock); - pm_runtime_mark_last_busy(info->dev); - pm_runtime_put_autosuspend(info->dev); + pm_runtime_mark_last_busy(arizona->dev); + pm_runtime_put_autosuspend(arizona->dev); return IRQ_HANDLED; } @@ -1366,7 +1366,6 @@ static int arizona_extcon_probe(struct platform_device *pdev) mutex_init(&info->lock); info->arizona = arizona; - info->dev = &pdev->dev; info->last_jackdet = ~(ARIZONA_MICD_CLAMP_STS | ARIZONA_JD1_STS); INIT_DELAYED_WORK(&info->hpdet_work, arizona_hpdet_work); INIT_DELAYED_WORK(&info->micd_detect_work, arizona_micd_detect); @@ -1617,9 +1616,7 @@ static int arizona_extcon_probe(struct platform_device *pdev) arizona_extcon_set_mode(info, 0); - pm_runtime_enable(&pdev->dev); - pm_runtime_idle(&pdev->dev); - pm_runtime_get_sync(&pdev->dev); + pm_runtime_get_sync(arizona->dev); if (info->micd_clamp) { jack_irq_rise = ARIZONA_IRQ_MICD_CLAMP_RISE; @@ -1689,7 +1686,7 @@ static int arizona_extcon_probe(struct platform_device *pdev) goto err_hpdet; } - pm_runtime_put(&pdev->dev); + pm_runtime_put(arizona->dev); return 0; @@ -1706,8 +1703,7 @@ err_rise_wake: err_rise: arizona_free_irq(arizona, jack_irq_rise, info); err_pm: - pm_runtime_put(&pdev->dev); - pm_runtime_disable(&pdev->dev); + pm_runtime_put(arizona->dev); err_gpio: gpiod_put(info->micd_pol_gpio); return ret; @@ -1747,7 +1743,7 @@ static int arizona_extcon_remove(struct platform_device *pdev) ret); } else if (change) { regulator_disable(info->micvdd); - pm_runtime_put(info->dev); + pm_runtime_put(arizona->dev); } regmap_update_bits(arizona->regmap, @@ -1759,8 +1755,6 @@ static int arizona_extcon_remove(struct platform_device *pdev) gpiod_put(info->micd_pol_gpio); - pm_runtime_disable(&pdev->dev); - return 0; } diff --git a/sound/soc/codecs/arizona.h b/sound/soc/codecs/arizona.h index fdd19dd9896d..afc34e13d33c 100644 --- a/sound/soc/codecs/arizona.h +++ b/sound/soc/codecs/arizona.h @@ -93,7 +93,6 @@ struct arizona_priv { bool dvfs_cached; /* Variables used by arizona-jack.c code */ - struct device *dev; struct mutex lock; struct delayed_work hpdet_work; struct delayed_work micd_detect_work; From ffcc84b9e814c8654e15e08816d0078d521a2724 Mon Sep 17 00:00:00 2001 From: Hans de Goede Date: Sun, 7 Mar 2021 16:18:03 +0100 Subject: [PATCH 312/587] ASoC: arizona-jack: convert into a helper library for codec drivers Convert the arizona extcon driver into a helper library for direct use from the arizona codec-drivers, rather then being bound to a separate MFD cell. Note the probe (and remove) sequence is split into 2 parts: 1. The arizona_jack_codec_dev_probe() function inits a bunch of jack-detect specific variables in struct arizona_priv and tries to get a number of resources where getting them may fail with -EPROBE_DEFER. 2. Then once the machine driver has create a snd_sock_jack through snd_soc_card_jack_new() it calls snd_soc_component_set_jack() on the codec component, which will call the new arizona_jack_set_jack(), which sets up jack-detection and requests the IRQs. This split is necessary, because the IRQ handlers need access to the arizona->dapm pointer and the snd_sock_jack which are not available when the codec-driver's probe function runs. Note this requires that machine-drivers for codecs which are converted to use the new helper functions from arizona-jack.c are modified to create a snd_soc_jack through snd_soc_card_jack_new() and register this jack with the codec through snd_soc_component_set_jack(). Reviewed-by: Andy Shevchenko Acked-by: Charles Keepax Tested-by: Charles Keepax Signed-off-by: Hans de Goede Link: https://lore.kernel.org/r/20210307151807.35201-10-hdegoede@redhat.com Signed-off-by: Mark Brown --- sound/soc/codecs/Makefile | 2 +- sound/soc/codecs/arizona-jack.c | 125 +++++++++++++++----------------- sound/soc/codecs/arizona.h | 6 ++ 3 files changed, 65 insertions(+), 68 deletions(-) diff --git a/sound/soc/codecs/Makefile b/sound/soc/codecs/Makefile index edff5c5b92d3..a710dfea7876 100644 --- a/sound/soc/codecs/Makefile +++ b/sound/soc/codecs/Makefile @@ -43,7 +43,7 @@ snd-soc-ak4642-objs := ak4642.o snd-soc-ak4671-objs := ak4671.o snd-soc-ak5386-objs := ak5386.o snd-soc-ak5558-objs := ak5558.o -snd-soc-arizona-objs := arizona.o +snd-soc-arizona-objs := arizona.o arizona-jack.o snd-soc-bd28623-objs := bd28623.o snd-soc-bt-sco-objs := bt-sco.o snd-soc-cpcap-objs := cpcap.o diff --git a/sound/soc/codecs/arizona-jack.c b/sound/soc/codecs/arizona-jack.c index a6e8071f84ab..e121490eb379 100644 --- a/sound/soc/codecs/arizona-jack.c +++ b/sound/soc/codecs/arizona-jack.c @@ -7,14 +7,12 @@ #include #include -#include #include #include #include #include #include #include -#include #include #include #include @@ -1337,27 +1335,16 @@ static int arizona_extcon_device_get_pdata(struct device *dev, return 0; } -static int arizona_extcon_probe(struct platform_device *pdev) +int arizona_jack_codec_dev_probe(struct arizona_priv *info, struct device *dev) { - struct arizona *arizona = dev_get_drvdata(pdev->dev.parent); + struct arizona *arizona = info->arizona; struct arizona_pdata *pdata = &arizona->pdata; - struct arizona_priv *info; - unsigned int val; - unsigned int clamp_mode; - int jack_irq_fall, jack_irq_rise; - int ret, mode, i, j; - - if (!arizona->dapm || !arizona->dapm->card) - return -EPROBE_DEFER; - - info = devm_kzalloc(&pdev->dev, sizeof(*info), GFP_KERNEL); - if (!info) - return -ENOMEM; + int ret, mode; if (!dev_get_platdata(arizona->dev)) - arizona_extcon_device_get_pdata(&pdev->dev, arizona); + arizona_extcon_device_get_pdata(dev, arizona); - info->micvdd = devm_regulator_get(&pdev->dev, "MICVDD"); + info->micvdd = devm_regulator_get(dev, "MICVDD"); if (IS_ERR(info->micvdd)) { ret = PTR_ERR(info->micvdd); dev_err(arizona->dev, "Failed to get MICVDD: %d\n", ret); @@ -1365,12 +1352,10 @@ static int arizona_extcon_probe(struct platform_device *pdev) } mutex_init(&info->lock); - info->arizona = arizona; info->last_jackdet = ~(ARIZONA_MICD_CLAMP_STS | ARIZONA_JD1_STS); INIT_DELAYED_WORK(&info->hpdet_work, arizona_hpdet_work); INIT_DELAYED_WORK(&info->micd_detect_work, arizona_micd_detect); INIT_DELAYED_WORK(&info->micd_timeout_work, arizona_micd_timeout_work); - platform_set_drvdata(pdev, info); switch (arizona->type) { case WM5102: @@ -1404,20 +1389,20 @@ static int arizona_extcon_probe(struct platform_device *pdev) break; } - info->edev = devm_extcon_dev_allocate(&pdev->dev, arizona_cable); + info->edev = devm_extcon_dev_allocate(dev, arizona_cable); if (IS_ERR(info->edev)) { - dev_err(&pdev->dev, "failed to allocate extcon device\n"); + dev_err(arizona->dev, "failed to allocate extcon device\n"); return -ENOMEM; } - ret = devm_extcon_dev_register(&pdev->dev, info->edev); + ret = devm_extcon_dev_register(dev, info->edev); if (ret < 0) { dev_err(arizona->dev, "extcon_dev_register() failed: %d\n", ret); return ret; } - info->input = devm_input_allocate_device(&pdev->dev); + info->input = devm_input_allocate_device(dev); if (!info->input) { dev_err(arizona->dev, "Can't allocate input dev\n"); ret = -ENOMEM; @@ -1448,7 +1433,7 @@ static int arizona_extcon_probe(struct platform_device *pdev) else mode = GPIOF_OUT_INIT_LOW; - ret = devm_gpio_request_one(&pdev->dev, pdata->micd_pol_gpio, + ret = devm_gpio_request_one(dev, pdata->micd_pol_gpio, mode, "MICD polarity"); if (ret != 0) { dev_err(arizona->dev, "Failed to request GPIO%d: %d\n", @@ -1481,17 +1466,38 @@ static int arizona_extcon_probe(struct platform_device *pdev) } if (arizona->pdata.hpdet_id_gpio > 0) { - ret = devm_gpio_request_one(&pdev->dev, - arizona->pdata.hpdet_id_gpio, + ret = devm_gpio_request_one(dev, arizona->pdata.hpdet_id_gpio, GPIOF_OUT_INIT_LOW, "HPDET"); if (ret != 0) { dev_err(arizona->dev, "Failed to request GPIO%d: %d\n", arizona->pdata.hpdet_id_gpio, ret); - goto err_gpio; + gpiod_put(info->micd_pol_gpio); + return ret; } } + return 0; +} +EXPORT_SYMBOL_GPL(arizona_jack_codec_dev_probe); + +int arizona_jack_codec_dev_remove(struct arizona_priv *info) +{ + gpiod_put(info->micd_pol_gpio); + return 0; +} +EXPORT_SYMBOL_GPL(arizona_jack_codec_dev_remove); + +static int arizona_jack_enable_jack_detect(struct arizona_priv *info, + struct snd_soc_jack *jack) +{ + struct arizona *arizona = info->arizona; + struct arizona_pdata *pdata = &arizona->pdata; + unsigned int val; + unsigned int clamp_mode; + int jack_irq_fall, jack_irq_rise; + int ret, i, j; + if (arizona->pdata.micd_bias_start_time) regmap_update_bits(arizona->regmap, ARIZONA_MIC_DETECT_1, ARIZONA_MICD_BIAS_STARTTIME_MASK, @@ -1532,16 +1538,15 @@ static int arizona_extcon_probe(struct platform_device *pdev) if (arizona->pdata.num_micd_ranges > ARIZONA_MAX_MICD_RANGE) { dev_err(arizona->dev, "Too many MICD ranges: %d\n", arizona->pdata.num_micd_ranges); + return -EINVAL; } if (info->num_micd_ranges > 1) { for (i = 1; i < info->num_micd_ranges; i++) { if (info->micd_ranges[i - 1].max > info->micd_ranges[i].max) { - dev_err(arizona->dev, - "MICD ranges must be sorted\n"); - ret = -EINVAL; - goto err_gpio; + dev_err(arizona->dev, "MICD ranges must be sorted\n"); + return -EINVAL; } } } @@ -1559,8 +1564,7 @@ static int arizona_extcon_probe(struct platform_device *pdev) if (j == ARIZONA_NUM_MICD_BUTTON_LEVELS) { dev_err(arizona->dev, "Unsupported MICD level %d\n", info->micd_ranges[i].max); - ret = -EINVAL; - goto err_gpio; + return -EINVAL; } dev_dbg(arizona->dev, "%d ohms for MICD threshold %d\n", @@ -1629,43 +1633,40 @@ static int arizona_extcon_probe(struct platform_device *pdev) ret = arizona_request_irq(arizona, jack_irq_rise, "JACKDET rise", arizona_jackdet, info); if (ret != 0) { - dev_err(&pdev->dev, "Failed to get JACKDET rise IRQ: %d\n", - ret); + dev_err(arizona->dev, "Failed to get JACKDET rise IRQ: %d\n", ret); goto err_pm; } ret = arizona_set_irq_wake(arizona, jack_irq_rise, 1); if (ret != 0) { - dev_err(&pdev->dev, "Failed to set JD rise IRQ wake: %d\n", - ret); + dev_err(arizona->dev, "Failed to set JD rise IRQ wake: %d\n", ret); goto err_rise; } ret = arizona_request_irq(arizona, jack_irq_fall, "JACKDET fall", arizona_jackdet, info); if (ret != 0) { - dev_err(&pdev->dev, "Failed to get JD fall IRQ: %d\n", ret); + dev_err(arizona->dev, "Failed to get JD fall IRQ: %d\n", ret); goto err_rise_wake; } ret = arizona_set_irq_wake(arizona, jack_irq_fall, 1); if (ret != 0) { - dev_err(&pdev->dev, "Failed to set JD fall IRQ wake: %d\n", - ret); + dev_err(arizona->dev, "Failed to set JD fall IRQ wake: %d\n", ret); goto err_fall; } ret = arizona_request_irq(arizona, ARIZONA_IRQ_MICDET, "MICDET", arizona_micdet, info); if (ret != 0) { - dev_err(&pdev->dev, "Failed to get MICDET IRQ: %d\n", ret); + dev_err(arizona->dev, "Failed to get MICDET IRQ: %d\n", ret); goto err_fall_wake; } ret = arizona_request_irq(arizona, ARIZONA_IRQ_HPDET, "HPDET", arizona_hpdet_irq, info); if (ret != 0) { - dev_err(&pdev->dev, "Failed to get HPDET IRQ: %d\n", ret); + dev_err(arizona->dev, "Failed to get HPDET IRQ: %d\n", ret); goto err_micdet; } @@ -1677,12 +1678,11 @@ static int arizona_extcon_probe(struct platform_device *pdev) ret = regulator_allow_bypass(info->micvdd, true); if (ret != 0) - dev_warn(arizona->dev, "Failed to set MICVDD to bypass: %d\n", - ret); + dev_warn(arizona->dev, "Failed to set MICVDD to bypass: %d\n", ret); ret = input_register_device(info->input); if (ret) { - dev_err(&pdev->dev, "Can't register input device: %d\n", ret); + dev_err(arizona->dev, "Can't register input device: %d\n", ret); goto err_hpdet; } @@ -1704,14 +1704,11 @@ err_rise: arizona_free_irq(arizona, jack_irq_rise, info); err_pm: pm_runtime_put(arizona->dev); -err_gpio: - gpiod_put(info->micd_pol_gpio); return ret; } -static int arizona_extcon_remove(struct platform_device *pdev) +static int arizona_jack_disable_jack_detect(struct arizona_priv *info) { - struct arizona_priv *info = platform_get_drvdata(pdev); struct arizona *arizona = info->arizona; int jack_irq_rise, jack_irq_fall; bool change; @@ -1739,8 +1736,7 @@ static int arizona_extcon_remove(struct platform_device *pdev) ARIZONA_MICD_ENA, 0, &change); if (ret < 0) { - dev_err(&pdev->dev, "Failed to disable micd on remove: %d\n", - ret); + dev_err(arizona->dev, "Failed to disable micd on remove: %d\n", ret); } else if (change) { regulator_disable(info->micvdd); pm_runtime_put(arizona->dev); @@ -1753,22 +1749,17 @@ static int arizona_extcon_remove(struct platform_device *pdev) ARIZONA_JD1_ENA, 0); arizona_clk32k_disable(arizona); - gpiod_put(info->micd_pol_gpio); - return 0; } -static struct platform_driver arizona_extcon_driver = { - .driver = { - .name = "arizona-extcon", - }, - .probe = arizona_extcon_probe, - .remove = arizona_extcon_remove, -}; +int arizona_jack_set_jack(struct snd_soc_component *component, + struct snd_soc_jack *jack, void *data) +{ + struct arizona_priv *info = snd_soc_component_get_drvdata(component); -module_platform_driver(arizona_extcon_driver); - -MODULE_DESCRIPTION("Arizona Extcon driver"); -MODULE_AUTHOR("Mark Brown "); -MODULE_LICENSE("GPL"); -MODULE_ALIAS("platform:extcon-arizona"); + if (jack) + return arizona_jack_enable_jack_detect(info, jack); + else + return arizona_jack_disable_jack_detect(info); +} +EXPORT_SYMBOL_GPL(arizona_jack_set_jack); diff --git a/sound/soc/codecs/arizona.h b/sound/soc/codecs/arizona.h index afc34e13d33c..f02012438e15 100644 --- a/sound/soc/codecs/arizona.h +++ b/sound/soc/codecs/arizona.h @@ -386,4 +386,10 @@ static inline int arizona_unregister_notifier(struct snd_soc_component *componen int arizona_of_get_audio_pdata(struct arizona *arizona); +int arizona_jack_codec_dev_probe(struct arizona_priv *info, struct device *dev); +int arizona_jack_codec_dev_remove(struct arizona_priv *info); + +int arizona_jack_set_jack(struct snd_soc_component *component, + struct snd_soc_jack *jack, void *data); + #endif From 236b7285e95af5cb5a8b63283e573f433fb9b305 Mon Sep 17 00:00:00 2001 From: Hans de Goede Date: Sun, 7 Mar 2021 16:18:04 +0100 Subject: [PATCH 313/587] ASoC: arizona-jack: Use snd_soc_jack to report jack events Use the snd_soc_jack code to report jack events, instead of using extcon for reporting the cable-type + an input_dev for reporting the button presses. The snd_soc_jack code will report the cable-type through both input_dev events and through ALSA controls and the button-presses through input_dev events. Note that this means that when the codec drivers are moved over to use the new arizona-jack.c library code instead of having a separate MFD extcon cell with the extcon-arizona.c driver, we will no longer report extcon events to userspace for cable-type changes. This should not be a problem since "standard" Linux distro userspace does not (and has never) used the extcon class interface for this. Android does have support for the extcon class interface, but that was introduced in the same release as support for input_dev cable-type events, so this should not be a problem for Android either. Note this also reduces ARIZONA_MAX_MICD_RANGE from 8 to 6, this is ok to do since this info is always provided through pdata (or defaults) and cannot be overridden from devicetree. All in-kernel users of the pdata (and the fallback defaults) define 6 or less buttons/ranges. Reviewed-by: Andy Shevchenko Acked-by: Charles Keepax Tested-by: Charles Keepax Signed-off-by: Hans de Goede Link: https://lore.kernel.org/r/20210307151807.35201-11-hdegoede@redhat.com Signed-off-by: Mark Brown --- sound/soc/codecs/arizona-jack.c | 149 +++++++++----------------------- sound/soc/codecs/arizona.h | 7 +- 2 files changed, 47 insertions(+), 109 deletions(-) diff --git a/sound/soc/codecs/arizona-jack.c b/sound/soc/codecs/arizona-jack.c index e121490eb379..268d2a44d891 100644 --- a/sound/soc/codecs/arizona-jack.c +++ b/sound/soc/codecs/arizona-jack.c @@ -16,8 +16,8 @@ #include #include #include -#include +#include #include #include @@ -29,6 +29,12 @@ #define ARIZONA_MAX_MICD_RANGE 8 +/* + * The hardware supports 8 ranges / buttons, but the snd-jack interface + * only supports 6 buttons (button 0-5). + */ +#define ARIZONA_MAX_MICD_BUTTONS 6 + #define ARIZONA_MICD_CLAMP_MODE_JDL 0x4 #define ARIZONA_MICD_CLAMP_MODE_JDH 0x5 #define ARIZONA_MICD_CLAMP_MODE_JDL_GP5H 0x9 @@ -86,14 +92,6 @@ static const int arizona_micd_levels[] = { 1257, 30000, }; -static const unsigned int arizona_cable[] = { - EXTCON_MECHANICAL, - EXTCON_JACK_MICROPHONE, - EXTCON_JACK_HEADPHONE, - EXTCON_JACK_LINE_OUT, - EXTCON_NONE, -}; - static void arizona_start_hpdet_acc_id(struct arizona_priv *info); static void arizona_extcon_hp_clamp(struct arizona_priv *info, @@ -559,8 +557,7 @@ static irqreturn_t arizona_hpdet_irq(int irq, void *data) struct arizona_priv *info = data; struct arizona *arizona = info->arizona; int id_gpio = arizona->pdata.hpdet_id_gpio; - unsigned int report = EXTCON_JACK_HEADPHONE; - int ret, reading, state; + int ret, reading, state, report; bool mic = false; mutex_lock(&info->lock); @@ -573,11 +570,8 @@ static irqreturn_t arizona_hpdet_irq(int irq, void *data) } /* If the cable was removed while measuring ignore the result */ - state = extcon_get_state(info->edev, EXTCON_MECHANICAL); - if (state < 0) { - dev_err(arizona->dev, "Failed to check cable state: %d\n", state); - goto out; - } else if (!state) { + state = info->jack->status & SND_JACK_MECHANICAL; + if (!state) { dev_dbg(arizona->dev, "Ignoring HPDET for removed cable\n"); goto done; } @@ -603,14 +597,11 @@ static irqreturn_t arizona_hpdet_irq(int irq, void *data) /* Report high impedence cables as line outputs */ if (reading >= 5000) - report = EXTCON_JACK_LINE_OUT; + report = SND_JACK_LINEOUT; else - report = EXTCON_JACK_HEADPHONE; + report = SND_JACK_HEADPHONE; - ret = extcon_set_state_sync(info->edev, report, true); - if (ret != 0) - dev_err(arizona->dev, "Failed to report HP/line: %d\n", - ret); + snd_soc_jack_report(info->jack, report, SND_JACK_LINEOUT | SND_JACK_HEADPHONE); done: /* Reset back to starting range */ @@ -686,9 +677,8 @@ err: pm_runtime_put_autosuspend(arizona->dev); /* Just report headphone */ - ret = extcon_set_state_sync(info->edev, EXTCON_JACK_HEADPHONE, true); - if (ret != 0) - dev_err(arizona->dev, "Failed to report headphone: %d\n", ret); + snd_soc_jack_report(info->jack, SND_JACK_HEADPHONE, + SND_JACK_LINEOUT | SND_JACK_HEADPHONE); if (info->mic) arizona_start_mic(info); @@ -740,9 +730,8 @@ static void arizona_start_hpdet_acc_id(struct arizona_priv *info) err: /* Just report headphone */ - ret = extcon_set_state_sync(info->edev, EXTCON_JACK_HEADPHONE, true); - if (ret != 0) - dev_err(arizona->dev, "Failed to report headphone: %d\n", ret); + snd_soc_jack_report(info->jack, SND_JACK_HEADPHONE, + SND_JACK_LINEOUT | SND_JACK_HEADPHONE); info->hpdet_active = false; } @@ -863,11 +852,7 @@ static int arizona_micdet_reading(void *priv) arizona_identify_headphone(info); - ret = extcon_set_state_sync(info->edev, - EXTCON_JACK_MICROPHONE, true); - if (ret != 0) - dev_err(arizona->dev, "Headset report failed: %d\n", - ret); + snd_soc_jack_report(info->jack, SND_JACK_MICROPHONE, SND_JACK_MICROPHONE); /* Don't need to regulate for button detection */ ret = regulator_allow_bypass(info->micvdd, true); @@ -930,7 +915,7 @@ static int arizona_button_reading(void *priv) { struct arizona_priv *info = priv; struct arizona *arizona = info->arizona; - int val, key, lvl, i; + int val, key, lvl; val = arizona_micd_read(info); if (val < 0) @@ -947,14 +932,11 @@ static int arizona_button_reading(void *priv) lvl = val & ARIZONA_MICD_LVL_MASK; lvl >>= ARIZONA_MICD_LVL_SHIFT; - for (i = 0; i < info->num_micd_ranges; i++) - input_report_key(info->input, - info->micd_ranges[i].key, 0); - if (lvl && ffs(lvl) - 1 < info->num_micd_ranges) { - key = info->micd_ranges[ffs(lvl) - 1].key; - input_report_key(info->input, key, 1); - input_sync(info->input); + key = ffs(lvl) - 1; + snd_soc_jack_report(info->jack, + SND_JACK_BTN_0 >> key, + info->micd_button_mask); } else { dev_err(arizona->dev, "Button out of range\n"); } @@ -964,10 +946,7 @@ static int arizona_button_reading(void *priv) } } else { dev_dbg(arizona->dev, "Mic button released\n"); - for (i = 0; i < info->num_micd_ranges; i++) - input_report_key(info->input, - info->micd_ranges[i].key, 0); - input_sync(info->input); + snd_soc_jack_report(info->jack, 0, info->micd_button_mask); arizona_extcon_pulse_micbias(info); } @@ -980,20 +959,13 @@ static void arizona_micd_detect(struct work_struct *work) struct arizona_priv, micd_detect_work.work); struct arizona *arizona = info->arizona; - int ret; cancel_delayed_work_sync(&info->micd_timeout_work); mutex_lock(&info->lock); /* If the cable was removed while measuring ignore the result */ - ret = extcon_get_state(info->edev, EXTCON_MECHANICAL); - if (ret < 0) { - dev_err(arizona->dev, "Failed to check cable state: %d\n", - ret); - mutex_unlock(&info->lock); - return; - } else if (!ret) { + if (!(info->jack->status & SND_JACK_MECHANICAL)) { dev_dbg(arizona->dev, "Ignoring MICDET for removed cable\n"); mutex_unlock(&info->lock); return; @@ -1134,12 +1106,7 @@ static irqreturn_t arizona_jackdet(int irq, void *data) if (info->last_jackdet == present) { dev_dbg(arizona->dev, "Detected jack\n"); - ret = extcon_set_state_sync(info->edev, - EXTCON_MECHANICAL, true); - - if (ret != 0) - dev_err(arizona->dev, "Mechanical report failed: %d\n", - ret); + snd_soc_jack_report(info->jack, SND_JACK_MECHANICAL, SND_JACK_MECHANICAL); info->detecting = true; info->mic = false; @@ -1170,18 +1137,7 @@ static irqreturn_t arizona_jackdet(int irq, void *data) info->hpdet_done = false; info->hpdet_retried = false; - for (i = 0; i < info->num_micd_ranges; i++) - input_report_key(info->input, - info->micd_ranges[i].key, 0); - input_sync(info->input); - - for (i = 0; i < ARRAY_SIZE(arizona_cable) - 1; i++) { - ret = extcon_set_state_sync(info->edev, - arizona_cable[i], false); - if (ret != 0) - dev_err(arizona->dev, - "Removal report failed: %d\n", ret); - } + snd_soc_jack_report(info->jack, 0, ARIZONA_JACK_MASK | info->micd_button_mask); /* * If the jack was removed during a headphone detection we @@ -1389,29 +1345,6 @@ int arizona_jack_codec_dev_probe(struct arizona_priv *info, struct device *dev) break; } - info->edev = devm_extcon_dev_allocate(dev, arizona_cable); - if (IS_ERR(info->edev)) { - dev_err(arizona->dev, "failed to allocate extcon device\n"); - return -ENOMEM; - } - - ret = devm_extcon_dev_register(dev, info->edev); - if (ret < 0) { - dev_err(arizona->dev, "extcon_dev_register() failed: %d\n", - ret); - return ret; - } - - info->input = devm_input_allocate_device(dev); - if (!info->input) { - dev_err(arizona->dev, "Can't allocate input dev\n"); - ret = -ENOMEM; - return ret; - } - - info->input->name = "Headset"; - info->input->phys = "arizona/extcon"; - if (!pdata->micd_timeout) pdata->micd_timeout = DEFAULT_MICD_TIMEOUT; @@ -1535,9 +1468,9 @@ static int arizona_jack_enable_jack_detect(struct arizona_priv *info, info->num_micd_ranges = ARRAY_SIZE(micd_default_ranges); } - if (arizona->pdata.num_micd_ranges > ARIZONA_MAX_MICD_RANGE) { - dev_err(arizona->dev, "Too many MICD ranges: %d\n", - arizona->pdata.num_micd_ranges); + if (arizona->pdata.num_micd_ranges > ARIZONA_MAX_MICD_BUTTONS) { + dev_err(arizona->dev, "Too many MICD ranges: %d > %d\n", + arizona->pdata.num_micd_ranges, ARIZONA_MAX_MICD_BUTTONS); return -EINVAL; } @@ -1571,8 +1504,11 @@ static int arizona_jack_enable_jack_detect(struct arizona_priv *info, arizona_micd_levels[j], i); arizona_micd_set_level(arizona, i, j); - input_set_capability(info->input, EV_KEY, - info->micd_ranges[i].key); + + /* SND_JACK_BTN_# masks start with the most significant bit */ + info->micd_button_mask |= SND_JACK_BTN_0 >> i; + snd_jack_set_key(jack->jack, SND_JACK_BTN_0 >> i, + info->micd_ranges[i].key); /* Enable reporting of that range */ regmap_update_bits(arizona->regmap, ARIZONA_MIC_DETECT_2, @@ -1620,6 +1556,8 @@ static int arizona_jack_enable_jack_detect(struct arizona_priv *info, arizona_extcon_set_mode(info, 0); + info->jack = jack; + pm_runtime_get_sync(arizona->dev); if (info->micd_clamp) { @@ -1680,18 +1618,10 @@ static int arizona_jack_enable_jack_detect(struct arizona_priv *info, if (ret != 0) dev_warn(arizona->dev, "Failed to set MICVDD to bypass: %d\n", ret); - ret = input_register_device(info->input); - if (ret) { - dev_err(arizona->dev, "Can't register input device: %d\n", ret); - goto err_hpdet; - } - pm_runtime_put(arizona->dev); return 0; -err_hpdet: - arizona_free_irq(arizona, ARIZONA_IRQ_HPDET, info); err_micdet: arizona_free_irq(arizona, ARIZONA_IRQ_MICDET, info); err_fall_wake: @@ -1704,6 +1634,7 @@ err_rise: arizona_free_irq(arizona, jack_irq_rise, info); err_pm: pm_runtime_put(arizona->dev); + info->jack = NULL; return ret; } @@ -1714,6 +1645,9 @@ static int arizona_jack_disable_jack_detect(struct arizona_priv *info) bool change; int ret; + if (!info->jack) + return 0; + if (info->micd_clamp) { jack_irq_rise = ARIZONA_IRQ_MICD_CLAMP_RISE; jack_irq_fall = ARIZONA_IRQ_MICD_CLAMP_FALL; @@ -1748,6 +1682,7 @@ static int arizona_jack_disable_jack_detect(struct arizona_priv *info) regmap_update_bits(arizona->regmap, ARIZONA_JACK_DETECT_ANALOGUE, ARIZONA_JD1_ENA, 0); arizona_clk32k_disable(arizona); + info->jack = NULL; return 0; } diff --git a/sound/soc/codecs/arizona.h b/sound/soc/codecs/arizona.h index f02012438e15..ecd8890eefc1 100644 --- a/sound/soc/codecs/arizona.h +++ b/sound/soc/codecs/arizona.h @@ -97,9 +97,8 @@ struct arizona_priv { struct delayed_work hpdet_work; struct delayed_work micd_detect_work; struct delayed_work micd_timeout_work; + struct snd_soc_jack *jack; struct regulator *micvdd; - struct input_dev *input; - struct extcon_dev *edev; struct gpio_desc *micd_pol_gpio; u16 last_jackdet; @@ -108,6 +107,7 @@ struct arizona_priv { const struct arizona_micd_config *micd_modes; int micd_num_modes; + int micd_button_mask; const struct arizona_micd_range *micd_ranges; int num_micd_ranges; @@ -257,6 +257,9 @@ extern unsigned int arizona_mixer_values[ARIZONA_NUM_MIXER_INPUTS]; #define ARIZONA_RATE_ENUM_SIZE 4 #define ARIZONA_SAMPLE_RATE_ENUM_SIZE 14 +/* SND_JACK_* mask for supported cable/switch types */ +#define ARIZONA_JACK_MASK (SND_JACK_HEADSET | SND_JACK_LINEOUT | SND_JACK_MECHANICAL) + extern const char * const arizona_rate_text[ARIZONA_RATE_ENUM_SIZE]; extern const unsigned int arizona_rate_val[ARIZONA_RATE_ENUM_SIZE]; extern const char * const arizona_sample_rate_text[ARIZONA_SAMPLE_RATE_ENUM_SIZE]; From 69c58eb61e9b649096a0ab8cbc3c6f8521efd303 Mon Sep 17 00:00:00 2001 From: Hans de Goede Date: Sun, 7 Mar 2021 16:18:05 +0100 Subject: [PATCH 314/587] ASoC: arizona-jack: Cleanup logging Cleanup the use of dev_foo functions used for logging: 1. Many of these are unnecessarily split over multiple lines 2. Use dev_err_probe() in cases where we might get a -EPROBE_DEFER return value Suggested-by: Andy Shevchenko Acked-by: Charles Keepax Tested-by: Charles Keepax Signed-off-by: Hans de Goede Link: https://lore.kernel.org/r/20210307151807.35201-12-hdegoede@redhat.com Signed-off-by: Mark Brown --- sound/soc/codecs/arizona-jack.c | 145 +++++++++++--------------------- 1 file changed, 51 insertions(+), 94 deletions(-) diff --git a/sound/soc/codecs/arizona-jack.c b/sound/soc/codecs/arizona-jack.c index 268d2a44d891..9c15ddba6008 100644 --- a/sound/soc/codecs/arizona-jack.c +++ b/sound/soc/codecs/arizona-jack.c @@ -123,9 +123,8 @@ static void arizona_extcon_hp_clamp(struct arizona_priv *info, ARIZONA_HP_TEST_CTRL_1, ARIZONA_HP1_TST_CAP_SEL_MASK, cap_sel); - if (ret != 0) - dev_warn(arizona->dev, - "Failed to set TST_CAP_SEL: %d\n", ret); + if (ret) + dev_warn(arizona->dev, "Failed to set TST_CAP_SEL: %d\n", ret); break; default: mask = ARIZONA_RMV_SHRT_HP1L; @@ -144,24 +143,20 @@ static void arizona_extcon_hp_clamp(struct arizona_priv *info, ARIZONA_OUTPUT_ENABLES_1, ARIZONA_OUT1L_ENA | ARIZONA_OUT1R_ENA, 0); - if (ret != 0) - dev_warn(arizona->dev, - "Failed to disable headphone outputs: %d\n", - ret); + if (ret) + dev_warn(arizona->dev, "Failed to disable headphone outputs: %d\n", ret); } if (mask) { ret = regmap_update_bits(arizona->regmap, ARIZONA_HP_CTRL_1L, mask, val); - if (ret != 0) - dev_warn(arizona->dev, "Failed to do clamp: %d\n", - ret); + if (ret) + dev_warn(arizona->dev, "Failed to do clamp: %d\n", ret); ret = regmap_update_bits(arizona->regmap, ARIZONA_HP_CTRL_1R, mask, val); - if (ret != 0) - dev_warn(arizona->dev, "Failed to do clamp: %d\n", - ret); + if (ret) + dev_warn(arizona->dev, "Failed to do clamp: %d\n", ret); } /* Restore the desired state while not doing the clamp */ @@ -170,10 +165,8 @@ static void arizona_extcon_hp_clamp(struct arizona_priv *info, ARIZONA_OUTPUT_ENABLES_1, ARIZONA_OUT1L_ENA | ARIZONA_OUT1R_ENA, arizona->hp_ena); - if (ret != 0) - dev_warn(arizona->dev, - "Failed to restore headphone outputs: %d\n", - ret); + if (ret) + dev_warn(arizona->dev, "Failed to restore headphone outputs: %d\n", ret); } snd_soc_dapm_mutex_unlock(arizona->dapm); @@ -223,17 +216,15 @@ static void arizona_extcon_pulse_micbias(struct arizona_priv *info) int ret; ret = snd_soc_component_force_enable_pin(component, widget); - if (ret != 0) - dev_warn(arizona->dev, "Failed to enable %s: %d\n", - widget, ret); + if (ret) + dev_warn(arizona->dev, "Failed to enable %s: %d\n", widget, ret); snd_soc_dapm_sync(dapm); if (!arizona->pdata.micd_force_micbias) { ret = snd_soc_component_disable_pin(component, widget); - if (ret != 0) - dev_warn(arizona->dev, "Failed to disable %s: %d\n", - widget, ret); + if (ret) + dev_warn(arizona->dev, "Failed to disable %s: %d\n", widget, ret); snd_soc_dapm_sync(dapm); } @@ -251,18 +242,13 @@ static void arizona_start_mic(struct arizona_priv *info) if (info->detecting) { ret = regulator_allow_bypass(info->micvdd, false); - if (ret != 0) { - dev_err(arizona->dev, - "Failed to regulate MICVDD: %d\n", - ret); - } + if (ret) + dev_err(arizona->dev, "Failed to regulate MICVDD: %d\n", ret); } ret = regulator_enable(info->micvdd); - if (ret != 0) { - dev_err(arizona->dev, "Failed to enable MICVDD: %d\n", - ret); - } + if (ret) + dev_err(arizona->dev, "Failed to enable MICVDD: %d\n", ret); if (info->micd_reva) { const struct reg_sequence reva[] = { @@ -312,10 +298,8 @@ static void arizona_stop_mic(struct arizona_priv *info) dev_err(arizona->dev, "Failed to disable micd: %d\n", ret); ret = snd_soc_component_disable_pin(component, widget); - if (ret != 0) - dev_warn(arizona->dev, - "Failed to disable %s: %d\n", - widget, ret); + if (ret) + dev_warn(arizona->dev, "Failed to disable %s: %d\n", widget, ret); snd_soc_dapm_sync(dapm); @@ -330,10 +314,8 @@ static void arizona_stop_mic(struct arizona_priv *info) } ret = regulator_allow_bypass(info->micvdd, true); - if (ret != 0) { - dev_err(arizona->dev, "Failed to bypass MICVDD: %d\n", - ret); - } + if (ret) + dev_err(arizona->dev, "Failed to bypass MICVDD: %d\n", ret); if (change) { regulator_disable(info->micvdd); @@ -371,17 +353,15 @@ static int arizona_hpdet_read(struct arizona_priv *info) int ret; ret = regmap_read(arizona->regmap, ARIZONA_HEADPHONE_DETECT_2, &val); - if (ret != 0) { - dev_err(arizona->dev, "Failed to read HPDET status: %d\n", - ret); + if (ret) { + dev_err(arizona->dev, "Failed to read HPDET status: %d\n", ret); return ret; } switch (info->hpdet_ip_version) { case 0: if (!(val & ARIZONA_HP_DONE)) { - dev_err(arizona->dev, "HPDET did not complete: %x\n", - val); + dev_err(arizona->dev, "HPDET did not complete: %x\n", val); return -EAGAIN; } @@ -390,15 +370,13 @@ static int arizona_hpdet_read(struct arizona_priv *info) case 1: if (!(val & ARIZONA_HP_DONE_B)) { - dev_err(arizona->dev, "HPDET did not complete: %x\n", - val); + dev_err(arizona->dev, "HPDET did not complete: %x\n", val); return -EAGAIN; } ret = regmap_read(arizona->regmap, ARIZONA_HP_DACVAL, &val); - if (ret != 0) { - dev_err(arizona->dev, "Failed to read HP value: %d\n", - ret); + if (ret) { + dev_err(arizona->dev, "Failed to read HP value: %d\n", ret); return -EAGAIN; } @@ -411,8 +389,7 @@ static int arizona_hpdet_read(struct arizona_priv *info) (val < arizona_hpdet_b_ranges[range].threshold || val >= ARIZONA_HPDET_B_RANGE_MAX)) { range++; - dev_dbg(arizona->dev, "Moving to HPDET range %d\n", - range); + dev_dbg(arizona->dev, "Moving to HPDET range %d\n", range); regmap_update_bits(arizona->regmap, ARIZONA_HEADPHONE_DETECT_1, ARIZONA_HP_IMPEDANCE_RANGE_MASK, @@ -428,8 +405,7 @@ static int arizona_hpdet_read(struct arizona_priv *info) return ARIZONA_HPDET_MAX; } - dev_dbg(arizona->dev, "HPDET read %d in range %d\n", - val, range); + dev_dbg(arizona->dev, "HPDET read %d in range %d\n", val, range); val = arizona_hpdet_b_ranges[range].factor_b / ((val * 100) - @@ -438,8 +414,7 @@ static int arizona_hpdet_read(struct arizona_priv *info) case 2: if (!(val & ARIZONA_HP_DONE_B)) { - dev_err(arizona->dev, "HPDET did not complete: %x\n", - val); + dev_err(arizona->dev, "HPDET did not complete: %x\n", val); return -EAGAIN; } @@ -475,8 +450,7 @@ static int arizona_hpdet_read(struct arizona_priv *info) break; default: - dev_warn(arizona->dev, "Unknown HPDET IP revision %d\n", - info->hpdet_ip_version); + dev_warn(arizona->dev, "Unknown HPDET IP revision %d\n", info->hpdet_ip_version); return -EINVAL; } @@ -664,9 +638,8 @@ static void arizona_identify_headphone(struct arizona_priv *info) ret = regmap_update_bits(arizona->regmap, ARIZONA_HEADPHONE_DETECT_1, ARIZONA_HP_POLL, ARIZONA_HP_POLL); - if (ret != 0) { - dev_err(arizona->dev, "Can't start HPDETL measurement: %d\n", - ret); + if (ret) { + dev_err(arizona->dev, "Can't start HPDETL measurement: %d\n", ret); goto err; } @@ -716,10 +689,8 @@ static void arizona_start_hpdet_acc_id(struct arizona_priv *info) ret = regmap_update_bits(arizona->regmap, ARIZONA_HEADPHONE_DETECT_1, ARIZONA_HP_POLL, ARIZONA_HP_POLL); - if (ret != 0) { - dev_err(arizona->dev, - "Can't start HPDETL measurement: %d\n", - ret); + if (ret) { + dev_err(arizona->dev, "Can't start HPDETL measurement: %d\n", ret); goto err; } } else { @@ -764,9 +735,8 @@ static int arizona_micd_adc_read(struct arizona_priv *info) ARIZONA_MICD_ENA, 0); ret = regmap_read(arizona->regmap, ARIZONA_MIC_DETECT_4, &val); - if (ret != 0) { - dev_err(arizona->dev, - "Failed to read MICDET_ADCVAL: %d\n", ret); + if (ret) { + dev_err(arizona->dev, "Failed to read MICDET_ADCVAL: %d\n", ret); return ret; } @@ -798,17 +768,15 @@ static int arizona_micd_read(struct arizona_priv *info) for (i = 0; i < 10 && !(val & MICD_LVL_0_TO_8); i++) { ret = regmap_read(arizona->regmap, ARIZONA_MIC_DETECT_3, &val); - if (ret != 0) { - dev_err(arizona->dev, - "Failed to read MICDET: %d\n", ret); + if (ret) { + dev_err(arizona->dev, "Failed to read MICDET: %d\n", ret); return ret; } dev_dbg(arizona->dev, "MICDET: %x\n", val); if (!(val & ARIZONA_MICD_VALID)) { - dev_warn(arizona->dev, - "Microphone detection state invalid\n"); + dev_warn(arizona->dev, "Microphone detection state invalid\n"); return -EINVAL; } } @@ -856,10 +824,8 @@ static int arizona_micdet_reading(void *priv) /* Don't need to regulate for button detection */ ret = regulator_allow_bypass(info->micvdd, true); - if (ret != 0) { - dev_err(arizona->dev, "Failed to bypass MICVDD: %d\n", - ret); - } + if (ret) + dev_err(arizona->dev, "Failed to bypass MICVDD: %d\n", ret); return 0; } @@ -941,8 +907,7 @@ static int arizona_button_reading(void *priv) dev_err(arizona->dev, "Button out of range\n"); } } else { - dev_warn(arizona->dev, "Button with no mic: %x\n", - val); + dev_warn(arizona->dev, "Button with no mic: %x\n", val); } } else { dev_dbg(arizona->dev, "Mic button released\n"); @@ -1025,8 +990,7 @@ static int arizona_hpdet_wait(struct arizona_priv *info) ret = regmap_read(arizona->regmap, ARIZONA_HEADPHONE_DETECT_2, &val); if (ret) { - dev_err(arizona->dev, - "Failed to read HPDET state: %d\n", ret); + dev_err(arizona->dev, "Failed to read HPDET state: %d\n", ret); return ret; } @@ -1076,9 +1040,8 @@ static irqreturn_t arizona_jackdet(int irq, void *data) } ret = regmap_read(arizona->regmap, ARIZONA_AOD_IRQ_RAW_STATUS, &val); - if (ret != 0) { - dev_err(arizona->dev, "Failed to read jackdet status: %d\n", - ret); + if (ret) { + dev_err(arizona->dev, "Failed to read jackdet status: %d\n", ret); mutex_unlock(&info->lock); pm_runtime_put_autosuspend(arizona->dev); return IRQ_NONE; @@ -1248,8 +1211,7 @@ static int arizona_extcon_device_get_pdata(struct device *dev, pdata->hpdet_channel = val; break; default: - dev_err(arizona->dev, - "Wrong wlf,hpdet-channel DT value %d\n", val); + dev_err(arizona->dev, "Wrong wlf,hpdet-channel DT value %d\n", val); pdata->hpdet_channel = ARIZONA_ACCDET_MODE_HPL; } @@ -1301,11 +1263,8 @@ int arizona_jack_codec_dev_probe(struct arizona_priv *info, struct device *dev) arizona_extcon_device_get_pdata(dev, arizona); info->micvdd = devm_regulator_get(dev, "MICVDD"); - if (IS_ERR(info->micvdd)) { - ret = PTR_ERR(info->micvdd); - dev_err(arizona->dev, "Failed to get MICVDD: %d\n", ret); - return ret; - } + if (IS_ERR(info->micvdd)) + return dev_err_probe(arizona->dev, PTR_ERR(info->micvdd), "getting MICVDD\n"); mutex_init(&info->lock); info->last_jackdet = ~(ARIZONA_MICD_CLAMP_STS | ARIZONA_JD1_STS); @@ -1391,9 +1350,7 @@ int arizona_jack_codec_dev_probe(struct arizona_priv *info, struct device *dev) mode); if (IS_ERR(info->micd_pol_gpio)) { ret = PTR_ERR(info->micd_pol_gpio); - dev_err(arizona->dev, - "Failed to get microphone polarity GPIO: %d\n", - ret); + dev_err_probe(arizona->dev, ret, "getting microphone polarity GPIO\n"); return ret; } } From 37dbabf14ff65510fa5aeecc1707ca390e608e00 Mon Sep 17 00:00:00 2001 From: Hans de Goede Date: Sun, 7 Mar 2021 16:18:06 +0100 Subject: [PATCH 315/587] ASoC: arizona: Make the wm5102, wm5110, wm8997 and wm8998 drivers use the new jack library Make all arizona codec drivers for which drivers/mfd/arizona-core.c used to instantiate a "arizona-extcon" child-device use the new arizona-jack.c library for jack-detection. This has been tested on a Lenovo Yoga Tablet 2 1051L with a WM5102 codec. Reviewed-by: Andy Shevchenko Acked-by: Charles Keepax Tested-by: Charles Keepax Signed-off-by: Hans de Goede Link: https://lore.kernel.org/r/20210307151807.35201-13-hdegoede@redhat.com Signed-off-by: Mark Brown --- sound/soc/codecs/wm5102.c | 12 +++++++++++- sound/soc/codecs/wm5110.c | 12 +++++++++++- sound/soc/codecs/wm8997.c | 14 ++++++++++++-- sound/soc/codecs/wm8998.c | 9 +++++++++ 4 files changed, 43 insertions(+), 4 deletions(-) diff --git a/sound/soc/codecs/wm5102.c b/sound/soc/codecs/wm5102.c index fe33f2d88f55..34b665895bdf 100644 --- a/sound/soc/codecs/wm5102.c +++ b/sound/soc/codecs/wm5102.c @@ -2004,6 +2004,7 @@ static const struct snd_soc_component_driver soc_component_dev_wm5102 = { .remove = wm5102_component_remove, .set_sysclk = arizona_set_sysclk, .set_pll = wm5102_set_fll, + .set_jack = arizona_jack_set_jack, .name = DRV_NAME, .compress_ops = &wm5102_compress_ops, .controls = wm5102_snd_controls, @@ -2057,6 +2058,11 @@ static int wm5102_probe(struct platform_device *pdev) if (ret != 0) return ret; + /* This may return -EPROBE_DEFER, so do this early on */ + ret = arizona_jack_codec_dev_probe(&wm5102->core, &pdev->dev); + if (ret) + return ret; + for (i = 0; i < ARRAY_SIZE(wm5102->fll); i++) wm5102->fll[i].vco_mult = 1; @@ -2089,7 +2095,7 @@ static int wm5102_probe(struct platform_device *pdev) wm5102); if (ret != 0) { dev_err(&pdev->dev, "Failed to request DSP IRQ: %d\n", ret); - return ret; + goto err_jack_codec_dev; } ret = arizona_set_irq_wake(arizona, ARIZONA_IRQ_DSP_IRQ1, 1); @@ -2123,6 +2129,8 @@ err_spk_irqs: err_dsp_irq: arizona_set_irq_wake(arizona, ARIZONA_IRQ_DSP_IRQ1, 0); arizona_free_irq(arizona, ARIZONA_IRQ_DSP_IRQ1, wm5102); +err_jack_codec_dev: + arizona_jack_codec_dev_remove(&wm5102->core); return ret; } @@ -2141,6 +2149,8 @@ static int wm5102_remove(struct platform_device *pdev) arizona_set_irq_wake(arizona, ARIZONA_IRQ_DSP_IRQ1, 0); arizona_free_irq(arizona, ARIZONA_IRQ_DSP_IRQ1, wm5102); + arizona_jack_codec_dev_remove(&wm5102->core); + return 0; } diff --git a/sound/soc/codecs/wm5110.c b/sound/soc/codecs/wm5110.c index 52c0a575cc4f..76efca0fe515 100644 --- a/sound/soc/codecs/wm5110.c +++ b/sound/soc/codecs/wm5110.c @@ -2370,6 +2370,7 @@ static const struct snd_soc_component_driver soc_component_dev_wm5110 = { .remove = wm5110_component_remove, .set_sysclk = arizona_set_sysclk, .set_pll = wm5110_set_fll, + .set_jack = arizona_jack_set_jack, .name = DRV_NAME, .compress_ops = &wm5110_compress_ops, .controls = wm5110_snd_controls, @@ -2424,6 +2425,11 @@ static int wm5110_probe(struct platform_device *pdev) return ret; } + /* This may return -EPROBE_DEFER, so do this early on */ + ret = arizona_jack_codec_dev_probe(&wm5110->core, &pdev->dev); + if (ret) + return ret; + for (i = 0; i < ARRAY_SIZE(wm5110->fll); i++) wm5110->fll[i].vco_mult = 3; @@ -2456,7 +2462,7 @@ static int wm5110_probe(struct platform_device *pdev) wm5110); if (ret != 0) { dev_err(&pdev->dev, "Failed to request DSP IRQ: %d\n", ret); - return ret; + goto err_jack_codec_dev; } ret = arizona_set_irq_wake(arizona, ARIZONA_IRQ_DSP_IRQ1, 1); @@ -2490,6 +2496,8 @@ err_spk_irqs: err_dsp_irq: arizona_set_irq_wake(arizona, ARIZONA_IRQ_DSP_IRQ1, 0); arizona_free_irq(arizona, ARIZONA_IRQ_DSP_IRQ1, wm5110); +err_jack_codec_dev: + arizona_jack_codec_dev_remove(&wm5110->core); return ret; } @@ -2510,6 +2518,8 @@ static int wm5110_remove(struct platform_device *pdev) arizona_set_irq_wake(arizona, ARIZONA_IRQ_DSP_IRQ1, 0); arizona_free_irq(arizona, ARIZONA_IRQ_DSP_IRQ1, wm5110); + arizona_jack_codec_dev_remove(&wm5110->core); + return 0; } diff --git a/sound/soc/codecs/wm8997.c b/sound/soc/codecs/wm8997.c index 99c3ebae6ba6..38ef631d1a1f 100644 --- a/sound/soc/codecs/wm8997.c +++ b/sound/soc/codecs/wm8997.c @@ -1096,6 +1096,7 @@ static const struct snd_soc_component_driver soc_component_dev_wm8997 = { .remove = wm8997_component_remove, .set_sysclk = arizona_set_sysclk, .set_pll = wm8997_set_fll, + .set_jack = arizona_jack_set_jack, .controls = wm8997_snd_controls, .num_controls = ARRAY_SIZE(wm8997_snd_controls), .dapm_widgets = wm8997_dapm_widgets, @@ -1132,6 +1133,11 @@ static int wm8997_probe(struct platform_device *pdev) arizona_init_dvfs(&wm8997->core); + /* This may return -EPROBE_DEFER, so do this early on */ + ret = arizona_jack_codec_dev_probe(&wm8997->core, &pdev->dev); + if (ret) + return ret; + for (i = 0; i < ARRAY_SIZE(wm8997->fll); i++) wm8997->fll[i].vco_mult = 1; @@ -1163,10 +1169,10 @@ static int wm8997_probe(struct platform_device *pdev) ret = arizona_init_vol_limit(arizona); if (ret < 0) - return ret; + goto err_jack_codec_dev; ret = arizona_init_spk_irqs(arizona); if (ret < 0) - return ret; + goto err_jack_codec_dev; ret = devm_snd_soc_register_component(&pdev->dev, &soc_component_dev_wm8997, @@ -1181,6 +1187,8 @@ static int wm8997_probe(struct platform_device *pdev) err_spk_irqs: arizona_free_spk_irqs(arizona); +err_jack_codec_dev: + arizona_jack_codec_dev_remove(&wm8997->core); return ret; } @@ -1194,6 +1202,8 @@ static int wm8997_remove(struct platform_device *pdev) arizona_free_spk_irqs(arizona); + arizona_jack_codec_dev_remove(&wm8997->core); + return 0; } diff --git a/sound/soc/codecs/wm8998.c b/sound/soc/codecs/wm8998.c index b6f717aa5478..00b59fc9b1fe 100644 --- a/sound/soc/codecs/wm8998.c +++ b/sound/soc/codecs/wm8998.c @@ -1316,6 +1316,7 @@ static const struct snd_soc_component_driver soc_component_dev_wm8998 = { .remove = wm8998_component_remove, .set_sysclk = arizona_set_sysclk, .set_pll = wm8998_set_fll, + .set_jack = arizona_jack_set_jack, .controls = wm8998_snd_controls, .num_controls = ARRAY_SIZE(wm8998_snd_controls), .dapm_widgets = wm8998_dapm_widgets, @@ -1350,6 +1351,11 @@ static int wm8998_probe(struct platform_device *pdev) wm8998->core.arizona = arizona; wm8998->core.num_inputs = 3; /* IN1L, IN1R, IN2 */ + /* This may return -EPROBE_DEFER, so do this early on */ + ret = arizona_jack_codec_dev_probe(&wm8998->core, &pdev->dev); + if (ret) + return ret; + for (i = 0; i < ARRAY_SIZE(wm8998->fll); i++) wm8998->fll[i].vco_mult = 1; @@ -1392,6 +1398,7 @@ err_spk_irqs: arizona_free_spk_irqs(arizona); err_pm_disable: pm_runtime_disable(&pdev->dev); + arizona_jack_codec_dev_remove(&wm8998->core); return ret; } @@ -1405,6 +1412,8 @@ static int wm8998_remove(struct platform_device *pdev) arizona_free_spk_irqs(arizona); + arizona_jack_codec_dev_remove(&wm8998->core); + return 0; } From ecd77d494ec995fb07102b408954c94f38374084 Mon Sep 17 00:00:00 2001 From: Hans de Goede Date: Sun, 7 Mar 2021 16:18:07 +0100 Subject: [PATCH 316/587] ASoC: Intel: bytcr_wm5102: Add jack detect support Add jack detect support by creating a jack and calling snd_soc_component_set_jack to register the created jack with the codec. Reviewed-by: Andy Shevchenko Signed-off-by: Hans de Goede Link: https://lore.kernel.org/r/20210307151807.35201-14-hdegoede@redhat.com Signed-off-by: Mark Brown --- sound/soc/intel/boards/bytcr_wm5102.c | 28 ++++++++++++++++++++++++++- 1 file changed, 27 insertions(+), 1 deletion(-) diff --git a/sound/soc/intel/boards/bytcr_wm5102.c b/sound/soc/intel/boards/bytcr_wm5102.c index fd584e380340..8d8ab9be256f 100644 --- a/sound/soc/intel/boards/bytcr_wm5102.c +++ b/sound/soc/intel/boards/bytcr_wm5102.c @@ -18,6 +18,7 @@ #include #include #include +#include #include #include #include @@ -31,6 +32,7 @@ #define WM5102_MAX_SYSCLK_11025 45158400 /* max sysclk for 11.025K family */ struct byt_wm5102_private { + struct snd_soc_jack jack; struct clk *mclk; struct gpio_desc *spkvdd_en_gpio; }; @@ -177,11 +179,23 @@ static const struct snd_kcontrol_new byt_wm5102_controls[] = { SOC_DAPM_PIN_SWITCH("Speaker"), }; +static struct snd_soc_jack_pin byt_wm5102_pins[] = { + { + .pin = "Headphone", + .mask = SND_JACK_HEADPHONE, + }, + { + .pin = "Headset Mic", + .mask = SND_JACK_MICROPHONE, + }, +}; + static int byt_wm5102_init(struct snd_soc_pcm_runtime *runtime) { struct snd_soc_card *card = runtime->card; struct byt_wm5102_private *priv = snd_soc_card_get_drvdata(card); - int ret; + struct snd_soc_component *component = asoc_rtd_to_codec(runtime, 0)->component; + int ret, jack_type; card->dapm.idle_bias_off = true; @@ -210,6 +224,18 @@ static int byt_wm5102_init(struct snd_soc_pcm_runtime *runtime) return ret; } + jack_type = ARIZONA_JACK_MASK | SND_JACK_BTN_0 | SND_JACK_BTN_1 | + SND_JACK_BTN_2 | SND_JACK_BTN_3; + ret = snd_soc_card_jack_new(card, "Headset", jack_type, + &priv->jack, byt_wm5102_pins, + ARRAY_SIZE(byt_wm5102_pins)); + if (ret) { + dev_err(card->dev, "Error creating jack: %d\n", ret); + return ret; + } + + snd_soc_component_set_jack(component, &priv->jack, NULL); + return 0; } From e839fbed26e8b8713803b8ac73da92fd2b0c7594 Mon Sep 17 00:00:00 2001 From: Kai Vehmanen Date: Wed, 24 Mar 2021 19:23:37 +0200 Subject: [PATCH 317/587] ALSA: hda/hdmi: fix max DP-MST dev_num for Intel TGL+ platforms Increase the device select range to 4 on platforms supporting 4 concurrent displays. This fixes a problem in scenario where total of 4 displays are active, and 3 of these are audio capable DP receivers and connected to a DP-MST hub. Due to incorrect range for device select, audio could not be played to the 3rd monitor in DP-MST hub. BugLink: https://github.com/thesofproject/linux/issues/2798 Signed-off-by: Kai Vehmanen Reviewed-by: Ranjani Sridharan Reviewed-by: Guennadi Liakhovetski Link: https://lore.kernel.org/r/20210324172337.51730-1-kai.vehmanen@linux.intel.com Signed-off-by: Takashi Iwai --- sound/pci/hda/patch_hdmi.c | 25 +++++++++++-------------- 1 file changed, 11 insertions(+), 14 deletions(-) diff --git a/sound/pci/hda/patch_hdmi.c b/sound/pci/hda/patch_hdmi.c index e6d0843ee9df..76d8f6c6060a 100644 --- a/sound/pci/hda/patch_hdmi.c +++ b/sound/pci/hda/patch_hdmi.c @@ -1848,16 +1848,12 @@ static int hdmi_add_pin(struct hda_codec *codec, hda_nid_t pin_nid) */ if (spec->intel_hsw_fixup) { /* - * On Intel platforms, device entries number is - * changed dynamically. If there is a DP MST - * hub connected, the device entries number is 3. - * Otherwise, it is 1. - * Here we manually set dev_num to 3, so that - * we can initialize all the device entries when - * bootup statically. + * On Intel platforms, device entries count returned + * by AC_PAR_DEVLIST_LEN is dynamic, and depends on + * the type of receiver that is connected. Allocate pin + * structures based on worst case. */ - dev_num = 3; - spec->dev_num = 3; + dev_num = spec->dev_num; } else if (spec->dyn_pcm_assign && codec->dp_mst) { dev_num = snd_hda_get_num_devices(codec, pin_nid) + 1; /* @@ -2929,7 +2925,7 @@ static int parse_intel_hdmi(struct hda_codec *codec) /* Intel Haswell and onwards; audio component with eld notifier */ static int intel_hsw_common_init(struct hda_codec *codec, hda_nid_t vendor_nid, - const int *port_map, int port_num) + const int *port_map, int port_num, int dev_num) { struct hdmi_spec *spec; int err; @@ -2944,6 +2940,7 @@ static int intel_hsw_common_init(struct hda_codec *codec, hda_nid_t vendor_nid, spec->port_map = port_map; spec->port_num = port_num; spec->intel_hsw_fixup = true; + spec->dev_num = dev_num; intel_haswell_enable_all_pins(codec, true); intel_haswell_fixup_enable_dp12(codec); @@ -2969,12 +2966,12 @@ static int intel_hsw_common_init(struct hda_codec *codec, hda_nid_t vendor_nid, static int patch_i915_hsw_hdmi(struct hda_codec *codec) { - return intel_hsw_common_init(codec, 0x08, NULL, 0); + return intel_hsw_common_init(codec, 0x08, NULL, 0, 3); } static int patch_i915_glk_hdmi(struct hda_codec *codec) { - return intel_hsw_common_init(codec, 0x0b, NULL, 0); + return intel_hsw_common_init(codec, 0x0b, NULL, 0, 3); } static int patch_i915_icl_hdmi(struct hda_codec *codec) @@ -2985,7 +2982,7 @@ static int patch_i915_icl_hdmi(struct hda_codec *codec) */ static const int map[] = {0x0, 0x4, 0x6, 0x8, 0xa, 0xb}; - return intel_hsw_common_init(codec, 0x02, map, ARRAY_SIZE(map)); + return intel_hsw_common_init(codec, 0x02, map, ARRAY_SIZE(map), 3); } static int patch_i915_tgl_hdmi(struct hda_codec *codec) @@ -2997,7 +2994,7 @@ static int patch_i915_tgl_hdmi(struct hda_codec *codec) static const int map[] = {0x4, 0x6, 0x8, 0xa, 0xb, 0xc, 0xd, 0xe, 0xf}; int ret; - ret = intel_hsw_common_init(codec, 0x02, map, ARRAY_SIZE(map)); + ret = intel_hsw_common_init(codec, 0x02, map, ARRAY_SIZE(map), 4); if (!ret) { struct hdmi_spec *spec = codec->spec; From 8bdfc0455e3a59e2c1207a56be22e910fae0e0d5 Mon Sep 17 00:00:00 2001 From: Shengjiu Wang Date: Fri, 12 Mar 2021 10:38:40 +0800 Subject: [PATCH 318/587] ASoC: soc-component: Add snd_soc_pcm_component_ack Add snd_soc_pcm_component_ack back, which can be used to get an updated buffer pointer in the platform driver. On Asymmetric multiprocessor, this pointer can be sent to Cortex-M core for audio processing. Signed-off-by: Shengjiu Wang Link: https://lore.kernel.org/r/1615516725-4975-2-git-send-email-shengjiu.wang@nxp.com Signed-off-by: Mark Brown --- include/sound/soc-component.h | 3 +++ sound/soc/soc-component.c | 14 ++++++++++++++ sound/soc/soc-pcm.c | 2 ++ 3 files changed, 19 insertions(+) diff --git a/include/sound/soc-component.h b/include/sound/soc-component.h index 7dc75b39287f..722cfab28d29 100644 --- a/include/sound/soc-component.h +++ b/include/sound/soc-component.h @@ -146,6 +146,8 @@ struct snd_soc_component_driver { int (*mmap)(struct snd_soc_component *component, struct snd_pcm_substream *substream, struct vm_area_struct *vma); + int (*ack)(struct snd_soc_component *component, + struct snd_pcm_substream *substream); const struct snd_compress_ops *compress_ops; @@ -498,5 +500,6 @@ int snd_soc_pcm_component_pm_runtime_get(struct snd_soc_pcm_runtime *rtd, void *stream); void snd_soc_pcm_component_pm_runtime_put(struct snd_soc_pcm_runtime *rtd, void *stream, int rollback); +int snd_soc_pcm_component_ack(struct snd_pcm_substream *substream); #endif /* __SOC_COMPONENT_H */ diff --git a/sound/soc/soc-component.c b/sound/soc/soc-component.c index 8415e9bd2932..3a5e84e16a87 100644 --- a/sound/soc/soc-component.c +++ b/sound/soc/soc-component.c @@ -1212,3 +1212,17 @@ void snd_soc_pcm_component_pm_runtime_put(struct snd_soc_pcm_runtime *rtd, soc_component_mark_pop(component, stream, pm); } } + +int snd_soc_pcm_component_ack(struct snd_pcm_substream *substream) +{ + struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream); + struct snd_soc_component *component; + int i; + + /* FIXME: use 1st pointer */ + for_each_rtd_components(rtd, i, component) + if (component->driver->ack) + return component->driver->ack(component, substream); + + return 0; +} diff --git a/sound/soc/soc-pcm.c b/sound/soc/soc-pcm.c index 2df70ab851ea..02968a4e52b4 100644 --- a/sound/soc/soc-pcm.c +++ b/sound/soc/soc-pcm.c @@ -2772,6 +2772,8 @@ int soc_new_pcm(struct snd_soc_pcm_runtime *rtd, int num) rtd->ops.page = snd_soc_pcm_component_page; if (drv->mmap) rtd->ops.mmap = snd_soc_pcm_component_mmap; + if (drv->ack) + rtd->ops.ack = snd_soc_pcm_component_ack; } if (playback) From b73d9e6225e86492f6a901223a34ecfa7b55c178 Mon Sep 17 00:00:00 2001 From: Shengjiu Wang Date: Fri, 12 Mar 2021 10:38:41 +0800 Subject: [PATCH 319/587] ASoC: fsl_rpmsg: Add CPU DAI driver for audio base on rpmsg This is a cpu dai driver for rpmsg audio use case, which is mainly used for getting the user's configuration from devicetree and configure the clocks which is used by Cortex-M core. Signed-off-by: Shengjiu Wang Link: https://lore.kernel.org/r/1615516725-4975-3-git-send-email-shengjiu.wang@nxp.com Signed-off-by: Mark Brown --- sound/soc/fsl/Kconfig | 10 ++ sound/soc/fsl/Makefile | 2 + sound/soc/fsl/fsl_rpmsg.c | 279 ++++++++++++++++++++++++++++++++++++++ sound/soc/fsl/fsl_rpmsg.h | 35 +++++ 4 files changed, 326 insertions(+) create mode 100644 sound/soc/fsl/fsl_rpmsg.c create mode 100644 sound/soc/fsl/fsl_rpmsg.h diff --git a/sound/soc/fsl/Kconfig b/sound/soc/fsl/Kconfig index d7f30036d434..3326f30e28f6 100644 --- a/sound/soc/fsl/Kconfig +++ b/sound/soc/fsl/Kconfig @@ -115,6 +115,16 @@ config SND_SOC_FSL_AUD2HTX config SND_SOC_FSL_UTILS tristate +config SND_SOC_FSL_RPMSG + tristate "NXP Audio Base On RPMSG support" + depends on COMMON_CLK + depends on RPMSG + select SND_SOC_IMX_RPMSG if SND_IMX_SOC != n + help + Say Y if you want to add rpmsg audio support for the Freescale CPUs. + This option is only useful for out-of-tree drivers since + in-tree drivers select it automatically. + config SND_SOC_IMX_PCM_DMA tristate select SND_SOC_GENERIC_DMAENGINE_PCM diff --git a/sound/soc/fsl/Makefile b/sound/soc/fsl/Makefile index 8c5fa8a859c0..b63802f345cc 100644 --- a/sound/soc/fsl/Makefile +++ b/sound/soc/fsl/Makefile @@ -27,6 +27,7 @@ snd-soc-fsl-mqs-objs := fsl_mqs.o snd-soc-fsl-easrc-objs := fsl_easrc.o snd-soc-fsl-xcvr-objs := fsl_xcvr.o snd-soc-fsl-aud2htx-objs := fsl_aud2htx.o +snd-soc-fsl-rpmsg-objs := fsl_rpmsg.o obj-$(CONFIG_SND_SOC_FSL_AUDMIX) += snd-soc-fsl-audmix.o obj-$(CONFIG_SND_SOC_FSL_ASOC_CARD) += snd-soc-fsl-asoc-card.o @@ -42,6 +43,7 @@ obj-$(CONFIG_SND_SOC_FSL_EASRC) += snd-soc-fsl-easrc.o obj-$(CONFIG_SND_SOC_POWERPC_DMA) += snd-soc-fsl-dma.o obj-$(CONFIG_SND_SOC_FSL_XCVR) += snd-soc-fsl-xcvr.o obj-$(CONFIG_SND_SOC_FSL_AUD2HTX) += snd-soc-fsl-aud2htx.o +obj-$(CONFIG_SND_SOC_FSL_RPMSG) += snd-soc-fsl-rpmsg.o # MPC5200 Platform Support obj-$(CONFIG_SND_MPC52xx_DMA) += mpc5200_dma.o diff --git a/sound/soc/fsl/fsl_rpmsg.c b/sound/soc/fsl/fsl_rpmsg.c new file mode 100644 index 000000000000..2d09d8850e2c --- /dev/null +++ b/sound/soc/fsl/fsl_rpmsg.c @@ -0,0 +1,279 @@ +// SPDX-License-Identifier: GPL-2.0+ +// Copyright 2018-2021 NXP + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "fsl_rpmsg.h" +#include "imx-pcm.h" + +#define FSL_RPMSG_RATES (SNDRV_PCM_RATE_8000 | \ + SNDRV_PCM_RATE_16000 | \ + SNDRV_PCM_RATE_48000) +#define FSL_RPMSG_FORMATS SNDRV_PCM_FMTBIT_S16_LE + +/* 192kHz/32bit/2ch/60s size is 0x574e00 */ +#define LPA_LARGE_BUFFER_SIZE (0x6000000) + +static const unsigned int fsl_rpmsg_rates[] = { + 8000, 11025, 16000, 22050, 44100, + 32000, 48000, 96000, 88200, 176400, 192000, + 352800, 384000, 705600, 768000, 1411200, 2822400, +}; + +static const struct snd_pcm_hw_constraint_list fsl_rpmsg_rate_constraints = { + .count = ARRAY_SIZE(fsl_rpmsg_rates), + .list = fsl_rpmsg_rates, +}; + +static int fsl_rpmsg_hw_params(struct snd_pcm_substream *substream, + struct snd_pcm_hw_params *params, + struct snd_soc_dai *dai) +{ + struct fsl_rpmsg *rpmsg = snd_soc_dai_get_drvdata(dai); + struct clk *p = rpmsg->mclk, *pll = 0, *npll = 0; + u64 rate = params_rate(params); + int ret = 0; + + /* Get current pll parent */ + while (p && rpmsg->pll8k && rpmsg->pll11k) { + struct clk *pp = clk_get_parent(p); + + if (clk_is_match(pp, rpmsg->pll8k) || + clk_is_match(pp, rpmsg->pll11k)) { + pll = pp; + break; + } + p = pp; + } + + /* Switch to another pll parent if needed. */ + if (pll) { + npll = (do_div(rate, 8000) ? rpmsg->pll11k : rpmsg->pll8k); + if (!clk_is_match(pll, npll)) { + ret = clk_set_parent(p, npll); + if (ret < 0) + dev_warn(dai->dev, "failed to set parent %s: %d\n", + __clk_get_name(npll), ret); + } + } + + if (!(rpmsg->mclk_streams & BIT(substream->stream))) { + ret = clk_prepare_enable(rpmsg->mclk); + if (ret) { + dev_err(dai->dev, "failed to enable mclk: %d\n", ret); + return ret; + } + + rpmsg->mclk_streams |= BIT(substream->stream); + } + + return ret; +} + +static int fsl_rpmsg_hw_free(struct snd_pcm_substream *substream, + struct snd_soc_dai *dai) +{ + struct fsl_rpmsg *rpmsg = snd_soc_dai_get_drvdata(dai); + + if (rpmsg->mclk_streams & BIT(substream->stream)) { + clk_disable_unprepare(rpmsg->mclk); + rpmsg->mclk_streams &= ~BIT(substream->stream); + } + + return 0; +} + +static int fsl_rpmsg_startup(struct snd_pcm_substream *substream, + struct snd_soc_dai *cpu_dai) +{ + int ret; + + ret = snd_pcm_hw_constraint_list(substream->runtime, 0, + SNDRV_PCM_HW_PARAM_RATE, + &fsl_rpmsg_rate_constraints); + + return ret; +} + +static const struct snd_soc_dai_ops fsl_rpmsg_dai_ops = { + .startup = fsl_rpmsg_startup, + .hw_params = fsl_rpmsg_hw_params, + .hw_free = fsl_rpmsg_hw_free, +}; + +static struct snd_soc_dai_driver fsl_rpmsg_dai = { + .playback = { + .stream_name = "CPU-Playback", + .channels_min = 2, + .channels_max = 2, + .rates = SNDRV_PCM_RATE_KNOT, + .formats = FSL_RPMSG_FORMATS, + }, + .capture = { + .stream_name = "CPU-Capture", + .channels_min = 2, + .channels_max = 2, + .rates = SNDRV_PCM_RATE_KNOT, + .formats = FSL_RPMSG_FORMATS, + }, + .symmetric_rate = 1, + .symmetric_channels = 1, + .symmetric_sample_bits = 1, + .ops = &fsl_rpmsg_dai_ops, +}; + +static const struct snd_soc_component_driver fsl_component = { + .name = "fsl-rpmsg", +}; + +static const struct of_device_id fsl_rpmsg_ids[] = { + { .compatible = "fsl,imx7ulp-rpmsg-audio"}, + { .compatible = "fsl,imx8mm-rpmsg-audio"}, + { .compatible = "fsl,imx8mn-rpmsg-audio"}, + { .compatible = "fsl,imx8mp-rpmsg-audio"}, + { /* sentinel */ } +}; +MODULE_DEVICE_TABLE(of, fsl_rpmsg_ids); + +static int fsl_rpmsg_probe(struct platform_device *pdev) +{ + struct device_node *np = pdev->dev.of_node; + struct fsl_rpmsg *rpmsg; + int ret; + + rpmsg = devm_kzalloc(&pdev->dev, sizeof(struct fsl_rpmsg), GFP_KERNEL); + if (!rpmsg) + return -ENOMEM; + + if (of_property_read_bool(np, "fsl,enable-lpa")) { + rpmsg->enable_lpa = 1; + rpmsg->buffer_size = LPA_LARGE_BUFFER_SIZE; + } else { + rpmsg->buffer_size = IMX_DEFAULT_DMABUF_SIZE; + } + + /* Get the optional clocks */ + rpmsg->ipg = devm_clk_get(&pdev->dev, "ipg"); + if (IS_ERR(rpmsg->ipg)) + rpmsg->ipg = NULL; + + rpmsg->mclk = devm_clk_get(&pdev->dev, "mclk"); + if (IS_ERR(rpmsg->mclk)) + rpmsg->mclk = NULL; + + rpmsg->dma = devm_clk_get(&pdev->dev, "dma"); + if (IS_ERR(rpmsg->dma)) + rpmsg->dma = NULL; + + rpmsg->pll8k = devm_clk_get(&pdev->dev, "pll8k"); + if (IS_ERR(rpmsg->pll8k)) + rpmsg->pll8k = NULL; + + rpmsg->pll11k = devm_clk_get(&pdev->dev, "pll11k"); + if (IS_ERR(rpmsg->pll11k)) + rpmsg->pll11k = NULL; + + platform_set_drvdata(pdev, rpmsg); + pm_runtime_enable(&pdev->dev); + + ret = devm_snd_soc_register_component(&pdev->dev, &fsl_component, + &fsl_rpmsg_dai, 1); + if (ret) + return ret; + + rpmsg->card_pdev = platform_device_register_data(&pdev->dev, + "imx-audio-rpmsg", + PLATFORM_DEVID_NONE, + NULL, + 0); + if (IS_ERR(rpmsg->card_pdev)) { + dev_err(&pdev->dev, "failed to register rpmsg card\n"); + ret = PTR_ERR(rpmsg->card_pdev); + return ret; + } + + return 0; +} + +static int fsl_rpmsg_remove(struct platform_device *pdev) +{ + struct fsl_rpmsg *rpmsg = platform_get_drvdata(pdev); + + if (rpmsg->card_pdev) + platform_device_unregister(rpmsg->card_pdev); + + return 0; +} + +#ifdef CONFIG_PM +static int fsl_rpmsg_runtime_resume(struct device *dev) +{ + struct fsl_rpmsg *rpmsg = dev_get_drvdata(dev); + int ret; + + ret = clk_prepare_enable(rpmsg->ipg); + if (ret) { + dev_err(dev, "failed to enable ipg clock: %d\n", ret); + goto ipg_err; + } + + ret = clk_prepare_enable(rpmsg->dma); + if (ret) { + dev_err(dev, "Failed to enable dma clock %d\n", ret); + goto dma_err; + } + + return 0; + +dma_err: + clk_disable_unprepare(rpmsg->ipg); +ipg_err: + return ret; +} + +static int fsl_rpmsg_runtime_suspend(struct device *dev) +{ + struct fsl_rpmsg *rpmsg = dev_get_drvdata(dev); + + clk_disable_unprepare(rpmsg->dma); + clk_disable_unprepare(rpmsg->ipg); + + return 0; +} +#endif + +static const struct dev_pm_ops fsl_rpmsg_pm_ops = { + SET_RUNTIME_PM_OPS(fsl_rpmsg_runtime_suspend, + fsl_rpmsg_runtime_resume, + NULL) + SET_SYSTEM_SLEEP_PM_OPS(pm_runtime_force_suspend, + pm_runtime_force_resume) +}; + +static struct platform_driver fsl_rpmsg_driver = { + .probe = fsl_rpmsg_probe, + .remove = fsl_rpmsg_remove, + .driver = { + .name = "fsl_rpmsg", + .pm = &fsl_rpmsg_pm_ops, + .of_match_table = fsl_rpmsg_ids, + }, +}; +module_platform_driver(fsl_rpmsg_driver); + +MODULE_DESCRIPTION("Freescale SoC Audio PRMSG CPU Interface"); +MODULE_AUTHOR("Shengjiu Wang "); +MODULE_ALIAS("platform:fsl_rpmsg"); +MODULE_LICENSE("GPL"); diff --git a/sound/soc/fsl/fsl_rpmsg.h b/sound/soc/fsl/fsl_rpmsg.h new file mode 100644 index 000000000000..4f5b49eb18d8 --- /dev/null +++ b/sound/soc/fsl/fsl_rpmsg.h @@ -0,0 +1,35 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Copyright 2017-2021 NXP + */ + +#ifndef __FSL_RPMSG_H +#define __FSL_RPMSG_H + +/* + * struct fsl_rpmsg - rpmsg private data + * + * @ipg: ipg clock for cpu dai (SAI) + * @mclk: master clock for cpu dai (SAI) + * @dma: clock for dma device + * @pll8k: parent clock for multiple of 8kHz frequency + * @pll11k: parent clock for multiple of 11kHz frequency + * @card_pdev: Platform_device pointer to register a sound card + * @mclk_streams: Active streams that are using baudclk + * @force_lpa: force enable low power audio routine if condition satisfy + * @enable_lpa: enable low power audio routine according to dts setting + * @buffer_size: pre allocated dma buffer size + */ +struct fsl_rpmsg { + struct clk *ipg; + struct clk *mclk; + struct clk *dma; + struct clk *pll8k; + struct clk *pll11k; + struct platform_device *card_pdev; + unsigned int mclk_streams; + int force_lpa; + int enable_lpa; + int buffer_size; +}; +#endif /* __FSL_RPMSG_H */ From 49c6bf62498344fa8f8af2314231f3eb37e0e150 Mon Sep 17 00:00:00 2001 From: Shengjiu Wang Date: Fri, 12 Mar 2021 10:38:42 +0800 Subject: [PATCH 320/587] ASoC: dt-bindings: fsl_rpmsg: Add binding doc for rpmsg audio device fsl_rpmsg is a virtual audio device. Mapping to real hardware devices are SAI, DMA controlled by Cortex M core. What we see from Linux side is a device which provides audio service by rpmsg channel. Signed-off-by: Shengjiu Wang Link: https://lore.kernel.org/r/1615516725-4975-4-git-send-email-shengjiu.wang@nxp.com Signed-off-by: Mark Brown --- .../devicetree/bindings/sound/fsl,rpmsg.yaml | 108 ++++++++++++++++++ 1 file changed, 108 insertions(+) create mode 100644 Documentation/devicetree/bindings/sound/fsl,rpmsg.yaml diff --git a/Documentation/devicetree/bindings/sound/fsl,rpmsg.yaml b/Documentation/devicetree/bindings/sound/fsl,rpmsg.yaml new file mode 100644 index 000000000000..b4c190bddd84 --- /dev/null +++ b/Documentation/devicetree/bindings/sound/fsl,rpmsg.yaml @@ -0,0 +1,108 @@ +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/sound/fsl,rpmsg.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: NXP Audio RPMSG CPU DAI Controller + +maintainers: + - Shengjiu Wang + +description: | + fsl_rpmsg is a virtual audio device. Mapping to real hardware devices + are SAI, DMA controlled by Cortex M core. What we see from Linux + side is a device which provides audio service by rpmsg channel. + +properties: + compatible: + enum: + - fsl,imx7ulp-rpmsg-audio + - fsl,imx8mn-rpmsg-audio + - fsl,imx8mm-rpmsg-audio + - fsl,imx8mp-rpmsg-audio + + model: + $ref: /schemas/types.yaml#/definitions/string + description: User specified audio sound card name + + clocks: + items: + - description: Peripheral clock for register access + - description: Master clock + - description: DMA clock for DMA register access + - description: Parent clock for multiple of 8kHz sample rates + - description: Parent clock for multiple of 11kHz sample rates + + clock-names: + items: + - const: ipg + - const: mclk + - const: dma + - const: pll8k + - const: pll11k + + power-domains: + description: + List of phandle and PM domain specifier as documented in + Documentation/devicetree/bindings/power/power_domain.txt + maxItems: 1 + + memory-region: + $ref: /schemas/types.yaml#/definitions/phandle + description: + phandle to a node describing reserved memory (System RAM memory) + The M core can't access all the DDR memory space on some platform, + So reserved a specific memory for dma buffer which M core can + access. + (see bindings/reserved-memory/reserved-memory.txt) + + audio-codec: + $ref: /schemas/types.yaml#/definitions/phandle + description: The phandle to a node of audio codec + + audio-routing: + $ref: /schemas/types.yaml#/definitions/non-unique-string-array + description: | + A list of the connections between audio components. Each entry is a + pair of strings, the first being the connection's sink, the second + being the connection's source. + + fsl,enable-lpa: + $ref: /schemas/types.yaml#/definitions/flag + description: enable low power audio path. + + fsl,rpmsg-out: + $ref: /schemas/types.yaml#/definitions/flag + description: | + This is a boolean property. If present, the transmitting function + will be enabled. + + fsl,rpmsg-in: + $ref: /schemas/types.yaml#/definitions/flag + description: | + This is a boolean property. If present, the receiving function + will be enabled. + +required: + - compatible + - model + +additionalProperties: false + +examples: + - | + #include + + rpmsg_audio: rpmsg_audio { + compatible = "fsl,imx8mn-rpmsg-audio"; + model = "wm8524-audio"; + fsl,enable-lpa; + fsl,rpmsg-out; + clocks = <&clk IMX8MN_CLK_SAI3_IPG>, + <&clk IMX8MN_CLK_SAI3_ROOT>, + <&clk IMX8MN_CLK_SDMA3_ROOT>, + <&clk IMX8MN_AUDIO_PLL1_OUT>, + <&clk IMX8MN_AUDIO_PLL2_OUT>; + clock-names = "ipg", "mclk", "dma", "pll8k", "pll11k"; + }; From 1935050de0b6c6c961e9de51d5b5d05642f861f1 Mon Sep 17 00:00:00 2001 From: Shengjiu Wang Date: Fri, 12 Mar 2021 10:38:43 +0800 Subject: [PATCH 321/587] ASoC: imx-audio-rpmsg: Add rpmsg_driver for audio channel This driver is used to accept the message from rpmsg audio channel, and if this driver is probed, it will help to register the platform driver, the platform driver will use this audio channel to send and receive messages to and from Cortex-M core. Signed-off-by: Shengjiu Wang Link: https://lore.kernel.org/r/1615516725-4975-5-git-send-email-shengjiu.wang@nxp.com Signed-off-by: Mark Brown --- sound/soc/fsl/Kconfig | 4 + sound/soc/fsl/Makefile | 1 + sound/soc/fsl/imx-audio-rpmsg.c | 140 ++++++++++++++++++++++++++++++++ 3 files changed, 145 insertions(+) create mode 100644 sound/soc/fsl/imx-audio-rpmsg.c diff --git a/sound/soc/fsl/Kconfig b/sound/soc/fsl/Kconfig index 3326f30e28f6..8dbdc0c5ba58 100644 --- a/sound/soc/fsl/Kconfig +++ b/sound/soc/fsl/Kconfig @@ -129,6 +129,10 @@ config SND_SOC_IMX_PCM_DMA tristate select SND_SOC_GENERIC_DMAENGINE_PCM +config SND_SOC_IMX_AUDIO_RPMSG + tristate + depends on RPMSG + config SND_SOC_IMX_AUDMUX tristate "Digital Audio Mux module support" help diff --git a/sound/soc/fsl/Makefile b/sound/soc/fsl/Makefile index b63802f345cc..f08f3cd07ff5 100644 --- a/sound/soc/fsl/Makefile +++ b/sound/soc/fsl/Makefile @@ -60,6 +60,7 @@ obj-$(CONFIG_SND_SOC_IMX_AUDMUX) += snd-soc-imx-audmux.o obj-$(CONFIG_SND_SOC_IMX_PCM_FIQ) += imx-pcm-fiq.o obj-$(CONFIG_SND_SOC_IMX_PCM_DMA) += imx-pcm-dma.o +obj-$(CONFIG_SND_SOC_IMX_AUDIO_RPMSG) += imx-audio-rpmsg.o # i.MX Machine Support snd-soc-eukrea-tlv320-objs := eukrea-tlv320.o diff --git a/sound/soc/fsl/imx-audio-rpmsg.c b/sound/soc/fsl/imx-audio-rpmsg.c new file mode 100644 index 000000000000..50099bcaa9cd --- /dev/null +++ b/sound/soc/fsl/imx-audio-rpmsg.c @@ -0,0 +1,140 @@ +// SPDX-License-Identifier: GPL-2.0+ +// Copyright 2017-2020 NXP + +#include +#include +#include "imx-pcm-rpmsg.h" + +/* + * struct imx_audio_rpmsg: private data + * + * @rpmsg_pdev: pointer of platform device + */ +struct imx_audio_rpmsg { + struct platform_device *rpmsg_pdev; +}; + +static int imx_audio_rpmsg_cb(struct rpmsg_device *rpdev, void *data, int len, + void *priv, u32 src) +{ + struct imx_audio_rpmsg *rpmsg = dev_get_drvdata(&rpdev->dev); + struct rpmsg_r_msg *r_msg = (struct rpmsg_r_msg *)data; + struct rpmsg_info *info; + struct rpmsg_msg *msg; + unsigned long flags; + + if (!rpmsg->rpmsg_pdev) + return 0; + + info = platform_get_drvdata(rpmsg->rpmsg_pdev); + + dev_dbg(&rpdev->dev, "get from%d: cmd:%d. %d\n", + src, r_msg->header.cmd, r_msg->param.resp); + + switch (r_msg->header.type) { + case MSG_TYPE_C: + /* TYPE C is notification from M core */ + switch (r_msg->header.cmd) { + case TX_PERIOD_DONE: + spin_lock_irqsave(&info->lock[TX], flags); + msg = &info->msg[TX_PERIOD_DONE + MSG_TYPE_A_NUM]; + msg->r_msg.param.buffer_tail = + r_msg->param.buffer_tail; + msg->r_msg.param.buffer_tail %= info->num_period[TX]; + spin_unlock_irqrestore(&info->lock[TX], flags); + info->callback[TX](info->callback_param[TX]); + break; + case RX_PERIOD_DONE: + spin_lock_irqsave(&info->lock[RX], flags); + msg = &info->msg[RX_PERIOD_DONE + MSG_TYPE_A_NUM]; + msg->r_msg.param.buffer_tail = + r_msg->param.buffer_tail; + msg->r_msg.param.buffer_tail %= info->num_period[1]; + spin_unlock_irqrestore(&info->lock[RX], flags); + info->callback[RX](info->callback_param[RX]); + break; + default: + dev_warn(&rpdev->dev, "unknown msg command\n"); + break; + } + break; + case MSG_TYPE_B: + /* TYPE B is response msg */ + memcpy(&info->r_msg, r_msg, sizeof(struct rpmsg_r_msg)); + complete(&info->cmd_complete); + break; + default: + dev_warn(&rpdev->dev, "unknown msg type\n"); + break; + } + + return 0; +} + +static int imx_audio_rpmsg_probe(struct rpmsg_device *rpdev) +{ + struct imx_audio_rpmsg *data; + int ret = 0; + + dev_info(&rpdev->dev, "new channel: 0x%x -> 0x%x!\n", + rpdev->src, rpdev->dst); + + data = devm_kzalloc(&rpdev->dev, sizeof(*data), GFP_KERNEL); + if (!data) + return -ENOMEM; + + dev_set_drvdata(&rpdev->dev, data); + + /* Register platform driver for rpmsg routine */ + data->rpmsg_pdev = platform_device_register_data(&rpdev->dev, + IMX_PCM_DRV_NAME, + PLATFORM_DEVID_NONE, + NULL, 0); + if (IS_ERR(data->rpmsg_pdev)) { + dev_err(&rpdev->dev, "failed to register rpmsg platform.\n"); + ret = PTR_ERR(data->rpmsg_pdev); + } + + return ret; +} + +static void imx_audio_rpmsg_remove(struct rpmsg_device *rpdev) +{ + struct imx_audio_rpmsg *data = dev_get_drvdata(&rpdev->dev); + + if (data->rpmsg_pdev) + platform_device_unregister(data->rpmsg_pdev); + + dev_info(&rpdev->dev, "audio rpmsg driver is removed\n"); +} + +static struct rpmsg_device_id imx_audio_rpmsg_id_table[] = { + { .name = "rpmsg-audio-channel" }, + { }, +}; + +static struct rpmsg_driver imx_audio_rpmsg_driver = { + .drv.name = "imx_audio_rpmsg", + .drv.owner = THIS_MODULE, + .id_table = imx_audio_rpmsg_id_table, + .probe = imx_audio_rpmsg_probe, + .callback = imx_audio_rpmsg_cb, + .remove = imx_audio_rpmsg_remove, +}; + +static int __init imx_audio_rpmsg_init(void) +{ + return register_rpmsg_driver(&imx_audio_rpmsg_driver); +} + +static void __exit imx_audio_rpmsg_exit(void) +{ + unregister_rpmsg_driver(&imx_audio_rpmsg_driver); +} +module_init(imx_audio_rpmsg_init); +module_exit(imx_audio_rpmsg_exit); + +MODULE_DESCRIPTION("Freescale SoC Audio RPMSG interface"); +MODULE_AUTHOR("Shengjiu Wang "); +MODULE_ALIAS("platform:imx_audio_rpmsg"); +MODULE_LICENSE("GPL v2"); From 3c00eceb2a5391ed1ca6703b71cad35ab8cd4352 Mon Sep 17 00:00:00 2001 From: Shengjiu Wang Date: Fri, 12 Mar 2021 10:38:44 +0800 Subject: [PATCH 322/587] ASoC: imx-pcm-rpmsg: Add platform driver for audio base on rpmsg Platform driver based on rpmsg is the interface for sending and receiving rpmsg to and from M core. It will tell the Cortex-M core sound format/rate/channel, where is the data buffer, where is the period size, when to start, when to stop and when suspend or resume happen, each this behavior there is defined rpmsg command. Especially we designed the low power audio case, that is to allocate a large buffer and fill the data, then Cortex-A core can go to sleep mode, Cortex-M core continue to play the sound, when the buffer is consumed, Cortex-M core will trigger the Cortex-A core to wake up. Signed-off-by: Shengjiu Wang Link: https://lore.kernel.org/r/1615516725-4975-6-git-send-email-shengjiu.wang@nxp.com Signed-off-by: Mark Brown --- sound/soc/fsl/Kconfig | 5 + sound/soc/fsl/Makefile | 1 + sound/soc/fsl/imx-pcm-rpmsg.c | 918 ++++++++++++++++++++++++++++++++++ sound/soc/fsl/imx-pcm-rpmsg.h | 512 +++++++++++++++++++ 4 files changed, 1436 insertions(+) create mode 100644 sound/soc/fsl/imx-pcm-rpmsg.c create mode 100644 sound/soc/fsl/imx-pcm-rpmsg.h diff --git a/sound/soc/fsl/Kconfig b/sound/soc/fsl/Kconfig index 8dbdc0c5ba58..3d3d14f3793e 100644 --- a/sound/soc/fsl/Kconfig +++ b/sound/soc/fsl/Kconfig @@ -133,6 +133,11 @@ config SND_SOC_IMX_AUDIO_RPMSG tristate depends on RPMSG +config SND_SOC_IMX_PCM_RPMSG + tristate + depends on SND_SOC_IMX_AUDIO_RPMSG + select SND_SOC_GENERIC_DMAENGINE_PCM + config SND_SOC_IMX_AUDMUX tristate "Digital Audio Mux module support" help diff --git a/sound/soc/fsl/Makefile b/sound/soc/fsl/Makefile index f08f3cd07ff5..ce4f4324c3a2 100644 --- a/sound/soc/fsl/Makefile +++ b/sound/soc/fsl/Makefile @@ -61,6 +61,7 @@ obj-$(CONFIG_SND_SOC_IMX_AUDMUX) += snd-soc-imx-audmux.o obj-$(CONFIG_SND_SOC_IMX_PCM_FIQ) += imx-pcm-fiq.o obj-$(CONFIG_SND_SOC_IMX_PCM_DMA) += imx-pcm-dma.o obj-$(CONFIG_SND_SOC_IMX_AUDIO_RPMSG) += imx-audio-rpmsg.o +obj-$(CONFIG_SND_SOC_IMX_PCM_RPMSG) += imx-pcm-rpmsg.o # i.MX Machine Support snd-soc-eukrea-tlv320-objs := eukrea-tlv320.o diff --git a/sound/soc/fsl/imx-pcm-rpmsg.c b/sound/soc/fsl/imx-pcm-rpmsg.c new file mode 100644 index 000000000000..875c0d6df339 --- /dev/null +++ b/sound/soc/fsl/imx-pcm-rpmsg.c @@ -0,0 +1,918 @@ +// SPDX-License-Identifier: GPL-2.0+ +// Copyright 2017-2021 NXP + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "imx-pcm.h" +#include "fsl_rpmsg.h" +#include "imx-pcm-rpmsg.h" + +static struct snd_pcm_hardware imx_rpmsg_pcm_hardware = { + .info = SNDRV_PCM_INFO_INTERLEAVED | + SNDRV_PCM_INFO_BLOCK_TRANSFER | + SNDRV_PCM_INFO_MMAP | + SNDRV_PCM_INFO_MMAP_VALID | + SNDRV_PCM_INFO_NO_PERIOD_WAKEUP | + SNDRV_PCM_INFO_PAUSE | + SNDRV_PCM_INFO_RESUME, + .buffer_bytes_max = IMX_DEFAULT_DMABUF_SIZE, + .period_bytes_min = 512, + .period_bytes_max = 65536, + .periods_min = 2, + .periods_max = 6000, + .fifo_size = 0, +}; + +static int imx_rpmsg_pcm_send_message(struct rpmsg_msg *msg, + struct rpmsg_info *info) +{ + struct rpmsg_device *rpdev = info->rpdev; + int ret = 0; + + mutex_lock(&info->msg_lock); + if (!rpdev) { + dev_err(info->dev, "rpmsg channel not ready\n"); + mutex_unlock(&info->msg_lock); + return -EINVAL; + } + + dev_dbg(&rpdev->dev, "send cmd %d\n", msg->s_msg.header.cmd); + + if (!(msg->s_msg.header.type == MSG_TYPE_C)) + reinit_completion(&info->cmd_complete); + + ret = rpmsg_send(rpdev->ept, (void *)&msg->s_msg, + sizeof(struct rpmsg_s_msg)); + if (ret) { + dev_err(&rpdev->dev, "rpmsg_send failed: %d\n", ret); + mutex_unlock(&info->msg_lock); + return ret; + } + + /* No receive msg for TYPE_C command */ + if (msg->s_msg.header.type == MSG_TYPE_C) { + mutex_unlock(&info->msg_lock); + return 0; + } + + /* wait response from rpmsg */ + ret = wait_for_completion_timeout(&info->cmd_complete, + msecs_to_jiffies(RPMSG_TIMEOUT)); + if (!ret) { + dev_err(&rpdev->dev, "rpmsg_send cmd %d timeout!\n", + msg->s_msg.header.cmd); + mutex_unlock(&info->msg_lock); + return -ETIMEDOUT; + } + + memcpy(&msg->r_msg, &info->r_msg, sizeof(struct rpmsg_r_msg)); + memcpy(&info->msg[msg->r_msg.header.cmd].r_msg, + &msg->r_msg, sizeof(struct rpmsg_r_msg)); + + /* + * Reset the buffer pointer to be zero, actully we have + * set the buffer pointer to be zero in imx_rpmsg_terminate_all + * But if there is timer task queued in queue, after it is + * executed the buffer pointer will be changed, so need to + * reset it again with TERMINATE command. + */ + switch (msg->s_msg.header.cmd) { + case TX_TERMINATE: + info->msg[TX_POINTER].r_msg.param.buffer_offset = 0; + break; + case RX_TERMINATE: + info->msg[RX_POINTER].r_msg.param.buffer_offset = 0; + break; + default: + break; + } + + dev_dbg(&rpdev->dev, "cmd:%d, resp %d\n", msg->s_msg.header.cmd, + info->r_msg.param.resp); + + mutex_unlock(&info->msg_lock); + + return 0; +} + +static int imx_rpmsg_insert_workqueue(struct snd_pcm_substream *substream, + struct rpmsg_msg *msg, + struct rpmsg_info *info) +{ + unsigned long flags; + int ret = 0; + + /* + * Queue the work to workqueue. + * If the queue is full, drop the message. + */ + spin_lock_irqsave(&info->wq_lock, flags); + if (info->work_write_index != info->work_read_index) { + int index = info->work_write_index; + + memcpy(&info->work_list[index].msg, msg, + sizeof(struct rpmsg_s_msg)); + + queue_work(info->rpmsg_wq, &info->work_list[index].work); + info->work_write_index++; + info->work_write_index %= WORK_MAX_NUM; + } else { + info->msg_drop_count[substream->stream]++; + ret = -EPIPE; + } + spin_unlock_irqrestore(&info->wq_lock, flags); + + return ret; +} + +static int imx_rpmsg_pcm_hw_params(struct snd_soc_component *component, + struct snd_pcm_substream *substream, + struct snd_pcm_hw_params *params) +{ + struct rpmsg_info *info = dev_get_drvdata(component->dev); + struct snd_pcm_runtime *runtime = substream->runtime; + struct rpmsg_msg *msg; + int ret = 0; + + if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { + msg = &info->msg[TX_HW_PARAM]; + msg->s_msg.header.cmd = TX_HW_PARAM; + } else { + msg = &info->msg[RX_HW_PARAM]; + msg->s_msg.header.cmd = RX_HW_PARAM; + } + + msg->s_msg.param.rate = params_rate(params); + + switch (params_format(params)) { + case SNDRV_PCM_FORMAT_S16_LE: + msg->s_msg.param.format = RPMSG_S16_LE; + break; + case SNDRV_PCM_FORMAT_S24_LE: + msg->s_msg.param.format = RPMSG_S24_LE; + break; + case SNDRV_PCM_FORMAT_DSD_U16_LE: + msg->s_msg.param.format = SNDRV_PCM_FORMAT_DSD_U16_LE; + break; + case SNDRV_PCM_FORMAT_DSD_U32_LE: + msg->s_msg.param.format = SNDRV_PCM_FORMAT_DSD_U32_LE; + break; + default: + msg->s_msg.param.format = RPMSG_S32_LE; + break; + } + + switch (params_channels(params)) { + case 1: + msg->s_msg.param.channels = RPMSG_CH_LEFT; + break; + case 2: + msg->s_msg.param.channels = RPMSG_CH_STEREO; + break; + default: + ret = -EINVAL; + break; + } + + snd_pcm_set_runtime_buffer(substream, &substream->dma_buffer); + runtime->dma_bytes = params_buffer_bytes(params); + + info->send_message(msg, info); + + return ret; +} + +static int imx_rpmsg_pcm_hw_free(struct snd_soc_component *component, + struct snd_pcm_substream *substream) +{ + snd_pcm_set_runtime_buffer(substream, NULL); + return 0; +} + +static snd_pcm_uframes_t imx_rpmsg_pcm_pointer(struct snd_soc_component *component, + struct snd_pcm_substream *substream) +{ + struct rpmsg_info *info = dev_get_drvdata(component->dev); + struct rpmsg_msg *msg; + unsigned int pos = 0; + int buffer_tail = 0; + + if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) + msg = &info->msg[TX_PERIOD_DONE + MSG_TYPE_A_NUM]; + else + msg = &info->msg[RX_PERIOD_DONE + MSG_TYPE_A_NUM]; + + buffer_tail = msg->r_msg.param.buffer_tail; + pos = buffer_tail * snd_pcm_lib_period_bytes(substream); + + return bytes_to_frames(substream->runtime, pos); +} + +static void imx_rpmsg_timer_callback(struct timer_list *t) +{ + struct stream_timer *stream_timer = + from_timer(stream_timer, t, timer); + struct snd_pcm_substream *substream = stream_timer->substream; + struct rpmsg_info *info = stream_timer->info; + struct rpmsg_msg *msg; + + if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { + msg = &info->msg[TX_PERIOD_DONE + MSG_TYPE_A_NUM]; + msg->s_msg.header.cmd = TX_PERIOD_DONE; + } else { + msg = &info->msg[RX_PERIOD_DONE + MSG_TYPE_A_NUM]; + msg->s_msg.header.cmd = RX_PERIOD_DONE; + } + + imx_rpmsg_insert_workqueue(substream, msg, info); +} + +static int imx_rpmsg_pcm_open(struct snd_soc_component *component, + struct snd_pcm_substream *substream) +{ + struct rpmsg_info *info = dev_get_drvdata(component->dev); + struct rpmsg_msg *msg; + int ret = 0; + int cmd; + + if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { + msg = &info->msg[TX_OPEN]; + msg->s_msg.header.cmd = TX_OPEN; + + /* reinitialize buffer counter*/ + cmd = TX_PERIOD_DONE + MSG_TYPE_A_NUM; + info->msg[cmd].s_msg.param.buffer_tail = 0; + info->msg[cmd].r_msg.param.buffer_tail = 0; + info->msg[TX_POINTER].r_msg.param.buffer_offset = 0; + + } else { + msg = &info->msg[RX_OPEN]; + msg->s_msg.header.cmd = RX_OPEN; + + /* reinitialize buffer counter*/ + cmd = RX_PERIOD_DONE + MSG_TYPE_A_NUM; + info->msg[cmd].s_msg.param.buffer_tail = 0; + info->msg[cmd].r_msg.param.buffer_tail = 0; + info->msg[RX_POINTER].r_msg.param.buffer_offset = 0; + } + + info->send_message(msg, info); + + imx_rpmsg_pcm_hardware.period_bytes_max = + imx_rpmsg_pcm_hardware.buffer_bytes_max / 2; + + snd_soc_set_runtime_hwparams(substream, &imx_rpmsg_pcm_hardware); + + ret = snd_pcm_hw_constraint_integer(substream->runtime, + SNDRV_PCM_HW_PARAM_PERIODS); + if (ret < 0) + return ret; + + info->msg_drop_count[substream->stream] = 0; + + /* Create timer*/ + info->stream_timer[substream->stream].info = info; + info->stream_timer[substream->stream].substream = substream; + timer_setup(&info->stream_timer[substream->stream].timer, + imx_rpmsg_timer_callback, 0); + return ret; +} + +static int imx_rpmsg_pcm_close(struct snd_soc_component *component, + struct snd_pcm_substream *substream) +{ + struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream); + struct rpmsg_info *info = dev_get_drvdata(component->dev); + struct rpmsg_msg *msg; + int ret = 0; + + /* Flush work in workqueue to make TX_CLOSE is the last message */ + flush_workqueue(info->rpmsg_wq); + + if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { + msg = &info->msg[TX_CLOSE]; + msg->s_msg.header.cmd = TX_CLOSE; + } else { + msg = &info->msg[RX_CLOSE]; + msg->s_msg.header.cmd = RX_CLOSE; + } + + info->send_message(msg, info); + + del_timer(&info->stream_timer[substream->stream].timer); + + rtd->dai_link->ignore_suspend = 0; + + if (info->msg_drop_count[substream->stream]) + dev_warn(rtd->dev, "Msg is dropped!, number is %d\n", + info->msg_drop_count[substream->stream]); + + return ret; +} + +static int imx_rpmsg_pcm_prepare(struct snd_soc_component *component, + struct snd_pcm_substream *substream) +{ + struct snd_pcm_runtime *runtime = substream->runtime; + struct snd_soc_pcm_runtime *rtd = substream->private_data; + struct snd_soc_dai *cpu_dai = asoc_rtd_to_cpu(rtd, 0); + struct fsl_rpmsg *rpmsg = dev_get_drvdata(cpu_dai->dev); + + /* + * NON-MMAP mode, NONBLOCK, Version 2, enable lpa in dts + * four conditions to determine the lpa is enabled. + */ + if ((runtime->access == SNDRV_PCM_ACCESS_RW_INTERLEAVED || + runtime->access == SNDRV_PCM_ACCESS_RW_NONINTERLEAVED) && + rpmsg->enable_lpa) { + /* + * Ignore suspend operation in low power mode + * M core will continue playback music on A core suspend. + */ + rtd->dai_link->ignore_suspend = 1; + rpmsg->force_lpa = 1; + } else { + rpmsg->force_lpa = 0; + } + + return 0; +} + +static int imx_rpmsg_pcm_mmap(struct snd_soc_component *component, + struct snd_pcm_substream *substream, + struct vm_area_struct *vma) +{ + struct snd_pcm_runtime *runtime = substream->runtime; + + return dma_mmap_wc(substream->pcm->card->dev, vma, + runtime->dma_area, + runtime->dma_addr, + runtime->dma_bytes); +} + +static void imx_rpmsg_pcm_dma_complete(void *arg) +{ + struct snd_pcm_substream *substream = arg; + + snd_pcm_period_elapsed(substream); +} + +static int imx_rpmsg_prepare_and_submit(struct snd_soc_component *component, + struct snd_pcm_substream *substream) +{ + struct rpmsg_info *info = dev_get_drvdata(component->dev); + struct rpmsg_msg *msg; + + if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { + msg = &info->msg[TX_BUFFER]; + msg->s_msg.header.cmd = TX_BUFFER; + } else { + msg = &info->msg[RX_BUFFER]; + msg->s_msg.header.cmd = RX_BUFFER; + } + + /* Send buffer address and buffer size */ + msg->s_msg.param.buffer_addr = substream->runtime->dma_addr; + msg->s_msg.param.buffer_size = snd_pcm_lib_buffer_bytes(substream); + msg->s_msg.param.period_size = snd_pcm_lib_period_bytes(substream); + msg->s_msg.param.buffer_tail = 0; + + info->num_period[substream->stream] = msg->s_msg.param.buffer_size / + msg->s_msg.param.period_size; + + info->callback[substream->stream] = imx_rpmsg_pcm_dma_complete; + info->callback_param[substream->stream] = substream; + + return imx_rpmsg_insert_workqueue(substream, msg, info); +} + +static int imx_rpmsg_async_issue_pending(struct snd_soc_component *component, + struct snd_pcm_substream *substream) +{ + struct rpmsg_info *info = dev_get_drvdata(component->dev); + struct rpmsg_msg *msg; + + if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { + msg = &info->msg[TX_START]; + msg->s_msg.header.cmd = TX_START; + } else { + msg = &info->msg[RX_START]; + msg->s_msg.header.cmd = RX_START; + } + + return imx_rpmsg_insert_workqueue(substream, msg, info); +} + +static int imx_rpmsg_restart(struct snd_soc_component *component, + struct snd_pcm_substream *substream) +{ + struct rpmsg_info *info = dev_get_drvdata(component->dev); + struct rpmsg_msg *msg; + + if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { + msg = &info->msg[TX_RESTART]; + msg->s_msg.header.cmd = TX_RESTART; + } else { + msg = &info->msg[RX_RESTART]; + msg->s_msg.header.cmd = RX_RESTART; + } + + return imx_rpmsg_insert_workqueue(substream, msg, info); +} + +static int imx_rpmsg_pause(struct snd_soc_component *component, + struct snd_pcm_substream *substream) +{ + struct rpmsg_info *info = dev_get_drvdata(component->dev); + struct rpmsg_msg *msg; + + if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { + msg = &info->msg[TX_PAUSE]; + msg->s_msg.header.cmd = TX_PAUSE; + } else { + msg = &info->msg[RX_PAUSE]; + msg->s_msg.header.cmd = RX_PAUSE; + } + + return imx_rpmsg_insert_workqueue(substream, msg, info); +} + +static int imx_rpmsg_terminate_all(struct snd_soc_component *component, + struct snd_pcm_substream *substream) +{ + struct rpmsg_info *info = dev_get_drvdata(component->dev); + struct rpmsg_msg *msg; + int cmd; + + if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { + msg = &info->msg[TX_TERMINATE]; + msg->s_msg.header.cmd = TX_TERMINATE; + /* Clear buffer count*/ + cmd = TX_PERIOD_DONE + MSG_TYPE_A_NUM; + info->msg[cmd].s_msg.param.buffer_tail = 0; + info->msg[cmd].r_msg.param.buffer_tail = 0; + info->msg[TX_POINTER].r_msg.param.buffer_offset = 0; + } else { + msg = &info->msg[RX_TERMINATE]; + msg->s_msg.header.cmd = RX_TERMINATE; + /* Clear buffer count*/ + cmd = RX_PERIOD_DONE + MSG_TYPE_A_NUM; + info->msg[cmd].s_msg.param.buffer_tail = 0; + info->msg[cmd].r_msg.param.buffer_tail = 0; + info->msg[RX_POINTER].r_msg.param.buffer_offset = 0; + } + + del_timer(&info->stream_timer[substream->stream].timer); + + return imx_rpmsg_insert_workqueue(substream, msg, info); +} + +static int imx_rpmsg_pcm_trigger(struct snd_soc_component *component, + struct snd_pcm_substream *substream, int cmd) +{ + struct snd_pcm_runtime *runtime = substream->runtime; + struct snd_soc_pcm_runtime *rtd = substream->private_data; + struct snd_soc_dai *cpu_dai = asoc_rtd_to_cpu(rtd, 0); + struct fsl_rpmsg *rpmsg = dev_get_drvdata(cpu_dai->dev); + int ret = 0; + + switch (cmd) { + case SNDRV_PCM_TRIGGER_START: + ret = imx_rpmsg_prepare_and_submit(component, substream); + if (ret) + return ret; + ret = imx_rpmsg_async_issue_pending(component, substream); + break; + case SNDRV_PCM_TRIGGER_RESUME: + if (rpmsg->force_lpa) + break; + fallthrough; + case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: + ret = imx_rpmsg_restart(component, substream); + break; + case SNDRV_PCM_TRIGGER_SUSPEND: + if (!rpmsg->force_lpa) { + if (runtime->info & SNDRV_PCM_INFO_PAUSE) + ret = imx_rpmsg_pause(component, substream); + else + ret = imx_rpmsg_terminate_all(component, substream); + } + break; + case SNDRV_PCM_TRIGGER_PAUSE_PUSH: + ret = imx_rpmsg_pause(component, substream); + break; + case SNDRV_PCM_TRIGGER_STOP: + ret = imx_rpmsg_terminate_all(component, substream); + break; + default: + return -EINVAL; + } + + if (ret) + return ret; + + return 0; +} + +/* + * imx_rpmsg_pcm_ack + * + * Send the period index to M core through rpmsg, but not send + * all the period index to M core, reduce some unnessesary msg + * to reduce the pressure of rpmsg bandwidth. + */ +static int imx_rpmsg_pcm_ack(struct snd_soc_component *component, + struct snd_pcm_substream *substream) +{ + struct snd_pcm_runtime *runtime = substream->runtime; + struct snd_soc_pcm_runtime *rtd = substream->private_data; + struct snd_soc_dai *cpu_dai = asoc_rtd_to_cpu(rtd, 0); + struct fsl_rpmsg *rpmsg = dev_get_drvdata(cpu_dai->dev); + struct rpmsg_info *info = dev_get_drvdata(component->dev); + snd_pcm_uframes_t period_size = runtime->period_size; + snd_pcm_sframes_t avail; + struct timer_list *timer; + struct rpmsg_msg *msg; + unsigned long flags; + int buffer_tail = 0; + int written_num = 0; + + if (!rpmsg->force_lpa) + return 0; + + if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { + msg = &info->msg[TX_PERIOD_DONE + MSG_TYPE_A_NUM]; + msg->s_msg.header.cmd = TX_PERIOD_DONE; + } else { + msg = &info->msg[RX_PERIOD_DONE + MSG_TYPE_A_NUM]; + msg->s_msg.header.cmd = RX_PERIOD_DONE; + } + + msg->s_msg.header.type = MSG_TYPE_C; + + buffer_tail = (frames_to_bytes(runtime, runtime->control->appl_ptr) % + snd_pcm_lib_buffer_bytes(substream)); + buffer_tail = buffer_tail / snd_pcm_lib_period_bytes(substream); + + /* There is update for period index */ + if (buffer_tail != msg->s_msg.param.buffer_tail) { + written_num = buffer_tail - msg->s_msg.param.buffer_tail; + if (written_num < 0) + written_num += runtime->periods; + + msg->s_msg.param.buffer_tail = buffer_tail; + + /* The notification message is updated to latest */ + spin_lock_irqsave(&info->lock[substream->stream], flags); + memcpy(&info->notify[substream->stream], msg, + sizeof(struct rpmsg_s_msg)); + info->notify_updated[substream->stream] = true; + spin_unlock_irqrestore(&info->lock[substream->stream], flags); + + if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) + avail = snd_pcm_playback_hw_avail(runtime); + else + avail = snd_pcm_capture_hw_avail(runtime); + + timer = &info->stream_timer[substream->stream].timer; + /* + * If the data in the buffer is less than one period before + * this fill, which means the data may not enough on M + * core side, we need to send message immediately to let + * M core know the pointer is updated. + * if there is more than one period data in the buffer before + * this fill, which means the data is enough on M core side, + * we can delay one period (using timer) to send the message + * for reduce the message number in workqueue, because the + * pointer may be updated by ack function later, we can + * send latest pointer to M core side. + */ + if ((avail - written_num * period_size) <= period_size) { + imx_rpmsg_insert_workqueue(substream, msg, info); + } else if (rpmsg->force_lpa && !timer_pending(timer)) { + int time_msec; + + time_msec = (int)(runtime->period_size * 1000 / runtime->rate); + mod_timer(timer, jiffies + msecs_to_jiffies(time_msec)); + } + } + + return 0; +} + +static int imx_rpmsg_pcm_preallocate_dma_buffer(struct snd_pcm *pcm, + int stream, int size) +{ + struct snd_pcm_substream *substream = pcm->streams[stream].substream; + struct snd_dma_buffer *buf = &substream->dma_buffer; + + buf->dev.type = SNDRV_DMA_TYPE_DEV; + buf->dev.dev = pcm->card->dev; + buf->private_data = NULL; + buf->area = dma_alloc_wc(pcm->card->dev, size, + &buf->addr, GFP_KERNEL); + if (!buf->area) + return -ENOMEM; + + buf->bytes = size; + return 0; +} + +static void imx_rpmsg_pcm_free_dma_buffers(struct snd_soc_component *component, + struct snd_pcm *pcm) +{ + struct snd_pcm_substream *substream; + struct snd_dma_buffer *buf; + int stream; + + for (stream = SNDRV_PCM_STREAM_PLAYBACK; + stream < SNDRV_PCM_STREAM_LAST; stream++) { + substream = pcm->streams[stream].substream; + if (!substream) + continue; + + buf = &substream->dma_buffer; + if (!buf->area) + continue; + + dma_free_wc(pcm->card->dev, buf->bytes, + buf->area, buf->addr); + buf->area = NULL; + } +} + +static int imx_rpmsg_pcm_new(struct snd_soc_component *component, + struct snd_soc_pcm_runtime *rtd) +{ + struct snd_card *card = rtd->card->snd_card; + struct snd_pcm *pcm = rtd->pcm; + struct snd_soc_dai *cpu_dai = asoc_rtd_to_cpu(rtd, 0); + struct fsl_rpmsg *rpmsg = dev_get_drvdata(cpu_dai->dev); + int ret; + + ret = dma_coerce_mask_and_coherent(card->dev, DMA_BIT_MASK(32)); + if (ret) + return ret; + + if (pcm->streams[SNDRV_PCM_STREAM_PLAYBACK].substream) { + ret = imx_rpmsg_pcm_preallocate_dma_buffer(pcm, SNDRV_PCM_STREAM_PLAYBACK, + rpmsg->buffer_size); + if (ret) + goto out; + } + + if (pcm->streams[SNDRV_PCM_STREAM_CAPTURE].substream) { + ret = imx_rpmsg_pcm_preallocate_dma_buffer(pcm, SNDRV_PCM_STREAM_CAPTURE, + rpmsg->buffer_size); + if (ret) + goto out; + } + + imx_rpmsg_pcm_hardware.buffer_bytes_max = rpmsg->buffer_size; +out: + /* free preallocated buffers in case of error */ + if (ret) + imx_rpmsg_pcm_free_dma_buffers(component, pcm); + + return ret; +} + +static const struct snd_soc_component_driver imx_rpmsg_soc_component = { + .name = IMX_PCM_DRV_NAME, + .pcm_construct = imx_rpmsg_pcm_new, + .pcm_destruct = imx_rpmsg_pcm_free_dma_buffers, + .open = imx_rpmsg_pcm_open, + .close = imx_rpmsg_pcm_close, + .hw_params = imx_rpmsg_pcm_hw_params, + .hw_free = imx_rpmsg_pcm_hw_free, + .trigger = imx_rpmsg_pcm_trigger, + .pointer = imx_rpmsg_pcm_pointer, + .mmap = imx_rpmsg_pcm_mmap, + .ack = imx_rpmsg_pcm_ack, + .prepare = imx_rpmsg_pcm_prepare, +}; + +static void imx_rpmsg_pcm_work(struct work_struct *work) +{ + struct work_of_rpmsg *work_of_rpmsg; + bool is_notification = false; + struct rpmsg_info *info; + struct rpmsg_msg msg; + unsigned long flags; + + work_of_rpmsg = container_of(work, struct work_of_rpmsg, work); + info = work_of_rpmsg->info; + + /* + * Every work in the work queue, first we check if there + * is update for period is filled, because there may be not + * enough data in M core side, need to let M core know + * data is updated immediately. + */ + spin_lock_irqsave(&info->lock[TX], flags); + if (info->notify_updated[TX]) { + memcpy(&msg, &info->notify[TX], sizeof(struct rpmsg_s_msg)); + info->notify_updated[TX] = false; + spin_unlock_irqrestore(&info->lock[TX], flags); + info->send_message(&msg, info); + } else { + spin_unlock_irqrestore(&info->lock[TX], flags); + } + + spin_lock_irqsave(&info->lock[RX], flags); + if (info->notify_updated[RX]) { + memcpy(&msg, &info->notify[RX], sizeof(struct rpmsg_s_msg)); + info->notify_updated[RX] = false; + spin_unlock_irqrestore(&info->lock[RX], flags); + info->send_message(&msg, info); + } else { + spin_unlock_irqrestore(&info->lock[RX], flags); + } + + /* Skip the notification message for it has been processed above */ + if (work_of_rpmsg->msg.s_msg.header.type == MSG_TYPE_C && + (work_of_rpmsg->msg.s_msg.header.cmd == TX_PERIOD_DONE || + work_of_rpmsg->msg.s_msg.header.cmd == RX_PERIOD_DONE)) + is_notification = true; + + if (!is_notification) + info->send_message(&work_of_rpmsg->msg, info); + + /* update read index */ + spin_lock_irqsave(&info->wq_lock, flags); + info->work_read_index++; + info->work_read_index %= WORK_MAX_NUM; + spin_unlock_irqrestore(&info->wq_lock, flags); +} + +static int imx_rpmsg_pcm_probe(struct platform_device *pdev) +{ + struct snd_soc_component *component; + struct rpmsg_info *info; + int ret, i; + + info = devm_kzalloc(&pdev->dev, sizeof(*info), GFP_KERNEL); + if (!info) + return -ENOMEM; + + platform_set_drvdata(pdev, info); + + 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", + WQ_HIGHPRI | + WQ_UNBOUND | + WQ_FREEZABLE); + if (!info->rpmsg_wq) { + dev_err(&pdev->dev, "workqueue create failed\n"); + return -ENOMEM; + } + + /* Write index initialize 1, make it differ with the read index */ + info->work_write_index = 1; + info->send_message = imx_rpmsg_pcm_send_message; + + for (i = 0; i < WORK_MAX_NUM; i++) { + INIT_WORK(&info->work_list[i].work, imx_rpmsg_pcm_work); + info->work_list[i].info = info; + } + + /* Initialize msg */ + for (i = 0; i < MSG_MAX_NUM; i++) { + info->msg[i].s_msg.header.cate = IMX_RPMSG_AUDIO; + info->msg[i].s_msg.header.major = IMX_RMPSG_MAJOR; + info->msg[i].s_msg.header.minor = IMX_RMPSG_MINOR; + info->msg[i].s_msg.header.type = MSG_TYPE_A; + info->msg[i].s_msg.param.audioindex = 0; + } + + init_completion(&info->cmd_complete); + mutex_init(&info->msg_lock); + spin_lock_init(&info->lock[TX]); + spin_lock_init(&info->lock[RX]); + spin_lock_init(&info->wq_lock); + + ret = devm_snd_soc_register_component(&pdev->dev, + &imx_rpmsg_soc_component, + NULL, 0); + if (ret) + goto fail; + + component = snd_soc_lookup_component(&pdev->dev, IMX_PCM_DRV_NAME); + if (!component) { + ret = -EINVAL; + goto fail; + } +#ifdef CONFIG_DEBUG_FS + component->debugfs_prefix = "rpmsg"; +#endif + + return 0; + +fail: + if (info->rpmsg_wq) + destroy_workqueue(info->rpmsg_wq); + + return ret; +} + +static int imx_rpmsg_pcm_remove(struct platform_device *pdev) +{ + struct rpmsg_info *info = platform_get_drvdata(pdev); + + if (info->rpmsg_wq) + destroy_workqueue(info->rpmsg_wq); + + return 0; +} + +#ifdef CONFIG_PM +static int imx_rpmsg_pcm_runtime_resume(struct device *dev) +{ + struct rpmsg_info *info = dev_get_drvdata(dev); + + cpu_latency_qos_add_request(&info->pm_qos_req, 0); + + return 0; +} + +static int imx_rpmsg_pcm_runtime_suspend(struct device *dev) +{ + struct rpmsg_info *info = dev_get_drvdata(dev); + + cpu_latency_qos_remove_request(&info->pm_qos_req); + + return 0; +} +#endif + +#ifdef CONFIG_PM_SLEEP +static int imx_rpmsg_pcm_suspend(struct device *dev) +{ + struct rpmsg_info *info = dev_get_drvdata(dev); + struct rpmsg_msg *rpmsg_tx; + struct rpmsg_msg *rpmsg_rx; + + rpmsg_tx = &info->msg[TX_SUSPEND]; + rpmsg_rx = &info->msg[RX_SUSPEND]; + + rpmsg_tx->s_msg.header.cmd = TX_SUSPEND; + info->send_message(rpmsg_tx, info); + + rpmsg_rx->s_msg.header.cmd = RX_SUSPEND; + info->send_message(rpmsg_rx, info); + + return 0; +} + +static int imx_rpmsg_pcm_resume(struct device *dev) +{ + struct rpmsg_info *info = dev_get_drvdata(dev); + struct rpmsg_msg *rpmsg_tx; + struct rpmsg_msg *rpmsg_rx; + + rpmsg_tx = &info->msg[TX_RESUME]; + rpmsg_rx = &info->msg[RX_RESUME]; + + rpmsg_tx->s_msg.header.cmd = TX_RESUME; + info->send_message(rpmsg_tx, info); + + rpmsg_rx->s_msg.header.cmd = RX_RESUME; + info->send_message(rpmsg_rx, info); + + return 0; +} +#endif /* CONFIG_PM_SLEEP */ + +static const struct dev_pm_ops imx_rpmsg_pcm_pm_ops = { + SET_RUNTIME_PM_OPS(imx_rpmsg_pcm_runtime_suspend, + imx_rpmsg_pcm_runtime_resume, + NULL) + SET_SYSTEM_SLEEP_PM_OPS(imx_rpmsg_pcm_suspend, + imx_rpmsg_pcm_resume) +}; + +static struct platform_driver imx_pcm_rpmsg_driver = { + .probe = imx_rpmsg_pcm_probe, + .remove = imx_rpmsg_pcm_remove, + .driver = { + .name = IMX_PCM_DRV_NAME, + .pm = &imx_rpmsg_pcm_pm_ops, + }, +}; +module_platform_driver(imx_pcm_rpmsg_driver); + +MODULE_DESCRIPTION("Freescale SoC Audio RPMSG PCM interface"); +MODULE_AUTHOR("Shengjiu Wang "); +MODULE_ALIAS("platform:" IMX_PCM_DRV_NAME); +MODULE_LICENSE("GPL v2"); diff --git a/sound/soc/fsl/imx-pcm-rpmsg.h b/sound/soc/fsl/imx-pcm-rpmsg.h new file mode 100644 index 000000000000..308d153920a3 --- /dev/null +++ b/sound/soc/fsl/imx-pcm-rpmsg.h @@ -0,0 +1,512 @@ +/* SPDX-License-Identifier: GPL-2.0+ */ +/* + * Copyright 2017-2021 NXP + * + ****************************************************************************** + * Communication stack of audio with rpmsg + ****************************************************************************** + * Packet structure: + * A SRTM message consists of a 10 bytes header followed by 0~N bytes of data + * + * +---------------+-------------------------------+ + * | | Content | + * +---------------+-------------------------------+ + * | Byte Offset | 7 6 5 4 3 2 1 0 | + * +---------------+---+---+---+---+---+---+---+---+ + * | 0 | Category | + * +---------------+---+---+---+---+---+---+---+---+ + * | 1 ~ 2 | Version | + * +---------------+---+---+---+---+---+---+---+---+ + * | 3 | Type | + * +---------------+---+---+---+---+---+---+---+---+ + * | 4 | Command | + * +---------------+---+---+---+---+---+---+---+---+ + * | 5 | Reserved0 | + * +---------------+---+---+---+---+---+---+---+---+ + * | 6 | Reserved1 | + * +---------------+---+---+---+---+---+---+---+---+ + * | 7 | Reserved2 | + * +---------------+---+---+---+---+---+---+---+---+ + * | 8 | Reserved3 | + * +---------------+---+---+---+---+---+---+---+---+ + * | 9 | Reserved4 | + * +---------------+---+---+---+---+---+---+---+---+ + * | 10 | DATA 0 | + * +---------------+---+---+---+---+---+---+---+---+ + * : : : : : : : : : : : : : + * +---------------+---+---+---+---+---+---+---+---+ + * | N + 10 - 1 | DATA N-1 | + * +---------------+---+---+---+---+---+---+---+---+ + * + * +----------+------------+------------------------------------------------+ + * | Field | Byte | | + * +----------+------------+------------------------------------------------+ + * | Category | 0 | The destination category. | + * +----------+------------+------------------------------------------------+ + * | Version | 1 ~ 2 | The category version of the sender of the | + * | | | packet. | + * | | | The first byte represent the major version of | + * | | | the packet.The second byte represent the minor | + * | | | version of the packet. | + * +----------+------------+------------------------------------------------+ + * | Type | 3 | The message type of current message packet. | + * +----------+------------+------------------------------------------------+ + * | Command | 4 | The command byte sent to remote processor/SoC. | + * +----------+------------+------------------------------------------------+ + * | Reserved | 5 ~ 9 | Reserved field for future extension. | + * +----------+------------+------------------------------------------------+ + * | Data | N | The data payload of the message packet. | + * +----------+------------+------------------------------------------------+ + * + * Audio control: + * SRTM Audio Control Category Request Command Table: + * +----------+---------+------+---------+-------------------------------+-----------------------+ + * | Category | Version | Type | Command | Data | Function | + * +----------+---------+------+---------+-------------------------------+-----------------------+ + * | 0x03 | 0x0100 | 0x00 | 0x00 | Data[0]: Audio Device Index | Open a TX Instance. | + * | | | | | Data[1]: format | | + * | | | | | Data[2]: channels | | + * | | | | | Data[3-6]: samplerate | | + * | | | | | Data[7-10]: buffer_addr | | + * | | | | | Data[11-14]: buffer_size | | + * | | | | | Data[15-18]: period_size | | + * | | | | | Data[19-22]: buffer_tail | | + * +----------+---------+------+---------+-------------------------------+-----------------------+ + * | 0x03 | 0x0100 | 0x00 | 0x01 | Data[0]: Audio Device Index | Start a TX Instance. | + * | | | | | Same as above command | | + * +----------+---------+------+---------+-------------------------------+-----------------------+ + * | 0x03 | 0x0100 | 0x00 | 0x02 | Data[0]: Audio Device Index | Pause a TX Instance. | + * | | | | | Same as above command | | + * +----------+---------+------+---------+-------------------------------+-----------------------+ + * | 0x03 | 0x0100 | 0x00 | 0x03 | Data[0]: Audio Device Index | Resume a TX Instance. | + * +----------+---------+------+---------+-------------------------------+-----------------------+ + * | 0x03 | 0x0100 | 0x00 | 0x04 | Data[0]: Audio Device Index | Stop a TX Instance. | + * +----------+---------+------+---------+-------------------------------+-----------------------+ + * | 0x03 | 0x0100 | 0x00 | 0x05 | Data[0]: Audio Device Index | Close a TX Instance. | + * +----------+---------+------+---------+-------------------------------+-----------------------+ + * | 0x03 | 0x0100 | 0x00 | 0x06 | Data[0]: Audio Device Index | Set Parameters for | + * | | | | | Data[1]: format | a TX Instance. | + * | | | | | Data[2]: channels | | + * | | | | | Data[3-6]: samplerate | | + * | | | | | Data[7-22]: reserved | | + * +----------+---------+------+---------+-------------------------------+-----------------------+ + * | 0x03 | 0x0100 | 0x00 | 0x07 | Data[0]: Audio Device Index | Set TX Buffer. | + * | | | | | Data[1-6]: reserved | | + * | | | | | Data[7-10]: buffer_addr | | + * | | | | | Data[11-14]: buffer_size | | + * | | | | | Data[15-18]: period_size | | + * | | | | | Data[19-22]: buffer_tail | | + * +----------+---------+------+---------+-------------------------------+-----------------------+ + * | 0x03 | 0x0100 | 0x00 | 0x08 | Data[0]: Audio Device Index | Suspend a TX Instance | + * +----------+---------+------+---------+-------------------------------+-----------------------+ + * | 0x03 | 0x0100 | 0x00 | 0x09 | Data[0]: Audio Device Index | Resume a TX Instance. | + * | | | | | Data[1]: format | | + * | | | | | Data[2]: channels | | + * | | | | | Data[3-6]: samplerate | | + * | | | | | Data[7-10]: buffer_addr | | + * | | | | | Data[11-14]: buffer_size | | + * | | | | | Data[15-18]: period_size | | + * | | | | | Data[19-22]: buffer_tail | | + * +----------+---------+------+---------+-------------------------------+-----------------------+ + * | 0x03 | 0x0100 | 0x00 | 0x0A | Data[0]: Audio Device Index | Open a RX Instance. | + * +----------+---------+------+---------+-------------------------------+-----------------------+ + * | 0x03 | 0x0100 | 0x00 | 0x0B | Data[0]: Audio Device Index | Start a RX Instance. | + * +----------+---------+------+---------+-------------------------------+-----------------------+ + * | 0x03 | 0x0100 | 0x00 | 0x0C | Data[0]: Audio Device Index | Pause a RX Instance. | + * +----------+---------+------+---------+-------------------------------+-----------------------+ + * | 0x03 | 0x0100 | 0x00 | 0x0D | Data[0]: Audio Device Index | Resume a RX Instance. | + * +----------+---------+------+---------+-------------------------------+-----------------------+ + * | 0x03 | 0x0100 | 0x00 | 0x0E | Data[0]: Audio Device Index | Stop a RX Instance. | + * +----------+---------+------+---------+-------------------------------+-----------------------+ + * | 0x03 | 0x0100 | 0x00 | 0x0F | Data[0]: Audio Device Index | Close a RX Instance. | + * +----------+---------+------+---------+-------------------------------+-----------------------+ + * | 0x03 | 0x0100 | 0x00 | 0x10 | Data[0]: Audio Device Index | Set Parameters for | + * | | | | | Data[1]: format | a RX Instance. | + * | | | | | Data[2]: channels | | + * | | | | | Data[3-6]: samplerate | | + * | | | | | Data[7-22]: reserved | | + * +----------+---------+------+---------+-------------------------------+-----------------------+ + * | 0x03 | 0x0100 | 0x00 | 0x11 | Data[0]: Audio Device Index | Set RX Buffer. | + * | | | | | Data[1-6]: reserved | | + * | | | | | Data[7-10]: buffer_addr | | + * | | | | | Data[11-14]: buffer_size | | + * | | | | | Data[15-18]: period_size | | + * | | | | | Data[19-22]: buffer_tail | | + * +----------+---------+------+---------+-------------------------------+-----------------------+ + * | 0x03 | 0x0100 | 0x00 | 0x12 | Data[0]: Audio Device Index | Suspend a RX Instance.| + * +----------+---------+------+---------+-------------------------------+-----------------------+ + * | 0x03 | 0x0100 | 0x00 | 0x13 | Data[0]: Audio Device Index | Resume a RX Instance. | + * | | | | | Data[1]: format | | + * | | | | | Data[2]: channels | | + * | | | | | Data[3-6]: samplerate | | + * | | | | | Data[7-10]: buffer_addr | | + * | | | | | Data[11-14]: buffer_size | | + * | | | | | Data[15-18]: period_size | | + * | | | | | Data[19-22]: buffer_tail | | + * +----------+---------+------+---------+-------------------------------+-----------------------+ + * | 0x03 | 0x0100 | 0x00 | 0x14 | Data[0]: Audio Device Index | Set register value | + * | | | | | Data[1-6]: reserved | to codec | + * | | | | | Data[7-10]: register | | + * | | | | | Data[11-14]: value | | + * | | | | | Data[15-22]: reserved | | + * +----------+---------+------+---------+-------------------------------+-----------------------+ + * | 0x03 | 0x0100 | 0x00 | 0x15 | Data[0]: Audio Device Index | Get register value | + * | | | | | Data[1-6]: reserved | from codec | + * | | | | | Data[7-10]: register | | + * | | | | | Data[11-22]: reserved | | + * +----------+---------+------+---------+-------------------------------+-----------------------+ + * Note 1: See for available value of + * Sample Format; + * Note 2: See for available value of Channels; + * Note 3: Sample Rate of Set Parameters for an Audio TX Instance + * Command and Set Parameters for an Audio RX Instance Command is + * in little-endian format. + * + * SRTM Audio Control Category Response Command Table: + * +----------+---------+------+---------+-------------------------------+-----------------------+ + * | Category | Version | Type | Command | Data | Function | + * +----------+---------+------+---------+-------------------------------+-----------------------+ + * | 0x03 | 0x0100 | 0x01 | 0x00 | Data[0]: Audio Device Index | Reply for Open | + * | | | | | Data[1]: Return code | a TX Instance | + * +----------+---------+------+---------+-------------------------------+-----------------------+ + * | 0x03 | 0x0100 | 0x01 | 0x01 | Data[0]: Audio Device Index | Reply for Start | + * | | | | | Data[1]: Return code | a TX Instance | + * +----------+---------+------+---------+-------------------------------+-----------------------+ + * | 0x03 | 0x0100 | 0x01 | 0x02 | Data[0]: Audio Device Index | Reply for Pause | + * | | | | | Data[1]: Return code | a TX Instance | + * +----------+---------+------+---------+-------------------------------+-----------------------+ + * | 0x03 | 0x0100 | 0x01 | 0x03 | Data[0]: Audio Device Index | Reply for Resume | + * | | | | | Data[1]: Return code | a TX Instance | + * +----------+---------+------+---------+-------------------------------+-----------------------+ + * | 0x03 | 0x0100 | 0x01 | 0x04 | Data[0]: Audio Device Index | Reply for Stop | + * | | | | | Data[1]: Return code | a TX Instance | + * +----------+---------+------+---------+-------------------------------+-----------------------+ + * | 0x03 | 0x0100 | 0x01 | 0x05 | Data[0]: Audio Device Index | Reply for Close | + * | | | | | Data[1]: Return code | a TX Instance | + * +----------+---------+------+---------+-------------------------------+-----------------------+ + * | 0x03 | 0x0100 | 0x01 | 0x06 | Data[0]: Audio Device Index | Reply for Set Param | + * | | | | | Data[1]: Return code | for a TX Instance. | + * +----------+---------+------+---------+-------------------------------+-----------------------+ + * | 0x03 | 0x0100 | 0x01 | 0x07 | Data[0]: Audio Device Index | Reply for Set | + * | | | | | Data[1]: Return code | TX Buffer | + * +----------+---------+------+---------+-------------------------------+-----------------------+ + * | 0x03 | 0x0100 | 0x01 | 0x08 | Data[0]: Audio Device Index | Reply for Suspend | + * | | | | | Data[1]: Return code | a TX Instance | + * +----------+---------+------+---------+-------------------------------+-----------------------+ + * | 0x03 | 0x0100 | 0x01 | 0x09 | Data[0]: Audio Device Index | Reply for Resume | + * | | | | | Data[1]: Return code | a TX Instance | + * +----------+---------+------+---------+-------------------------------+-----------------------+ + * | 0x03 | 0x0100 | 0x01 | 0x0A | Data[0]: Audio Device Index | Reply for Open | + * | | | | | Data[1]: Return code | a TX Instance | + * +----------+---------+------+---------+-------------------------------+-----------------------+ + * | 0x03 | 0x0100 | 0x01 | 0x0B | Data[0]: Audio Device Index | Reply for Start | + * | | | | | Data[1]: Return code | a TX Instance | + * +----------+---------+------+---------+-------------------------------+-----------------------+ + * | 0x03 | 0x0100 | 0x01 | 0x0C | Data[0]: Audio Device Index | Reply for Pause | + * | | | | | Data[1]: Return code | a TX Instance | + * +----------+---------+------+---------+-------------------------------+-----------------------+ + * | 0x03 | 0x0100 | 0x01 | 0x0D | Data[0]: Audio Device Index | Reply for Resume | + * | | | | | Data[1]: Return code | a RX Instance | + * +----------+---------+------+---------+-------------------------------+-----------------------+ + * | 0x03 | 0x0100 | 0x01 | 0x0E | Data[0]: Audio Device Index | Reply for Stop | + * | | | | | Data[1]: Return code | a RX Instance | + * +----------+---------+------+---------+-------------------------------+-----------------------+ + * | 0x03 | 0x0100 | 0x01 | 0x0F | Data[0]: Audio Device Index | Reply for Close | + * | | | | | Data[1]: Return code | a RX Instance | + * +----------+---------+------+---------+-------------------------------+-----------------------+ + * | 0x03 | 0x0100 | 0x01 | 0x10 | Data[0]: Audio Device Index | Reply for Set Param | + * | | | | | Data[1]: Return code | for a RX Instance. | + * +----------+---------+------+---------+-------------------------------+-----------------------+ + * | 0x03 | 0x0100 | 0x01 | 0x11 | Data[0]: Audio Device Index | Reply for Set | + * | | | | | Data[1]: Return code | RX Buffer | + * +----------+---------+------+---------+-------------------------------+-----------------------+ + * | 0x03 | 0x0100 | 0x01 | 0x12 | Data[0]: Audio Device Index | Reply for Suspend | + * | | | | | Data[1]: Return code | a RX Instance | + * +----------+---------+------+---------+-------------------------------+-----------------------+ + * | 0x03 | 0x0100 | 0x01 | 0x13 | Data[0]: Audio Device Index | Reply for Resume | + * | | | | | Data[1]: Return code | a RX Instance | + * +----------+---------+------+---------+-------------------------------+-----------------------+ + * | 0x03 | 0x0100 | 0x01 | 0x14 | Data[0]: Audio Device Index | Reply for Set codec | + * | | | | | Data[1]: Return code | register value | + * +----------+---------+------+---------+-------------------------------+-----------------------+ + * | 0x03 | 0x0100 | 0x01 | 0x15 | Data[0]: Audio Device Index | Reply for Get codec | + * | | | | | Data[1]: Return code | register value | + * | | | | | Data[2-6]: reserved | | + * | | | | | Data[7-10]: register | | + * | | | | | Data[11-14]: value | | + * | | | | | Data[15-22]: reserved | | + * +----------+---------+------+---------+-------------------------------+-----------------------+ + * + * SRTM Audio Control Category Notification Command Table: + * +----------+---------+------+---------+-------------------------------+-----------------------+ + * | Category | Version | Type | Command | Data | Function | + * +----------+---------+------+---------+-------------------------------+-----------------------+ + * | 0x03 | 0x0100 | 0x02 | 0x00 | Data[0]: Audio Device Index | Notify one TX period | + * | | | | | | is finished | + * +----------+---------+------+---------+-------------------------------+-----------------------+ + * | 0x03 | 0x0100 | 0x02 | 0x01 | Data[0]: Audio Device Index | Notify one RX period | + * | | | | | | is finished | + * +----------+---------+------+---------+-------------------------------+-----------------------+ + * + * List of Sample Format: + * +------------------+-----------------------+ + * | Sample Format | Description | + * +------------------+-----------------------+ + * | 0x0 | S16_LE | + * +------------------+-----------------------+ + * | 0x1 | S24_LE | + * +------------------+-----------------------+ + * + * List of Audio Channels + * +------------------+-----------------------+ + * | Audio Channel | Description | + * +------------------+-----------------------+ + * | 0x0 | Left Channel | + * +------------------+-----------------------+ + * | 0x1 | Right Channel | + * +------------------+---------------- ------+ + * | 0x2 | Left & Right Channel | + * +------------------+-----------------------+ + * + */ + +#ifndef _IMX_PCM_RPMSG_H +#define _IMX_PCM_RPMSG_H + +#include +#include +#include + +#define RPMSG_TIMEOUT 1000 + +/* RPMSG Command (TYPE A)*/ +#define TX_OPEN 0x0 +#define TX_START 0x1 +#define TX_PAUSE 0x2 +#define TX_RESTART 0x3 +#define TX_TERMINATE 0x4 +#define TX_CLOSE 0x5 +#define TX_HW_PARAM 0x6 +#define TX_BUFFER 0x7 +#define TX_SUSPEND 0x8 +#define TX_RESUME 0x9 + +#define RX_OPEN 0xA +#define RX_START 0xB +#define RX_PAUSE 0xC +#define RX_RESTART 0xD +#define RX_TERMINATE 0xE +#define RX_CLOSE 0xF +#define RX_HW_PARAM 0x10 +#define RX_BUFFER 0x11 +#define RX_SUSPEND 0x12 +#define RX_RESUME 0x13 +#define SET_CODEC_VALUE 0x14 +#define GET_CODEC_VALUE 0x15 +#define TX_POINTER 0x16 +#define RX_POINTER 0x17 +/* Total msg numver for type A */ +#define MSG_TYPE_A_NUM 0x18 + +/* RPMSG Command (TYPE C)*/ +#define TX_PERIOD_DONE 0x0 +#define RX_PERIOD_DONE 0x1 +/* Total msg numver for type C */ +#define MSG_TYPE_C_NUM 0x2 + +#define MSG_MAX_NUM (MSG_TYPE_A_NUM + MSG_TYPE_C_NUM) + +#define MSG_TYPE_A 0x0 +#define MSG_TYPE_B 0x1 +#define MSG_TYPE_C 0x2 + +#define RESP_NONE 0x0 +#define RESP_NOT_ALLOWED 0x1 +#define RESP_SUCCESS 0x2 +#define RESP_FAILED 0x3 + +#define RPMSG_S16_LE 0x0 +#define RPMSG_S24_LE 0x1 +#define RPMSG_S32_LE 0x2 +#define RPMSG_DSD_U16_LE 0x3 +#define RPMSG_DSD_U24_LE 0x4 +#define RPMSG_DSD_U32_LE 0x5 + +#define RPMSG_CH_LEFT 0x0 +#define RPMSG_CH_RIGHT 0x1 +#define RPMSG_CH_STEREO 0x2 + +#define WORK_MAX_NUM 0x30 + +/* Category define */ +#define IMX_RMPSG_LIFECYCLE 1 +#define IMX_RPMSG_PMIC 2 +#define IMX_RPMSG_AUDIO 3 +#define IMX_RPMSG_KEY 4 +#define IMX_RPMSG_GPIO 5 +#define IMX_RPMSG_RTC 6 +#define IMX_RPMSG_SENSOR 7 + +/* rpmsg version */ +#define IMX_RMPSG_MAJOR 1 +#define IMX_RMPSG_MINOR 0 + +#define TX SNDRV_PCM_STREAM_PLAYBACK +#define RX SNDRV_PCM_STREAM_CAPTURE + +/** + * struct rpmsg_head: rpmsg header structure + * + * @cate: category + * @major: major version + * @minor: minor version + * @type: message type (A/B/C) + * @cmd: message command + * @reserved: reserved space + */ +struct rpmsg_head { + u8 cate; + u8 major; + u8 minor; + u8 type; + u8 cmd; + u8 reserved[5]; +} __packed; + +/** + * struct param_s: sent rpmsg parameter + * + * @audioindex: audio instance index + * @format: audio format + * @channels: audio channel number + * @rate: sample rate + * @buffer_addr: dma buffer physical address or register for SET_CODEC_VALUE + * @buffer_size: dma buffer size or register value for SET_CODEC_VALUE + * @period_size: period size + * @buffer_tail: current period index + */ +struct param_s { + unsigned char audioindex; + unsigned char format; + unsigned char channels; + unsigned int rate; + unsigned int buffer_addr; + unsigned int buffer_size; + unsigned int period_size; + unsigned int buffer_tail; +} __packed; + +/** + * struct param_s: send rpmsg parameter + * + * @audioindex: audio instance index + * @resp: response value + * @reserved1: reserved space + * @buffer_offset: the consumed offset of buffer + * @reg_addr: register addr of codec + * @reg_data: register value of codec + * @reserved2: reserved space + * @buffer_tail: current period index + */ +struct param_r { + unsigned char audioindex; + unsigned char resp; + unsigned char reserved1[1]; + unsigned int buffer_offset; + unsigned int reg_addr; + unsigned int reg_data; + unsigned char reserved2[4]; + unsigned int buffer_tail; +} __packed; + +/* Struct of sent message */ +struct rpmsg_s_msg { + struct rpmsg_head header; + struct param_s param; +}; + +/* Struct of received message */ +struct rpmsg_r_msg { + struct rpmsg_head header; + struct param_r param; +}; + +/* Struct of rpmsg */ +struct rpmsg_msg { + struct rpmsg_s_msg s_msg; + struct rpmsg_r_msg r_msg; +}; + +/* Struct of rpmsg for workqueue */ +struct work_of_rpmsg { + struct rpmsg_info *info; + /* Sent msg for each work */ + struct rpmsg_msg msg; + struct work_struct work; +}; + +/* Struct of timer */ +struct stream_timer { + struct timer_list timer; + struct rpmsg_info *info; + struct snd_pcm_substream *substream; +}; + +typedef void (*dma_callback)(void *arg); + +/** + * struct rpmsg_info: rpmsg audio information + * + * @rpdev: pointer of rpmsg_device + * @dev: pointer for imx_pcm_rpmsg device + * @cmd_complete: command is finished + * @pm_qos_req: request of pm qos + * @r_msg: received rpmsg + * @msg: array of rpmsg + * @notify: notification msg (type C) for TX & RX + * @notify_updated: notification flag for TX & RX + * @rpmsg_wq: rpmsg workqueue + * @work_list: array of work list for workqueue + * @work_write_index: write index of work list + * @work_read_index: read index of work list + * @msg_drop_count: counter of dropped msg for TX & RX + * @num_period: period number for TX & RX + * @callback_param: parameter for period elapse callback for TX & RX + * @callback: period elapse callback for TX & RX + * @send_message: function pointer for send message + * @lock: spin lock for TX & RX + * @wq_lock: lock for work queue + * @msg_lock: lock for send message + * @stream_timer: timer for tigger workqueue + */ +struct rpmsg_info { + struct rpmsg_device *rpdev; + struct device *dev; + struct completion cmd_complete; + struct pm_qos_request pm_qos_req; + + /* Received msg (global) */ + struct rpmsg_r_msg r_msg; + struct rpmsg_msg msg[MSG_MAX_NUM]; + /* period done */ + struct rpmsg_msg notify[2]; + bool notify_updated[2]; + + struct workqueue_struct *rpmsg_wq; + struct work_of_rpmsg work_list[WORK_MAX_NUM]; + int work_write_index; + int work_read_index; + int msg_drop_count[2]; + int num_period[2]; + void *callback_param[2]; + dma_callback callback[2]; + int (*send_message)(struct rpmsg_msg *msg, struct rpmsg_info *info); + spinlock_t lock[2]; /* spin lock for resource protection */ + spinlock_t wq_lock; /* spin lock for resource protection */ + struct mutex msg_lock; /* mutex for resource protection */ + struct stream_timer stream_timer[2]; +}; + +#define IMX_PCM_DRV_NAME "imx_pcm_rpmsg" + +#endif /* IMX_PCM_RPMSG_H */ From 39f8405c3e502e7b9d0533fa0b0bfe715b3e89c1 Mon Sep 17 00:00:00 2001 From: Shengjiu Wang Date: Fri, 12 Mar 2021 10:38:45 +0800 Subject: [PATCH 323/587] ASoC: imx-rpmsg: Add machine driver for audio base on rpmsg The platform device is not registered by device tree or cpu dai driver, it is registered by the rpmsg channel, So add a dedicated machine driver to handle this case. Signed-off-by: Shengjiu Wang Link: https://lore.kernel.org/r/1615516725-4975-7-git-send-email-shengjiu.wang@nxp.com Signed-off-by: Mark Brown --- sound/soc/fsl/Kconfig | 11 +++ sound/soc/fsl/Makefile | 2 + sound/soc/fsl/imx-rpmsg.c | 150 ++++++++++++++++++++++++++++++++++++++ 3 files changed, 163 insertions(+) create mode 100644 sound/soc/fsl/imx-rpmsg.c diff --git a/sound/soc/fsl/Kconfig b/sound/soc/fsl/Kconfig index 3d3d14f3793e..c71c6024320b 100644 --- a/sound/soc/fsl/Kconfig +++ b/sound/soc/fsl/Kconfig @@ -337,6 +337,17 @@ config SND_SOC_IMX_HDMI Say Y if you want to add support for SoC audio on an i.MX board with IMX HDMI. +config SND_SOC_IMX_RPMSG + tristate "SoC Audio support for i.MX boards with rpmsg" + depends on RPMSG + select SND_SOC_IMX_PCM_RPMSG + select SND_SOC_IMX_AUDIO_RPMSG + help + SoC Audio support for i.MX boards with rpmsg. + There should be rpmsg devices defined in other core (M core) + Say Y if you want to add support for SoC audio on an i.MX board with + a rpmsg devices. + endif # SND_IMX_SOC endmenu diff --git a/sound/soc/fsl/Makefile b/sound/soc/fsl/Makefile index ce4f4324c3a2..f146ce464acd 100644 --- a/sound/soc/fsl/Makefile +++ b/sound/soc/fsl/Makefile @@ -70,6 +70,7 @@ snd-soc-imx-sgtl5000-objs := imx-sgtl5000.o snd-soc-imx-spdif-objs := imx-spdif.o snd-soc-imx-audmix-objs := imx-audmix.o snd-soc-imx-hdmi-objs := imx-hdmi.o +snd-soc-imx-rpmsg-objs := imx-rpmsg.o obj-$(CONFIG_SND_SOC_EUKREA_TLV320) += snd-soc-eukrea-tlv320.o obj-$(CONFIG_SND_SOC_IMX_ES8328) += snd-soc-imx-es8328.o @@ -77,3 +78,4 @@ obj-$(CONFIG_SND_SOC_IMX_SGTL5000) += snd-soc-imx-sgtl5000.o obj-$(CONFIG_SND_SOC_IMX_SPDIF) += snd-soc-imx-spdif.o obj-$(CONFIG_SND_SOC_IMX_AUDMIX) += snd-soc-imx-audmix.o obj-$(CONFIG_SND_SOC_IMX_HDMI) += snd-soc-imx-hdmi.o +obj-$(CONFIG_SND_SOC_IMX_RPMSG) += snd-soc-imx-rpmsg.o diff --git a/sound/soc/fsl/imx-rpmsg.c b/sound/soc/fsl/imx-rpmsg.c new file mode 100644 index 000000000000..5a9a470d203f --- /dev/null +++ b/sound/soc/fsl/imx-rpmsg.c @@ -0,0 +1,150 @@ +// SPDX-License-Identifier: GPL-2.0+ +// Copyright 2017-2020 NXP + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "imx-pcm-rpmsg.h" + +struct imx_rpmsg { + struct snd_soc_dai_link dai; + struct snd_soc_card card; +}; + +static const struct snd_soc_dapm_widget imx_rpmsg_dapm_widgets[] = { + SND_SOC_DAPM_HP("Headphone Jack", NULL), + SND_SOC_DAPM_SPK("Ext Spk", NULL), + SND_SOC_DAPM_MIC("Mic Jack", NULL), + SND_SOC_DAPM_MIC("Main MIC", NULL), +}; + +static int imx_rpmsg_probe(struct platform_device *pdev) +{ + struct snd_soc_dai_link_component *dlc; + struct device *dev = pdev->dev.parent; + /* rpmsg_pdev is the platform device for the rpmsg node that probed us */ + struct platform_device *rpmsg_pdev = to_platform_device(dev); + struct device_node *np = rpmsg_pdev->dev.of_node; + struct of_phandle_args args; + struct imx_rpmsg *data; + int ret = 0; + + dlc = devm_kzalloc(&pdev->dev, 3 * sizeof(*dlc), GFP_KERNEL); + if (!dlc) + return -ENOMEM; + + data = devm_kzalloc(&pdev->dev, sizeof(*data), GFP_KERNEL); + if (!data) { + ret = -ENOMEM; + goto fail; + } + + ret = of_reserved_mem_device_init_by_idx(&pdev->dev, np, 0); + if (ret) + dev_warn(&pdev->dev, "no reserved DMA memory\n"); + + data->dai.cpus = &dlc[0]; + data->dai.num_cpus = 1; + data->dai.platforms = &dlc[1]; + data->dai.num_platforms = 1; + data->dai.codecs = &dlc[2]; + data->dai.num_codecs = 1; + + data->dai.name = "rpmsg hifi"; + data->dai.stream_name = "rpmsg hifi"; + data->dai.dai_fmt = SND_SOC_DAIFMT_I2S | + SND_SOC_DAIFMT_NB_NF | + SND_SOC_DAIFMT_CBS_CFS; + + /* Optional codec node */ + ret = of_parse_phandle_with_fixed_args(np, "audio-codec", 0, 0, &args); + if (ret) { + data->dai.codecs->dai_name = "snd-soc-dummy-dai"; + data->dai.codecs->name = "snd-soc-dummy"; + } else { + data->dai.codecs->of_node = args.np; + ret = snd_soc_get_dai_name(&args, &data->dai.codecs->dai_name); + if (ret) { + dev_err(&pdev->dev, "Unable to get codec_dai_name\n"); + goto fail; + } + } + + data->dai.cpus->dai_name = dev_name(&rpmsg_pdev->dev); + data->dai.platforms->name = IMX_PCM_DRV_NAME; + data->dai.playback_only = true; + data->dai.capture_only = true; + data->card.num_links = 1; + data->card.dai_link = &data->dai; + + if (of_property_read_bool(np, "fsl,rpmsg-out")) + data->dai.capture_only = false; + + if (of_property_read_bool(np, "fsl,rpmsg-in")) + data->dai.playback_only = false; + + if (data->dai.playback_only && data->dai.capture_only) { + dev_err(&pdev->dev, "no enabled rpmsg DAI link\n"); + ret = -EINVAL; + goto fail; + } + + data->card.dev = &pdev->dev; + data->card.owner = THIS_MODULE; + data->card.dapm_widgets = imx_rpmsg_dapm_widgets; + data->card.num_dapm_widgets = ARRAY_SIZE(imx_rpmsg_dapm_widgets); + /* + * Inoder to use common api to get card name and audio routing. + * Use parent of_node for this device, revert it after finishing using + */ + data->card.dev->of_node = np; + + ret = snd_soc_of_parse_card_name(&data->card, "model"); + if (ret) + goto fail; + + if (of_property_read_bool(np, "audio-routing")) { + ret = snd_soc_of_parse_audio_routing(&data->card, "audio-routing"); + if (ret) { + dev_err(&pdev->dev, "failed to parse audio-routing: %d\n", ret); + goto fail; + } + } + + platform_set_drvdata(pdev, &data->card); + snd_soc_card_set_drvdata(&data->card, data); + ret = devm_snd_soc_register_card(&pdev->dev, &data->card); + if (ret) { + dev_err(&pdev->dev, "snd_soc_register_card failed (%d)\n", ret); + goto fail; + } + +fail: + pdev->dev.of_node = NULL; + return ret; +} + +static struct platform_driver imx_rpmsg_driver = { + .driver = { + .name = "imx-audio-rpmsg", + .owner = THIS_MODULE, + .pm = &snd_soc_pm_ops, + }, + .probe = imx_rpmsg_probe, +}; +module_platform_driver(imx_rpmsg_driver); + +MODULE_DESCRIPTION("Freescale SoC Audio RPMSG Machine Driver"); +MODULE_AUTHOR("Shengjiu Wang "); +MODULE_ALIAS("platform:imx-audio-rpmsg"); +MODULE_LICENSE("GPL v2"); From 4da40cb9955c63c3aca02be267faea4abbd2c649 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Mon, 22 Mar 2021 11:48:15 +0900 Subject: [PATCH 324/587] ASoC: soc.h: add asoc_link_to_cpu/codec/platform() macro We shouldn't use dai_link->cpus/codecs/platforms directly, because these are array now to supporting multi CPU/Codec/Platform. This patch adds asoc_link_to_xxx() macro for it. Signed-off-by: Kuninori Morimoto Link: https://lore.kernel.org/r/874kh3aopc.wl-kuninori.morimoto.gx@renesas.com Signed-off-by: Mark Brown --- include/sound/soc.h | 24 +++++++++++++++++++++--- 1 file changed, 21 insertions(+), 3 deletions(-) diff --git a/include/sound/soc.h b/include/sound/soc.h index 78609ab331c8..e4161071f300 100644 --- a/include/sound/soc.h +++ b/include/sound/soc.h @@ -716,20 +716,38 @@ struct snd_soc_dai_link { struct snd_soc_dobj dobj; /* For topology */ #endif }; + +static inline struct snd_soc_dai_link_component* +asoc_link_to_cpu(struct snd_soc_dai_link *link, int n) { + return &(link)->cpus[n]; +} + +static inline struct snd_soc_dai_link_component* +asoc_link_to_codec(struct snd_soc_dai_link *link, int n) { + return &(link)->codecs[n]; +} + +static inline struct snd_soc_dai_link_component* +asoc_link_to_platform(struct snd_soc_dai_link *link, int n) { + return &(link)->platforms[n]; +} + #define for_each_link_codecs(link, i, codec) \ for ((i) = 0; \ - ((i) < link->num_codecs) && ((codec) = &link->codecs[i]); \ + ((i) < link->num_codecs) && \ + ((codec) = asoc_link_to_codec(link, i)); \ (i)++) #define for_each_link_platforms(link, i, platform) \ for ((i) = 0; \ ((i) < link->num_platforms) && \ - ((platform) = &link->platforms[i]); \ + ((platform) = asoc_link_to_platform(link, i)); \ (i)++) #define for_each_link_cpus(link, i, cpu) \ for ((i) = 0; \ - ((i) < link->num_cpus) && ((cpu) = &link->cpus[i]); \ + ((i) < link->num_cpus) && \ + ((cpu) = asoc_link_to_cpu(link, i)); \ (i)++) /* From 4a50724eb0ba96b849f4a0c8da28b2b796859f9e Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Mon, 22 Mar 2021 11:48:40 +0900 Subject: [PATCH 325/587] ASoC: soc.h: fixup return timing for snd_soc_fixup_dai_links_platform_name() Current snd_soc_fixup_dai_links_platform_name() creates name first (A), and checks setup target pointer (B), and set it (C). We should check target pointer first IMO. This patch exchange the order to (B) -> (A) -> (C). int snd_soc_fixup_dai_links_platform_name(...) { ... /* set platform name for each dailink */ for_each_card_prelinks(card, i, dai_link) { (A) name = devm_kstrdup(...); if (!name) return -ENOMEM; (B) if (!dai_link->platforms) return -EINVAL; /* only single platform is supported for now */ (C) dai_link->platforms->name = name; } return 0; } Signed-off-by: Kuninori Morimoto Link: https://lore.kernel.org/r/8735wnaoon.wl-kuninori.morimoto.gx@renesas.com Signed-off-by: Mark Brown --- include/sound/soc.h | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/include/sound/soc.h b/include/sound/soc.h index e4161071f300..200815ca4112 100644 --- a/include/sound/soc.h +++ b/include/sound/soc.h @@ -1280,13 +1280,13 @@ int snd_soc_fixup_dai_links_platform_name(struct snd_soc_card *card, /* set platform name for each dailink */ for_each_card_prelinks(card, i, dai_link) { + if (!dai_link->platforms) + return -EINVAL; + name = devm_kstrdup(card->dev, platform_name, GFP_KERNEL); if (!name) return -ENOMEM; - if (!dai_link->platforms) - return -EINVAL; - /* only single platform is supported for now */ dai_link->platforms->name = name; } From d908b922c71791568384336ccc3d12a8cbcd1777 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Mon, 22 Mar 2021 11:48:54 +0900 Subject: [PATCH 326/587] ASoC: soc.h: return error if multi platform at snd_soc_fixup_dai_links_platform_name() snd_soc_fixup_dai_links_platform_name() is assuming it is single platform. return error if multi platforms. Signed-off-by: Kuninori Morimoto Link: https://lore.kernel.org/r/871rc7aoo9.wl-kuninori.morimoto.gx@renesas.com Signed-off-by: Mark Brown --- include/sound/soc.h | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/include/sound/soc.h b/include/sound/soc.h index 200815ca4112..e746da996351 100644 --- a/include/sound/soc.h +++ b/include/sound/soc.h @@ -1280,6 +1280,10 @@ int snd_soc_fixup_dai_links_platform_name(struct snd_soc_card *card, /* set platform name for each dailink */ for_each_card_prelinks(card, i, dai_link) { + /* only single platform is supported for now */ + if (dai_link->num_platforms != 1) + return -EINVAL; + if (!dai_link->platforms) return -EINVAL; From 200d925e236f1a839bd52680f13649b23f727d51 Mon Sep 17 00:00:00 2001 From: Tian Tao Date: Mon, 22 Mar 2021 11:57:56 +0800 Subject: [PATCH 327/587] spi: imx: Use of_device_get_match_data() helper Use the of_device_get_match_data() helper instead of open coding. Signed-off-by: Tian Tao Link: https://lore.kernel.org/r/1616385476-53327-1-git-send-email-tiantao6@hisilicon.com Signed-off-by: Mark Brown --- drivers/spi/spi-imx.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/drivers/spi/spi-imx.c b/drivers/spi/spi-imx.c index 5dc4ea4b4450..916580740e77 100644 --- a/drivers/spi/spi-imx.c +++ b/drivers/spi/spi-imx.c @@ -1548,13 +1548,12 @@ static int spi_imx_slave_abort(struct spi_master *master) static int spi_imx_probe(struct platform_device *pdev) { struct device_node *np = pdev->dev.of_node; - const struct of_device_id *of_id = - of_match_device(spi_imx_dt_ids, &pdev->dev); struct spi_master *master; struct spi_imx_data *spi_imx; struct resource *res; int ret, irq, spi_drctl; - const struct spi_imx_devtype_data *devtype_data = of_id->data; + const struct spi_imx_devtype_data *devtype_data = + of_device_get_match_data(&pdev->dev); bool slave_mode; u32 val; From 9f44673b7af2e776b55b1d15b3a35d8e8eb51331 Mon Sep 17 00:00:00 2001 From: Jack Yu Date: Mon, 22 Mar 2021 13:50:53 +0800 Subject: [PATCH 328/587] ASoC: rt1015: Add bclk detection and dc detection Add bclk detection and dc detection before playback. Signed-off-by: Jack Yu Link: https://lore.kernel.org/r/20210322055053.31797-1-jack.yu@realtek.com Signed-off-by: Mark Brown --- sound/soc/codecs/rt1015.c | 18 +++++++++++++++++- sound/soc/codecs/rt1015.h | 10 ++++++++++ 2 files changed, 27 insertions(+), 1 deletion(-) diff --git a/sound/soc/codecs/rt1015.c b/sound/soc/codecs/rt1015.c index 10a7b7745f4b..9238f12999aa 100644 --- a/sound/soc/codecs/rt1015.c +++ b/sound/soc/codecs/rt1015.c @@ -669,8 +669,23 @@ static int rt1015_amp_drv_event(struct snd_soc_dapm_widget *w, struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm); struct rt1015_priv *rt1015 = snd_soc_component_get_drvdata(component); + unsigned int ret, ret2; switch (event) { + case SND_SOC_DAPM_PRE_PMU: + ret = snd_soc_component_read(component, RT1015_CLK_DET); + ret2 = snd_soc_component_read(component, RT1015_SPK_DC_DETECT1); + if (!((ret >> 15) & 0x1)) { + snd_soc_component_update_bits(component, RT1015_CLK_DET, + RT1015_EN_BCLK_DET_MASK, RT1015_EN_BCLK_DET); + dev_dbg(component->dev, "BCLK Detection Enabled.\n"); + } + if (!((ret2 >> 12) & 0x1)) { + snd_soc_component_update_bits(component, RT1015_SPK_DC_DETECT1, + RT1015_EN_CLA_D_DC_DET_MASK, RT1015_EN_CLA_D_DC_DET); + dev_dbg(component->dev, "Class-D DC Detection Enabled.\n"); + } + break; case SND_SOC_DAPM_POST_PMU: if (rt1015->hw_config == RT1015_HW_28) schedule_delayed_work(&rt1015->flush_work, msecs_to_jiffies(10)); @@ -690,7 +705,8 @@ static const struct snd_soc_dapm_widget rt1015_dapm_widgets[] = { r1015_dac_event, SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD), SND_SOC_DAPM_OUT_DRV_E("Amp Drv", SND_SOC_NOPM, 0, 0, NULL, 0, - rt1015_amp_drv_event, SND_SOC_DAPM_POST_PMU), + rt1015_amp_drv_event, SND_SOC_DAPM_PRE_PMU | + SND_SOC_DAPM_POST_PMU), SND_SOC_DAPM_OUTPUT("SPO"), }; diff --git a/sound/soc/codecs/rt1015.h b/sound/soc/codecs/rt1015.h index 2aeaf65ba793..14344532048e 100644 --- a/sound/soc/codecs/rt1015.h +++ b/sound/soc/codecs/rt1015.h @@ -209,6 +209,11 @@ #define RT1015_PLL_K_MASK (RT1015_PLL_K_MAX) #define RT1015_PLL_K_SFT 0 +/* 0x0020 */ +#define RT1015_EN_BCLK_DET_MASK (0x1 << 15) +#define RT1015_EN_BCLK_DET (0x1 << 15) +#define RT1015_DIS_BCLK_DET (0x0 << 15) + /* 0x007a */ #define RT1015_ID_MASK 0xff #define RT1015_ID_VERA 0x0 @@ -374,6 +379,11 @@ #define RT1015_PWR_SWR (0x1 << 12) #define RT1015_PWR_SWR_BIT 12 +/* 0x0519 */ +#define RT1015_EN_CLA_D_DC_DET_MASK (0x1 << 12) +#define RT1015_EN_CLA_D_DC_DET (0x1 << 12) +#define RT1015_DIS_CLA_D_DC_DET (0x0 << 12) + /* 0x1300 */ #define RT1015_PWR_CLSD (0x1 << 12) #define RT1015_PWR_CLSD_BIT 12 From 7a0d884986f3693aca8a2dc4e1b31d35c508542e Mon Sep 17 00:00:00 2001 From: Ryan Lee Date: Wed, 24 Mar 2021 20:35:55 -0700 Subject: [PATCH 329/587] ASoC: max98373: Added controls for autorestart config 3 new controls are added. "OVC Autorestart Switch" : controls whether or not the speaker amplifier automatically re-enables after an overcurrent fault condition. "THERM Autorestart Switch" : controls whether or not the device automatically resumes playback when the die temperature recovers from thermal shutdown. "CMON Autorestart Switch" : controls whether or not the device automatically resumes playback when the clock returns after stopping. Above Auto Restart functions are enabled by default. Signed-off-by: Ryan Lee Link: https://lore.kernel.org/r/20210325033555.29377-3-ryans.lee@maximintegrated.com Signed-off-by: Mark Brown --- sound/soc/codecs/max98373.c | 14 ++++++++++++++ sound/soc/codecs/max98373.h | 3 +++ 2 files changed, 17 insertions(+) diff --git a/sound/soc/codecs/max98373.c b/sound/soc/codecs/max98373.c index 746c829312b8..b1e43c26dd6b 100644 --- a/sound/soc/codecs/max98373.c +++ b/sound/soc/codecs/max98373.c @@ -202,6 +202,15 @@ SOC_SINGLE("Ramp Up Switch", MAX98373_R203F_AMP_DSP_CFG, MAX98373_AMP_DSP_CFG_RMP_UP_SHIFT, 1, 0), SOC_SINGLE("Ramp Down Switch", MAX98373_R203F_AMP_DSP_CFG, MAX98373_AMP_DSP_CFG_RMP_DN_SHIFT, 1, 0), +/* Speaker Amplifier Overcurrent Automatic Restart Enable */ +SOC_SINGLE("OVC Autorestart Switch", MAX98373_R20FE_DEVICE_AUTO_RESTART_CFG, + MAX98373_OVC_AUTORESTART_SHIFT, 1, 0), +/* Thermal Shutdown Automatic Restart Enable */ +SOC_SINGLE("THERM Autorestart Switch", MAX98373_R20FE_DEVICE_AUTO_RESTART_CFG, + MAX98373_THERM_AUTORESTART_SHIFT, 1, 0), +/* Clock Monitor Automatic Restart Enable */ +SOC_SINGLE("CMON Autorestart Switch", MAX98373_R20FE_DEVICE_AUTO_RESTART_CFG, + MAX98373_CMON_AUTORESTART_SHIFT, 1, 0), SOC_SINGLE("CLK Monitor Switch", MAX98373_R20FE_DEVICE_AUTO_RESTART_CFG, MAX98373_CLOCK_MON_SHIFT, 1, 0), SOC_SINGLE("Dither Switch", MAX98373_R203F_AMP_DSP_CFG, @@ -390,6 +399,11 @@ static int max98373_probe(struct snd_soc_component *component) MAX98373_R2021_PCM_TX_HIZ_EN_2, 1 << (max98373->i_slot - 8), 0); + /* enable auto restart function by default */ + regmap_write(max98373->regmap, + MAX98373_R20FE_DEVICE_AUTO_RESTART_CFG, + 0xF); + /* speaker feedback slot configuration */ regmap_write(max98373->regmap, MAX98373_R2023_PCM_TX_SRC_2, diff --git a/sound/soc/codecs/max98373.h b/sound/soc/codecs/max98373.h index 71f5a5228f34..73a2cf69d84a 100644 --- a/sound/soc/codecs/max98373.h +++ b/sound/soc/codecs/max98373.h @@ -195,6 +195,9 @@ #define MAX98373_LIMITER_EN_SHIFT (0) /* MAX98373_R20FE_DEVICE_AUTO_RESTART_CFG */ +#define MAX98373_OVC_AUTORESTART_SHIFT (3) +#define MAX98373_THERM_AUTORESTART_SHIFT (2) +#define MAX98373_CMON_AUTORESTART_SHIFT (1) #define MAX98373_CLOCK_MON_SHIFT (0) /* MAX98373_R20FF_GLOBAL_SHDN */ From efd0b1660829a987354cea6a446179c7ac7cd0e6 Mon Sep 17 00:00:00 2001 From: Shengjiu Wang Date: Wed, 17 Mar 2021 21:05:02 +0800 Subject: [PATCH 330/587] ASoC: fsl-asoc-card: Add support for WM8958 codec WM8958 codec is used on some i.MX based platform. So add it support in this generic driver. Signed-off-by: Shengjiu Wang Link: https://lore.kernel.org/r/1615986303-27959-1-git-send-email-shengjiu.wang@nxp.com Signed-off-by: Mark Brown --- sound/soc/fsl/Kconfig | 2 ++ sound/soc/fsl/fsl-asoc-card.c | 17 +++++++++++++++-- 2 files changed, 17 insertions(+), 2 deletions(-) diff --git a/sound/soc/fsl/Kconfig b/sound/soc/fsl/Kconfig index d7f30036d434..f4c498f50997 100644 --- a/sound/soc/fsl/Kconfig +++ b/sound/soc/fsl/Kconfig @@ -291,6 +291,8 @@ config SND_SOC_FSL_ASOC_CARD select SND_SOC_FSL_ESAI select SND_SOC_FSL_SAI select SND_SOC_FSL_SSI + select SND_SOC_WM8994 + select MFD_WM8994 help ALSA SoC Audio support with ASRC feature for Freescale SoCs that have ESAI/SAI/SSI and connect with external CODECs such as WM8962, CS42888, diff --git a/sound/soc/fsl/fsl-asoc-card.c b/sound/soc/fsl/fsl-asoc-card.c index f62f81ceab0d..c62bfd1c3ac7 100644 --- a/sound/soc/fsl/fsl-asoc-card.c +++ b/sound/soc/fsl/fsl-asoc-card.c @@ -25,6 +25,7 @@ #include "../codecs/sgtl5000.h" #include "../codecs/wm8962.h" #include "../codecs/wm8960.h" +#include "../codecs/wm8994.h" #define CS427x_SYSCLK_MCLK 0 @@ -37,12 +38,14 @@ /** * struct codec_priv - CODEC private data * @mclk_freq: Clock rate of MCLK + * @free_freq: Clock rate of MCLK for hw_free() * @mclk_id: MCLK (or main clock) id for set_sysclk() * @fll_id: FLL (or secordary clock) id for set_sysclk() * @pll_id: PLL id for set_pll() */ struct codec_priv { unsigned long mclk_freq; + unsigned long free_freq; u32 mclk_id; u32 fll_id; u32 pll_id; @@ -235,10 +238,10 @@ static int fsl_asoc_card_hw_free(struct snd_pcm_substream *substream) priv->streams &= ~BIT(substream->stream); if (!priv->streams && codec_priv->pll_id && codec_priv->fll_id) { - /* Force freq to be 0 to avoid error message in codec */ + /* Force freq to be free_freq to avoid error message in codec */ ret = snd_soc_dai_set_sysclk(asoc_rtd_to_codec(rtd, 0), codec_priv->mclk_id, - 0, + codec_priv->free_freq, SND_SOC_CLOCK_IN); if (ret) { dev_err(dev, "failed to switch away from FLL: %d\n", ret); @@ -665,6 +668,15 @@ static int fsl_asoc_card_probe(struct platform_device *pdev) priv->dai_fmt |= SND_SOC_DAIFMT_CBS_CFS; priv->card.dapm_routes = audio_map_rx; priv->card.num_dapm_routes = ARRAY_SIZE(audio_map_rx); + } else if (of_device_is_compatible(np, "fsl,imx-audio-wm8958")) { + codec_dai_name = "wm8994-aif1"; + priv->dai_fmt |= SND_SOC_DAIFMT_CBM_CFM; + priv->codec_priv.mclk_id = WM8994_FLL_SRC_MCLK1; + priv->codec_priv.fll_id = WM8994_SYSCLK_FLL1; + priv->codec_priv.pll_id = WM8994_FLL1; + priv->codec_priv.free_freq = priv->codec_priv.mclk_freq; + priv->card.dapm_routes = NULL; + priv->card.num_dapm_routes = 0; } else { dev_err(&pdev->dev, "unknown Device Tree compatible\n"); ret = -EINVAL; @@ -882,6 +894,7 @@ static const struct of_device_id fsl_asoc_card_dt_ids[] = { { .compatible = "fsl,imx-audio-mqs", }, { .compatible = "fsl,imx-audio-wm8524", }, { .compatible = "fsl,imx-audio-si476x", }, + { .compatible = "fsl,imx-audio-wm8958", }, {} }; MODULE_DEVICE_TABLE(of, fsl_asoc_card_dt_ids); From df8077c6fe64fe98c1b1c1f9ecf84afc773e726f Mon Sep 17 00:00:00 2001 From: Shengjiu Wang Date: Wed, 17 Mar 2021 21:05:03 +0800 Subject: [PATCH 331/587] ASoC: bindings: fsl-asoc-card: add compatible string for WM8958 codec The WM8958 codec is used on i.MX7D val board. Signed-off-by: Shengjiu Wang Link: https://lore.kernel.org/r/1615986303-27959-2-git-send-email-shengjiu.wang@nxp.com Signed-off-by: Mark Brown --- Documentation/devicetree/bindings/sound/fsl-asoc-card.txt | 2 ++ 1 file changed, 2 insertions(+) diff --git a/Documentation/devicetree/bindings/sound/fsl-asoc-card.txt b/Documentation/devicetree/bindings/sound/fsl-asoc-card.txt index 90d9e9d81624..23d83fa7609f 100644 --- a/Documentation/devicetree/bindings/sound/fsl-asoc-card.txt +++ b/Documentation/devicetree/bindings/sound/fsl-asoc-card.txt @@ -42,6 +42,8 @@ The compatible list for this generic sound card currently: "fsl,imx-audio-si476x" + "fsl,imx-audio-wm8958" + Required properties: - compatible : Contains one of entries in the compatible list. From 99067c07e8d877035f6249d194a317c78b7d052d Mon Sep 17 00:00:00 2001 From: Shengjiu Wang Date: Wed, 3 Mar 2021 11:07:42 +0800 Subject: [PATCH 332/587] ASoC: wm8960: Remove bitclk relax condition in wm8960_configure_sysclk The call sequence in wm8960_configure_clocking is ret = wm8960_configure_sysclk(); if (ret >= 0) goto configure_clock; .... ret = wm8960_configure_pll(); configure_clock: ... wm8960_configure_sysclk is called before wm8960_configure_pll, as there is bitclk relax on both functions, so wm8960_configure_sysclk always return success, then wm8960_configure_pll() never be called. With this case: aplay -Dhw:0,0 -d 5 -r 48000 -f S24_LE -c 2 audio48k24b2c.wav the required bitclk is 48000 * 24 * 2 = 2304000, bitclk got from wm8960_configure_sysclk is 3072000, but if go to wm8960_configure_pll. it can get correct bitclk 2304000. So bitclk relax condition should be removed in wm8960_configure_sysclk, then wm8960_configure_pll can be called, and there is also bitclk relax function in wm8960_configure_pll. Fixes: 3c01b9ee2ab9 ("ASoC: codec: wm8960: Relax bit clock computation") Signed-off-by: Shengjiu Wang Signed-off-by: Daniel Baluta Acked-by: Charles Keepax Link: https://lore.kernel.org/r/1614740862-30196-1-git-send-email-shengjiu.wang@nxp.com Signed-off-by: Mark Brown --- sound/soc/codecs/wm8960.c | 12 +----------- 1 file changed, 1 insertion(+), 11 deletions(-) diff --git a/sound/soc/codecs/wm8960.c b/sound/soc/codecs/wm8960.c index df351519a3a6..847ca16b9841 100644 --- a/sound/soc/codecs/wm8960.c +++ b/sound/soc/codecs/wm8960.c @@ -608,10 +608,6 @@ static const int bclk_divs[] = { * - lrclk = sysclk / dac_divs * - 10 * bclk = sysclk / bclk_divs * - * If we cannot find an exact match for (sysclk, lrclk, bclk) - * triplet, we relax the bclk such that bclk is chosen as the - * closest available frequency greater than expected bclk. - * * @wm8960: codec private data * @mclk: MCLK used to derive sysclk * @sysclk_idx: sysclk_divs index for found sysclk @@ -629,7 +625,7 @@ int wm8960_configure_sysclk(struct wm8960_priv *wm8960, int mclk, { int sysclk, bclk, lrclk; int i, j, k; - int diff, closest = mclk; + int diff; /* marker for no match */ *bclk_idx = -1; @@ -653,12 +649,6 @@ int wm8960_configure_sysclk(struct wm8960_priv *wm8960, int mclk, *bclk_idx = k; break; } - if (diff > 0 && closest > diff) { - *sysclk_idx = i; - *dac_idx = j; - *bclk_idx = k; - closest = diff; - } } if (k != ARRAY_SIZE(bclk_divs)) break; From e61c589587c772c5f672b22683c3e0b38be20702 Mon Sep 17 00:00:00 2001 From: Argus Lin Date: Wed, 10 Mar 2021 21:33:05 +0800 Subject: [PATCH 333/587] ASoC: mt6359: add ASoC mt6359 ASoC accdet jack document This patch adds MediaTek MT6359 ASoC accdet jack document. Signed-off-by: Argus Lin Link: https://lore.kernel.org/r/1615383186-18500-2-git-send-email-argus.lin@mediatek.com Signed-off-by: Mark Brown --- .../bindings/sound/mt6359-accdet.yaml | 164 ++++++++++++++++++ 1 file changed, 164 insertions(+) create mode 100644 Documentation/devicetree/bindings/sound/mt6359-accdet.yaml diff --git a/Documentation/devicetree/bindings/sound/mt6359-accdet.yaml b/Documentation/devicetree/bindings/sound/mt6359-accdet.yaml new file mode 100644 index 000000000000..7fb3e8dfb4c5 --- /dev/null +++ b/Documentation/devicetree/bindings/sound/mt6359-accdet.yaml @@ -0,0 +1,164 @@ +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/sound/mt6359-accdet.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Mediatek Technologies Inc. MT6359 ASoC accdet jack driver bindings + +maintainers: + - Chipeng Chang + +description: | + This binding describes the Mediatek Technologies MT6359 ASoC + accdet jack driver. + +properties: + mediatek,accdet-name: + maxItems: 1 + description: named as "mt6359-accdet" jack. + + mediatek,mic-vol: + maxItems: 1 + description: | + accdet micbias1 voltage. + + enum: + - 0x00 # 1.7v - micbias1 volage is 1.7v. + - 0x01 # 1.8v - micbias1 volage is 1.8v. + - 0x02 # 1.9v - micbias1 volage is 1.9v. + - 0x03 # 2.0v - micbias1 volage is 2.0v. + - 0x04 # 2.1v - micbias1 volage is 2.1v. + - 0x05 # 2.5v - micbias1 volage is 2.5v. + - 0x06 # 2.6v - micbias1 volage is 2.6v. + - 0x07 # 2.7v - micbias1 volage is 2.7v. + - 0x08 # 2.8v - micbias1 volage is 2.8v. + - 0x09 # 2.85v - micbias1 volage is 2.85v. + + mediatek,mic-mode: + maxItems: 1 + description: | + value as 1, 2, 6 to indicate ACC/DCC mode. default is DCC mode 2. + + enum: + - 0x01 # ACC - ACC mode. + - 0x02 # DCC - low cost without in bias. + - 0x06 # DCC - low cost with in bias. + + mediatek,pwm-deb-setting: + maxItems: 15 + description: | + headset-mode-setting : Indicates customized pwm, debounce setting + accdet pwm_width, pwm_thresh, fall_delay, rise_delay + debounce0, debounce1, debounce3, debounce4 + eint pwm_width, eint pwm_thresh + eint deb(debounce0, debounce1, debounce2, debounce3), inv_debounce. + + mediatek,eint-use-ap: + maxItems: 1 + description: | + indicates to use ap gpio. + + enum: + - 0x00 # MT6359 eint detection mode. + - 0x01 # SoC GPIO detection mode. + + mediatek,eint-detect-mode: + maxItems: 1 + description: | + indicates to use ap gpio. + + enum: + - 0x00 # detection mode with higher detection power. + - 0x01 # detection mode with lower detection power. + - 0x02 # detection mode with sw moisture detection mode. + - 0x03 # detection mode with hw moisture detection mode1. + - 0x04 # detection mode with hw moisture detection mode2. + + mediatek,eint-num: + maxItems: 1 + description: | + incicates pmic eint usage. + + enum: + - 0x0 # PMIC_EINT0 - use pmic eint0 to trigger plug interrupt. + - 0x1 # PMIC_EINT1 - use pmic eint1 to trigger plug interrupt. + - 0x2 # PMIC_BI_EINT - use pmic eint0/1 to trigger plug interrupt. + + mediatek,eint-trig-mode: + maxItems: 1 + description: | + incicates pmic eint trigger mode. + + enum: + - 0x0 # PMIC_GPIO - use pmic gpio to detect plug status. + - 0x1 # PMIC_INVERTER - use pmic inverter to detect plug status. + + mediatek,eint-use-ext-res: + maxItems: 1 + description: | + select HP_EINT pull up resistance, default 0 use internal resistance. + + enum: + - 0x0 # use internal resistor. + - 0x1 # use external resistor. + + mediatek,eint-comp-vth: + maxItems: 1 + description: | + indicates comparator detection voltage. + + enum: + - 0x00 # 2.8v. + - 0x01 # 2.4v. + - 0x02 # 2.0v. + - 0x03 # 0.7v. + + mediatek,key-mode: + maxItems: 1 + description: | + incicates key mode type. + + enum: + - 0x0 # THREE_KEY - support 3-key key mode. + - 0x1 # FOUR_KEY - support 4-key key mode. + - 0x2 # TRI_KEY_CDD - support 3-key google CDD key mode. + + mediatek,three-key-thr: + maxItems: 4 + description: | + 3 key device detection threshold: 0--MD_MAX--UP_MAX--DW_MAX. + + mediatek,tri-key-cdd-thr: + maxItems: 4 + description: | + 3 key CDD device detection threshold: 0--MD_MAX--UP_MAX--DW_MAX. + + mediatek,four-key-thr: + maxItems: 4 + description: | + 4 key device detection threshold: 0--MD_MAX--VOICE_MAX--UP_MAX--DW_MAX. + +additionalProperties: false + +examples: + - | + accdet: accdet { + mediatek,accdet-name = "mt6359-accdet"; + mediatek,mic-vol = <8>; + mediatek,mic-mode = <2>; + mediatek,pwm-deb-setting = <0x500 0x500 1 0x1f0 + 0x800 0x800 0x20 0x44 + 0x4 0x1 + 0x5 0x3 0x3 0x5 0xe>; + mediatek,eint-use-ap = <0>; + mediatek,eint-detect-mode = <4>; + mediatek,eint-num = <0>; + mediatek,eint-trig-mode = <1>; + mediatek,eint-use-ext-res = <0>; + mediatek,eint-comp-vth = <2>; + mediatek,key-mode = <0>; + mediatek,three-key-thr = <0 80 220 400>; + status = "okay"; + }; +... From eef07b9e0925e16457ab9444b56a7f93b541aee3 Mon Sep 17 00:00:00 2001 From: Argus Lin Date: Wed, 10 Mar 2021 21:33:06 +0800 Subject: [PATCH 334/587] ASoC: mediatek: mt6359: add MT6359 accdet jack driver MT6359 audio codec supports jack detection feature, adds MT6359 accdet driver to support jack plugged detection and key detection. Signed-off-by: Argus Lin Link: https://lore.kernel.org/r/1615383186-18500-3-git-send-email-argus.lin@mediatek.com Signed-off-by: Mark Brown --- sound/soc/codecs/Kconfig | 8 + sound/soc/codecs/Makefile | 2 + sound/soc/codecs/mt6359-accdet.c | 1080 +++++++++++++++++ sound/soc/codecs/mt6359-accdet.h | 128 ++ sound/soc/codecs/mt6359.h | 1858 ++++++++++++++++++++++++++++-- 5 files changed, 2972 insertions(+), 104 deletions(-) create mode 100644 sound/soc/codecs/mt6359-accdet.c create mode 100644 sound/soc/codecs/mt6359-accdet.h diff --git a/sound/soc/codecs/Kconfig b/sound/soc/codecs/Kconfig index 4ab34bca71aa..6d9cb00aa3d2 100644 --- a/sound/soc/codecs/Kconfig +++ b/sound/soc/codecs/Kconfig @@ -1812,6 +1812,14 @@ config SND_SOC_MT6359 Enable support for the platform which uses MT6359 as external codec device. +config SND_SOC_MT6359_ACCDET + tristate "MediaTek MT6359 ACCDET driver" + depends on MTK_PMIC_WRAP + help + ACCDET means Accessory Detection technology, MediaTek develop it + for ASoC codec soc-jack detection mechanism. + Select N if you don't have jack on board. + config SND_SOC_MT6660 tristate "Mediatek MT6660 Speaker Amplifier" depends on I2C diff --git a/sound/soc/codecs/Makefile b/sound/soc/codecs/Makefile index a710dfea7876..1d8980be7019 100644 --- a/sound/soc/codecs/Makefile +++ b/sound/soc/codecs/Makefile @@ -136,6 +136,7 @@ snd-soc-msm8916-digital-objs := msm8916-wcd-digital.o snd-soc-mt6351-objs := mt6351.o snd-soc-mt6358-objs := mt6358.o snd-soc-mt6359-objs := mt6359.o +snd-soc-mt6359-accdet-objs := mt6359-accdet.o snd-soc-mt6660-objs := mt6660.o snd-soc-nau8315-objs := nau8315.o snd-soc-nau8540-objs := nau8540.o @@ -454,6 +455,7 @@ obj-$(CONFIG_SND_SOC_MSM8916_WCD_DIGITAL) +=snd-soc-msm8916-digital.o obj-$(CONFIG_SND_SOC_MT6351) += snd-soc-mt6351.o obj-$(CONFIG_SND_SOC_MT6358) += snd-soc-mt6358.o obj-$(CONFIG_SND_SOC_MT6359) += snd-soc-mt6359.o +obj-$(CONFIG_SND_SOC_MT6359_ACCDET) += mt6359-accdet.o obj-$(CONFIG_SND_SOC_MT6660) += snd-soc-mt6660.o obj-$(CONFIG_SND_SOC_NAU8315) += snd-soc-nau8315.o obj-$(CONFIG_SND_SOC_NAU8540) += snd-soc-nau8540.o diff --git a/sound/soc/codecs/mt6359-accdet.c b/sound/soc/codecs/mt6359-accdet.c new file mode 100644 index 000000000000..0bef6eaad5ad --- /dev/null +++ b/sound/soc/codecs/mt6359-accdet.c @@ -0,0 +1,1080 @@ +// SPDX-License-Identifier: GPL-2.0 +// +// mt6359-accdet.c -- ALSA SoC mt6359 accdet driver +// +// Copyright (C) 2021 MediaTek Inc. +// Author: Argus Lin +// + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "mt6359-accdet.h" +#include "mt6359.h" + +/* global variable definitions */ +#define REGISTER_VAL(x) ((x) - 1) + +/* mt6359 accdet capability */ +#define ACCDET_PMIC_EINT_IRQ BIT(0) +#define ACCDET_AP_GPIO_EINT BIT(1) + +#define ACCDET_PMIC_EINT0 BIT(2) +#define ACCDET_PMIC_EINT1 BIT(3) +#define ACCDET_PMIC_BI_EINT BIT(4) + +#define ACCDET_PMIC_GPIO_TRIG_EINT BIT(5) +#define ACCDET_PMIC_INVERTER_TRIG_EINT BIT(6) +#define ACCDET_PMIC_RSV_EINT BIT(7) + +#define ACCDET_THREE_KEY BIT(8) +#define ACCDET_FOUR_KEY BIT(9) +#define ACCDET_TRI_KEY_CDD BIT(10) +#define ACCDET_RSV_KEY BIT(11) + +#define ACCDET_ANALOG_FASTDISCHARGE BIT(12) +#define ACCDET_DIGITAL_FASTDISCHARGE BIT(13) +#define ACCDET_AD_FASTDISCHRAGE BIT(14) + +static struct platform_driver mt6359_accdet_driver; +static const struct snd_soc_component_driver mt6359_accdet_soc_driver; + +/* local function declaration */ +static void accdet_set_debounce(struct mt6359_accdet *priv, int state, + unsigned int debounce); +static unsigned int adjust_eint_analog_setting(struct mt6359_accdet *priv); +static void config_digital_init_by_mode(struct mt6359_accdet *priv); +static void config_eint_init_by_mode(struct mt6359_accdet *priv); +static inline void mt6359_accdet_init(struct mt6359_accdet *priv); +static unsigned int mt6359_accdet_jd_setting(struct mt6359_accdet *priv); +static void mt6359_accdet_recover_jd_setting(struct mt6359_accdet *priv); +static void mt6359_accdet_jack_report(struct mt6359_accdet *priv); +static void recover_eint_analog_setting(struct mt6359_accdet *priv); +static void recover_eint_digital_setting(struct mt6359_accdet *priv); +static void recover_eint_setting(struct mt6359_accdet *priv); + +static unsigned int adjust_eint_analog_setting(struct mt6359_accdet *priv) +{ + if (priv->data->eint_detect_mode == 0x3 || + priv->data->eint_detect_mode == 0x4) { + /* ESD switches off */ + regmap_update_bits(priv->regmap, + RG_ACCDETSPARE_ADDR, 1 << 8, 0); + } + if (priv->data->eint_detect_mode == 0x4) { + if (priv->caps & ACCDET_PMIC_EINT0) { + /* enable RG_EINT0CONFIGACCDET */ + regmap_update_bits(priv->regmap, + RG_EINT0CONFIGACCDET_ADDR, + RG_EINT0CONFIGACCDET_MASK_SFT, + BIT(RG_EINT0CONFIGACCDET_SFT)); + } else if (priv->caps & ACCDET_PMIC_EINT1) { + /* enable RG_EINT1CONFIGACCDET */ + regmap_update_bits(priv->regmap, + RG_EINT1CONFIGACCDET_ADDR, + RG_EINT1CONFIGACCDET_MASK_SFT, + BIT(RG_EINT1CONFIGACCDET_SFT)); + } + if (priv->data->eint_use_ext_res == 0x3 || + priv->data->eint_use_ext_res == 0x4) { + /*select 500k, use internal resistor */ + regmap_update_bits(priv->regmap, + RG_EINT0HIRENB_ADDR, + RG_EINT0HIRENB_MASK_SFT, + BIT(RG_EINT0HIRENB_SFT)); + } + } + return 0; +} + +static unsigned int adjust_eint_digital_setting(struct mt6359_accdet *priv) +{ + if (priv->caps & ACCDET_PMIC_EINT0) { + /* disable inverter */ + regmap_update_bits(priv->regmap, + ACCDET_EINT0_INVERTER_SW_EN_ADDR, + ACCDET_EINT0_INVERTER_SW_EN_MASK_SFT, 0); + } else if (priv->caps & ACCDET_PMIC_EINT1) { + /* disable inverter */ + regmap_update_bits(priv->regmap, + ACCDET_EINT1_INVERTER_SW_EN_ADDR, + ACCDET_EINT1_INVERTER_SW_EN_MASK_SFT, 0); + } + + if (priv->data->eint_detect_mode == 0x4) { + if (priv->caps & ACCDET_PMIC_EINT0) { + /* set DA stable signal */ + regmap_update_bits(priv->regmap, + ACCDET_DA_STABLE_ADDR, + ACCDET_EINT0_CEN_STABLE_MASK_SFT, 0); + } else if (priv->caps & ACCDET_PMIC_EINT1) { + /* set DA stable signal */ + regmap_update_bits(priv->regmap, + ACCDET_DA_STABLE_ADDR, + ACCDET_EINT1_CEN_STABLE_MASK_SFT, 0); + } + } + return 0; +} + +static unsigned int mt6359_accdet_jd_setting(struct mt6359_accdet *priv) +{ + if (priv->jd_sts == M_PLUG_IN) { + /* adjust digital setting */ + adjust_eint_digital_setting(priv); + /* adjust analog setting */ + adjust_eint_analog_setting(priv); + } else if (priv->jd_sts == M_PLUG_OUT) { + /* set debounce to 1ms */ + accdet_set_debounce(priv, eint_state000, + priv->data->pwm_deb->eint_debounce0); + } else { + dev_dbg(priv->dev, "should not be here %s()\n", __func__); + } + + return 0; +} + +static void recover_eint_analog_setting(struct mt6359_accdet *priv) +{ + if (priv->data->eint_detect_mode == 0x3 || + priv->data->eint_detect_mode == 0x4) { + /* ESD switches on */ + regmap_update_bits(priv->regmap, RG_ACCDETSPARE_ADDR, + 1 << 8, 1 << 8); + } + if (priv->data->eint_detect_mode == 0x4) { + if (priv->caps & ACCDET_PMIC_EINT0) { + /* disable RG_EINT0CONFIGACCDET */ + regmap_update_bits(priv->regmap, + RG_EINT0CONFIGACCDET_ADDR, + RG_EINT0CONFIGACCDET_MASK_SFT, 0); + } else if (priv->caps & ACCDET_PMIC_EINT1) { + /* disable RG_EINT1CONFIGACCDET */ + regmap_update_bits(priv->regmap, + RG_EINT1CONFIGACCDET_ADDR, + RG_EINT1CONFIGACCDET_MASK_SFT, 0); + } + regmap_update_bits(priv->regmap, RG_EINT0HIRENB_ADDR, + RG_EINT0HIRENB_MASK_SFT, 0); + } +} + +static void recover_eint_digital_setting(struct mt6359_accdet *priv) +{ + if (priv->caps & ACCDET_PMIC_EINT0) { + regmap_update_bits(priv->regmap, + ACCDET_EINT0_M_SW_EN_ADDR, + ACCDET_EINT0_M_SW_EN_MASK_SFT, 0); + } else if (priv->caps & ACCDET_PMIC_EINT1) { + regmap_update_bits(priv->regmap, + ACCDET_EINT1_M_SW_EN_ADDR, + ACCDET_EINT1_M_SW_EN_MASK_SFT, 0); + } + if (priv->data->eint_detect_mode == 0x4) { + /* enable eint0cen */ + if (priv->caps & ACCDET_PMIC_EINT0) { + /* enable eint0cen */ + regmap_update_bits(priv->regmap, + ACCDET_DA_STABLE_ADDR, + ACCDET_EINT0_CEN_STABLE_MASK_SFT, + BIT(ACCDET_EINT0_CEN_STABLE_SFT)); + } else if (priv->caps & ACCDET_PMIC_EINT1) { + /* enable eint1cen */ + regmap_update_bits(priv->regmap, + ACCDET_DA_STABLE_ADDR, + ACCDET_EINT1_CEN_STABLE_MASK_SFT, + BIT(ACCDET_EINT1_CEN_STABLE_SFT)); + } + } + + if (priv->data->eint_detect_mode != 0x1) { + if (priv->caps & ACCDET_PMIC_EINT0) { + /* enable inverter */ + regmap_update_bits(priv->regmap, + ACCDET_EINT0_INVERTER_SW_EN_ADDR, + ACCDET_EINT0_INVERTER_SW_EN_MASK_SFT, + BIT(ACCDET_EINT0_INVERTER_SW_EN_SFT)); + } else if (priv->caps & ACCDET_PMIC_EINT1) { + /* enable inverter */ + regmap_update_bits(priv->regmap, + ACCDET_EINT1_INVERTER_SW_EN_ADDR, + ACCDET_EINT1_INVERTER_SW_EN_MASK_SFT, + BIT(ACCDET_EINT1_INVERTER_SW_EN_SFT)); + } + } +} + +static void recover_eint_setting(struct mt6359_accdet *priv) +{ + if (priv->jd_sts == M_PLUG_OUT) { + recover_eint_analog_setting(priv); + recover_eint_digital_setting(priv); + } +} + +static void mt6359_accdet_recover_jd_setting(struct mt6359_accdet *priv) +{ + int ret = 0; + unsigned int value = 0; + + regmap_update_bits(priv->regmap, ACCDET_IRQ_ADDR, + ACCDET_IRQ_CLR_MASK_SFT, BIT(ACCDET_IRQ_CLR_SFT)); + usleep_range(200, 300); + ret = regmap_read_poll_timeout(priv->regmap, + ACCDET_IRQ_ADDR, + value, + (value & ACCDET_IRQ_MASK_SFT) == 0, + 0, + 1000); + if (ret) + dev_warn(priv->dev, "%s(), ret %d\n", __func__, ret); + /* clear accdet int, modify for fix interrupt trigger twice error */ + regmap_update_bits(priv->regmap, ACCDET_IRQ_ADDR, + ACCDET_IRQ_CLR_MASK_SFT, 0); + regmap_update_bits(priv->regmap, RG_INT_STATUS_ACCDET_ADDR, + RG_INT_STATUS_ACCDET_MASK_SFT, + BIT(RG_INT_STATUS_ACCDET_SFT)); + + /* recover accdet debounce0,3 */ + accdet_set_debounce(priv, accdet_state000, + priv->data->pwm_deb->debounce0); + accdet_set_debounce(priv, accdet_state001, + priv->data->pwm_deb->debounce1); + accdet_set_debounce(priv, accdet_state011, + priv->data->pwm_deb->debounce3); + + priv->jack_type = 0; + priv->btn_type = 0; + priv->accdet_status = 0x3; + mt6359_accdet_jack_report(priv); +} + +static void accdet_set_debounce(struct mt6359_accdet *priv, int state, + unsigned int debounce) +{ + switch (state) { + case accdet_state000: + regmap_write(priv->regmap, ACCDET_DEBOUNCE0_ADDR, debounce); + break; + case accdet_state001: + regmap_write(priv->regmap, ACCDET_DEBOUNCE1_ADDR, debounce); + break; + case accdet_state010: + regmap_write(priv->regmap, ACCDET_DEBOUNCE2_ADDR, debounce); + break; + case accdet_state011: + regmap_write(priv->regmap, ACCDET_DEBOUNCE3_ADDR, debounce); + break; + case accdet_auxadc: + regmap_write(priv->regmap, + ACCDET_CONNECT_AUXADC_TIME_DIG_ADDR, debounce); + break; + case eint_state000: + regmap_update_bits(priv->regmap, ACCDET_EINT_DEBOUNCE0_ADDR, + 0xF << ACCDET_EINT_DEBOUNCE0_SFT, + debounce << ACCDET_EINT_DEBOUNCE0_SFT); + break; + case eint_state001: + regmap_update_bits(priv->regmap, ACCDET_EINT_DEBOUNCE1_ADDR, + 0xF << ACCDET_EINT_DEBOUNCE1_SFT, + debounce << ACCDET_EINT_DEBOUNCE1_SFT); + break; + case eint_state010: + regmap_update_bits(priv->regmap, ACCDET_EINT_DEBOUNCE2_ADDR, + 0xF << ACCDET_EINT_DEBOUNCE2_SFT, + debounce << ACCDET_EINT_DEBOUNCE2_SFT); + break; + case eint_state011: + regmap_update_bits(priv->regmap, ACCDET_EINT_DEBOUNCE3_ADDR, + 0xF << ACCDET_EINT_DEBOUNCE3_SFT, + debounce << ACCDET_EINT_DEBOUNCE3_SFT); + break; + case eint_inverter_state000: + regmap_write(priv->regmap, ACCDET_EINT_INVERTER_DEBOUNCE_ADDR, + debounce); + break; + default: + dev_warn(priv->dev, "Error: %s error state (%d)\n", __func__, + state); + break; + } +} + +static void mt6359_accdet_jack_report(struct mt6359_accdet *priv) +{ + int report = 0; + + if (!priv->jack) + return; + + report = priv->jack_type | priv->btn_type; + snd_soc_jack_report(priv->jack, report, MT6359_ACCDET_JACK_MASK); +} + +static unsigned int check_button(struct mt6359_accdet *priv, unsigned int v) +{ + if (priv->caps & ACCDET_FOUR_KEY) { + if (v < priv->data->four_key.down && + v >= priv->data->four_key.up) + priv->btn_type = SND_JACK_BTN_1; + if (v < priv->data->four_key.up && + v >= priv->data->four_key.voice) + priv->btn_type = SND_JACK_BTN_2; + if (v < priv->data->four_key.voice && + v >= priv->data->four_key.mid) + priv->btn_type = SND_JACK_BTN_3; + if (v < priv->data->four_key.mid) + priv->btn_type = SND_JACK_BTN_0; + } else { + if (v < priv->data->three_key.down && + v >= priv->data->three_key.up) + priv->btn_type = SND_JACK_BTN_1; + if (v < priv->data->three_key.up && + v >= priv->data->three_key.mid) + priv->btn_type = SND_JACK_BTN_2; + if (v < priv->data->three_key.mid) + priv->btn_type = SND_JACK_BTN_0; + } + return 0; +} + +static void is_key_pressed(struct mt6359_accdet *priv, bool pressed) +{ + priv->btn_type = priv->jack_type & ~MT6359_ACCDET_BTN_MASK; + + if (pressed) + check_button(priv, priv->cali_voltage); +} + +static inline void check_jack_btn_type(struct mt6359_accdet *priv) +{ + unsigned int val = 0; + + regmap_read(priv->regmap, ACCDET_MEM_IN_ADDR, &val); + + priv->accdet_status = + (val >> ACCDET_STATE_MEM_IN_OFFSET) & ACCDET_STATE_AB_MASK; + + switch (priv->accdet_status) { + case 0: + if (priv->jack_type == SND_JACK_HEADSET) + is_key_pressed(priv, true); + else + priv->jack_type = SND_JACK_HEADPHONE; + break; + case 1: + if (priv->jack_type == SND_JACK_HEADSET) { + is_key_pressed(priv, false); + } else { + priv->jack_type = SND_JACK_HEADSET; + accdet_set_debounce(priv, eint_state011, 0x1); + } + break; + case 3: + default: + priv->jack_type = 0; + break; + } +} + +static void mt6359_accdet_work(struct work_struct *work) +{ + struct mt6359_accdet *priv = + container_of(work, struct mt6359_accdet, accdet_work); + + mutex_lock(&priv->res_lock); + priv->pre_accdet_status = priv->accdet_status; + check_jack_btn_type(priv); + + if (priv->jack_plugged && + priv->pre_accdet_status != priv->accdet_status) + mt6359_accdet_jack_report(priv); + mutex_unlock(&priv->res_lock); +} + +static void mt6359_accdet_jd_work(struct work_struct *work) +{ + int ret = 0; + unsigned int value = 0; + + struct mt6359_accdet *priv = + container_of(work, struct mt6359_accdet, jd_work); + + mutex_lock(&priv->res_lock); + if (priv->jd_sts == M_PLUG_IN) { + priv->jack_plugged = true; + + /* set and clear initial bit every eint interrupt */ + regmap_update_bits(priv->regmap, ACCDET_SEQ_INIT_ADDR, + ACCDET_SEQ_INIT_MASK_SFT, + BIT(ACCDET_SEQ_INIT_SFT)); + regmap_update_bits(priv->regmap, ACCDET_SEQ_INIT_ADDR, + ACCDET_SEQ_INIT_MASK_SFT, 0); + ret = regmap_read_poll_timeout(priv->regmap, + ACCDET_SEQ_INIT_ADDR, + value, + (value & ACCDET_SEQ_INIT_MASK_SFT) == 0, + 0, + 1000); + if (ret) + dev_err(priv->dev, "%s(), ret %d\n", __func__, ret); + + /* enable ACCDET unit */ + regmap_update_bits(priv->regmap, ACCDET_SW_EN_ADDR, + ACCDET_SW_EN_MASK_SFT, BIT(ACCDET_SW_EN_SFT)); + } else if (priv->jd_sts == M_PLUG_OUT) { + priv->jack_plugged = false; + + accdet_set_debounce(priv, accdet_state011, + priv->data->pwm_deb->debounce3); + regmap_update_bits(priv->regmap, ACCDET_SW_EN_ADDR, + ACCDET_SW_EN_MASK_SFT, 0); + mt6359_accdet_recover_jd_setting(priv); + } + + if (priv->caps & ACCDET_PMIC_EINT_IRQ) + recover_eint_setting(priv); + mutex_unlock(&priv->res_lock); +} + +static irqreturn_t mt6359_accdet_irq(int irq, void *data) +{ + struct mt6359_accdet *priv = data; + unsigned int irq_val = 0, val = 0, value = 0; + int ret = 0; + + mutex_lock(&priv->res_lock); + regmap_read(priv->regmap, ACCDET_IRQ_ADDR, &irq_val); + + if (irq_val & ACCDET_IRQ_MASK_SFT) { + regmap_update_bits(priv->regmap, ACCDET_IRQ_ADDR, + ACCDET_IRQ_CLR_MASK_SFT, + BIT(ACCDET_IRQ_CLR_SFT)); + ret = regmap_read_poll_timeout(priv->regmap, + ACCDET_IRQ_ADDR, + value, + (value & ACCDET_IRQ_MASK_SFT) == 0, + 0, + 1000); + if (ret) { + dev_err(priv->dev, "%s(), ret %d\n", __func__, ret); + mutex_unlock(&priv->res_lock); + return IRQ_NONE; + } + regmap_update_bits(priv->regmap, ACCDET_IRQ_ADDR, + ACCDET_IRQ_CLR_MASK_SFT, 0); + regmap_update_bits(priv->regmap, RG_INT_STATUS_ACCDET_ADDR, + RG_INT_STATUS_ACCDET_MASK_SFT, + BIT(RG_INT_STATUS_ACCDET_SFT)); + + queue_work(priv->accdet_workqueue, &priv->accdet_work); + } else { + if (irq_val & ACCDET_EINT0_IRQ_MASK_SFT) { + regmap_update_bits(priv->regmap, ACCDET_IRQ_ADDR, + ACCDET_EINT0_IRQ_CLR_MASK_SFT, + BIT(ACCDET_EINT0_IRQ_CLR_SFT)); + ret = regmap_read_poll_timeout(priv->regmap, + ACCDET_IRQ_ADDR, + value, + (value & ACCDET_EINT0_IRQ_MASK_SFT) == 0, + 0, + 1000); + if (ret) { + dev_err(priv->dev, "%s(), ret %d\n", __func__, + ret); + mutex_unlock(&priv->res_lock); + return IRQ_NONE; + } + regmap_update_bits(priv->regmap, ACCDET_IRQ_ADDR, + ACCDET_EINT0_IRQ_CLR_MASK_SFT, 0); + regmap_update_bits(priv->regmap, + RG_INT_STATUS_ACCDET_ADDR, + RG_INT_STATUS_ACCDET_EINT0_MASK_SFT, + BIT(RG_INT_STATUS_ACCDET_EINT0_SFT)); + } + if (irq_val & ACCDET_EINT1_IRQ_MASK_SFT) { + regmap_update_bits(priv->regmap, ACCDET_IRQ_ADDR, + ACCDET_EINT1_IRQ_CLR_MASK_SFT, + BIT(ACCDET_EINT1_IRQ_CLR_SFT)); + ret = regmap_read_poll_timeout(priv->regmap, + ACCDET_IRQ_ADDR, + value, + (value & ACCDET_EINT1_IRQ_MASK_SFT) == 0, + 0, + 1000); + if (ret) { + dev_err(priv->dev, "%s(), ret %d\n", __func__, + ret); + mutex_unlock(&priv->res_lock); + return IRQ_NONE; + } + regmap_update_bits(priv->regmap, ACCDET_IRQ_ADDR, + ACCDET_EINT1_IRQ_CLR_MASK_SFT, 0); + regmap_update_bits(priv->regmap, + RG_INT_STATUS_ACCDET_ADDR, + RG_INT_STATUS_ACCDET_EINT1_MASK_SFT, + BIT(RG_INT_STATUS_ACCDET_EINT1_SFT)); + } + /* get jack detection status */ + regmap_read(priv->regmap, ACCDET_EINT0_MEM_IN_ADDR, &val); + priv->jd_sts = ((val >> ACCDET_EINT0_MEM_IN_SFT) & + ACCDET_EINT0_MEM_IN_MASK); + /* adjust eint digital/analog setting */ + mt6359_accdet_jd_setting(priv); + + queue_work(priv->jd_workqueue, &priv->jd_work); + } + mutex_unlock(&priv->res_lock); + + return IRQ_HANDLED; +} + +static int mt6359_accdet_parse_dt(struct mt6359_accdet *priv) +{ + int ret = 0; + struct device *dev = priv->dev; + struct device_node *node = NULL; + int pwm_deb[15] = {0}; + unsigned int tmp = 0; + + node = of_get_child_by_name(dev->parent->of_node, "accdet"); + if (!node) + return -EINVAL; + + ret = of_property_read_u32(node, "mediatek,mic-vol", + &priv->data->mic_vol); + if (ret) + priv->data->mic_vol = 8; + + ret = of_property_read_u32(node, "mediatek,plugout-debounce", + &priv->data->plugout_deb); + if (ret) + priv->data->plugout_deb = 1; + + ret = of_property_read_u32(node, "mediatek,mic-mode", + &priv->data->mic_mode); + if (ret) + priv->data->mic_mode = 2; + + ret = of_property_read_u32_array(node, "mediatek,pwm-deb-setting", + pwm_deb, ARRAY_SIZE(pwm_deb)); + /* debounce8(auxadc debounce) is default, needn't get from dts */ + if (!ret) + memcpy(priv->data->pwm_deb, pwm_deb, sizeof(pwm_deb)); + + ret = of_property_read_u32(node, "mediatek,eint-level-pol", + &priv->data->eint_pol); + if (ret) + priv->data->eint_pol = 8; + + ret = of_property_read_u32(node, "mediatek,eint-use-ap", &tmp); + if (ret) + tmp = 0; + if (tmp == 0) + priv->caps |= ACCDET_PMIC_EINT_IRQ; + else if (tmp == 1) + priv->caps |= ACCDET_AP_GPIO_EINT; + + ret = of_property_read_u32(node, "mediatek,eint-detect-mode", + &priv->data->eint_detect_mode); + if (ret) { + /* eint detection mode equals to EINT HW Mode */ + priv->data->eint_detect_mode = 0x4; + } + + ret = of_property_read_u32(node, "mediatek,eint-num", &tmp); + if (ret) + tmp = 0; + if (tmp == 0) + priv->caps |= ACCDET_PMIC_EINT0; + else if (tmp == 1) + priv->caps |= ACCDET_PMIC_EINT1; + else if (tmp == 2) + priv->caps |= ACCDET_PMIC_BI_EINT; + + ret = of_property_read_u32(node, "mediatek,eint-trig-mode", + &tmp); + if (ret) + tmp = 0; + if (tmp == 0) + priv->caps |= ACCDET_PMIC_GPIO_TRIG_EINT; + else if (tmp == 1) + priv->caps |= ACCDET_PMIC_INVERTER_TRIG_EINT; + + ret = of_property_read_u32(node, "mediatek,eint-use-ext-res", + &priv->data->eint_use_ext_res); + if (ret) { + /* eint use internal resister */ + priv->data->eint_use_ext_res = 0x0; + } + + ret = of_property_read_u32(node, "mediatek,eint-comp-vth", + &priv->data->eint_comp_vth); + if (ret) + priv->data->eint_comp_vth = 0x0; + + ret = of_property_read_u32(node, "mediatek,key-mode", &tmp); + if (ret) + tmp = 0; + if (tmp == 0) { + int three_key[4]; + + priv->caps |= ACCDET_THREE_KEY; + ret = of_property_read_u32_array(node, + "mediatek,three-key-thr", + three_key, + ARRAY_SIZE(three_key)); + if (!ret) + memcpy(&priv->data->three_key, three_key + 1, + sizeof(struct three_key_threshold)); + } else if (tmp == 1) { + int four_key[5]; + + priv->caps |= ACCDET_FOUR_KEY; + ret = of_property_read_u32_array(node, + "mediatek,four-key-thr", + four_key, + ARRAY_SIZE(four_key)); + if (!ret) { + memcpy(&priv->data->four_key, four_key + 1, + sizeof(struct four_key_threshold)); + } else { + dev_warn(priv->dev, + "accdet no 4-key-thrsh dts, use efuse\n"); + } + } else if (tmp == 2) { + int three_key[4]; + + priv->caps |= ACCDET_TRI_KEY_CDD; + ret = of_property_read_u32_array(node, + "mediatek,tri-key-cdd-thr", + three_key, + ARRAY_SIZE(three_key)); + if (!ret) + memcpy(&priv->data->three_key, three_key + 1, + sizeof(struct three_key_threshold)); + } + + dev_warn(priv->dev, "accdet caps=%x\n", priv->caps); + + return 0; +} + +static void config_digital_init_by_mode(struct mt6359_accdet *priv) +{ + /* enable eint cmpmem pwm */ + regmap_write(priv->regmap, ACCDET_EINT_CMPMEN_PWM_THRESH_ADDR, + (priv->data->pwm_deb->eint_pwm_width << 4 | + priv->data->pwm_deb->eint_pwm_thresh)); + /* DA signal stable */ + if (priv->caps & ACCDET_PMIC_EINT0) { + regmap_write(priv->regmap, ACCDET_DA_STABLE_ADDR, + ACCDET_EINT0_STABLE_VAL); + } else if (priv->caps & ACCDET_PMIC_EINT1) { + regmap_write(priv->regmap, ACCDET_DA_STABLE_ADDR, + ACCDET_EINT1_STABLE_VAL); + } + /* after receive n+1 number, interrupt issued. */ + regmap_update_bits(priv->regmap, ACCDET_EINT_M_PLUG_IN_NUM_ADDR, + ACCDET_EINT_M_PLUG_IN_NUM_MASK_SFT, + BIT(ACCDET_EINT_M_PLUG_IN_NUM_SFT)); + /* setting HW mode, enable digital fast discharge + * if use EINT0 & EINT1 detection, please modify + * ACCDET_HWMODE_EN_ADDR[2:1] + */ + regmap_write(priv->regmap, ACCDET_HWMODE_EN_ADDR, 0x100); + + regmap_update_bits(priv->regmap, ACCDET_EINT_M_DETECT_EN_ADDR, + ACCDET_EINT_M_DETECT_EN_MASK_SFT, 0); + + /* enable PWM */ + regmap_write(priv->regmap, ACCDET_CMP_PWM_EN_ADDR, 0x67); + /* enable inverter detection */ + if (priv->data->eint_detect_mode == 0x1) { + /* disable inverter detection */ + if (priv->caps & ACCDET_PMIC_EINT0) { + regmap_update_bits(priv->regmap, + ACCDET_EINT0_INVERTER_SW_EN_ADDR, + ACCDET_EINT0_INVERTER_SW_EN_MASK_SFT, + 0); + } else if (priv->caps & ACCDET_PMIC_EINT1) { + regmap_update_bits(priv->regmap, + ACCDET_EINT1_INVERTER_SW_EN_ADDR, + ACCDET_EINT1_INVERTER_SW_EN_MASK_SFT, + 0); + } + } else { + if (priv->caps & ACCDET_PMIC_EINT0) { + regmap_update_bits(priv->regmap, + ACCDET_EINT0_INVERTER_SW_EN_ADDR, + ACCDET_EINT0_INVERTER_SW_EN_MASK_SFT, + BIT(ACCDET_EINT0_INVERTER_SW_EN_SFT)); + } else if (priv->caps & ACCDET_PMIC_EINT1) { + regmap_update_bits(priv->regmap, + ACCDET_EINT1_INVERTER_SW_EN_ADDR, + ACCDET_EINT1_INVERTER_SW_EN_MASK_SFT, + BIT(ACCDET_EINT1_INVERTER_SW_EN_SFT)); + } + } +} + +static void config_eint_init_by_mode(struct mt6359_accdet *priv) +{ + unsigned int val = 0; + + if (priv->caps & ACCDET_PMIC_EINT0) { + regmap_update_bits(priv->regmap, RG_EINT0EN_ADDR, + RG_EINT0EN_MASK_SFT, BIT(RG_EINT0EN_SFT)); + } else if (priv->caps & ACCDET_PMIC_EINT1) { + regmap_update_bits(priv->regmap, RG_EINT1EN_ADDR, + RG_EINT1EN_MASK_SFT, BIT(RG_EINT1EN_SFT)); + } + /* ESD switches on */ + regmap_update_bits(priv->regmap, RG_ACCDETSPARE_ADDR, + 1 << 8, 1 << 8); + /* before playback, set NCP pull low before nagative voltage */ + regmap_update_bits(priv->regmap, RG_NCP_PDDIS_EN_ADDR, + RG_NCP_PDDIS_EN_MASK_SFT, BIT(RG_NCP_PDDIS_EN_SFT)); + + if (priv->data->eint_detect_mode == 0x1 || + priv->data->eint_detect_mode == 0x2 || + priv->data->eint_detect_mode == 0x3) { + if (priv->data->eint_use_ext_res == 0x1) { + if (priv->caps & ACCDET_PMIC_EINT0) { + regmap_update_bits(priv->regmap, + RG_EINT0CONFIGACCDET_ADDR, + RG_EINT0CONFIGACCDET_MASK_SFT, + 0); + } else if (priv->caps & ACCDET_PMIC_EINT1) { + regmap_update_bits(priv->regmap, + RG_EINT1CONFIGACCDET_ADDR, + RG_EINT1CONFIGACCDET_MASK_SFT, + 0); + } + } else { + if (priv->caps & ACCDET_PMIC_EINT0) { + regmap_update_bits(priv->regmap, + RG_EINT0CONFIGACCDET_ADDR, + RG_EINT0CONFIGACCDET_MASK_SFT, + BIT(RG_EINT0CONFIGACCDET_SFT)); + } else if (priv->caps & ACCDET_PMIC_EINT1) { + regmap_update_bits(priv->regmap, + RG_EINT1CONFIGACCDET_ADDR, + RG_EINT1CONFIGACCDET_MASK_SFT, + BIT(RG_EINT1CONFIGACCDET_SFT)); + } + } + } + + if (priv->data->eint_detect_mode != 0x1) { + /* current detect set 0.25uA */ + regmap_update_bits(priv->regmap, RG_ACCDETSPARE_ADDR, + 0x3 << RG_ACCDETSPARE_SFT, + 0x3 << RG_ACCDETSPARE_SFT); + } + regmap_write(priv->regmap, RG_EINTCOMPVTH_ADDR, + val | priv->data->eint_comp_vth << RG_EINTCOMPVTH_SFT); +} + +static void mt6359_accdet_init(struct mt6359_accdet *priv) +{ + unsigned int reg = 0; + + regmap_update_bits(priv->regmap, ACCDET_SEQ_INIT_ADDR, + ACCDET_SEQ_INIT_MASK_SFT, BIT(ACCDET_SEQ_INIT_SFT)); + mdelay(2); + regmap_update_bits(priv->regmap, ACCDET_SEQ_INIT_ADDR, + ACCDET_SEQ_INIT_MASK_SFT, 0); + mdelay(1); + /* init the debounce time (debounce/32768)sec */ + accdet_set_debounce(priv, accdet_state000, + priv->data->pwm_deb->debounce0); + accdet_set_debounce(priv, accdet_state001, + priv->data->pwm_deb->debounce1); + accdet_set_debounce(priv, accdet_state011, + priv->data->pwm_deb->debounce3); + accdet_set_debounce(priv, accdet_auxadc, + priv->data->pwm_deb->debounce4); + + accdet_set_debounce(priv, eint_state000, + priv->data->pwm_deb->eint_debounce0); + accdet_set_debounce(priv, eint_state001, + priv->data->pwm_deb->eint_debounce1); + accdet_set_debounce(priv, eint_state011, + priv->data->pwm_deb->eint_debounce3); + accdet_set_debounce(priv, eint_inverter_state000, + priv->data->pwm_deb->eint_inverter_debounce); + + regmap_update_bits(priv->regmap, RG_ACCDET_RST_ADDR, + RG_ACCDET_RST_MASK_SFT, BIT(RG_ACCDET_RST_SFT)); + regmap_update_bits(priv->regmap, RG_ACCDET_RST_ADDR, + RG_ACCDET_RST_MASK_SFT, 0); + + /* clear high micbias1 voltage setting */ + regmap_update_bits(priv->regmap, RG_AUDPWDBMICBIAS1_ADDR, + 0x3 << RG_AUDMICBIAS1HVEN_SFT, 0); + regmap_update_bits(priv->regmap, RG_AUDPWDBMICBIAS1_ADDR, + 0x7 << RG_AUDMICBIAS1VREF_SFT, 0); + + /* init pwm frequency, duty & rise/falling delay */ + regmap_write(priv->regmap, ACCDET_PWM_WIDTH_ADDR, + REGISTER_VAL(priv->data->pwm_deb->pwm_width)); + regmap_write(priv->regmap, ACCDET_PWM_THRESH_ADDR, + REGISTER_VAL(priv->data->pwm_deb->pwm_thresh)); + regmap_write(priv->regmap, ACCDET_RISE_DELAY_ADDR, + (priv->data->pwm_deb->fall_delay << 15 | + priv->data->pwm_deb->rise_delay)); + + regmap_read(priv->regmap, RG_AUDPWDBMICBIAS1_ADDR, ®); + if (priv->data->mic_vol <= 7) { + /* micbias1 <= 2.7V */ + regmap_write(priv->regmap, RG_AUDPWDBMICBIAS1_ADDR, + reg | (priv->data->mic_vol << RG_AUDMICBIAS1VREF_SFT) | + RG_AUDMICBIAS1LOWPEN_MASK_SFT); + } else if (priv->data->mic_vol == 8) { + /* micbias1 = 2.8v */ + regmap_write(priv->regmap, RG_AUDPWDBMICBIAS1_ADDR, + reg | (3 << RG_AUDMICBIAS1HVEN_SFT) | + RG_AUDMICBIAS1LOWPEN_MASK_SFT); + } else if (priv->data->mic_vol == 9) { + /* micbias1 = 2.85v */ + regmap_write(priv->regmap, RG_AUDPWDBMICBIAS1_ADDR, + reg | (1 << RG_AUDMICBIAS1HVEN_SFT) | + RG_AUDMICBIAS1LOWPEN_MASK_SFT); + } + /* mic mode setting */ + regmap_read(priv->regmap, RG_AUDACCDETMICBIAS0PULLLOW_ADDR, ®); + if (priv->data->mic_mode == HEADSET_MODE_1) { + /* ACC mode*/ + regmap_write(priv->regmap, RG_AUDACCDETMICBIAS0PULLLOW_ADDR, + reg | RG_ACCDET_MODE_ANA11_MODE1); + /* enable analog fast discharge */ + regmap_update_bits(priv->regmap, RG_ANALOGFDEN_ADDR, + RG_ANALOGFDEN_MASK_SFT, + BIT(RG_ANALOGFDEN_SFT)); + regmap_update_bits(priv->regmap, RG_ACCDETSPARE_ADDR, + 0x3 << 11, 0x3 << 11); + } else if (priv->data->mic_mode == HEADSET_MODE_2) { + /* DCC mode Low cost mode without internal bias */ + regmap_write(priv->regmap, RG_AUDACCDETMICBIAS0PULLLOW_ADDR, + reg | RG_ACCDET_MODE_ANA11_MODE2); + /* enable analog fast discharge */ + regmap_update_bits(priv->regmap, RG_ANALOGFDEN_ADDR, + 0x3 << RG_ANALOGFDEN_SFT, + 0x3 << RG_ANALOGFDEN_SFT); + } else if (priv->data->mic_mode == HEADSET_MODE_6) { + /* DCC mode Low cost mode with internal bias, + * bit8 = 1 to use internal bias + */ + regmap_write(priv->regmap, RG_AUDACCDETMICBIAS0PULLLOW_ADDR, + reg | RG_ACCDET_MODE_ANA11_MODE6); + regmap_update_bits(priv->regmap, RG_AUDPWDBMICBIAS1_ADDR, + RG_AUDMICBIAS1DCSW1PEN_MASK_SFT, + BIT(RG_AUDMICBIAS1DCSW1PEN_SFT)); + /* enable analog fast discharge */ + regmap_update_bits(priv->regmap, RG_ANALOGFDEN_ADDR, + 0x3 << RG_ANALOGFDEN_SFT, + 0x3 << RG_ANALOGFDEN_SFT); + } + + if (priv->caps & ACCDET_PMIC_EINT_IRQ) { + config_eint_init_by_mode(priv); + config_digital_init_by_mode(priv); + } +} + +int mt6359_accdet_enable_jack_detect(struct snd_soc_component *component, + struct snd_soc_jack *jack) +{ + struct mt6359_accdet *priv = + snd_soc_component_get_drvdata(component); + + snd_jack_set_key(jack->jack, SND_JACK_BTN_0, KEY_PLAYPAUSE); + snd_jack_set_key(jack->jack, SND_JACK_BTN_1, KEY_VOLUMEDOWN); + snd_jack_set_key(jack->jack, SND_JACK_BTN_2, KEY_VOLUMEUP); + snd_jack_set_key(jack->jack, SND_JACK_BTN_3, KEY_VOICECOMMAND); + + priv->jack = jack; + + mt6359_accdet_jack_report(priv); + + return 0; +} +EXPORT_SYMBOL_GPL(mt6359_accdet_enable_jack_detect); + +static int mt6359_accdet_probe(struct platform_device *pdev) +{ + struct mt6359_accdet *priv; + struct mt6397_chip *mt6397 = dev_get_drvdata(pdev->dev.parent); + int ret = 0; + + dev_dbg(&pdev->dev, "%s(), dev name %s\n", + __func__, dev_name(&pdev->dev)); + + priv = devm_kzalloc(&pdev->dev, sizeof(struct mt6359_accdet), + GFP_KERNEL); + if (!priv) + return -ENOMEM; + + priv->data = devm_kzalloc(&pdev->dev, sizeof(struct dts_data), + GFP_KERNEL); + if (!priv->data) + return -ENOMEM; + + priv->data->pwm_deb = devm_kzalloc(&pdev->dev, + sizeof(struct pwm_deb_settings), + GFP_KERNEL); + if (!priv->data->pwm_deb) + return -ENOMEM; + + priv->regmap = mt6397->regmap; + if (IS_ERR(priv->regmap)) { + ret = PTR_ERR(priv->regmap); + dev_err(&pdev->dev, "Failed to allocate register map: %d\n", + ret); + return ret; + } + priv->dev = &pdev->dev; + + ret = mt6359_accdet_parse_dt(priv); + if (ret) { + dev_err(&pdev->dev, "Failed to parse dts\n"); + return ret; + } + mutex_init(&priv->res_lock); + + priv->accdet_irq = platform_get_irq(pdev, 0); + if (priv->accdet_irq) { + ret = devm_request_threaded_irq(&pdev->dev, priv->accdet_irq, + NULL, mt6359_accdet_irq, + IRQF_TRIGGER_HIGH | IRQF_ONESHOT, + "ACCDET_IRQ", priv); + if (ret) { + dev_err(&pdev->dev, + "Failed to request IRQ: (%d)\n", ret); + return ret; + } + } + + if (priv->caps & ACCDET_PMIC_EINT0) { + priv->accdet_eint0 = platform_get_irq(pdev, 1); + if (priv->accdet_eint0) { + ret = devm_request_threaded_irq(&pdev->dev, + priv->accdet_eint0, + NULL, mt6359_accdet_irq, + IRQF_TRIGGER_HIGH | IRQF_ONESHOT, + "ACCDET_EINT0", priv); + if (ret) { + dev_err(&pdev->dev, + "Failed to request eint0 IRQ (%d)\n", + ret); + return ret; + } + } + } else if (priv->caps & ACCDET_PMIC_EINT1) { + priv->accdet_eint1 = platform_get_irq(pdev, 2); + if (priv->accdet_eint1) { + ret = devm_request_threaded_irq(&pdev->dev, + priv->accdet_eint1, + NULL, mt6359_accdet_irq, + IRQF_TRIGGER_HIGH | IRQF_ONESHOT, + "ACCDET_EINT1", priv); + if (ret) { + dev_err(&pdev->dev, + "Failed to request eint1 IRQ (%d)\n", + ret); + return ret; + } + } + } + + priv->accdet_workqueue = create_singlethread_workqueue("accdet"); + INIT_WORK(&priv->accdet_work, mt6359_accdet_work); + if (!priv->accdet_workqueue) { + dev_err(&pdev->dev, "Failed to create accdet workqueue\n"); + ret = -1; + goto err_accdet_wq; + } + + priv->jd_workqueue = create_singlethread_workqueue("mt6359_accdet_jd"); + INIT_WORK(&priv->jd_work, mt6359_accdet_jd_work); + if (!priv->jd_workqueue) { + dev_err(&pdev->dev, "Failed to reate jack detect workqueue\n"); + ret = -1; + goto err_eint_wq; + } + + platform_set_drvdata(pdev, priv); + ret = devm_snd_soc_register_component(&pdev->dev, + &mt6359_accdet_soc_driver, + NULL, 0); + if (ret) { + dev_err(&pdev->dev, "Failed to register component\n"); + return ret; + } + + priv->jd_sts = M_PLUG_OUT; + priv->jack_type = 0; + priv->btn_type = 0; + priv->accdet_status = 0x3; + mt6359_accdet_init(priv); + + mt6359_accdet_jack_report(priv); + + return 0; + +err_eint_wq: + destroy_workqueue(priv->accdet_workqueue); +err_accdet_wq: + dev_err(&pdev->dev, "%s error. now exit.!\n", __func__); + return ret; +} + +static struct platform_driver mt6359_accdet_driver = { + .driver = { + .name = "pmic-codec-accdet", + }, + .probe = mt6359_accdet_probe, +}; + +static int __init mt6359_accdet_driver_init(void) +{ + int ret = 0; + + ret = platform_driver_register(&mt6359_accdet_driver); + if (ret) + return -ENODEV; + return 0; +} + +static void __exit mt6359_accdet_driver_exit(void) +{ + platform_driver_unregister(&mt6359_accdet_driver); +} +module_init(mt6359_accdet_driver_init); +module_exit(mt6359_accdet_driver_exit); + +/* Module information */ +MODULE_DESCRIPTION("MT6359 ALSA SoC codec jack driver"); +MODULE_AUTHOR("Argus Lin "); +MODULE_LICENSE("GPL v2"); diff --git a/sound/soc/codecs/mt6359-accdet.h b/sound/soc/codecs/mt6359-accdet.h new file mode 100644 index 000000000000..c234f2f4276a --- /dev/null +++ b/sound/soc/codecs/mt6359-accdet.h @@ -0,0 +1,128 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Copyright (C) 2021 MediaTek Inc. + * Author: Argus Lin + */ + +#ifndef _ACCDET_H_ +#define _ACCDET_H_ + +#include +#include + +#define ACCDET_DEVNAME "accdet" + +#define HEADSET_MODE_1 (1) +#define HEADSET_MODE_2 (2) +#define HEADSET_MODE_6 (6) + +#define MT6359_ACCDET_NUM_BUTTONS 4 +#define MT6359_ACCDET_JACK_MASK (SND_JACK_HEADPHONE | \ + SND_JACK_HEADSET | \ + SND_JACK_BTN_0 | \ + SND_JACK_BTN_1 | \ + SND_JACK_BTN_2 | \ + SND_JACK_BTN_3) +#define MT6359_ACCDET_BTN_MASK (SND_JACK_BTN_0 | \ + SND_JACK_BTN_1 | \ + SND_JACK_BTN_2 | \ + SND_JACK_BTN_3) + +enum eint_moisture_status { + M_PLUG_IN = 0, + M_WATER_IN = 1, + M_HP_PLUG_IN = 2, + M_PLUG_OUT = 3, + M_NO_ACT = 4, + M_UNKNOWN = 5, +}; + +enum { + accdet_state000 = 0, + accdet_state001, + accdet_state010, + accdet_state011, + accdet_auxadc, + eint_state000, + eint_state001, + eint_state010, + eint_state011, + eint_inverter_state000, +}; + +struct three_key_threshold { + unsigned int mid; + unsigned int up; + unsigned int down; +}; + +struct four_key_threshold { + unsigned int mid; + unsigned int voice; + unsigned int up; + unsigned int down; +}; + +struct pwm_deb_settings { + unsigned int pwm_width; + unsigned int pwm_thresh; + unsigned int fall_delay; + unsigned int rise_delay; + unsigned int debounce0; + unsigned int debounce1; + unsigned int debounce3; + unsigned int debounce4; + unsigned int eint_pwm_width; + unsigned int eint_pwm_thresh; + unsigned int eint_debounce0; + unsigned int eint_debounce1; + unsigned int eint_debounce2; + unsigned int eint_debounce3; + unsigned int eint_inverter_debounce; + +}; + +struct dts_data { + unsigned int mic_vol; + unsigned int mic_mode; + unsigned int plugout_deb; + unsigned int eint_pol; + struct pwm_deb_settings *pwm_deb; + struct three_key_threshold three_key; + struct four_key_threshold four_key; + unsigned int moisture_detect_enable; + unsigned int eint_detect_mode; + unsigned int eint_use_ext_res; + unsigned int eint_comp_vth; + unsigned int moisture_detect_mode; + unsigned int moisture_comp_vth; + unsigned int moisture_comp_vref2; + unsigned int moisture_use_ext_res; +}; + +struct mt6359_accdet { + struct snd_soc_jack *jack; + struct device *dev; + struct regmap *regmap; + struct dts_data *data; + unsigned int caps; + int accdet_irq; + int accdet_eint0; + int accdet_eint1; + struct mutex res_lock; /* lock protection */ + bool jack_plugged; + unsigned int jack_type; + unsigned int btn_type; + unsigned int accdet_status; + unsigned int pre_accdet_status; + unsigned int cali_voltage; + unsigned int jd_sts; + struct work_struct accdet_work; + struct workqueue_struct *accdet_workqueue; + struct work_struct jd_work; + struct workqueue_struct *jd_workqueue; +}; + +int mt6359_accdet_enable_jack_detect(struct snd_soc_component *component, + struct snd_soc_jack *jack); +#endif diff --git a/sound/soc/codecs/mt6359.h b/sound/soc/codecs/mt6359.h index 35f806b7396d..296ffa7f50b5 100644 --- a/sound/soc/codecs/mt6359.h +++ b/sound/soc/codecs/mt6359.h @@ -8,129 +8,1779 @@ #define _MT6359_H_ /*************Register Bit Define*************/ -#define PMIC_ACCDET_IRQ_SHIFT 0 -#define PMIC_ACCDET_EINT0_IRQ_SHIFT 2 -#define PMIC_ACCDET_EINT1_IRQ_SHIFT 3 -#define PMIC_ACCDET_IRQ_CLR_SHIFT 8 -#define PMIC_ACCDET_EINT0_IRQ_CLR_SHIFT 10 -#define PMIC_ACCDET_EINT1_IRQ_CLR_SHIFT 11 -#define PMIC_RG_INT_STATUS_ACCDET_SHIFT 5 -#define PMIC_RG_INT_STATUS_ACCDET_EINT0_SHIFT 6 -#define PMIC_RG_INT_STATUS_ACCDET_EINT1_SHIFT 7 -#define PMIC_RG_EINT0CONFIGACCDET_SHIFT 11 -#define PMIC_RG_EINT1CONFIGACCDET_SHIFT 0 -#define PMIC_ACCDET_EINT0_INVERTER_SW_EN_SHIFT 6 -#define PMIC_ACCDET_EINT1_INVERTER_SW_EN_SHIFT 8 -#define PMIC_RG_MTEST_EN_SHIFT 8 -#define PMIC_RG_MTEST_SEL_SHIFT 9 -#define PMIC_ACCDET_EINT0_M_SW_EN_SHIFT 10 -#define PMIC_ACCDET_EINT1_M_SW_EN_SHIFT 11 -#define PMIC_ACCDET_EINT0_CEN_STABLE_SHIFT 5 -#define PMIC_ACCDET_EINT1_CEN_STABLE_SHIFT 10 -#define PMIC_ACCDET_DA_STABLE_SHIFT 0 -#define PMIC_ACCDET_EINT0_EN_STABLE_SHIFT 1 -#define PMIC_ACCDET_EINT0_CMPEN_STABLE_SHIFT 2 -#define PMIC_ACCDET_EINT1_EN_STABLE_SHIFT 6 -#define PMIC_ACCDET_EINT1_CMPEN_STABLE_SHIFT 7 -#define PMIC_ACCDET_EINT_CTURBO_SEL_SHIFT 7 -#define PMIC_ACCDET_EINT0_CTURBO_SW_SHIFT 7 -#define PMIC_RG_EINTCOMPVTH_SHIFT 4 -#define PMIC_RG_EINT0HIRENB_SHIFT 12 -#define PMIC_RG_EINT0NOHYS_SHIFT 10 -#define PMIC_ACCDET_SW_EN_SHIFT 0 -#define PMIC_ACCDET_EINT0_MEM_IN_SHIFT 6 -#define PMIC_ACCDET_MEM_IN_SHIFT 6 -#define PMIC_ACCDET_EINT_DEBOUNCE0_SHIFT 0 -#define PMIC_ACCDET_EINT_DEBOUNCE1_SHIFT 4 -#define PMIC_ACCDET_EINT_DEBOUNCE2_SHIFT 8 -#define PMIC_ACCDET_EINT_DEBOUNCE3_SHIFT 12 -#define PMIC_RG_ACCDET2AUXSWEN_SHIFT 14 -#define PMIC_AUDACCDETAUXADCSWCTRL_SEL_SHIFT 9 -#define PMIC_AUDACCDETAUXADCSWCTRL_SW_SHIFT 10 -#define PMIC_RG_EINT0CTURBO_SHIFT 5 -#define PMIC_RG_EINT1CTURBO_SHIFT 13 -#define PMIC_ACCDET_EINT_M_PLUG_IN_NUM_SHIFT 12 -#define PMIC_ACCDET_EINT_M_DETECT_EN_SHIFT 12 -#define PMIC_ACCDET_EINT0_SW_EN_SHIFT 2 -#define PMIC_ACCDET_EINT1_SW_EN_SHIFT 4 -#define PMIC_ACCDET_EINT_CMPMOUT_SEL_SHIFT 12 -#define PMIC_ACCDET_EINT_CMPMEN_SEL_SHIFT 6 -#define PMIC_RG_HPLOUTPUTSTBENH_VAUDP32_SHIFT 0 -#define PMIC_RG_HPROUTPUTSTBENH_VAUDP32_SHIFT 4 -#define PMIC_RG_EINT0EN_SHIFT 2 -#define PMIC_RG_EINT1EN_SHIFT 10 -#define PMIC_RG_NCP_PDDIS_EN_SHIFT 0 -#define PMIC_RG_ACCDETSPARE_SHIFT 0 -#define PMIC_RG_ACCDET_RST_SHIFT 1 -#define PMIC_RG_AUDMICBIAS1HVEN_SHIFT 12 -#define PMIC_RG_AUDMICBIAS1VREF_SHIFT 4 -#define PMIC_RG_ANALOGFDEN_SHIFT 12 -#define PMIC_RG_AUDMICBIAS1DCSW1PEN_SHIFT 8 -#define PMIC_RG_AUDMICBIAS1LOWPEN_SHIFT 2 -#define PMIC_ACCDET_SEQ_INIT_SHIFT 1 -#define PMIC_RG_EINTCOMPVTH_MASK 0xf -#define PMIC_ACCDET_EINT0_MEM_IN_MASK 0x3 -#define PMIC_ACCDET_EINT_DEBOUNCE0_MASK 0xf -#define PMIC_ACCDET_EINT_DEBOUNCE1_MASK 0xf -#define PMIC_ACCDET_EINT_DEBOUNCE2_MASK 0xf -#define PMIC_ACCDET_EINT_DEBOUNCE3_MASK 0xf -#define PMIC_ACCDET_EINT0_IRQ_SHIFT 2 -#define PMIC_ACCDET_EINT1_IRQ_SHIFT 3 +#define MT6359_TOP0_ID 0x0 +#define MT6359_SMT_CON1 0x32 +#define MT6359_DRV_CON2 0x3c +#define MT6359_DRV_CON3 0x3e +#define MT6359_DRV_CON4 0x40 +#define MT6359_TOP_CKPDN_CON0 0x10c +#define MT6359_TOP_CKPDN_CON0_SET 0x10e +#define MT6359_TOP_CKPDN_CON0_CLR 0x110 +#define MT6359_AUXADC_RQST0 0x1108 +#define MT6359_AUXADC_CON10 0x11a0 +#define MT6359_AUXADC_ACCDET 0x11ba +#define MT6359_LDO_VUSB_OP_EN 0x1d0c +#define MT6359_LDO_VUSB_OP_EN_SET 0x1d0e +#define MT6359_LDO_VUSB_OP_EN_CLR 0x1d10 +#define MT6359_AUD_TOP_CKPDN_CON0 0x230c +#define MT6359_AUD_TOP_CKPDN_CON0_SET 0x230e +#define MT6359_AUD_TOP_CKPDN_CON0_CLR 0x2310 +#define MT6359_AUD_TOP_RST_CON0 0x2320 +#define MT6359_AUD_TOP_RST_CON0_SET 0x2322 +#define MT6359_AUD_TOP_RST_CON0_CLR 0x2324 +#define MT6359_AUD_TOP_INT_CON0 0x2328 +#define MT6359_AUD_TOP_INT_CON0_SET 0x232a +#define MT6359_AUD_TOP_INT_CON0_CLR 0x232c +#define MT6359_AUD_TOP_INT_MASK_CON0 0x232e +#define MT6359_AUD_TOP_INT_MASK_CON0_SET 0x2330 +#define MT6359_AUD_TOP_INT_MASK_CON0_CLR 0x2332 +#define MT6359_AUD_TOP_INT_STATUS0 0x2334 +#define MT6359_AFE_NCP_CFG2 0x24e2 +#define MT6359_AUDENC_DSN_ID 0x2500 +#define MT6359_AUDENC_DSN_REV0 0x2502 +#define MT6359_AUDENC_DSN_DBI 0x2504 +#define MT6359_AUDENC_DSN_FPI 0x2506 +#define MT6359_AUDENC_ANA_CON0 0x2508 +#define MT6359_AUDENC_ANA_CON1 0x250a +#define MT6359_AUDENC_ANA_CON2 0x250c +#define MT6359_AUDENC_ANA_CON3 0x250e +#define MT6359_AUDENC_ANA_CON4 0x2510 +#define MT6359_AUDENC_ANA_CON5 0x2512 +#define MT6359_AUDENC_ANA_CON6 0x2514 +#define MT6359_AUDENC_ANA_CON7 0x2516 +#define MT6359_AUDENC_ANA_CON8 0x2518 +#define MT6359_AUDENC_ANA_CON9 0x251a +#define MT6359_AUDENC_ANA_CON10 0x251c +#define MT6359_AUDENC_ANA_CON11 0x251e +#define MT6359_AUDENC_ANA_CON12 0x2520 +#define MT6359_AUDENC_ANA_CON13 0x2522 +#define MT6359_AUDENC_ANA_CON14 0x2524 +#define MT6359_AUDENC_ANA_CON15 0x2526 +#define MT6359_AUDENC_ANA_CON16 0x2528 +#define MT6359_AUDENC_ANA_CON17 0x252a +#define MT6359_AUDENC_ANA_CON18 0x252c +#define MT6359_AUDENC_ANA_CON19 0x252e +#define MT6359_AUDENC_ANA_CON20 0x2530 +#define MT6359_AUDENC_ANA_CON21 0x2532 +#define MT6359_AUDENC_ANA_CON22 0x2534 +#define MT6359_AUDENC_ANA_CON23 0x2536 +#define MT6359_AUDDEC_DSN_ID 0x2580 +#define MT6359_AUDDEC_DSN_REV0 0x2582 +#define MT6359_AUDDEC_DSN_DBI 0x2584 +#define MT6359_AUDDEC_DSN_FPI 0x2586 +#define MT6359_AUDDEC_ANA_CON0 0x2588 +#define MT6359_AUDDEC_ANA_CON1 0x258a +#define MT6359_AUDDEC_ANA_CON2 0x258c +#define MT6359_AUDDEC_ANA_CON3 0x258e +#define MT6359_AUDDEC_ANA_CON4 0x2590 +#define MT6359_AUDDEC_ANA_CON5 0x2592 +#define MT6359_AUDDEC_ANA_CON6 0x2594 +#define MT6359_AUDDEC_ANA_CON7 0x2596 +#define MT6359_AUDDEC_ANA_CON8 0x2598 +#define MT6359_AUDDEC_ANA_CON9 0x259a +#define MT6359_AUDDEC_ANA_CON10 0x259c +#define MT6359_AUDDEC_ANA_CON11 0x259e +#define MT6359_AUDDEC_ANA_CON12 0x25a0 +#define MT6359_AUDDEC_ANA_CON13 0x25a2 +#define MT6359_AUDDEC_ANA_CON14 0x25a4 +#define MT6359_ACCDET_DSN_DIG_ID 0x2680 +#define MT6359_ACCDET_DSN_DIG_REV0 0x2682 +#define MT6359_ACCDET_DSN_DBI 0x2684 +#define MT6359_ACCDET_DSN_FPI 0x2686 +#define MT6359_ACCDET_CON0 0x2688 +#define MT6359_ACCDET_CON1 0x268a +#define MT6359_ACCDET_CON2 0x268c +#define MT6359_ACCDET_CON3 0x268e +#define MT6359_ACCDET_CON4 0x2690 +#define MT6359_ACCDET_CON5 0x2692 +#define MT6359_ACCDET_CON6 0x2694 +#define MT6359_ACCDET_CON7 0x2696 +#define MT6359_ACCDET_CON8 0x2698 +#define MT6359_ACCDET_CON9 0x269a +#define MT6359_ACCDET_CON10 0x269c +#define MT6359_ACCDET_CON11 0x269e +#define MT6359_ACCDET_CON12 0x26a0 +#define MT6359_ACCDET_CON13 0x26a2 +#define MT6359_ACCDET_CON14 0x26a4 +#define MT6359_ACCDET_CON15 0x26a6 +#define MT6359_ACCDET_CON16 0x26a8 +#define MT6359_ACCDET_CON17 0x26aa +#define MT6359_ACCDET_CON18 0x26ac +#define MT6359_ACCDET_CON19 0x26ae +#define MT6359_ACCDET_CON20 0x26b0 +#define MT6359_ACCDET_CON21 0x26b2 +#define MT6359_ACCDET_CON22 0x26b4 +#define MT6359_ACCDET_CON23 0x26b6 +#define MT6359_ACCDET_CON24 0x26b8 +#define MT6359_ACCDET_CON25 0x26ba +#define MT6359_ACCDET_CON26 0x26bc +#define MT6359_ACCDET_CON27 0x26be +#define MT6359_ACCDET_CON28 0x26c0 +#define MT6359_ACCDET_CON29 0x26c2 +#define MT6359_ACCDET_CON30 0x26c4 +#define MT6359_ACCDET_CON31 0x26c6 +#define MT6359_ACCDET_CON32 0x26c8 +#define MT6359_ACCDET_CON33 0x26ca +#define MT6359_ACCDET_CON34 0x26cc +#define MT6359_ACCDET_CON35 0x26ce +#define MT6359_ACCDET_CON36 0x26d0 +#define MT6359_ACCDET_CON37 0x26d2 +#define MT6359_ACCDET_CON38 0x26d4 +#define MT6359_ACCDET_CON39 0x26d6 +#define MT6359_ACCDET_CON40 0x26d8 -/* AUDENC_ANA_CON16: */ -#define RG_AUD_MICBIAS1_LOWP_EN BIT(PMIC_RG_AUDMICBIAS1LOWPEN_SHIFT) +#define TOP0_ANA_ID_ADDR \ + MT6359_TOP0_ID +#define TOP0_ANA_ID_SFT 0 +#define TOP0_ANA_ID_MASK 0xFF +#define TOP0_ANA_ID_MASK_SFT (0xFF << 0) +#define AUXADC_RQST_CH0_ADDR \ + MT6359_AUXADC_RQST0 +#define AUXADC_RQST_CH0_SFT 0 +#define AUXADC_RQST_CH0_MASK 0x1 +#define AUXADC_RQST_CH0_MASK_SFT (0x1 << 0) +#define AUXADC_ACCDET_ANASWCTRL_EN_ADDR \ + MT6359_AUXADC_CON15 +#define AUXADC_ACCDET_ANASWCTRL_EN_SFT 6 +#define AUXADC_ACCDET_ANASWCTRL_EN_MASK 0x1 +#define AUXADC_ACCDET_ANASWCTRL_EN_MASK_SFT (0x1 << 6) +#define AUXADC_ACCDET_AUTO_SPL_ADDR \ + MT6359_AUXADC_ACCDET +#define AUXADC_ACCDET_AUTO_SPL_SFT 0 +#define AUXADC_ACCDET_AUTO_SPL_MASK 0x1 +#define AUXADC_ACCDET_AUTO_SPL_MASK_SFT (0x1 << 0) +#define AUXADC_ACCDET_AUTO_RQST_CLR_ADDR \ + MT6359_AUXADC_ACCDET +#define AUXADC_ACCDET_AUTO_RQST_CLR_SFT 1 +#define AUXADC_ACCDET_AUTO_RQST_CLR_MASK 0x1 +#define AUXADC_ACCDET_AUTO_RQST_CLR_MASK_SFT (0x1 << 1) +#define AUXADC_ACCDET_DIG1_RSV0_ADDR \ + MT6359_AUXADC_ACCDET +#define AUXADC_ACCDET_DIG1_RSV0_SFT 2 +#define AUXADC_ACCDET_DIG1_RSV0_MASK 0x3F +#define AUXADC_ACCDET_DIG1_RSV0_MASK_SFT (0x3F << 2) +#define AUXADC_ACCDET_DIG0_RSV0_ADDR \ + MT6359_AUXADC_ACCDET +#define AUXADC_ACCDET_DIG0_RSV0_SFT 8 +#define AUXADC_ACCDET_DIG0_RSV0_MASK 0xFF +#define AUXADC_ACCDET_DIG0_RSV0_MASK_SFT (0xFF << 8) + +#define RG_ACCDET_CK_PDN_ADDR \ + MT6359_AUD_TOP_CKPDN_CON0 +#define RG_ACCDET_CK_PDN_SFT 0 +#define RG_ACCDET_CK_PDN_MASK 0x1 +#define RG_ACCDET_CK_PDN_MASK_SFT (0x1 << 0) + +#define RG_ACCDET_RST_ADDR \ + MT6359_AUD_TOP_RST_CON0 +#define RG_ACCDET_RST_SFT 1 +#define RG_ACCDET_RST_MASK 0x1 +#define RG_ACCDET_RST_MASK_SFT (0x1 << 1) +#define BANK_ACCDET_SWRST_ADDR \ + MT6359_AUD_TOP_RST_BANK_CON0 +#define BANK_ACCDET_SWRST_SFT 0 +#define BANK_ACCDET_SWRST_MASK 0x1 +#define BANK_ACCDET_SWRST_MASK_SFT (0x1 << 0) + +#define RG_INT_EN_ACCDET_ADDR \ + MT6359_AUD_TOP_INT_CON0 +#define RG_INT_EN_ACCDET_SFT 5 +#define RG_INT_EN_ACCDET_MASK 0x1 +#define RG_INT_EN_ACCDET_MASK_SFT (0x1 << 5) +#define RG_INT_EN_ACCDET_EINT0_ADDR \ + MT6359_AUD_TOP_INT_CON0 +#define RG_INT_EN_ACCDET_EINT0_SFT 6 +#define RG_INT_EN_ACCDET_EINT0_MASK 0x1 +#define RG_INT_EN_ACCDET_EINT0_MASK_SFT (0x1 << 6) +#define RG_INT_EN_ACCDET_EINT1_ADDR \ + MT6359_AUD_TOP_INT_CON0 +#define RG_INT_EN_ACCDET_EINT1_SFT 7 +#define RG_INT_EN_ACCDET_EINT1_MASK 0x1 +#define RG_INT_EN_ACCDET_EINT1_MASK_SFT (0x1 << 7) + +#define RG_INT_MASK_ACCDET_ADDR \ + MT6359_AUD_TOP_INT_MASK_CON0 +#define RG_INT_MASK_ACCDET_SFT 5 +#define RG_INT_MASK_ACCDET_MASK 0x1 +#define RG_INT_MASK_ACCDET_MASK_SFT (0x1 << 5) +#define RG_INT_MASK_ACCDET_EINT0_ADDR \ + MT6359_AUD_TOP_INT_MASK_CON0 +#define RG_INT_MASK_ACCDET_EINT0_SFT 6 +#define RG_INT_MASK_ACCDET_EINT0_MASK 0x1 +#define RG_INT_MASK_ACCDET_EINT0_MASK_SFT (0x1 << 6) +#define RG_INT_MASK_ACCDET_EINT1_ADDR \ + MT6359_AUD_TOP_INT_MASK_CON0 +#define RG_INT_MASK_ACCDET_EINT1_SFT 7 +#define RG_INT_MASK_ACCDET_EINT1_MASK 0x1 +#define RG_INT_MASK_ACCDET_EINT1_MASK_SFT (0x1 << 7) + +#define RG_INT_STATUS_ACCDET_ADDR \ + MT6359_AUD_TOP_INT_STATUS0 +#define RG_INT_STATUS_ACCDET_SFT 5 +#define RG_INT_STATUS_ACCDET_MASK 0x1 +#define RG_INT_STATUS_ACCDET_MASK_SFT (0x1 << 5) +#define RG_INT_STATUS_ACCDET_EINT0_ADDR \ + MT6359_AUD_TOP_INT_STATUS0 +#define RG_INT_STATUS_ACCDET_EINT0_SFT 6 +#define RG_INT_STATUS_ACCDET_EINT0_MASK 0x1 +#define RG_INT_STATUS_ACCDET_EINT0_MASK_SFT (0x1 << 6) +#define RG_INT_STATUS_ACCDET_EINT1_ADDR \ + MT6359_AUD_TOP_INT_STATUS0 +#define RG_INT_STATUS_ACCDET_EINT1_SFT 7 +#define RG_INT_STATUS_ACCDET_EINT1_MASK 0x1 +#define RG_INT_STATUS_ACCDET_EINT1_MASK_SFT (0x1 << 7) + +#define RG_INT_RAW_STATUS_ACCDET_ADDR \ + MT6359_AUD_TOP_INT_RAW_STATUS0 +#define RG_INT_RAW_STATUS_ACCDET_SFT 5 +#define RG_INT_RAW_STATUS_ACCDET_MASK 0x1 +#define RG_INT_RAW_STATUS_ACCDET_MASK_SFT (0x1 << 5) +#define RG_INT_RAW_STATUS_ACCDET_EINT0_ADDR \ + MT6359_AUD_TOP_INT_RAW_STATUS0 +#define RG_INT_RAW_STATUS_ACCDET_EINT0_SFT 6 +#define RG_INT_RAW_STATUS_ACCDET_EINT0_MASK 0x1 +#define RG_INT_RAW_STATUS_ACCDET_EINT0_MASK_SFT (0x1 << 6) +#define RG_INT_RAW_STATUS_ACCDET_EINT1_ADDR \ + MT6359_AUD_TOP_INT_RAW_STATUS0 +#define RG_INT_RAW_STATUS_ACCDET_EINT1_SFT 7 +#define RG_INT_RAW_STATUS_ACCDET_EINT1_MASK 0x1 +#define RG_INT_RAW_STATUS_ACCDET_EINT1_MASK_SFT (0x1 << 7) + +#define RG_AUDACCDETMICBIAS0PULLLOW_ADDR \ + MT6359_AUDENC_ANA_CON18 +#define RG_AUDACCDETMICBIAS0PULLLOW_SFT 0 +#define RG_AUDACCDETMICBIAS0PULLLOW_MASK 0x1 +#define RG_AUDACCDETMICBIAS0PULLLOW_MASK_SFT (0x1 << 0) +#define RG_AUDACCDETMICBIAS1PULLLOW_ADDR \ + MT6359_AUDENC_ANA_CON18 +#define RG_AUDACCDETMICBIAS1PULLLOW_SFT 1 +#define RG_AUDACCDETMICBIAS1PULLLOW_MASK 0x1 +#define RG_AUDACCDETMICBIAS1PULLLOW_MASK_SFT (0x1 << 1) +#define RG_AUDACCDETMICBIAS2PULLLOW_ADDR \ + MT6359_AUDENC_ANA_CON18 +#define RG_AUDACCDETMICBIAS2PULLLOW_SFT 2 +#define RG_AUDACCDETMICBIAS2PULLLOW_MASK 0x1 +#define RG_AUDACCDETMICBIAS2PULLLOW_MASK_SFT (0x1 << 2) +#define RG_AUDACCDETVIN1PULLLOW_ADDR \ + MT6359_AUDENC_ANA_CON18 +#define RG_AUDACCDETVIN1PULLLOW_SFT 3 +#define RG_AUDACCDETVIN1PULLLOW_MASK 0x1 +#define RG_AUDACCDETVIN1PULLLOW_MASK_SFT (0x1 << 3) +#define RG_AUDACCDETVTHACAL_ADDR \ + MT6359_AUDENC_ANA_CON18 +#define RG_AUDACCDETVTHACAL_SFT 4 +#define RG_AUDACCDETVTHACAL_MASK 0x1 +#define RG_AUDACCDETVTHACAL_MASK_SFT (0x1 << 4) +#define RG_AUDACCDETVTHBCAL_ADDR \ + MT6359_AUDENC_ANA_CON18 +#define RG_AUDACCDETVTHBCAL_SFT 5 +#define RG_AUDACCDETVTHBCAL_MASK 0x1 +#define RG_AUDACCDETVTHBCAL_MASK_SFT (0x1 << 5) +#define RG_AUDACCDETTVDET_ADDR \ + MT6359_AUDENC_ANA_CON18 +#define RG_AUDACCDETTVDET_SFT 6 +#define RG_AUDACCDETTVDET_MASK 0x1 +#define RG_AUDACCDETTVDET_MASK_SFT (0x1 << 6) +#define RG_ACCDETSEL_ADDR \ + MT6359_AUDENC_ANA_CON18 +#define RG_ACCDETSEL_SFT 7 +#define RG_ACCDETSEL_MASK 0x1 +#define RG_ACCDETSEL_MASK_SFT (0x1 << 7) + +#define RG_AUDPWDBMICBIAS1_ADDR \ + MT6359_AUDENC_ANA_CON16 +#define RG_AUDPWDBMICBIAS1_SFT 0 +#define RG_AUDPWDBMICBIAS1_MASK 0x1 +#define RG_AUDPWDBMICBIAS1_MASK_SFT (0x1 << 0) +#define RG_AUDMICBIAS1BYPASSEN_ADDR \ + MT6359_AUDENC_ANA_CON16 +#define RG_AUDMICBIAS1BYPASSEN_SFT 1 +#define RG_AUDMICBIAS1BYPASSEN_MASK 0x1 +#define RG_AUDMICBIAS1BYPASSEN_MASK_SFT (0x1 << 1) +#define RG_AUDMICBIAS1LOWPEN_ADDR \ + MT6359_AUDENC_ANA_CON16 +#define RG_AUDMICBIAS1LOWPEN_SFT 2 +#define RG_AUDMICBIAS1LOWPEN_MASK 0x1 +#define RG_AUDMICBIAS1LOWPEN_MASK_SFT (0x1 << 2) +#define RG_AUDMICBIAS1VREF_ADDR \ + MT6359_AUDENC_ANA_CON16 +#define RG_AUDMICBIAS1VREF_SFT 4 +#define RG_AUDMICBIAS1VREF_MASK 0x7 +#define RG_AUDMICBIAS1VREF_MASK_SFT (0x7 << 4) +#define RG_AUDMICBIAS1DCSW1PEN_ADDR \ + MT6359_AUDENC_ANA_CON16 +#define RG_AUDMICBIAS1DCSW1PEN_SFT 8 +#define RG_AUDMICBIAS1DCSW1PEN_MASK 0x1 +#define RG_AUDMICBIAS1DCSW1PEN_MASK_SFT (0x1 << 8) +#define RG_AUDMICBIAS1DCSW1NEN_ADDR \ + MT6359_AUDENC_ANA_CON16 +#define RG_AUDMICBIAS1DCSW1NEN_SFT 9 +#define RG_AUDMICBIAS1DCSW1NEN_MASK 0x1 +#define RG_AUDMICBIAS1DCSW1NEN_MASK_SFT (0x1 << 9) +#define RG_BANDGAPGEN_ADDR \ + MT6359_AUDENC_ANA_CON16 +#define RG_BANDGAPGEN_SFT 10 +#define RG_BANDGAPGEN_MASK 0x1 +#define RG_BANDGAPGEN_MASK_SFT (0x1 << 10) +#define RG_AUDMICBIAS1HVEN_ADDR \ + MT6359_AUDENC_ANA_CON16 +#define RG_AUDMICBIAS1HVEN_SFT 12 +#define RG_AUDMICBIAS1HVEN_MASK 0x1 +#define RG_AUDMICBIAS1HVEN_MASK_SFT (0x1 << 12) +#define RG_AUDMICBIAS1HVVREF_ADDR \ + MT6359_AUDENC_ANA_CON16 +#define RG_AUDMICBIAS1HVVREF_SFT 13 +#define RG_AUDMICBIAS1HVVREF_MASK 0x1 +#define RG_AUDMICBIAS1HVVREF_MASK_SFT (0x1 << 13) + +#define RG_EINT0NOHYS_ADDR \ + MT6359_AUDENC_ANA_CON18 +#define RG_EINT0NOHYS_SFT 10 +#define RG_EINT0NOHYS_MASK 0x1 +#define RG_EINT0NOHYS_MASK_SFT (0x1 << 10) +#define RG_EINT0CONFIGACCDET_ADDR \ + MT6359_AUDENC_ANA_CON18 +#define RG_EINT0CONFIGACCDET_SFT 11 +#define RG_EINT0CONFIGACCDET_MASK 0x1 +#define RG_EINT0CONFIGACCDET_MASK_SFT (0x1 << 11) +#define RG_EINT0HIRENB_ADDR \ + MT6359_AUDENC_ANA_CON18 +#define RG_EINT0HIRENB_SFT 12 +#define RG_EINT0HIRENB_MASK 0x1 +#define RG_EINT0HIRENB_MASK_SFT (0x1 << 12) +#define RG_ACCDET2AUXRESBYPASS_ADDR \ + MT6359_AUDENC_ANA_CON18 +#define RG_ACCDET2AUXRESBYPASS_SFT 13 +#define RG_ACCDET2AUXRESBYPASS_MASK 0x1 +#define RG_ACCDET2AUXRESBYPASS_MASK_SFT (0x1 << 13) +#define RG_ACCDET2AUXSWEN_ADDR \ + MT6359_AUDENC_ANA_CON18 +#define RG_ACCDET2AUXSWEN_SFT 14 +#define RG_ACCDET2AUXSWEN_MASK 0x1 +#define RG_ACCDET2AUXSWEN_MASK_SFT (0x1 << 14) +#define RG_AUDACCDETMICBIAS3PULLLOW_ADDR \ + MT6359_AUDENC_ANA_CON18 +#define RG_AUDACCDETMICBIAS3PULLLOW_SFT 15 +#define RG_AUDACCDETMICBIAS3PULLLOW_MASK 0x1 +#define RG_AUDACCDETMICBIAS3PULLLOW_MASK_SFT (0x1 << 15) +#define RG_EINT1CONFIGACCDET_ADDR \ + MT6359_AUDENC_ANA_CON19 +#define RG_EINT1CONFIGACCDET_SFT 0 +#define RG_EINT1CONFIGACCDET_MASK 0x1 +#define RG_EINT1CONFIGACCDET_MASK_SFT (0x1 << 0) +#define RG_EINT1HIRENB_ADDR \ + MT6359_AUDENC_ANA_CON19 +#define RG_EINT1HIRENB_SFT 1 +#define RG_EINT1HIRENB_MASK 0x1 +#define RG_EINT1HIRENB_MASK_SFT (0x1 << 1) +#define RG_EINT1NOHYS_ADDR \ + MT6359_AUDENC_ANA_CON19 +#define RG_EINT1NOHYS_SFT 2 +#define RG_EINT1NOHYS_MASK 0x1 +#define RG_EINT1NOHYS_MASK_SFT (0x1 << 2) +#define RG_EINTCOMPVTH_ADDR \ + MT6359_AUDENC_ANA_CON19 +#define RG_MTEST_EN_ADDR \ + MT6359_AUDENC_ANA_CON19 +#define RG_MTEST_EN_SFT 8 +#define RG_MTEST_EN_MASK 0x1 +#define RG_MTEST_EN_MASK_SFT (0x1 << 8) +#define RG_MTEST_SEL_ADDR \ + MT6359_AUDENC_ANA_CON19 +#define RG_MTEST_SEL_SFT 9 +#define RG_MTEST_SEL_MASK 0x1 +#define RG_MTEST_SEL_MASK_SFT (0x1 << 9) +#define RG_MTEST_CURRENT_ADDR \ + MT6359_AUDENC_ANA_CON19 +#define RG_MTEST_CURRENT_SFT 10 +#define RG_MTEST_CURRENT_MASK 0x1 +#define RG_MTEST_CURRENT_MASK_SFT (0x1 << 10) +#define RG_ANALOGFDEN_ADDR \ + MT6359_AUDENC_ANA_CON19 +#define RG_ANALOGFDEN_SFT 12 +#define RG_ANALOGFDEN_MASK 0x1 +#define RG_ANALOGFDEN_MASK_SFT (0x1 << 12) +#define RG_FDVIN1PPULLLOW_ADDR \ + MT6359_AUDENC_ANA_CON19 +#define RG_FDVIN1PPULLLOW_SFT 13 +#define RG_FDVIN1PPULLLOW_MASK 0x1 +#define RG_FDVIN1PPULLLOW_MASK_SFT (0x1 << 13) +#define RG_FDEINT0TYPE_ADDR \ + MT6359_AUDENC_ANA_CON19 +#define RG_FDEINT0TYPE_SFT 14 +#define RG_FDEINT0TYPE_MASK 0x1 +#define RG_FDEINT0TYPE_MASK_SFT (0x1 << 14) +#define RG_FDEINT1TYPE_ADDR \ + MT6359_AUDENC_ANA_CON19 +#define RG_FDEINT1TYPE_SFT 15 +#define RG_FDEINT1TYPE_MASK 0x1 +#define RG_FDEINT1TYPE_MASK_SFT (0x1 << 15) +#define RG_EINT0CMPEN_ADDR \ + MT6359_AUDENC_ANA_CON20 +#define RG_EINT0CMPEN_SFT 0 +#define RG_EINT0CMPEN_MASK 0x1 +#define RG_EINT0CMPEN_MASK_SFT (0x1 << 0) +#define RG_EINT0CMPMEN_ADDR \ + MT6359_AUDENC_ANA_CON20 +#define RG_EINT0CMPMEN_SFT 1 +#define RG_EINT0CMPMEN_MASK 0x1 +#define RG_EINT0CMPMEN_MASK_SFT (0x1 << 1) +#define RG_EINT0EN_ADDR \ + MT6359_AUDENC_ANA_CON20 +#define RG_EINT0EN_SFT 2 +#define RG_EINT0EN_MASK 0x1 +#define RG_EINT0EN_MASK_SFT (0x1 << 2) +#define RG_EINT0CEN_ADDR \ + MT6359_AUDENC_ANA_CON20 +#define RG_EINT0CEN_SFT 3 +#define RG_EINT0CEN_MASK 0x1 +#define RG_EINT0CEN_MASK_SFT (0x1 << 3) +#define RG_EINT0INVEN_ADDR \ + MT6359_AUDENC_ANA_CON20 +#define RG_EINT0INVEN_SFT 4 +#define RG_EINT0INVEN_MASK 0x1 +#define RG_EINT0INVEN_MASK_SFT (0x1 << 4) +#define RG_EINT0CTURBO_ADDR \ + MT6359_AUDENC_ANA_CON20 +#define RG_EINT0CTURBO_SFT 5 +#define RG_EINT0CTURBO_MASK 0x7 +#define RG_EINT0CTURBO_MASK_SFT (0x7 << 5) +#define RG_EINT1CMPEN_ADDR \ + MT6359_AUDENC_ANA_CON20 +#define RG_EINT1CMPEN_SFT 8 +#define RG_EINT1CMPEN_MASK 0x1 +#define RG_EINT1CMPEN_MASK_SFT (0x1 << 8) +#define RG_EINT1CMPMEN_ADDR \ + MT6359_AUDENC_ANA_CON20 +#define RG_EINT1CMPMEN_SFT 9 +#define RG_EINT1CMPMEN_MASK 0x1 +#define RG_EINT1CMPMEN_MASK_SFT (0x1 << 9) +#define RG_EINT1EN_ADDR \ + MT6359_AUDENC_ANA_CON20 +#define RG_EINT1EN_SFT 10 +#define RG_EINT1EN_MASK 0x1 +#define RG_EINT1EN_MASK_SFT (0x1 << 10) +#define RG_EINT1CEN_ADDR \ + MT6359_AUDENC_ANA_CON20 +#define RG_EINT1CEN_SFT 11 +#define RG_EINT1CEN_MASK 0x1 +#define RG_EINT1CEN_MASK_SFT (0x1 << 11) +#define RG_EINT1INVEN_ADDR \ + MT6359_AUDENC_ANA_CON20 +#define RG_EINT1INVEN_SFT 12 +#define RG_EINT1INVEN_MASK 0x1 +#define RG_EINT1INVEN_MASK_SFT (0x1 << 12) +#define RG_EINT1CTURBO_ADDR \ + MT6359_AUDENC_ANA_CON20 +#define RG_EINT1CTURBO_SFT 13 +#define RG_EINT1CTURBO_MASK 0x7 +#define RG_EINT1CTURBO_MASK_SFT (0x7 << 13) +#define RG_ACCDETSPARE_ADDR \ + MT6359_AUDENC_ANA_CON21 + +#define ACCDET_ANA_ID_ADDR \ + MT6359_ACCDET_DSN_DIG_ID +#define ACCDET_ANA_ID_SFT 0 +#define ACCDET_ANA_ID_MASK 0xFF +#define ACCDET_ANA_ID_MASK_SFT (0xFF << 0) +#define ACCDET_DIG_ID_ADDR \ + MT6359_ACCDET_DSN_DIG_ID +#define ACCDET_DIG_ID_SFT 8 +#define ACCDET_DIG_ID_MASK 0xFF +#define ACCDET_DIG_ID_MASK_SFT (0xFF << 8) +#define ACCDET_ANA_MINOR_REV_ADDR \ + MT6359_ACCDET_DSN_DIG_REV0 +#define ACCDET_ANA_MINOR_REV_SFT 0 +#define ACCDET_ANA_MINOR_REV_MASK 0xF +#define ACCDET_ANA_MINOR_REV_MASK_SFT (0xF << 0) +#define ACCDET_ANA_MAJOR_REV_ADDR \ + MT6359_ACCDET_DSN_DIG_REV0 +#define ACCDET_ANA_MAJOR_REV_SFT 4 +#define ACCDET_ANA_MAJOR_REV_MASK 0xF +#define ACCDET_ANA_MAJOR_REV_MASK_SFT (0xF << 4) +#define ACCDET_DIG_MINOR_REV_ADDR \ + MT6359_ACCDET_DSN_DIG_REV0 +#define ACCDET_DIG_MINOR_REV_SFT 8 +#define ACCDET_DIG_MINOR_REV_MASK 0xF +#define ACCDET_DIG_MINOR_REV_MASK_SFT (0xF << 8) +#define ACCDET_DIG_MAJOR_REV_ADDR \ + MT6359_ACCDET_DSN_DIG_REV0 +#define ACCDET_DIG_MAJOR_REV_SFT 12 +#define ACCDET_DIG_MAJOR_REV_MASK 0xF +#define ACCDET_DIG_MAJOR_REV_MASK_SFT (0xF << 12) +#define ACCDET_DSN_CBS_ADDR \ + MT6359_ACCDET_DSN_DBI +#define ACCDET_DSN_CBS_SFT 0 +#define ACCDET_DSN_CBS_MASK 0x3 +#define ACCDET_DSN_CBS_MASK_SFT (0x3 << 0) +#define ACCDET_DSN_BIX_ADDR \ + MT6359_ACCDET_DSN_DBI +#define ACCDET_DSN_BIX_SFT 2 +#define ACCDET_DSN_BIX_MASK 0x3 +#define ACCDET_DSN_BIX_MASK_SFT (0x3 << 2) +#define ACCDET_ESP_ADDR \ + MT6359_ACCDET_DSN_DBI +#define ACCDET_ESP_SFT 8 +#define ACCDET_ESP_MASK 0xFF +#define ACCDET_ESP_MASK_SFT (0xFF << 8) +#define ACCDET_DSN_FPI_ADDR \ + MT6359_ACCDET_DSN_FPI +#define ACCDET_DSN_FPI_SFT 0 +#define ACCDET_DSN_FPI_MASK 0xFF +#define ACCDET_DSN_FPI_MASK_SFT (0xFF << 0) +#define ACCDET_AUXADC_SEL_ADDR \ + MT6359_ACCDET_CON0 +#define ACCDET_AUXADC_SEL_SFT 0 +#define ACCDET_AUXADC_SEL_MASK 0x1 +#define ACCDET_AUXADC_SEL_MASK_SFT (0x1 << 0) +#define ACCDET_AUXADC_SW_ADDR \ + MT6359_ACCDET_CON0 +#define ACCDET_AUXADC_SW_SFT 1 +#define ACCDET_AUXADC_SW_MASK 0x1 +#define ACCDET_AUXADC_SW_MASK_SFT (0x1 << 1) +#define ACCDET_TEST_AUXADC_ADDR \ + MT6359_ACCDET_CON0 +#define ACCDET_TEST_AUXADC_SFT 2 +#define ACCDET_TEST_AUXADC_MASK 0x1 +#define ACCDET_TEST_AUXADC_MASK_SFT (0x1 << 2) +#define ACCDET_AUXADC_ANASWCTRL_SEL_ADDR \ + MT6359_ACCDET_CON0 +#define ACCDET_AUXADC_ANASWCTRL_SEL_SFT 8 +#define ACCDET_AUXADC_ANASWCTRL_SEL_MASK 0x1 +#define ACCDET_AUXADC_ANASWCTRL_SEL_MASK_SFT (0x1 << 8) +#define AUDACCDETAUXADCSWCTRL_SEL_ADDR \ + MT6359_ACCDET_CON0 +#define AUDACCDETAUXADCSWCTRL_SEL_SFT 9 +#define AUDACCDETAUXADCSWCTRL_SEL_MASK 0x1 +#define AUDACCDETAUXADCSWCTRL_SEL_MASK_SFT (0x1 << 9) +#define AUDACCDETAUXADCSWCTRL_SW_ADDR \ + MT6359_ACCDET_CON0 +#define AUDACCDETAUXADCSWCTRL_SW_SFT 10 +#define AUDACCDETAUXADCSWCTRL_SW_MASK 0x1 +#define AUDACCDETAUXADCSWCTRL_SW_MASK_SFT (0x1 << 10) +#define ACCDET_TEST_ANA_ADDR \ + MT6359_ACCDET_CON0 +#define ACCDET_TEST_ANA_SFT 11 +#define ACCDET_TEST_ANA_MASK 0x1 +#define ACCDET_TEST_ANA_MASK_SFT (0x1 << 11) +#define RG_AUDACCDETRSV_ADDR \ + MT6359_ACCDET_CON0 +#define RG_AUDACCDETRSV_SFT 13 +#define RG_AUDACCDETRSV_MASK 0x3 +#define RG_AUDACCDETRSV_MASK_SFT (0x3 << 13) +#define ACCDET_SW_EN_ADDR \ + MT6359_ACCDET_CON1 +#define ACCDET_SW_EN_SFT 0 +#define ACCDET_SW_EN_MASK 0x1 +#define ACCDET_SW_EN_MASK_SFT (0x1 << 0) +#define ACCDET_SEQ_INIT_ADDR \ + MT6359_ACCDET_CON1 +#define ACCDET_SEQ_INIT_SFT 1 +#define ACCDET_SEQ_INIT_MASK 0x1 +#define ACCDET_SEQ_INIT_MASK_SFT (0x1 << 1) +#define ACCDET_EINT0_SW_EN_ADDR \ + MT6359_ACCDET_CON1 +#define ACCDET_EINT0_SW_EN_SFT 2 +#define ACCDET_EINT0_SW_EN_MASK 0x1 +#define ACCDET_EINT0_SW_EN_MASK_SFT (0x1 << 2) +#define ACCDET_EINT0_SEQ_INIT_ADDR \ + MT6359_ACCDET_CON1 +#define ACCDET_EINT0_SEQ_INIT_SFT 3 +#define ACCDET_EINT0_SEQ_INIT_MASK 0x1 +#define ACCDET_EINT0_SEQ_INIT_MASK_SFT (0x1 << 3) +#define ACCDET_EINT1_SW_EN_ADDR \ + MT6359_ACCDET_CON1 +#define ACCDET_EINT1_SW_EN_SFT 4 +#define ACCDET_EINT1_SW_EN_MASK 0x1 +#define ACCDET_EINT1_SW_EN_MASK_SFT (0x1 << 4) +#define ACCDET_EINT1_SEQ_INIT_ADDR \ + MT6359_ACCDET_CON1 +#define ACCDET_EINT1_SEQ_INIT_SFT 5 +#define ACCDET_EINT1_SEQ_INIT_MASK 0x1 +#define ACCDET_EINT1_SEQ_INIT_MASK_SFT (0x1 << 5) +#define ACCDET_EINT0_INVERTER_SW_EN_ADDR \ + MT6359_ACCDET_CON1 +#define ACCDET_EINT0_INVERTER_SW_EN_SFT 6 +#define ACCDET_EINT0_INVERTER_SW_EN_MASK 0x1 +#define ACCDET_EINT0_INVERTER_SW_EN_MASK_SFT (0x1 << 6) +#define ACCDET_EINT0_INVERTER_SEQ_INIT_ADDR \ + MT6359_ACCDET_CON1 +#define ACCDET_EINT0_INVERTER_SEQ_INIT_SFT 7 +#define ACCDET_EINT0_INVERTER_SEQ_INIT_MASK 0x1 +#define ACCDET_EINT0_INVERTER_SEQ_INIT_MASK_SFT (0x1 << 7) +#define ACCDET_EINT1_INVERTER_SW_EN_ADDR \ + MT6359_ACCDET_CON1 +#define ACCDET_EINT1_INVERTER_SW_EN_SFT 8 +#define ACCDET_EINT1_INVERTER_SW_EN_MASK 0x1 +#define ACCDET_EINT1_INVERTER_SW_EN_MASK_SFT (0x1 << 8) +#define ACCDET_EINT1_INVERTER_SEQ_INIT_ADDR \ + MT6359_ACCDET_CON1 +#define ACCDET_EINT1_INVERTER_SEQ_INIT_SFT 9 +#define ACCDET_EINT1_INVERTER_SEQ_INIT_MASK 0x1 +#define ACCDET_EINT1_INVERTER_SEQ_INIT_MASK_SFT (0x1 << 9) +#define ACCDET_EINT0_M_SW_EN_ADDR \ + MT6359_ACCDET_CON1 +#define ACCDET_EINT0_M_SW_EN_SFT 10 +#define ACCDET_EINT0_M_SW_EN_MASK 0x1 +#define ACCDET_EINT0_M_SW_EN_MASK_SFT (0x1 << 10) +#define ACCDET_EINT1_M_SW_EN_ADDR \ + MT6359_ACCDET_CON1 +#define ACCDET_EINT1_M_SW_EN_SFT 11 +#define ACCDET_EINT1_M_SW_EN_MASK 0x1 +#define ACCDET_EINT1_M_SW_EN_MASK_SFT (0x1 << 11) +#define ACCDET_EINT_M_DETECT_EN_ADDR \ + MT6359_ACCDET_CON1 +#define ACCDET_EINT_M_DETECT_EN_SFT 12 +#define ACCDET_EINT_M_DETECT_EN_MASK 0x1 +#define ACCDET_EINT_M_DETECT_EN_MASK_SFT (0x1 << 12) +#define ACCDET_CMP_PWM_EN_ADDR \ + MT6359_ACCDET_CON2 +#define ACCDET_CMP_PWM_EN_SFT 0 +#define ACCDET_CMP_PWM_EN_MASK 0x1 +#define ACCDET_CMP_PWM_EN_MASK_SFT (0x1 << 0) +#define ACCDET_VTH_PWM_EN_ADDR \ + MT6359_ACCDET_CON2 +#define ACCDET_VTH_PWM_EN_SFT 1 +#define ACCDET_VTH_PWM_EN_MASK 0x1 +#define ACCDET_VTH_PWM_EN_MASK_SFT (0x1 << 1) +#define ACCDET_MBIAS_PWM_EN_ADDR \ + MT6359_ACCDET_CON2 +#define ACCDET_MBIAS_PWM_EN_SFT 2 +#define ACCDET_MBIAS_PWM_EN_MASK 0x1 +#define ACCDET_MBIAS_PWM_EN_MASK_SFT (0x1 << 2) +#define ACCDET_EINT_EN_PWM_EN_ADDR \ + MT6359_ACCDET_CON2 +#define ACCDET_EINT_EN_PWM_EN_SFT 3 +#define ACCDET_EINT_EN_PWM_EN_MASK 0x1 +#define ACCDET_EINT_EN_PWM_EN_MASK_SFT (0x1 << 3) +#define ACCDET_EINT_CMPEN_PWM_EN_ADDR \ + MT6359_ACCDET_CON2 +#define ACCDET_EINT_CMPEN_PWM_EN_SFT 4 +#define ACCDET_EINT_CMPEN_PWM_EN_MASK 0x1 +#define ACCDET_EINT_CMPEN_PWM_EN_MASK_SFT (0x1 << 4) +#define ACCDET_EINT_CMPMEN_PWM_EN_ADDR \ + MT6359_ACCDET_CON2 +#define ACCDET_EINT_CMPMEN_PWM_EN_SFT 5 +#define ACCDET_EINT_CMPMEN_PWM_EN_MASK 0x1 +#define ACCDET_EINT_CMPMEN_PWM_EN_MASK_SFT (0x1 << 5) +#define ACCDET_EINT_CTURBO_PWM_EN_ADDR \ + MT6359_ACCDET_CON2 +#define ACCDET_EINT_CTURBO_PWM_EN_SFT 6 +#define ACCDET_EINT_CTURBO_PWM_EN_MASK 0x1 +#define ACCDET_EINT_CTURBO_PWM_EN_MASK_SFT (0x1 << 6) +#define ACCDET_CMP_PWM_IDLE_ADDR \ + MT6359_ACCDET_CON2 +#define ACCDET_CMP_PWM_IDLE_SFT 8 +#define ACCDET_CMP_PWM_IDLE_MASK 0x1 +#define ACCDET_CMP_PWM_IDLE_MASK_SFT (0x1 << 8) +#define ACCDET_VTH_PWM_IDLE_ADDR \ + MT6359_ACCDET_CON2 +#define ACCDET_VTH_PWM_IDLE_SFT 9 +#define ACCDET_VTH_PWM_IDLE_MASK 0x1 +#define ACCDET_VTH_PWM_IDLE_MASK_SFT (0x1 << 9) +#define ACCDET_MBIAS_PWM_IDLE_ADDR \ + MT6359_ACCDET_CON2 +#define ACCDET_MBIAS_PWM_IDLE_SFT 10 +#define ACCDET_MBIAS_PWM_IDLE_MASK 0x1 +#define ACCDET_MBIAS_PWM_IDLE_MASK_SFT (0x1 << 10) +#define ACCDET_EINT0_CMPEN_PWM_IDLE_ADDR \ + MT6359_ACCDET_CON2 +#define ACCDET_EINT0_CMPEN_PWM_IDLE_SFT 11 +#define ACCDET_EINT0_CMPEN_PWM_IDLE_MASK 0x1 +#define ACCDET_EINT0_CMPEN_PWM_IDLE_MASK_SFT (0x1 << 11) +#define ACCDET_EINT1_CMPEN_PWM_IDLE_ADDR \ + MT6359_ACCDET_CON2 +#define ACCDET_EINT1_CMPEN_PWM_IDLE_SFT 12 +#define ACCDET_EINT1_CMPEN_PWM_IDLE_MASK 0x1 +#define ACCDET_EINT1_CMPEN_PWM_IDLE_MASK_SFT (0x1 << 12) +#define ACCDET_PWM_EN_SW_ADDR \ + MT6359_ACCDET_CON2 +#define ACCDET_PWM_EN_SW_SFT 13 +#define ACCDET_PWM_EN_SW_MASK 0x1 +#define ACCDET_PWM_EN_SW_MASK_SFT (0x1 << 13) +#define ACCDET_PWM_EN_SEL_ADDR \ + MT6359_ACCDET_CON2 +#define ACCDET_PWM_EN_SEL_SFT 14 +#define ACCDET_PWM_EN_SEL_MASK 0x3 +#define ACCDET_PWM_EN_SEL_MASK_SFT (0x3 << 14) +#define ACCDET_PWM_WIDTH_ADDR \ + MT6359_ACCDET_CON3 +#define ACCDET_PWM_WIDTH_SFT 0 +#define ACCDET_PWM_WIDTH_MASK 0xFFFF +#define ACCDET_PWM_WIDTH_MASK_SFT (0xFFFF << 0) +#define ACCDET_PWM_THRESH_ADDR \ + MT6359_ACCDET_CON4 +#define ACCDET_PWM_THRESH_SFT 0 +#define ACCDET_PWM_THRESH_MASK 0xFFFF +#define ACCDET_PWM_THRESH_MASK_SFT (0xFFFF << 0) +#define ACCDET_RISE_DELAY_ADDR \ + MT6359_ACCDET_CON5 +#define ACCDET_RISE_DELAY_SFT 0 +#define ACCDET_RISE_DELAY_MASK 0x7FFF +#define ACCDET_RISE_DELAY_MASK_SFT (0x7FFF << 0) +#define ACCDET_FALL_DELAY_ADDR \ + MT6359_ACCDET_CON5 +#define ACCDET_FALL_DELAY_SFT 15 +#define ACCDET_FALL_DELAY_MASK 0x1 +#define ACCDET_FALL_DELAY_MASK_SFT (0x1 << 15) +#define ACCDET_EINT_CMPMEN_PWM_THRESH_ADDR \ + MT6359_ACCDET_CON6 +#define ACCDET_EINT_CMPMEN_PWM_THRESH_SFT 0 +#define ACCDET_EINT_CMPMEN_PWM_THRESH_MASK 0x7 +#define ACCDET_EINT_CMPMEN_PWM_THRESH_MASK_SFT (0x7 << 0) +#define ACCDET_EINT_CMPMEN_PWM_WIDTH_ADDR \ + MT6359_ACCDET_CON6 +#define ACCDET_EINT_CMPMEN_PWM_WIDTH_SFT 4 +#define ACCDET_EINT_CMPMEN_PWM_WIDTH_MASK 0x7 +#define ACCDET_EINT_CMPMEN_PWM_WIDTH_MASK_SFT (0x7 << 4) +#define ACCDET_EINT_EN_PWM_THRESH_ADDR \ + MT6359_ACCDET_CON7 +#define ACCDET_EINT_EN_PWM_THRESH_SFT 0 +#define ACCDET_EINT_EN_PWM_THRESH_MASK 0x7 +#define ACCDET_EINT_EN_PWM_THRESH_MASK_SFT (0x7 << 0) +#define ACCDET_EINT_EN_PWM_WIDTH_ADDR \ + MT6359_ACCDET_CON7 +#define ACCDET_EINT_EN_PWM_WIDTH_SFT 4 +#define ACCDET_EINT_EN_PWM_WIDTH_MASK 0x3 +#define ACCDET_EINT_EN_PWM_WIDTH_MASK_SFT (0x3 << 4) +#define ACCDET_EINT_CMPEN_PWM_THRESH_ADDR \ + MT6359_ACCDET_CON7 +#define ACCDET_EINT_CMPEN_PWM_THRESH_SFT 8 +#define ACCDET_EINT_CMPEN_PWM_THRESH_MASK 0x7 +#define ACCDET_EINT_CMPEN_PWM_THRESH_MASK_SFT (0x7 << 8) +#define ACCDET_EINT_CMPEN_PWM_WIDTH_ADDR \ + MT6359_ACCDET_CON7 +#define ACCDET_EINT_CMPEN_PWM_WIDTH_SFT 12 +#define ACCDET_EINT_CMPEN_PWM_WIDTH_MASK 0x3 +#define ACCDET_EINT_CMPEN_PWM_WIDTH_MASK_SFT (0x3 << 12) +#define ACCDET_DEBOUNCE0_ADDR \ + MT6359_ACCDET_CON8 +#define ACCDET_DEBOUNCE0_SFT 0 +#define ACCDET_DEBOUNCE0_MASK 0xFFFF +#define ACCDET_DEBOUNCE0_MASK_SFT (0xFFFF << 0) +#define ACCDET_DEBOUNCE1_ADDR \ + MT6359_ACCDET_CON9 +#define ACCDET_DEBOUNCE1_SFT 0 +#define ACCDET_DEBOUNCE1_MASK 0xFFFF +#define ACCDET_DEBOUNCE1_MASK_SFT (0xFFFF << 0) +#define ACCDET_DEBOUNCE2_ADDR \ + MT6359_ACCDET_CON10 +#define ACCDET_DEBOUNCE2_SFT 0 +#define ACCDET_DEBOUNCE2_MASK 0xFFFF +#define ACCDET_DEBOUNCE2_MASK_SFT (0xFFFF << 0) +#define ACCDET_DEBOUNCE3_ADDR \ + MT6359_ACCDET_CON11 +#define ACCDET_DEBOUNCE3_SFT 0 +#define ACCDET_DEBOUNCE3_MASK 0xFFFF +#define ACCDET_DEBOUNCE3_MASK_SFT (0xFFFF << 0) +#define ACCDET_CONNECT_AUXADC_TIME_DIG_ADDR \ + MT6359_ACCDET_CON12 +#define ACCDET_CONNECT_AUXADC_TIME_DIG_SFT 0 +#define ACCDET_CONNECT_AUXADC_TIME_DIG_MASK 0xFFFF +#define ACCDET_CONNECT_AUXADC_TIME_DIG_MASK_SFT (0xFFFF << 0) +#define ACCDET_CONNECT_AUXADC_TIME_ANA_ADDR \ + MT6359_ACCDET_CON13 +#define ACCDET_CONNECT_AUXADC_TIME_ANA_SFT 0 +#define ACCDET_CONNECT_AUXADC_TIME_ANA_MASK 0xFFFF +#define ACCDET_CONNECT_AUXADC_TIME_ANA_MASK_SFT (0xFFFF << 0) +#define ACCDET_EINT_DEBOUNCE0_ADDR \ + MT6359_ACCDET_CON14 +#define ACCDET_EINT_DEBOUNCE0_SFT 0 +#define ACCDET_EINT_DEBOUNCE0_MASK 0xF +#define ACCDET_EINT_DEBOUNCE0_MASK_SFT (0xF << 0) +#define ACCDET_EINT_DEBOUNCE1_ADDR \ + MT6359_ACCDET_CON14 +#define ACCDET_EINT_DEBOUNCE1_SFT 4 +#define ACCDET_EINT_DEBOUNCE1_MASK 0xF +#define ACCDET_EINT_DEBOUNCE1_MASK_SFT (0xF << 4) +#define ACCDET_EINT_DEBOUNCE2_ADDR \ + MT6359_ACCDET_CON14 +#define ACCDET_EINT_DEBOUNCE2_SFT 8 +#define ACCDET_EINT_DEBOUNCE2_MASK 0xF +#define ACCDET_EINT_DEBOUNCE2_MASK_SFT (0xF << 8) +#define ACCDET_EINT_DEBOUNCE3_ADDR \ + MT6359_ACCDET_CON14 +#define ACCDET_EINT_DEBOUNCE3_SFT 12 +#define ACCDET_EINT_DEBOUNCE3_MASK 0xF +#define ACCDET_EINT_DEBOUNCE3_MASK_SFT (0xF << 12) +#define ACCDET_EINT_INVERTER_DEBOUNCE_ADDR \ + MT6359_ACCDET_CON15 +#define ACCDET_EINT_INVERTER_DEBOUNCE_SFT 0 +#define ACCDET_EINT_INVERTER_DEBOUNCE_MASK 0xF +#define ACCDET_EINT_INVERTER_DEBOUNCE_MASK_SFT (0xF << 0) +#define ACCDET_IVAL_CUR_IN_ADDR \ + MT6359_ACCDET_CON16 +#define ACCDET_IVAL_CUR_IN_SFT 0 +#define ACCDET_IVAL_CUR_IN_MASK 0x3 +#define ACCDET_IVAL_CUR_IN_MASK_SFT (0x3 << 0) +#define ACCDET_IVAL_SAM_IN_ADDR \ + MT6359_ACCDET_CON16 +#define ACCDET_IVAL_SAM_IN_SFT 2 +#define ACCDET_IVAL_SAM_IN_MASK 0x3 +#define ACCDET_IVAL_SAM_IN_MASK_SFT (0x3 << 2) +#define ACCDET_IVAL_MEM_IN_ADDR \ + MT6359_ACCDET_CON16 +#define ACCDET_IVAL_MEM_IN_SFT 4 +#define ACCDET_IVAL_MEM_IN_MASK 0x3 +#define ACCDET_IVAL_MEM_IN_MASK_SFT (0x3 << 4) +#define ACCDET_EINT_IVAL_CUR_IN_ADDR \ + MT6359_ACCDET_CON16 +#define ACCDET_EINT_IVAL_CUR_IN_SFT 6 +#define ACCDET_EINT_IVAL_CUR_IN_MASK 0x3 +#define ACCDET_EINT_IVAL_CUR_IN_MASK_SFT (0x3 << 6) +#define ACCDET_EINT_IVAL_SAM_IN_ADDR \ + MT6359_ACCDET_CON16 +#define ACCDET_EINT_IVAL_SAM_IN_SFT 8 +#define ACCDET_EINT_IVAL_SAM_IN_MASK 0x3 +#define ACCDET_EINT_IVAL_SAM_IN_MASK_SFT (0x3 << 8) +#define ACCDET_EINT_IVAL_MEM_IN_ADDR \ + MT6359_ACCDET_CON16 +#define ACCDET_EINT_IVAL_MEM_IN_SFT 10 +#define ACCDET_EINT_IVAL_MEM_IN_MASK 0x3 +#define ACCDET_EINT_IVAL_MEM_IN_MASK_SFT (0x3 << 10) +#define ACCDET_IVAL_SEL_ADDR \ + MT6359_ACCDET_CON16 +#define ACCDET_IVAL_SEL_SFT 12 +#define ACCDET_IVAL_SEL_MASK 0x1 +#define ACCDET_IVAL_SEL_MASK_SFT (0x1 << 12) +#define ACCDET_EINT_IVAL_SEL_ADDR \ + MT6359_ACCDET_CON16 +#define ACCDET_EINT_IVAL_SEL_SFT 13 +#define ACCDET_EINT_IVAL_SEL_MASK 0x1 +#define ACCDET_EINT_IVAL_SEL_MASK_SFT (0x1 << 13) +#define ACCDET_EINT_INVERTER_IVAL_CUR_IN_ADDR \ + MT6359_ACCDET_CON17 +#define ACCDET_EINT_INVERTER_IVAL_CUR_IN_SFT 0 +#define ACCDET_EINT_INVERTER_IVAL_CUR_IN_MASK 0x1 +#define ACCDET_EINT_INVERTER_IVAL_CUR_IN_MASK_SFT (0x1 << 0) +#define ACCDET_EINT_INVERTER_IVAL_SAM_IN_ADDR \ + MT6359_ACCDET_CON17 +#define ACCDET_EINT_INVERTER_IVAL_SAM_IN_SFT 1 +#define ACCDET_EINT_INVERTER_IVAL_SAM_IN_MASK 0x1 +#define ACCDET_EINT_INVERTER_IVAL_SAM_IN_MASK_SFT (0x1 << 1) +#define ACCDET_EINT_INVERTER_IVAL_MEM_IN_ADDR \ + MT6359_ACCDET_CON17 +#define ACCDET_EINT_INVERTER_IVAL_MEM_IN_SFT 2 +#define ACCDET_EINT_INVERTER_IVAL_MEM_IN_MASK 0x1 +#define ACCDET_EINT_INVERTER_IVAL_MEM_IN_MASK_SFT (0x1 << 2) +#define ACCDET_EINT_INVERTER_IVAL_SEL_ADDR \ + MT6359_ACCDET_CON17 +#define ACCDET_EINT_INVERTER_IVAL_SEL_SFT 3 +#define ACCDET_EINT_INVERTER_IVAL_SEL_MASK 0x1 +#define ACCDET_EINT_INVERTER_IVAL_SEL_MASK_SFT (0x1 << 3) +#define ACCDET_IRQ_ADDR \ + MT6359_ACCDET_CON18 +#define ACCDET_IRQ_SFT 0 +#define ACCDET_IRQ_MASK 0x1 +#define ACCDET_IRQ_MASK_SFT (0x1 << 0) +#define ACCDET_EINT0_IRQ_ADDR \ + MT6359_ACCDET_CON18 +#define ACCDET_EINT0_IRQ_SFT 2 +#define ACCDET_EINT0_IRQ_MASK 0x1 +#define ACCDET_EINT0_IRQ_MASK_SFT (0x1 << 2) +#define ACCDET_EINT1_IRQ_ADDR \ + MT6359_ACCDET_CON18 +#define ACCDET_EINT1_IRQ_SFT 3 +#define ACCDET_EINT1_IRQ_MASK 0x1 +#define ACCDET_EINT1_IRQ_MASK_SFT (0x1 << 3) +#define ACCDET_EINT_IN_INVERSE_ADDR \ + MT6359_ACCDET_CON18 +#define ACCDET_EINT_IN_INVERSE_SFT 4 +#define ACCDET_EINT_IN_INVERSE_MASK 0x1 +#define ACCDET_EINT_IN_INVERSE_MASK_SFT (0x1 << 4) +#define ACCDET_IRQ_CLR_ADDR \ + MT6359_ACCDET_CON18 +#define ACCDET_IRQ_CLR_SFT 8 +#define ACCDET_IRQ_CLR_MASK 0x1 +#define ACCDET_IRQ_CLR_MASK_SFT (0x1 << 8) +#define ACCDET_EINT0_IRQ_CLR_ADDR \ + MT6359_ACCDET_CON18 +#define ACCDET_EINT0_IRQ_CLR_SFT 10 +#define ACCDET_EINT0_IRQ_CLR_MASK 0x1 +#define ACCDET_EINT0_IRQ_CLR_MASK_SFT (0x1 << 10) +#define ACCDET_EINT1_IRQ_CLR_ADDR \ + MT6359_ACCDET_CON18 +#define ACCDET_EINT1_IRQ_CLR_SFT 11 +#define ACCDET_EINT1_IRQ_CLR_MASK 0x1 +#define ACCDET_EINT1_IRQ_CLR_MASK_SFT (0x1 << 11) +#define ACCDET_EINT_M_PLUG_IN_NUM_ADDR \ + MT6359_ACCDET_CON18 +#define ACCDET_EINT_M_PLUG_IN_NUM_SFT 12 +#define ACCDET_EINT_M_PLUG_IN_NUM_MASK 0x7 +#define ACCDET_EINT_M_PLUG_IN_NUM_MASK_SFT (0x7 << 12) +#define ACCDET_DA_STABLE_ADDR \ + MT6359_ACCDET_CON19 +#define ACCDET_DA_STABLE_SFT 0 +#define ACCDET_DA_STABLE_MASK 0x1 +#define ACCDET_DA_STABLE_MASK_SFT (0x1 << 0) +#define ACCDET_EINT0_EN_STABLE_ADDR \ + MT6359_ACCDET_CON19 +#define ACCDET_EINT0_EN_STABLE_SFT 1 +#define ACCDET_EINT0_EN_STABLE_MASK 0x1 +#define ACCDET_EINT0_EN_STABLE_MASK_SFT (0x1 << 1) +#define ACCDET_EINT0_CMPEN_STABLE_ADDR \ + MT6359_ACCDET_CON19 +#define ACCDET_EINT0_CMPEN_STABLE_SFT 2 +#define ACCDET_EINT0_CMPEN_STABLE_MASK 0x1 +#define ACCDET_EINT0_CMPEN_STABLE_MASK_SFT (0x1 << 2) +#define ACCDET_EINT0_CMPMEN_STABLE_ADDR \ + MT6359_ACCDET_CON19 +#define ACCDET_EINT0_CMPMEN_STABLE_SFT 3 +#define ACCDET_EINT0_CMPMEN_STABLE_MASK 0x1 +#define ACCDET_EINT0_CMPMEN_STABLE_MASK_SFT (0x1 << 3) +#define ACCDET_EINT0_CTURBO_STABLE_ADDR \ + MT6359_ACCDET_CON19 +#define ACCDET_EINT0_CTURBO_STABLE_SFT 4 +#define ACCDET_EINT0_CTURBO_STABLE_MASK 0x1 +#define ACCDET_EINT0_CTURBO_STABLE_MASK_SFT (0x1 << 4) +#define ACCDET_EINT0_CEN_STABLE_ADDR \ + MT6359_ACCDET_CON19 +#define ACCDET_EINT0_CEN_STABLE_SFT 5 +#define ACCDET_EINT0_CEN_STABLE_MASK 0x1 +#define ACCDET_EINT0_CEN_STABLE_MASK_SFT (0x1 << 5) +#define ACCDET_EINT1_EN_STABLE_ADDR \ + MT6359_ACCDET_CON19 +#define ACCDET_EINT1_EN_STABLE_SFT 6 +#define ACCDET_EINT1_EN_STABLE_MASK 0x1 +#define ACCDET_EINT1_EN_STABLE_MASK_SFT (0x1 << 6) +#define ACCDET_EINT1_CMPEN_STABLE_ADDR \ + MT6359_ACCDET_CON19 +#define ACCDET_EINT1_CMPEN_STABLE_SFT 7 +#define ACCDET_EINT1_CMPEN_STABLE_MASK 0x1 +#define ACCDET_EINT1_CMPEN_STABLE_MASK_SFT (0x1 << 7) +#define ACCDET_EINT1_CMPMEN_STABLE_ADDR \ + MT6359_ACCDET_CON19 +#define ACCDET_EINT1_CMPMEN_STABLE_SFT 8 +#define ACCDET_EINT1_CMPMEN_STABLE_MASK 0x1 +#define ACCDET_EINT1_CMPMEN_STABLE_MASK_SFT (0x1 << 8) +#define ACCDET_EINT1_CTURBO_STABLE_ADDR \ + MT6359_ACCDET_CON19 +#define ACCDET_EINT1_CTURBO_STABLE_SFT 9 +#define ACCDET_EINT1_CTURBO_STABLE_MASK 0x1 +#define ACCDET_EINT1_CTURBO_STABLE_MASK_SFT (0x1 << 9) +#define ACCDET_EINT1_CEN_STABLE_ADDR \ + MT6359_ACCDET_CON19 +#define ACCDET_EINT1_CEN_STABLE_SFT 10 +#define ACCDET_EINT1_CEN_STABLE_MASK 0x1 +#define ACCDET_EINT1_CEN_STABLE_MASK_SFT (0x1 << 10) +#define ACCDET_HWMODE_EN_ADDR \ + MT6359_ACCDET_CON20 +#define ACCDET_HWMODE_EN_SFT 0 +#define ACCDET_HWMODE_EN_MASK 0x1 +#define ACCDET_HWMODE_EN_MASK_SFT (0x1 << 0) +#define ACCDET_HWMODE_SEL_ADDR \ + MT6359_ACCDET_CON20 +#define ACCDET_HWMODE_SEL_SFT 1 +#define ACCDET_HWMODE_SEL_MASK 0x3 +#define ACCDET_HWMODE_SEL_MASK_SFT (0x3 << 1) +#define ACCDET_PLUG_OUT_DETECT_ADDR \ + MT6359_ACCDET_CON20 +#define ACCDET_PLUG_OUT_DETECT_SFT 3 +#define ACCDET_PLUG_OUT_DETECT_MASK 0x1 +#define ACCDET_PLUG_OUT_DETECT_MASK_SFT (0x1 << 3) +#define ACCDET_EINT0_REVERSE_ADDR \ + MT6359_ACCDET_CON20 +#define ACCDET_EINT0_REVERSE_SFT 4 +#define ACCDET_EINT0_REVERSE_MASK 0x1 +#define ACCDET_EINT0_REVERSE_MASK_SFT (0x1 << 4) +#define ACCDET_EINT1_REVERSE_ADDR \ + MT6359_ACCDET_CON20 +#define ACCDET_EINT1_REVERSE_SFT 5 +#define ACCDET_EINT1_REVERSE_MASK 0x1 +#define ACCDET_EINT1_REVERSE_MASK_SFT (0x1 << 5) +#define ACCDET_EINT_HWMODE_EN_ADDR \ + MT6359_ACCDET_CON20 +#define ACCDET_EINT_HWMODE_EN_SFT 8 +#define ACCDET_EINT_HWMODE_EN_MASK 0x1 +#define ACCDET_EINT_HWMODE_EN_MASK_SFT (0x1 << 8) +#define ACCDET_EINT_PLUG_OUT_BYPASS_DEB_ADDR \ + MT6359_ACCDET_CON20 +#define ACCDET_EINT_PLUG_OUT_BYPASS_DEB_SFT 9 +#define ACCDET_EINT_PLUG_OUT_BYPASS_DEB_MASK 0x1 +#define ACCDET_EINT_PLUG_OUT_BYPASS_DEB_MASK_SFT (0x1 << 9) +#define ACCDET_EINT_M_PLUG_IN_EN_ADDR \ + MT6359_ACCDET_CON20 +#define ACCDET_EINT_M_PLUG_IN_EN_SFT 10 +#define ACCDET_EINT_M_PLUG_IN_EN_MASK 0x1 +#define ACCDET_EINT_M_PLUG_IN_EN_MASK_SFT (0x1 << 10) +#define ACCDET_EINT_M_HWMODE_EN_ADDR \ + MT6359_ACCDET_CON20 +#define ACCDET_EINT_M_HWMODE_EN_SFT 11 +#define ACCDET_EINT_M_HWMODE_EN_MASK 0x1 +#define ACCDET_EINT_M_HWMODE_EN_MASK_SFT (0x1 << 11) +#define ACCDET_TEST_CMPEN_ADDR \ + MT6359_ACCDET_CON21 +#define ACCDET_TEST_CMPEN_SFT 0 +#define ACCDET_TEST_CMPEN_MASK 0x1 +#define ACCDET_TEST_CMPEN_MASK_SFT (0x1 << 0) +#define ACCDET_TEST_VTHEN_ADDR \ + MT6359_ACCDET_CON21 +#define ACCDET_TEST_VTHEN_SFT 1 +#define ACCDET_TEST_VTHEN_MASK 0x1 +#define ACCDET_TEST_VTHEN_MASK_SFT (0x1 << 1) +#define ACCDET_TEST_MBIASEN_ADDR \ + MT6359_ACCDET_CON21 +#define ACCDET_TEST_MBIASEN_SFT 2 +#define ACCDET_TEST_MBIASEN_MASK 0x1 +#define ACCDET_TEST_MBIASEN_MASK_SFT (0x1 << 2) +#define ACCDET_EINT_TEST_EN_ADDR \ + MT6359_ACCDET_CON21 +#define ACCDET_EINT_TEST_EN_SFT 3 +#define ACCDET_EINT_TEST_EN_MASK 0x1 +#define ACCDET_EINT_TEST_EN_MASK_SFT (0x1 << 3) +#define ACCDET_EINT_TEST_INVEN_ADDR \ + MT6359_ACCDET_CON21 +#define ACCDET_EINT_TEST_INVEN_SFT 4 +#define ACCDET_EINT_TEST_INVEN_MASK 0x1 +#define ACCDET_EINT_TEST_INVEN_MASK_SFT (0x1 << 4) +#define ACCDET_EINT_TEST_CMPEN_ADDR \ + MT6359_ACCDET_CON21 +#define ACCDET_EINT_TEST_CMPEN_SFT 5 +#define ACCDET_EINT_TEST_CMPEN_MASK 0x1 +#define ACCDET_EINT_TEST_CMPEN_MASK_SFT (0x1 << 5) +#define ACCDET_EINT_TEST_CMPMEN_ADDR \ + MT6359_ACCDET_CON21 +#define ACCDET_EINT_TEST_CMPMEN_SFT 6 +#define ACCDET_EINT_TEST_CMPMEN_MASK 0x1 +#define ACCDET_EINT_TEST_CMPMEN_MASK_SFT (0x1 << 6) +#define ACCDET_EINT_TEST_CTURBO_ADDR \ + MT6359_ACCDET_CON21 +#define ACCDET_EINT_TEST_CTURBO_SFT 7 +#define ACCDET_EINT_TEST_CTURBO_MASK 0x1 +#define ACCDET_EINT_TEST_CTURBO_MASK_SFT (0x1 << 7) +#define ACCDET_EINT_TEST_CEN_ADDR \ + MT6359_ACCDET_CON21 +#define ACCDET_EINT_TEST_CEN_SFT 8 +#define ACCDET_EINT_TEST_CEN_MASK 0x1 +#define ACCDET_EINT_TEST_CEN_MASK_SFT (0x1 << 8) +#define ACCDET_TEST_B_ADDR \ + MT6359_ACCDET_CON21 +#define ACCDET_TEST_B_SFT 9 +#define ACCDET_TEST_B_MASK 0x1 +#define ACCDET_TEST_B_MASK_SFT (0x1 << 9) +#define ACCDET_TEST_A_ADDR \ + MT6359_ACCDET_CON21 +#define ACCDET_TEST_A_SFT 10 +#define ACCDET_TEST_A_MASK 0x1 +#define ACCDET_TEST_A_MASK_SFT (0x1 << 10) +#define ACCDET_EINT_TEST_CMPOUT_ADDR \ + MT6359_ACCDET_CON21 +#define ACCDET_EINT_TEST_CMPOUT_SFT 11 +#define ACCDET_EINT_TEST_CMPOUT_MASK 0x1 +#define ACCDET_EINT_TEST_CMPOUT_MASK_SFT (0x1 << 11) +#define ACCDET_EINT_TEST_CMPMOUT_ADDR \ + MT6359_ACCDET_CON21 +#define ACCDET_EINT_TEST_CMPMOUT_SFT 12 +#define ACCDET_EINT_TEST_CMPMOUT_MASK 0x1 +#define ACCDET_EINT_TEST_CMPMOUT_MASK_SFT (0x1 << 12) +#define ACCDET_EINT_TEST_INVOUT_ADDR \ + MT6359_ACCDET_CON21 +#define ACCDET_EINT_TEST_INVOUT_SFT 13 +#define ACCDET_EINT_TEST_INVOUT_MASK 0x1 +#define ACCDET_EINT_TEST_INVOUT_MASK_SFT (0x1 << 13) +#define ACCDET_CMPEN_SEL_ADDR \ + MT6359_ACCDET_CON22 +#define ACCDET_CMPEN_SEL_SFT 0 +#define ACCDET_CMPEN_SEL_MASK 0x1 +#define ACCDET_CMPEN_SEL_MASK_SFT (0x1 << 0) +#define ACCDET_VTHEN_SEL_ADDR \ + MT6359_ACCDET_CON22 +#define ACCDET_VTHEN_SEL_SFT 1 +#define ACCDET_VTHEN_SEL_MASK 0x1 +#define ACCDET_VTHEN_SEL_MASK_SFT (0x1 << 1) +#define ACCDET_MBIASEN_SEL_ADDR \ + MT6359_ACCDET_CON22 +#define ACCDET_MBIASEN_SEL_SFT 2 +#define ACCDET_MBIASEN_SEL_MASK 0x1 +#define ACCDET_MBIASEN_SEL_MASK_SFT (0x1 << 2) +#define ACCDET_EINT_EN_SEL_ADDR \ + MT6359_ACCDET_CON22 +#define ACCDET_EINT_EN_SEL_SFT 3 +#define ACCDET_EINT_EN_SEL_MASK 0x1 +#define ACCDET_EINT_EN_SEL_MASK_SFT (0x1 << 3) +#define ACCDET_EINT_INVEN_SEL_ADDR \ + MT6359_ACCDET_CON22 +#define ACCDET_EINT_INVEN_SEL_SFT 4 +#define ACCDET_EINT_INVEN_SEL_MASK 0x1 +#define ACCDET_EINT_INVEN_SEL_MASK_SFT (0x1 << 4) +#define ACCDET_EINT_CMPEN_SEL_ADDR \ + MT6359_ACCDET_CON22 +#define ACCDET_EINT_CMPEN_SEL_SFT 5 +#define ACCDET_EINT_CMPEN_SEL_MASK 0x1 +#define ACCDET_EINT_CMPEN_SEL_MASK_SFT (0x1 << 5) +#define ACCDET_EINT_CMPMEN_SEL_ADDR \ + MT6359_ACCDET_CON22 +#define ACCDET_EINT_CMPMEN_SEL_SFT 6 +#define ACCDET_EINT_CMPMEN_SEL_MASK 0x1 +#define ACCDET_EINT_CMPMEN_SEL_MASK_SFT (0x1 << 6) +#define ACCDET_EINT_CTURBO_SEL_ADDR \ + MT6359_ACCDET_CON22 +#define ACCDET_EINT_CTURBO_SEL_SFT 7 +#define ACCDET_EINT_CTURBO_SEL_MASK 0x1 +#define ACCDET_EINT_CTURBO_SEL_MASK_SFT (0x1 << 7) +#define ACCDET_B_SEL_ADDR \ + MT6359_ACCDET_CON22 +#define ACCDET_B_SEL_SFT 9 +#define ACCDET_B_SEL_MASK 0x1 +#define ACCDET_B_SEL_MASK_SFT (0x1 << 9) +#define ACCDET_A_SEL_ADDR \ + MT6359_ACCDET_CON22 +#define ACCDET_A_SEL_SFT 10 +#define ACCDET_A_SEL_MASK 0x1 +#define ACCDET_A_SEL_MASK_SFT (0x1 << 10) +#define ACCDET_EINT_CMPOUT_SEL_ADDR \ + MT6359_ACCDET_CON22 +#define ACCDET_EINT_CMPOUT_SEL_SFT 11 +#define ACCDET_EINT_CMPOUT_SEL_MASK 0x1 +#define ACCDET_EINT_CMPOUT_SEL_MASK_SFT (0x1 << 11) +#define ACCDET_EINT_CMPMOUT_SEL_ADDR \ + MT6359_ACCDET_CON22 +#define ACCDET_EINT_CMPMOUT_SEL_SFT 12 +#define ACCDET_EINT_CMPMOUT_SEL_MASK 0x1 +#define ACCDET_EINT_CMPMOUT_SEL_MASK_SFT (0x1 << 12) +#define ACCDET_EINT_INVOUT_SEL_ADDR \ + MT6359_ACCDET_CON22 +#define ACCDET_EINT_INVOUT_SEL_SFT 13 +#define ACCDET_EINT_INVOUT_SEL_MASK 0x1 +#define ACCDET_EINT_INVOUT_SEL_MASK_SFT (0x1 << 13) +#define ACCDET_CMPEN_SW_ADDR \ + MT6359_ACCDET_CON23 +#define ACCDET_CMPEN_SW_SFT 0 +#define ACCDET_CMPEN_SW_MASK 0x1 +#define ACCDET_CMPEN_SW_MASK_SFT (0x1 << 0) +#define ACCDET_VTHEN_SW_ADDR \ + MT6359_ACCDET_CON23 +#define ACCDET_VTHEN_SW_SFT 1 +#define ACCDET_VTHEN_SW_MASK 0x1 +#define ACCDET_VTHEN_SW_MASK_SFT (0x1 << 1) +#define ACCDET_MBIASEN_SW_ADDR \ + MT6359_ACCDET_CON23 +#define ACCDET_MBIASEN_SW_SFT 2 +#define ACCDET_MBIASEN_SW_MASK 0x1 +#define ACCDET_MBIASEN_SW_MASK_SFT (0x1 << 2) +#define ACCDET_EINT0_EN_SW_ADDR \ + MT6359_ACCDET_CON23 +#define ACCDET_EINT0_EN_SW_SFT 3 +#define ACCDET_EINT0_EN_SW_MASK 0x1 +#define ACCDET_EINT0_EN_SW_MASK_SFT (0x1 << 3) +#define ACCDET_EINT0_INVEN_SW_ADDR \ + MT6359_ACCDET_CON23 +#define ACCDET_EINT0_INVEN_SW_SFT 4 +#define ACCDET_EINT0_INVEN_SW_MASK 0x1 +#define ACCDET_EINT0_INVEN_SW_MASK_SFT (0x1 << 4) +#define ACCDET_EINT0_CMPEN_SW_ADDR \ + MT6359_ACCDET_CON23 +#define ACCDET_EINT0_CMPEN_SW_SFT 5 +#define ACCDET_EINT0_CMPEN_SW_MASK 0x1 +#define ACCDET_EINT0_CMPEN_SW_MASK_SFT (0x1 << 5) +#define ACCDET_EINT0_CMPMEN_SW_ADDR \ + MT6359_ACCDET_CON23 +#define ACCDET_EINT0_CMPMEN_SW_SFT 6 +#define ACCDET_EINT0_CMPMEN_SW_MASK 0x1 +#define ACCDET_EINT0_CMPMEN_SW_MASK_SFT (0x1 << 6) +#define ACCDET_EINT0_CTURBO_SW_ADDR \ + MT6359_ACCDET_CON23 +#define ACCDET_EINT0_CTURBO_SW_SFT 7 +#define ACCDET_EINT0_CTURBO_SW_MASK 0x1 +#define ACCDET_EINT0_CTURBO_SW_MASK_SFT (0x1 << 7) +#define ACCDET_EINT1_EN_SW_ADDR \ + MT6359_ACCDET_CON23 +#define ACCDET_EINT1_EN_SW_SFT 8 +#define ACCDET_EINT1_EN_SW_MASK 0x1 +#define ACCDET_EINT1_EN_SW_MASK_SFT (0x1 << 8) +#define ACCDET_EINT1_INVEN_SW_ADDR \ + MT6359_ACCDET_CON23 +#define ACCDET_EINT1_INVEN_SW_SFT 9 +#define ACCDET_EINT1_INVEN_SW_MASK 0x1 +#define ACCDET_EINT1_INVEN_SW_MASK_SFT (0x1 << 9) +#define ACCDET_EINT1_CMPEN_SW_ADDR \ + MT6359_ACCDET_CON23 +#define ACCDET_EINT1_CMPEN_SW_SFT 10 +#define ACCDET_EINT1_CMPEN_SW_MASK 0x1 +#define ACCDET_EINT1_CMPEN_SW_MASK_SFT (0x1 << 10) +#define ACCDET_EINT1_CMPMEN_SW_ADDR \ + MT6359_ACCDET_CON23 +#define ACCDET_EINT1_CMPMEN_SW_SFT 11 +#define ACCDET_EINT1_CMPMEN_SW_MASK 0x1 +#define ACCDET_EINT1_CMPMEN_SW_MASK_SFT (0x1 << 11) +#define ACCDET_EINT1_CTURBO_SW_ADDR \ + MT6359_ACCDET_CON23 +#define ACCDET_EINT1_CTURBO_SW_SFT 12 +#define ACCDET_EINT1_CTURBO_SW_MASK 0x1 +#define ACCDET_EINT1_CTURBO_SW_MASK_SFT (0x1 << 12) +#define ACCDET_B_SW_ADDR \ + MT6359_ACCDET_CON24 +#define ACCDET_B_SW_SFT 0 +#define ACCDET_B_SW_MASK 0x1 +#define ACCDET_B_SW_MASK_SFT (0x1 << 0) +#define ACCDET_A_SW_ADDR \ + MT6359_ACCDET_CON24 +#define ACCDET_A_SW_SFT 1 +#define ACCDET_A_SW_MASK 0x1 +#define ACCDET_A_SW_MASK_SFT (0x1 << 1) +#define ACCDET_EINT0_CMPOUT_SW_ADDR \ + MT6359_ACCDET_CON24 +#define ACCDET_EINT0_CMPOUT_SW_SFT 2 +#define ACCDET_EINT0_CMPOUT_SW_MASK 0x1 +#define ACCDET_EINT0_CMPOUT_SW_MASK_SFT (0x1 << 2) +#define ACCDET_EINT0_CMPMOUT_SW_ADDR \ + MT6359_ACCDET_CON24 +#define ACCDET_EINT0_CMPMOUT_SW_SFT 3 +#define ACCDET_EINT0_CMPMOUT_SW_MASK 0x1 +#define ACCDET_EINT0_CMPMOUT_SW_MASK_SFT (0x1 << 3) +#define ACCDET_EINT0_INVOUT_SW_ADDR \ + MT6359_ACCDET_CON24 +#define ACCDET_EINT0_INVOUT_SW_SFT 4 +#define ACCDET_EINT0_INVOUT_SW_MASK 0x1 +#define ACCDET_EINT0_INVOUT_SW_MASK_SFT (0x1 << 4) +#define ACCDET_EINT1_CMPOUT_SW_ADDR \ + MT6359_ACCDET_CON24 +#define ACCDET_EINT1_CMPOUT_SW_SFT 5 +#define ACCDET_EINT1_CMPOUT_SW_MASK 0x1 +#define ACCDET_EINT1_CMPOUT_SW_MASK_SFT (0x1 << 5) +#define ACCDET_EINT1_CMPMOUT_SW_ADDR \ + MT6359_ACCDET_CON24 +#define ACCDET_EINT1_CMPMOUT_SW_SFT 6 +#define ACCDET_EINT1_CMPMOUT_SW_MASK 0x1 +#define ACCDET_EINT1_CMPMOUT_SW_MASK_SFT (0x1 << 6) +#define ACCDET_EINT1_INVOUT_SW_ADDR \ + MT6359_ACCDET_CON24 +#define ACCDET_EINT1_INVOUT_SW_SFT 7 +#define ACCDET_EINT1_INVOUT_SW_MASK 0x1 +#define ACCDET_EINT1_INVOUT_SW_MASK_SFT (0x1 << 7) +#define AD_AUDACCDETCMPOB_ADDR \ + MT6359_ACCDET_CON25 +#define AD_AUDACCDETCMPOB_SFT 0 +#define AD_AUDACCDETCMPOB_MASK 0x1 +#define AD_AUDACCDETCMPOB_MASK_SFT (0x1 << 0) +#define AD_AUDACCDETCMPOA_ADDR \ + MT6359_ACCDET_CON25 +#define AD_AUDACCDETCMPOA_SFT 1 +#define AD_AUDACCDETCMPOA_MASK 0x1 +#define AD_AUDACCDETCMPOA_MASK_SFT (0x1 << 1) +#define ACCDET_CUR_IN_ADDR \ + MT6359_ACCDET_CON25 +#define ACCDET_CUR_IN_SFT 2 +#define ACCDET_CUR_IN_MASK 0x3 +#define ACCDET_CUR_IN_MASK_SFT (0x3 << 2) +#define ACCDET_SAM_IN_ADDR \ + MT6359_ACCDET_CON25 +#define ACCDET_SAM_IN_SFT 4 +#define ACCDET_SAM_IN_MASK 0x3 +#define ACCDET_SAM_IN_MASK_SFT (0x3 << 4) +#define ACCDET_MEM_IN_ADDR \ + MT6359_ACCDET_CON25 +#define ACCDET_MEM_IN_SFT 6 +#define ACCDET_MEM_IN_MASK 0x3 +#define ACCDET_MEM_IN_MASK_SFT (0x3 << 6) +#define ACCDET_STATE_ADDR \ + MT6359_ACCDET_CON25 +#define ACCDET_STATE_SFT 8 +#define ACCDET_STATE_MASK 0x7 +#define ACCDET_STATE_MASK_SFT (0x7 << 8) +#define DA_AUDACCDETMBIASCLK_ADDR \ + MT6359_ACCDET_CON25 +#define DA_AUDACCDETMBIASCLK_SFT 12 +#define DA_AUDACCDETMBIASCLK_MASK 0x1 +#define DA_AUDACCDETMBIASCLK_MASK_SFT (0x1 << 12) +#define DA_AUDACCDETVTHCLK_ADDR \ + MT6359_ACCDET_CON25 +#define DA_AUDACCDETVTHCLK_SFT 13 +#define DA_AUDACCDETVTHCLK_MASK 0x1 +#define DA_AUDACCDETVTHCLK_MASK_SFT (0x1 << 13) +#define DA_AUDACCDETCMPCLK_ADDR \ + MT6359_ACCDET_CON25 +#define DA_AUDACCDETCMPCLK_SFT 14 +#define DA_AUDACCDETCMPCLK_MASK 0x1 +#define DA_AUDACCDETCMPCLK_MASK_SFT (0x1 << 14) +#define DA_AUDACCDETAUXADCSWCTRL_ADDR \ + MT6359_ACCDET_CON25 +#define DA_AUDACCDETAUXADCSWCTRL_SFT 15 +#define DA_AUDACCDETAUXADCSWCTRL_MASK 0x1 +#define DA_AUDACCDETAUXADCSWCTRL_MASK_SFT (0x1 << 15) +#define AD_EINT0CMPMOUT_ADDR \ + MT6359_ACCDET_CON26 +#define AD_EINT0CMPMOUT_SFT 0 +#define AD_EINT0CMPMOUT_MASK 0x1 +#define AD_EINT0CMPMOUT_MASK_SFT (0x1 << 0) +#define AD_EINT0CMPOUT_ADDR \ + MT6359_ACCDET_CON26 +#define AD_EINT0CMPOUT_SFT 1 +#define AD_EINT0CMPOUT_MASK 0x1 +#define AD_EINT0CMPOUT_MASK_SFT (0x1 << 1) +#define ACCDET_EINT0_CUR_IN_ADDR \ + MT6359_ACCDET_CON26 +#define ACCDET_EINT0_CUR_IN_SFT 2 +#define ACCDET_EINT0_CUR_IN_MASK 0x3 +#define ACCDET_EINT0_CUR_IN_MASK_SFT (0x3 << 2) +#define ACCDET_EINT0_SAM_IN_ADDR \ + MT6359_ACCDET_CON26 +#define ACCDET_EINT0_SAM_IN_SFT 4 +#define ACCDET_EINT0_SAM_IN_MASK 0x3 +#define ACCDET_EINT0_SAM_IN_MASK_SFT (0x3 << 4) +#define ACCDET_EINT0_MEM_IN_ADDR \ + MT6359_ACCDET_CON26 +#define ACCDET_EINT0_MEM_IN_SFT 6 +#define ACCDET_EINT0_MEM_IN_MASK 0x3 +#define ACCDET_EINT0_MEM_IN_MASK_SFT (0x3 << 6) +#define ACCDET_EINT0_STATE_ADDR \ + MT6359_ACCDET_CON26 +#define ACCDET_EINT0_STATE_SFT 8 +#define ACCDET_EINT0_STATE_MASK 0x7 +#define ACCDET_EINT0_STATE_MASK_SFT (0x7 << 8) +#define DA_EINT0CMPEN_ADDR \ + MT6359_ACCDET_CON26 +#define DA_EINT0CMPEN_SFT 13 +#define DA_EINT0CMPEN_MASK 0x1 +#define DA_EINT0CMPEN_MASK_SFT (0x1 << 13) +#define DA_EINT0CMPMEN_ADDR \ + MT6359_ACCDET_CON26 +#define DA_EINT0CMPMEN_SFT 14 +#define DA_EINT0CMPMEN_MASK 0x1 +#define DA_EINT0CMPMEN_MASK_SFT (0x1 << 14) +#define DA_EINT0CTURBO_ADDR \ + MT6359_ACCDET_CON26 +#define DA_EINT0CTURBO_SFT 15 +#define DA_EINT0CTURBO_MASK 0x1 +#define DA_EINT0CTURBO_MASK_SFT (0x1 << 15) +#define AD_EINT1CMPMOUT_ADDR \ + MT6359_ACCDET_CON27 +#define AD_EINT1CMPMOUT_SFT 0 +#define AD_EINT1CMPMOUT_MASK 0x1 +#define AD_EINT1CMPMOUT_MASK_SFT (0x1 << 0) +#define AD_EINT1CMPOUT_ADDR \ + MT6359_ACCDET_CON27 +#define AD_EINT1CMPOUT_SFT 1 +#define AD_EINT1CMPOUT_MASK 0x1 +#define AD_EINT1CMPOUT_MASK_SFT (0x1 << 1) +#define ACCDET_EINT1_CUR_IN_ADDR \ + MT6359_ACCDET_CON27 +#define ACCDET_EINT1_CUR_IN_SFT 2 +#define ACCDET_EINT1_CUR_IN_MASK 0x3 +#define ACCDET_EINT1_CUR_IN_MASK_SFT (0x3 << 2) +#define ACCDET_EINT1_SAM_IN_ADDR \ + MT6359_ACCDET_CON27 +#define ACCDET_EINT1_SAM_IN_SFT 4 +#define ACCDET_EINT1_SAM_IN_MASK 0x3 +#define ACCDET_EINT1_SAM_IN_MASK_SFT (0x3 << 4) +#define ACCDET_EINT1_MEM_IN_ADDR \ + MT6359_ACCDET_CON27 +#define ACCDET_EINT1_MEM_IN_SFT 6 +#define ACCDET_EINT1_MEM_IN_MASK 0x3 +#define ACCDET_EINT1_MEM_IN_MASK_SFT (0x3 << 6) +#define ACCDET_EINT1_STATE_ADDR \ + MT6359_ACCDET_CON27 +#define ACCDET_EINT1_STATE_SFT 8 +#define ACCDET_EINT1_STATE_MASK 0x7 +#define ACCDET_EINT1_STATE_MASK_SFT (0x7 << 8) +#define DA_EINT1CMPEN_ADDR \ + MT6359_ACCDET_CON27 +#define DA_EINT1CMPEN_SFT 13 +#define DA_EINT1CMPEN_MASK 0x1 +#define DA_EINT1CMPEN_MASK_SFT (0x1 << 13) +#define DA_EINT1CMPMEN_ADDR \ + MT6359_ACCDET_CON27 +#define DA_EINT1CMPMEN_SFT 14 +#define DA_EINT1CMPMEN_MASK 0x1 +#define DA_EINT1CMPMEN_MASK_SFT (0x1 << 14) +#define DA_EINT1CTURBO_ADDR \ + MT6359_ACCDET_CON27 +#define DA_EINT1CTURBO_SFT 15 +#define DA_EINT1CTURBO_MASK 0x1 +#define DA_EINT1CTURBO_MASK_SFT (0x1 << 15) +#define AD_EINT0INVOUT_ADDR \ + MT6359_ACCDET_CON28 +#define AD_EINT0INVOUT_SFT 0 +#define AD_EINT0INVOUT_MASK 0x1 +#define AD_EINT0INVOUT_MASK_SFT (0x1 << 0) +#define ACCDET_EINT0_INVERTER_CUR_IN_ADDR \ + MT6359_ACCDET_CON28 +#define ACCDET_EINT0_INVERTER_CUR_IN_SFT 1 +#define ACCDET_EINT0_INVERTER_CUR_IN_MASK 0x1 +#define ACCDET_EINT0_INVERTER_CUR_IN_MASK_SFT (0x1 << 1) +#define ACCDET_EINT0_INVERTER_SAM_IN_ADDR \ + MT6359_ACCDET_CON28 +#define ACCDET_EINT0_INVERTER_SAM_IN_SFT 2 +#define ACCDET_EINT0_INVERTER_SAM_IN_MASK 0x1 +#define ACCDET_EINT0_INVERTER_SAM_IN_MASK_SFT (0x1 << 2) +#define ACCDET_EINT0_INVERTER_MEM_IN_ADDR \ + MT6359_ACCDET_CON28 +#define ACCDET_EINT0_INVERTER_MEM_IN_SFT 3 +#define ACCDET_EINT0_INVERTER_MEM_IN_MASK 0x1 +#define ACCDET_EINT0_INVERTER_MEM_IN_MASK_SFT (0x1 << 3) +#define ACCDET_EINT0_INVERTER_STATE_ADDR \ + MT6359_ACCDET_CON28 +#define ACCDET_EINT0_INVERTER_STATE_SFT 8 +#define ACCDET_EINT0_INVERTER_STATE_MASK 0x7 +#define ACCDET_EINT0_INVERTER_STATE_MASK_SFT (0x7 << 8) +#define DA_EINT0EN_ADDR \ + MT6359_ACCDET_CON28 +#define DA_EINT0EN_SFT 12 +#define DA_EINT0EN_MASK 0x1 +#define DA_EINT0EN_MASK_SFT (0x1 << 12) +#define DA_EINT0INVEN_ADDR \ + MT6359_ACCDET_CON28 +#define DA_EINT0INVEN_SFT 13 +#define DA_EINT0INVEN_MASK 0x1 +#define DA_EINT0INVEN_MASK_SFT (0x1 << 13) +#define DA_EINT0CEN_ADDR \ + MT6359_ACCDET_CON28 +#define DA_EINT0CEN_SFT 14 +#define DA_EINT0CEN_MASK 0x1 +#define DA_EINT0CEN_MASK_SFT (0x1 << 14) +#define AD_EINT1INVOUT_ADDR \ + MT6359_ACCDET_CON29 +#define AD_EINT1INVOUT_SFT 0 +#define AD_EINT1INVOUT_MASK 0x1 +#define AD_EINT1INVOUT_MASK_SFT (0x1 << 0) +#define ACCDET_EINT1_INVERTER_CUR_IN_ADDR \ + MT6359_ACCDET_CON29 +#define ACCDET_EINT1_INVERTER_CUR_IN_SFT 1 +#define ACCDET_EINT1_INVERTER_CUR_IN_MASK 0x1 +#define ACCDET_EINT1_INVERTER_CUR_IN_MASK_SFT (0x1 << 1) +#define ACCDET_EINT1_INVERTER_SAM_IN_ADDR \ + MT6359_ACCDET_CON29 +#define ACCDET_EINT1_INVERTER_SAM_IN_SFT 2 +#define ACCDET_EINT1_INVERTER_SAM_IN_MASK 0x1 +#define ACCDET_EINT1_INVERTER_SAM_IN_MASK_SFT (0x1 << 2) +#define ACCDET_EINT1_INVERTER_MEM_IN_ADDR \ + MT6359_ACCDET_CON29 +#define ACCDET_EINT1_INVERTER_MEM_IN_SFT 3 +#define ACCDET_EINT1_INVERTER_MEM_IN_MASK 0x1 +#define ACCDET_EINT1_INVERTER_MEM_IN_MASK_SFT (0x1 << 3) +#define ACCDET_EINT1_INVERTER_STATE_ADDR \ + MT6359_ACCDET_CON29 +#define ACCDET_EINT1_INVERTER_STATE_SFT 8 +#define ACCDET_EINT1_INVERTER_STATE_MASK 0x7 +#define ACCDET_EINT1_INVERTER_STATE_MASK_SFT (0x7 << 8) +#define DA_EINT1EN_ADDR \ + MT6359_ACCDET_CON29 +#define DA_EINT1EN_SFT 12 +#define DA_EINT1EN_MASK 0x1 +#define DA_EINT1EN_MASK_SFT (0x1 << 12) +#define DA_EINT1INVEN_ADDR \ + MT6359_ACCDET_CON29 +#define DA_EINT1INVEN_SFT 13 +#define DA_EINT1INVEN_MASK 0x1 +#define DA_EINT1INVEN_MASK_SFT (0x1 << 13) +#define DA_EINT1CEN_ADDR \ + MT6359_ACCDET_CON29 +#define DA_EINT1CEN_SFT 14 +#define DA_EINT1CEN_MASK 0x1 +#define DA_EINT1CEN_MASK_SFT (0x1 << 14) +#define ACCDET_EN_ADDR \ + MT6359_ACCDET_CON30 +#define ACCDET_EN_SFT 0 +#define ACCDET_EN_MASK 0x1 +#define ACCDET_EN_MASK_SFT (0x1 << 0) +#define ACCDET_EINT0_EN_ADDR \ + MT6359_ACCDET_CON30 +#define ACCDET_EINT0_EN_SFT 1 +#define ACCDET_EINT0_EN_MASK 0x1 +#define ACCDET_EINT0_EN_MASK_SFT (0x1 << 1) +#define ACCDET_EINT1_EN_ADDR \ + MT6359_ACCDET_CON30 +#define ACCDET_EINT1_EN_SFT 2 +#define ACCDET_EINT1_EN_MASK 0x1 +#define ACCDET_EINT1_EN_MASK_SFT (0x1 << 2) +#define ACCDET_EINT0_M_EN_ADDR \ + MT6359_ACCDET_CON30 +#define ACCDET_EINT0_M_EN_SFT 3 +#define ACCDET_EINT0_M_EN_MASK 0x1 +#define ACCDET_EINT0_M_EN_MASK_SFT (0x1 << 3) +#define ACCDET_EINT0_DETECT_MOISTURE_ADDR \ + MT6359_ACCDET_CON30 +#define ACCDET_EINT0_DETECT_MOISTURE_SFT 4 +#define ACCDET_EINT0_DETECT_MOISTURE_MASK 0x1 +#define ACCDET_EINT0_DETECT_MOISTURE_MASK_SFT (0x1 << 4) +#define ACCDET_EINT0_PLUG_IN_ADDR \ + MT6359_ACCDET_CON30 +#define ACCDET_EINT0_PLUG_IN_SFT 5 +#define ACCDET_EINT0_PLUG_IN_MASK 0x1 +#define ACCDET_EINT0_PLUG_IN_MASK_SFT (0x1 << 5) +#define ACCDET_EINT0_M_PLUG_IN_ADDR \ + MT6359_ACCDET_CON30 +#define ACCDET_EINT0_M_PLUG_IN_SFT 6 +#define ACCDET_EINT0_M_PLUG_IN_MASK 0x1 +#define ACCDET_EINT0_M_PLUG_IN_MASK_SFT (0x1 << 6) +#define ACCDET_EINT1_M_EN_ADDR \ + MT6359_ACCDET_CON30 +#define ACCDET_EINT1_M_EN_SFT 7 +#define ACCDET_EINT1_M_EN_MASK 0x1 +#define ACCDET_EINT1_M_EN_MASK_SFT (0x1 << 7) +#define ACCDET_EINT1_DETECT_MOISTURE_ADDR \ + MT6359_ACCDET_CON30 +#define ACCDET_EINT1_DETECT_MOISTURE_SFT 8 +#define ACCDET_EINT1_DETECT_MOISTURE_MASK 0x1 +#define ACCDET_EINT1_DETECT_MOISTURE_MASK_SFT (0x1 << 8) +#define ACCDET_EINT1_PLUG_IN_ADDR \ + MT6359_ACCDET_CON30 +#define ACCDET_EINT1_PLUG_IN_SFT 9 +#define ACCDET_EINT1_PLUG_IN_MASK 0x1 +#define ACCDET_EINT1_PLUG_IN_MASK_SFT (0x1 << 9) +#define ACCDET_EINT1_M_PLUG_IN_ADDR \ + MT6359_ACCDET_CON30 +#define ACCDET_EINT1_M_PLUG_IN_SFT 10 +#define ACCDET_EINT1_M_PLUG_IN_MASK 0x1 +#define ACCDET_EINT1_M_PLUG_IN_MASK_SFT (0x1 << 10) +#define ACCDET_CUR_DEB_ADDR \ + MT6359_ACCDET_CON31 +#define ACCDET_CUR_DEB_SFT 0 +#define ACCDET_CUR_DEB_MASK 0xFFFF +#define ACCDET_CUR_DEB_MASK_SFT (0xFFFF << 0) +#define ACCDET_EINT0_CUR_DEB_ADDR \ + MT6359_ACCDET_CON32 +#define ACCDET_EINT0_CUR_DEB_SFT 0 +#define ACCDET_EINT0_CUR_DEB_MASK 0x7FFF +#define ACCDET_EINT0_CUR_DEB_MASK_SFT (0x7FFF << 0) +#define ACCDET_EINT1_CUR_DEB_ADDR \ + MT6359_ACCDET_CON33 +#define ACCDET_EINT1_CUR_DEB_SFT 0 +#define ACCDET_EINT1_CUR_DEB_MASK 0x7FFF +#define ACCDET_EINT1_CUR_DEB_MASK_SFT (0x7FFF << 0) +#define ACCDET_EINT0_INVERTER_CUR_DEB_ADDR \ + MT6359_ACCDET_CON34 +#define ACCDET_EINT0_INVERTER_CUR_DEB_SFT 0 +#define ACCDET_EINT0_INVERTER_CUR_DEB_MASK 0x7FFF +#define ACCDET_EINT0_INVERTER_CUR_DEB_MASK_SFT (0x7FFF << 0) +#define ACCDET_EINT1_INVERTER_CUR_DEB_ADDR \ + MT6359_ACCDET_CON35 +#define ACCDET_EINT1_INVERTER_CUR_DEB_SFT 0 +#define ACCDET_EINT1_INVERTER_CUR_DEB_MASK 0x7FFF +#define ACCDET_EINT1_INVERTER_CUR_DEB_MASK_SFT (0x7FFF << 0) +#define AD_AUDACCDETCMPOB_MON_ADDR \ + MT6359_ACCDET_CON36 +#define AD_AUDACCDETCMPOB_MON_SFT 0 +#define AD_AUDACCDETCMPOB_MON_MASK 0x1 +#define AD_AUDACCDETCMPOB_MON_MASK_SFT (0x1 << 0) +#define AD_AUDACCDETCMPOA_MON_ADDR \ + MT6359_ACCDET_CON36 +#define AD_AUDACCDETCMPOA_MON_SFT 1 +#define AD_AUDACCDETCMPOA_MON_MASK 0x1 +#define AD_AUDACCDETCMPOA_MON_MASK_SFT (0x1 << 1) +#define AD_EINT0CMPMOUT_MON_ADDR \ + MT6359_ACCDET_CON36 +#define AD_EINT0CMPMOUT_MON_SFT 2 +#define AD_EINT0CMPMOUT_MON_MASK 0x1 +#define AD_EINT0CMPMOUT_MON_MASK_SFT (0x1 << 2) +#define AD_EINT0CMPOUT_MON_ADDR \ + MT6359_ACCDET_CON36 +#define AD_EINT0CMPOUT_MON_SFT 3 +#define AD_EINT0CMPOUT_MON_MASK 0x1 +#define AD_EINT0CMPOUT_MON_MASK_SFT (0x1 << 3) +#define AD_EINT0INVOUT_MON_ADDR \ + MT6359_ACCDET_CON36 +#define AD_EINT0INVOUT_MON_SFT 4 +#define AD_EINT0INVOUT_MON_MASK 0x1 +#define AD_EINT0INVOUT_MON_MASK_SFT (0x1 << 4) +#define AD_EINT1CMPMOUT_MON_ADDR \ + MT6359_ACCDET_CON36 +#define AD_EINT1CMPMOUT_MON_SFT 5 +#define AD_EINT1CMPMOUT_MON_MASK 0x1 +#define AD_EINT1CMPMOUT_MON_MASK_SFT (0x1 << 5) +#define AD_EINT1CMPOUT_MON_ADDR \ + MT6359_ACCDET_CON36 +#define AD_EINT1CMPOUT_MON_SFT 6 +#define AD_EINT1CMPOUT_MON_MASK 0x1 +#define AD_EINT1CMPOUT_MON_MASK_SFT (0x1 << 6) +#define AD_EINT1INVOUT_MON_ADDR \ + MT6359_ACCDET_CON36 +#define AD_EINT1INVOUT_MON_SFT 7 +#define AD_EINT1INVOUT_MON_MASK 0x1 +#define AD_EINT1INVOUT_MON_MASK_SFT (0x1 << 7) +#define DA_AUDACCDETCMPCLK_MON_ADDR \ + MT6359_ACCDET_CON37 +#define DA_AUDACCDETCMPCLK_MON_SFT 0 +#define DA_AUDACCDETCMPCLK_MON_MASK 0x1 +#define DA_AUDACCDETCMPCLK_MON_MASK_SFT (0x1 << 0) +#define DA_AUDACCDETVTHCLK_MON_ADDR \ + MT6359_ACCDET_CON37 +#define DA_AUDACCDETVTHCLK_MON_SFT 1 +#define DA_AUDACCDETVTHCLK_MON_MASK 0x1 +#define DA_AUDACCDETVTHCLK_MON_MASK_SFT (0x1 << 1) +#define DA_AUDACCDETMBIASCLK_MON_ADDR \ + MT6359_ACCDET_CON37 +#define DA_AUDACCDETMBIASCLK_MON_SFT 2 +#define DA_AUDACCDETMBIASCLK_MON_MASK 0x1 +#define DA_AUDACCDETMBIASCLK_MON_MASK_SFT (0x1 << 2) +#define DA_AUDACCDETAUXADCSWCTRL_MON_ADDR \ + MT6359_ACCDET_CON37 +#define DA_AUDACCDETAUXADCSWCTRL_MON_SFT 3 +#define DA_AUDACCDETAUXADCSWCTRL_MON_MASK 0x1 +#define DA_AUDACCDETAUXADCSWCTRL_MON_MASK_SFT (0x1 << 3) +#define DA_EINT0CTURBO_MON_ADDR \ + MT6359_ACCDET_CON38 +#define DA_EINT0CTURBO_MON_SFT 0 +#define DA_EINT0CTURBO_MON_MASK 0x1 +#define DA_EINT0CTURBO_MON_MASK_SFT (0x1 << 0) +#define DA_EINT0CMPMEN_MON_ADDR \ + MT6359_ACCDET_CON38 +#define DA_EINT0CMPMEN_MON_SFT 1 +#define DA_EINT0CMPMEN_MON_MASK 0x1 +#define DA_EINT0CMPMEN_MON_MASK_SFT (0x1 << 1) +#define DA_EINT0CMPEN_MON_ADDR \ + MT6359_ACCDET_CON38 +#define DA_EINT0CMPEN_MON_SFT 2 +#define DA_EINT0CMPEN_MON_MASK 0x1 +#define DA_EINT0CMPEN_MON_MASK_SFT (0x1 << 2) +#define DA_EINT0INVEN_MON_ADDR \ + MT6359_ACCDET_CON38 +#define DA_EINT0INVEN_MON_SFT 3 +#define DA_EINT0INVEN_MON_MASK 0x1 +#define DA_EINT0INVEN_MON_MASK_SFT (0x1 << 3) +#define DA_EINT0CEN_MON_ADDR \ + MT6359_ACCDET_CON38 +#define DA_EINT0CEN_MON_SFT 4 +#define DA_EINT0CEN_MON_MASK 0x1 +#define DA_EINT0CEN_MON_MASK_SFT (0x1 << 4) +#define DA_EINT0EN_MON_ADDR \ + MT6359_ACCDET_CON38 +#define DA_EINT0EN_MON_SFT 5 +#define DA_EINT0EN_MON_MASK 0x1 +#define DA_EINT0EN_MON_MASK_SFT (0x1 << 5) +#define DA_EINT1CTURBO_MON_ADDR \ + MT6359_ACCDET_CON38 +#define DA_EINT1CTURBO_MON_SFT 8 +#define DA_EINT1CTURBO_MON_MASK 0x1 +#define DA_EINT1CTURBO_MON_MASK_SFT (0x1 << 8) +#define DA_EINT1CMPMEN_MON_ADDR \ + MT6359_ACCDET_CON38 +#define DA_EINT1CMPMEN_MON_SFT 9 +#define DA_EINT1CMPMEN_MON_MASK 0x1 +#define DA_EINT1CMPMEN_MON_MASK_SFT (0x1 << 9) +#define DA_EINT1CMPEN_MON_ADDR \ + MT6359_ACCDET_CON38 +#define DA_EINT1CMPEN_MON_SFT 10 +#define DA_EINT1CMPEN_MON_MASK 0x1 +#define DA_EINT1CMPEN_MON_MASK_SFT (0x1 << 10) +#define DA_EINT1INVEN_MON_ADDR \ + MT6359_ACCDET_CON38 +#define DA_EINT1INVEN_MON_SFT 11 +#define DA_EINT1INVEN_MON_MASK 0x1 +#define DA_EINT1INVEN_MON_MASK_SFT (0x1 << 11) +#define DA_EINT1CEN_MON_ADDR \ + MT6359_ACCDET_CON38 +#define DA_EINT1CEN_MON_SFT 12 +#define DA_EINT1CEN_MON_MASK 0x1 +#define DA_EINT1CEN_MON_MASK_SFT (0x1 << 12) +#define DA_EINT1EN_MON_ADDR \ + MT6359_ACCDET_CON38 +#define DA_EINT1EN_MON_SFT 13 +#define DA_EINT1EN_MON_MASK 0x1 +#define DA_EINT1EN_MON_MASK_SFT (0x1 << 13) +#define ACCDET_EINT0_M_PLUG_IN_COUNT_ADDR \ + MT6359_ACCDET_CON39 +#define ACCDET_EINT0_M_PLUG_IN_COUNT_SFT 0 +#define ACCDET_EINT0_M_PLUG_IN_COUNT_MASK 0x7 +#define ACCDET_EINT0_M_PLUG_IN_COUNT_MASK_SFT (0x7 << 0) +#define ACCDET_EINT1_M_PLUG_IN_COUNT_ADDR \ + MT6359_ACCDET_CON39 +#define ACCDET_EINT1_M_PLUG_IN_COUNT_SFT 4 +#define ACCDET_EINT1_M_PLUG_IN_COUNT_MASK 0x7 +#define ACCDET_EINT1_M_PLUG_IN_COUNT_MASK_SFT (0x7 << 4) +#define ACCDET_MON_FLAG_EN_ADDR \ + MT6359_ACCDET_CON40 +#define ACCDET_MON_FLAG_EN_SFT 0 +#define ACCDET_MON_FLAG_EN_MASK 0x1 +#define ACCDET_MON_FLAG_EN_MASK_SFT (0x1 << 0) +#define ACCDET_MON_FLAG_SEL_ADDR \ + MT6359_ACCDET_CON40 +#define ACCDET_MON_FLAG_SEL_SFT 4 +#define ACCDET_MON_FLAG_SEL_MASK 0xF +#define ACCDET_MON_FLAG_SEL_MASK_SFT (0xF << 4) + +#define RG_AUDPWDBMICBIAS0_ADDR \ + MT6359_AUDENC_ANA_CON15 +#define RG_AUDPWDBMICBIAS0_SFT 0 +#define RG_AUDPWDBMICBIAS0_MASK 0x1 +#define RG_AUDPWDBMICBIAS0_MASK_SFT (0x1 << 0) +#define RG_AUDPREAMPLON_ADDR \ + MT6359_AUDENC_ANA_CON0 +#define RG_AUDPREAMPLON_SFT 0 +#define RG_AUDPREAMPLON_MASK 0x1 +#define RG_AUDPREAMPLON_MASK_SFT (0x1 << 0) +#define RG_CLKSQ_EN_ADDR \ + MT6359_AUDENC_ANA_CON23 +#define RG_CLKSQ_EN_SFT 0 +#define RG_CLKSQ_EN_MASK 0x1 +#define RG_CLKSQ_EN_MASK_SFT (0x1 << 0) +#define RG_RTC32K_CK_PDN_ADDR \ + MT6359_TOP_CKPDN_CON0 +#define RG_RTC32K_CK_PDN_SFT 15 +#define RG_RTC32K_CK_PDN_MASK 0x1 +#define RG_RTC32K_CK_PDN_MASK_SFT (0x1 << 15) +#define RG_HPLOUTPUTSTBENH_VAUDP32_ADDR \ + MT6359_AUDDEC_ANA_CON2 +#define RG_HPLOUTPUTSTBENH_VAUDP32_SFT 0 +#define RG_HPLOUTPUTSTBENH_VAUDP32_MASK 0x7 +#define RG_HPLOUTPUTSTBENH_VAUDP32_MASK_SFT (0x7 << 0) +#define AUXADC_RQST_CH5_ADDR \ + MT6359_AUXADC_RQST0 +#define AUXADC_RQST_CH5_SFT 5 +#define AUXADC_RQST_CH5_MASK 0x1 +#define AUXADC_RQST_CH5_MASK_SFT (0x1 << 5) +#define RG_LDO_VUSB_HW0_OP_EN_ADDR \ + MT6359_LDO_VUSB_OP_EN +#define RG_LDO_VUSB_HW0_OP_EN_SFT 0 +#define RG_LDO_VUSB_HW0_OP_EN_MASK 0x1 +#define RG_LDO_VUSB_HW0_OP_EN_MASK_SFT (0x1 << 0) +#define RG_HPROUTPUTSTBENH_VAUDP32_ADDR \ + MT6359_AUDDEC_ANA_CON2 +#define RG_HPROUTPUTSTBENH_VAUDP32_SFT 4 +#define RG_HPROUTPUTSTBENH_VAUDP32_MASK 0x7 +#define RG_HPROUTPUTSTBENH_VAUDP32_MASK_SFT (0x7 << 4) +#define RG_NCP_PDDIS_EN_ADDR \ + MT6359_AFE_NCP_CFG2 +#define RG_NCP_PDDIS_EN_SFT 0 +#define RG_NCP_PDDIS_EN_MASK 0x1 +#define RG_NCP_PDDIS_EN_MASK_SFT (0x1 << 0) +#define RG_SCK32K_CK_PDN_ADDR \ + MT6359_TOP_CKPDN_CON0 +#define RG_SCK32K_CK_PDN_SFT 0 +#define RG_SCK32K_CK_PDN_MASK 0x1 +#define RG_SCK32K_CK_PDN_MASK_SFT (0x1 << 0) /* AUDENC_ANA_CON18: */ -#define RG_ACCDET_MODE_ANA11_MODE1 (0x000f) -#define RG_ACCDET_MODE_ANA11_MODE2 (0x008f) -#define RG_ACCDET_MODE_ANA11_MODE6 (0x008f) +#define RG_ACCDET_MODE_ANA11_MODE1 (0x000F) +#define RG_ACCDET_MODE_ANA11_MODE2 (0x008F) +#define RG_ACCDET_MODE_ANA11_MODE6 (0x008F) /* AUXADC_ADC5: Auxadc CH5 read data */ #define AUXADC_DATA_RDY_CH5 BIT(15) #define AUXADC_DATA_PROCEED_CH5 BIT(15) -#define AUXADC_DATA_MASK (0x0fff) +#define AUXADC_DATA_MASK (0x0FFF) /* AUXADC_RQST0_SET: Auxadc CH5 request, relevant 0x07EC */ #define AUXADC_RQST_CH5_SET BIT(5) /* AUXADC_RQST0_CLR: Auxadc CH5 request, relevant 0x07EC */ #define AUXADC_RQST_CH5_CLR BIT(5) -#define ACCDET_CALI_MASK0 (0xff) -#define ACCDET_CALI_MASK1 (0xff << 8) -#define ACCDET_CALI_MASK2 (0xff) -#define ACCDET_CALI_MASK3 (0xff << 8) -#define ACCDET_CALI_MASK4 (0xff) +#define ACCDET_CALI_MASK0 (0xFF) +#define ACCDET_CALI_MASK1 (0xFF << 8) +#define ACCDET_CALI_MASK2 (0xFF) +#define ACCDET_CALI_MASK3 (0xFF << 8) +#define ACCDET_CALI_MASK4 (0xFF) -#define ACCDET_EINT1_IRQ_CLR_B11 BIT(PMIC_ACCDET_EINT1_IRQ_CLR_SHIFT) -#define ACCDET_EINT0_IRQ_CLR_B10 BIT(PMIC_ACCDET_EINT0_IRQ_CLR_SHIFT) -#define ACCDET_EINT_IRQ_CLR_B10_11 (0x03 << \ - PMIC_ACCDET_EINT0_IRQ_CLR_SHIFT) -#define ACCDET_IRQ_CLR_B8 BIT(PMIC_ACCDET_IRQ_CLR_SHIFT) - -#define ACCDET_EINT1_IRQ_B3 BIT(PMIC_ACCDET_EINT1_IRQ_SHIFT) -#define ACCDET_EINT0_IRQ_B2 BIT(PMIC_ACCDET_EINT0_IRQ_SHIFT) -#define ACCDET_EINT_IRQ_B2_B3 (0x03 << PMIC_ACCDET_EINT0_IRQ_SHIFT) -#define ACCDET_IRQ_B0 BIT(PMIC_ACCDET_IRQ_SHIFT) +#define ACCDET_EINT_IRQ_B2_B3 (0x03 << ACCDET_EINT0_IRQ_SFT) /* ACCDET_CON25: RO, accdet FSM state,etc.*/ -#define ACCDET_STATE_MEM_IN_OFFSET (PMIC_ACCDET_MEM_IN_SHIFT) -#define ACCDET_STATE_AB_MASK (0x03) -#define ACCDET_STATE_AB_00 (0x00) -#define ACCDET_STATE_AB_01 (0x01) -#define ACCDET_STATE_AB_10 (0x02) -#define ACCDET_STATE_AB_11 (0x03) +#define ACCDET_STATE_MEM_IN_OFFSET (ACCDET_MEM_IN_SFT) +#define ACCDET_STATE_AB_MASK (0x03) +#define ACCDET_STATE_AB_00 (0x00) +#define ACCDET_STATE_AB_01 (0x01) +#define ACCDET_STATE_AB_10 (0x02) +#define ACCDET_STATE_AB_11 (0x03) /* ACCDET_CON19 */ -#define ACCDET_EINT0_STABLE_VAL ((1 << PMIC_ACCDET_DA_STABLE_SHIFT) | \ - (1 << PMIC_ACCDET_EINT0_EN_STABLE_SHIFT) | \ - (1 << PMIC_ACCDET_EINT0_CMPEN_STABLE_SHIFT) | \ - (1 << PMIC_ACCDET_EINT0_CEN_STABLE_SHIFT)) - -#define ACCDET_EINT1_STABLE_VAL ((1 << PMIC_ACCDET_DA_STABLE_SHIFT) | \ - (1 << PMIC_ACCDET_EINT1_EN_STABLE_SHIFT) | \ - (1 << PMIC_ACCDET_EINT1_CMPEN_STABLE_SHIFT) | \ - (1 << PMIC_ACCDET_EINT1_CEN_STABLE_SHIFT)) +#define ACCDET_EINT0_STABLE_VAL ((ACCDET_DA_STABLE_MASK_SFT) | \ + (ACCDET_EINT0_EN_STABLE_MASK_SFT) | \ + (ACCDET_EINT0_CMPEN_STABLE_MASK_SFT) | \ + (ACCDET_EINT0_CEN_STABLE_MASK_SFT)) +#define ACCDET_EINT1_STABLE_VAL ((ACCDET_DA_STABLE_MASK_SFT) | \ + (ACCDET_EINT1_EN_STABLE_MASK_SFT) | \ + (ACCDET_EINT1_CMPEN_STABLE_MASK_SFT) | \ + (ACCDET_EINT1_CEN_STABLE_MASK_SFT)) /* The following are used for mt6359.c */ /* MT6359_DCXO_CW12 */ #define RG_XO_AUDIO_EN_M_SFT 13 From 69644fca2716699cc6896aff51d37b1e886c94d2 Mon Sep 17 00:00:00 2001 From: Kai-Heng Feng Date: Fri, 26 Mar 2021 00:59:12 +0800 Subject: [PATCH 335/587] ALSA: usb-audio: Carve out connector value checking into a helper This is preparation for next patch, no functional change intended. Signed-off-by: Kai-Heng Feng Link: https://lore.kernel.org/r/20210325165918.22593-1-kai.heng.feng@canonical.com Signed-off-by: Takashi Iwai --- sound/usb/mixer.c | 34 +++++++++++++++++++++++++--------- 1 file changed, 25 insertions(+), 9 deletions(-) diff --git a/sound/usb/mixer.c b/sound/usb/mixer.c index b004b2e63a5d..5a2d9a768f70 100644 --- a/sound/usb/mixer.c +++ b/sound/usb/mixer.c @@ -1446,13 +1446,11 @@ static int mixer_ctl_master_bool_get(struct snd_kcontrol *kcontrol, return 0; } -/* get the connectors status and report it as boolean type */ -static int mixer_ctl_connector_get(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_value *ucontrol) +static int get_connector_value(struct usb_mixer_elem_info *cval, + char *name, int *val) { - struct usb_mixer_elem_info *cval = kcontrol->private_data; struct snd_usb_audio *chip = cval->head.mixer->chip; - int idx = 0, validx, ret, val; + int idx = 0, validx, ret; validx = cval->control << 8 | 0; @@ -1467,21 +1465,24 @@ static int mixer_ctl_connector_get(struct snd_kcontrol *kcontrol, ret = snd_usb_ctl_msg(chip->dev, usb_rcvctrlpipe(chip->dev, 0), UAC2_CS_CUR, USB_RECIP_INTERFACE | USB_TYPE_CLASS | USB_DIR_IN, validx, idx, &uac2_conn, sizeof(uac2_conn)); - val = !!uac2_conn.bNrChannels; + if (val) + *val = !!uac2_conn.bNrChannels; } else { /* UAC_VERSION_3 */ struct uac3_insertion_ctl_blk uac3_conn; ret = snd_usb_ctl_msg(chip->dev, usb_rcvctrlpipe(chip->dev, 0), UAC2_CS_CUR, USB_RECIP_INTERFACE | USB_TYPE_CLASS | USB_DIR_IN, validx, idx, &uac3_conn, sizeof(uac3_conn)); - val = !!uac3_conn.bmConInserted; + if (val) + *val = !!uac3_conn.bmConInserted; } snd_usb_unlock_shutdown(chip); if (ret < 0) { - if (strstr(kcontrol->id.name, "Speaker")) { - ucontrol->value.integer.value[0] = 1; + if (name && strstr(name, "Speaker")) { + if (val) + *val = 1; return 0; } error: @@ -1491,6 +1492,21 @@ error: return filter_error(cval, ret); } + return ret; +} + +/* get the connectors status and report it as boolean type */ +static int mixer_ctl_connector_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct usb_mixer_elem_info *cval = kcontrol->private_data; + int ret, val; + + ret = get_connector_value(cval, kcontrol->id.name, &val); + + if (ret < 0) + return ret; + ucontrol->value.integer.value[0] = val; return 0; } From 44609fc01f280d6b4067262ecbb00e3128d718ae Mon Sep 17 00:00:00 2001 From: Kai-Heng Feng Date: Fri, 26 Mar 2021 00:59:13 +0800 Subject: [PATCH 336/587] ALSA: usb-audio: Check connector value on resume Rear Mic on Lenovo P620 cannot record after S3, despite that there's no error and the other two functions of the USB audio, Line In and Line Out, work just fine. The mic starts to work again after running userspace app like "alsactl store". Following the lead, the evidence shows that as soon as connector status is queried, the mic can work again. So also check connector value on resume to "wake up" the USB audio to make it functional. This can be device specific, however I think this generic approach may benefit more than one device. Now the resume callback checks connector, and a new callback, reset_resume, to also restore switches and volumes. Suggested-by: Takashi Iwai Signed-off-by: Kai-Heng Feng Link: https://lore.kernel.org/r/20210325165918.22593-2-kai.heng.feng@canonical.com Signed-off-by: Takashi Iwai --- sound/usb/mixer.c | 44 +++++++++++++++++++++++++++++++--------- sound/usb/mixer.h | 1 + sound/usb/mixer_quirks.c | 2 +- 3 files changed, 36 insertions(+), 11 deletions(-) diff --git a/sound/usb/mixer.c b/sound/usb/mixer.c index 5a2d9a768f70..2faf5767c7f8 100644 --- a/sound/usb/mixer.c +++ b/sound/usb/mixer.c @@ -3631,20 +3631,43 @@ static int restore_mixer_value(struct usb_mixer_elem_list *list) return 0; } +static int default_mixer_resume(struct usb_mixer_elem_list *list) +{ + struct usb_mixer_elem_info *cval = mixer_elem_list_to_info(list); + + /* get connector value to "wake up" the USB audio */ + if (cval->val_type == USB_MIXER_BOOLEAN && cval->channels == 1) + get_connector_value(cval, NULL, NULL); + + return 0; +} + +static int default_mixer_reset_resume(struct usb_mixer_elem_list *list) +{ + int err = default_mixer_resume(list); + + if (err < 0) + return err; + return restore_mixer_value(list); +} + int snd_usb_mixer_resume(struct usb_mixer_interface *mixer, bool reset_resume) { struct usb_mixer_elem_list *list; + usb_mixer_elem_resume_func_t f; int id, err; - if (reset_resume) { - /* restore cached mixer values */ - for (id = 0; id < MAX_ID_ELEMS; id++) { - for_each_mixer_elem(list, mixer, id) { - if (list->resume) { - err = list->resume(list); - if (err < 0) - return err; - } + /* restore cached mixer values */ + for (id = 0; id < MAX_ID_ELEMS; id++) { + for_each_mixer_elem(list, mixer, id) { + if (reset_resume) + f = list->reset_resume; + else + f = list->resume; + if (f) { + err = f(list); + if (err < 0) + return err; } } } @@ -3663,6 +3686,7 @@ void snd_usb_mixer_elem_init_std(struct usb_mixer_elem_list *list, list->id = unitid; list->dump = snd_usb_mixer_dump_cval; #ifdef CONFIG_PM - list->resume = restore_mixer_value; + list->resume = default_mixer_resume; + list->reset_resume = default_mixer_reset_resume; #endif } diff --git a/sound/usb/mixer.h b/sound/usb/mixer.h index c29e27ac43a7..e5a01f17bf3c 100644 --- a/sound/usb/mixer.h +++ b/sound/usb/mixer.h @@ -69,6 +69,7 @@ struct usb_mixer_elem_list { bool is_std_info; usb_mixer_elem_dump_func_t dump; usb_mixer_elem_resume_func_t resume; + usb_mixer_elem_resume_func_t reset_resume; }; /* iterate over mixer element list of the given unit id */ diff --git a/sound/usb/mixer_quirks.c b/sound/usb/mixer_quirks.c index 5b77e8140ba6..e64cd4b11fc6 100644 --- a/sound/usb/mixer_quirks.c +++ b/sound/usb/mixer_quirks.c @@ -151,7 +151,7 @@ static int add_single_ctl_with_resume(struct usb_mixer_interface *mixer, *listp = list; list->mixer = mixer; list->id = id; - list->resume = resume; + list->reset_resume = resume; kctl = snd_ctl_new1(knew, list); if (!kctl) { kfree(list); From 583770e84a44c4e4ea206546ea07cc534fcd6d58 Mon Sep 17 00:00:00 2001 From: Bhaskar Chowdhury Date: Fri, 26 Mar 2021 12:12:11 +0530 Subject: [PATCH 337/587] ALSA: pcm: Fix couple of typos s/unconditonally/unconditionally/ s/succesful/successful/ Signed-off-by: Bhaskar Chowdhury Link: https://lore.kernel.org/r/20210326064211.6509-1-unixbhaskar@gmail.com Signed-off-by: Takashi Iwai --- sound/core/pcm_native.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/sound/core/pcm_native.c b/sound/core/pcm_native.c index 17a85f4815d5..8dbe86cf2e4f 100644 --- a/sound/core/pcm_native.c +++ b/sound/core/pcm_native.c @@ -1425,7 +1425,7 @@ static int snd_pcm_do_stop(struct snd_pcm_substream *substream, substream->ops->trigger(substream, SNDRV_PCM_TRIGGER_STOP); substream->runtime->stop_operating = true; } - return 0; /* unconditonally stop all substreams */ + return 0; /* unconditionally stop all substreams */ } static void snd_pcm_post_stop(struct snd_pcm_substream *substream, @@ -1469,7 +1469,7 @@ EXPORT_SYMBOL(snd_pcm_stop); * After stopping, the state is changed to SETUP. * Unlike snd_pcm_stop(), this affects only the given stream. * - * Return: Zero if succesful, or a negative error code. + * Return: Zero if successful, or a negative error code. */ int snd_pcm_drain_done(struct snd_pcm_substream *substream) { From 0803a5cb5b7cf369c3e2af4108ee44d0b6e1c197 Mon Sep 17 00:00:00 2001 From: YueHaibing Date: Mon, 29 Mar 2021 23:05:24 +0800 Subject: [PATCH 338/587] ASoC: dwc: Fix -Wmissing-prototypes warnings MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit while CONFIG_SND_DESIGNWARE_PCM is not set, building with W=1 shows this: sound/soc/dwc/local.h:127:6: warning: no previous prototype for ‘dw_pcm_push_tx’ [-Wmissing-prototypes] void dw_pcm_push_tx(struct dw_i2s_dev *dev) { } ^~~~~~~~~~~~~~ sound/soc/dwc/local.h:128:6: warning: no previous prototype for ‘dw_pcm_pop_rx’ [-Wmissing-prototypes] void dw_pcm_pop_rx(struct dw_i2s_dev *dev) { } ^~~~~~~~~~~~~ sound/soc/dwc/local.h:129:5: warning: no previous prototype for ‘dw_pcm_register’ [-Wmissing-prototypes] int dw_pcm_register(struct platform_device *pdev) ^~~~~~~~~~~~~~~ Change these to inline functions to fix the warnings. Signed-off-by: YueHaibing Link: https://lore.kernel.org/r/20210329150524.18184-1-yuehaibing@huawei.com Signed-off-by: Mark Brown --- sound/soc/dwc/local.h | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/sound/soc/dwc/local.h b/sound/soc/dwc/local.h index 91dc70a826f8..1c361eb6127e 100644 --- a/sound/soc/dwc/local.h +++ b/sound/soc/dwc/local.h @@ -124,9 +124,9 @@ void dw_pcm_push_tx(struct dw_i2s_dev *dev); void dw_pcm_pop_rx(struct dw_i2s_dev *dev); int dw_pcm_register(struct platform_device *pdev); #else -void dw_pcm_push_tx(struct dw_i2s_dev *dev) { } -void dw_pcm_pop_rx(struct dw_i2s_dev *dev) { } -int dw_pcm_register(struct platform_device *pdev) +static inline void dw_pcm_push_tx(struct dw_i2s_dev *dev) { } +static inline void dw_pcm_pop_rx(struct dw_i2s_dev *dev) { } +static inline int dw_pcm_register(struct platform_device *pdev) { return -EINVAL; } From 23f23db29ac996a824dce2b3a800c7a002f1c480 Mon Sep 17 00:00:00 2001 From: Vijendar Mukunda Date: Fri, 26 Mar 2021 22:14:30 +0530 Subject: [PATCH 339/587] ASoC: amd: update spdx license for acp machine driver update SPDX license for acp machine driver. Signed-off-by: Vijendar Mukunda Link: https://lore.kernel.org/r/1616777074-5151-1-git-send-email-Vijendar.Mukunda@amd.com Signed-off-by: Mark Brown --- sound/soc/amd/acp-da7219-max98357a.c | 29 +++++----------------------- 1 file changed, 5 insertions(+), 24 deletions(-) diff --git a/sound/soc/amd/acp-da7219-max98357a.c b/sound/soc/amd/acp-da7219-max98357a.c index e65e007fc604..84e3906abd4f 100644 --- a/sound/soc/amd/acp-da7219-max98357a.c +++ b/sound/soc/amd/acp-da7219-max98357a.c @@ -1,27 +1,8 @@ -/* - * Machine driver for AMD ACP Audio engine using DA7219 & MAX98357 codec - * - * Copyright 2017 Advanced Micro Devices, Inc. - * - * Permission is hereby granted, free of charge, to any person obtaining a - * copy of this software and associated documentation files (the "Software"), - * to deal in the Software without restriction, including without limitation - * the rights to use, copy, modify, merge, publish, distribute, sublicense, - * and/or sell copies of the Software, and to permit persons to whom the - * Software is furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR - * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, - * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR - * OTHER DEALINGS IN THE SOFTWARE. - * - */ +// SPDX-License-Identifier: MIT +// +// Machine driver for AMD ACP Audio engine using DA7219, RT5682 & MAX98357 codec +// +//Copyright 2017-2021 Advanced Micro Devices, Inc. #include #include From d463cead11ace05c81de31a0fb9c2507c5c1d0a2 Mon Sep 17 00:00:00 2001 From: Vijendar Mukunda Date: Fri, 26 Mar 2021 22:14:31 +0530 Subject: [PATCH 340/587] ASoC: amd: fix acpi dependency kernel warning Fix ACPI dependency kernel warning produced by powerpc allyesconfig. sound/soc/amd/acp-da7219-max98357a.c:684:28: warning: 'cz_rt5682_card' defined but not used [-Wunused-variable] sound/soc/amd/acp-da7219-max98357a.c:671:28: warning: 'cz_card' defined but not used [-Wunused-variable] Reported-by: Stephen Rothwell Signed-off-by: Vijendar Mukunda Link: https://lore.kernel.org/r/1616777074-5151-2-git-send-email-Vijendar.Mukunda@amd.com Signed-off-by: Mark Brown --- sound/soc/amd/Kconfig | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sound/soc/amd/Kconfig b/sound/soc/amd/Kconfig index 43f5d29d7c53..256c19275d45 100644 --- a/sound/soc/amd/Kconfig +++ b/sound/soc/amd/Kconfig @@ -11,7 +11,7 @@ config SND_SOC_AMD_CZ_DA7219MX98357_MACH select SND_SOC_MAX98357A select SND_SOC_ADAU7002 select REGULATOR - depends on SND_SOC_AMD_ACP && I2C && GPIOLIB + depends on SND_SOC_AMD_ACP && I2C && GPIOLIB && ACPI help This option enables machine driver for DA7219, RT5682 and MAX9835. From 502e5321d89214a34a7b8bda697fc98d14b51cae Mon Sep 17 00:00:00 2001 From: Shengjiu Wang Date: Mon, 29 Mar 2021 11:34:28 +0800 Subject: [PATCH 341/587] ASoC: fsl_rpmsg: initialise pointers to NULL This fixes the following sparse warnings: sound/soc/fsl/fsl_rpmsg.c:45:45: sparse: sparse: Using plain integer as NULL pointer sound/soc/fsl/fsl_rpmsg.c:45:56: sparse: sparse: Using plain integer as NULL pointer Fixes: b73d9e6225e8 ("ASoC: fsl_rpmsg: Add CPU DAI driver for audio base on rpmsg") Signed-off-by: Shengjiu Wang Reported-by: kernel test robot Link: https://lore.kernel.org/r/1616988868-971-1-git-send-email-shengjiu.wang@nxp.com Signed-off-by: Mark Brown --- sound/soc/fsl/fsl_rpmsg.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sound/soc/fsl/fsl_rpmsg.c b/sound/soc/fsl/fsl_rpmsg.c index 2d09d8850e2c..ea5c973e2e84 100644 --- a/sound/soc/fsl/fsl_rpmsg.c +++ b/sound/soc/fsl/fsl_rpmsg.c @@ -42,7 +42,7 @@ static int fsl_rpmsg_hw_params(struct snd_pcm_substream *substream, struct snd_soc_dai *dai) { struct fsl_rpmsg *rpmsg = snd_soc_dai_get_drvdata(dai); - struct clk *p = rpmsg->mclk, *pll = 0, *npll = 0; + struct clk *p = rpmsg->mclk, *pll = NULL, *npll = NULL; u64 rate = params_rate(params); int ret = 0; From c1c03888f1e89e669aa6da0c9a491f02fd6a999e Mon Sep 17 00:00:00 2001 From: Jaska Uimonen Date: Fri, 26 Mar 2021 18:51:48 +0200 Subject: [PATCH 342/587] ASoC: SOF: parse multiple SSP DAI and hw configs ASoC parses multiple hw_configs defined in topology. However currently in SOF only the first config is used and others are discarded. First change SOF driver to parse and save possible multiple configs in ssp case. Also save the default config value provided by ASoC. Functionality with only one defined config stays the same. Signed-off-by: Jaska Uimonen Reviewed-by: Ranjani Sridharan Reviewed-by: Pierre-Louis Bossart Reviewed-by: Guennadi Liakhovetski Signed-off-by: Kai Vehmanen Link: https://lore.kernel.org/r/20210326165150.255533-1-kai.vehmanen@linux.intel.com Signed-off-by: Mark Brown --- sound/soc/sof/pcm.c | 8 +- sound/soc/sof/sof-audio.h | 2 + sound/soc/sof/topology.c | 188 ++++++++++++++++++++++---------------- 3 files changed, 115 insertions(+), 83 deletions(-) diff --git a/sound/soc/sof/pcm.c b/sound/soc/sof/pcm.c index 61c3fe17342d..c3dc533f2627 100644 --- a/sound/soc/sof/pcm.c +++ b/sound/soc/sof/pcm.c @@ -673,10 +673,10 @@ int sof_pcm_dai_link_fixup(struct snd_soc_pcm_runtime *rtd, struct snd_pcm_hw_pa /* read rate and channels from topology */ switch (dai->dai_config->type) { case SOF_DAI_INTEL_SSP: - rate->min = dai->dai_config->ssp.fsync_rate; - rate->max = dai->dai_config->ssp.fsync_rate; - channels->min = dai->dai_config->ssp.tdm_slots; - channels->max = dai->dai_config->ssp.tdm_slots; + rate->min = dai->dai_config[dai->current_config].ssp.fsync_rate; + rate->max = dai->dai_config[dai->current_config].ssp.fsync_rate; + channels->min = dai->dai_config[dai->current_config].ssp.tdm_slots; + channels->max = dai->dai_config[dai->current_config].ssp.tdm_slots; dev_dbg(component->dev, "rate_min: %d rate_max: %d\n", rate->min, rate->max); diff --git a/sound/soc/sof/sof-audio.h b/sound/soc/sof/sof-audio.h index dc930fc2f4b5..dc274e63ed9a 100644 --- a/sound/soc/sof/sof-audio.h +++ b/sound/soc/sof/sof-audio.h @@ -112,6 +112,8 @@ struct snd_sof_dai { const char *cpu_dai_name; struct sof_ipc_comp_dai comp_dai; + int number_configs; + int current_config; struct sof_ipc_dai_config *dai_config; struct list_head list; /* list in sdev dai list */ }; diff --git a/sound/soc/sof/topology.c b/sound/soc/sof/topology.c index 10f99620eb31..036202768b75 100644 --- a/sound/soc/sof/topology.c +++ b/sound/soc/sof/topology.c @@ -2811,12 +2811,14 @@ static void sof_dai_set_format(struct snd_soc_tplg_hw_config *hw_config, * name. Note that the function can only be used for the case that all DAIs * have a common DAI config for now. */ -static int sof_set_dai_config(struct snd_sof_dev *sdev, u32 size, - struct snd_soc_dai_link *link, - struct sof_ipc_dai_config *config) +static int sof_set_dai_config_multi(struct snd_sof_dev *sdev, u32 size, + struct snd_soc_dai_link *link, + struct sof_ipc_dai_config *config, + int num_conf, int curr_conf) { struct snd_sof_dai *dai; int found = 0; + int i; list_for_each_entry(dai, &sdev->dai_list, list) { if (!dai->name) @@ -2832,19 +2834,27 @@ static int sof_set_dai_config(struct snd_sof_dev *sdev, u32 size, * dai config's dai_index match to the component's * dai_index. */ - config->dai_index = dai->comp_dai.dai_index; + for (i = 0; i < num_conf; i++) + config[i].dai_index = dai->comp_dai.dai_index; + dev_dbg(sdev->dev, "set DAI config for %s index %d\n", + dai->name, config[curr_conf].dai_index); /* send message to DSP */ ret = sof_ipc_tx_message(sdev->ipc, - config->hdr.cmd, config, size, + config[curr_conf].hdr.cmd, + &config[curr_conf], size, &reply, sizeof(reply)); if (ret < 0) { - dev_err(sdev->dev, "error: failed to set DAI config for %s index %d\n", - dai->name, config->dai_index); + dev_err(sdev->dev, + "error: failed to set DAI config for %s index %d\n", + dai->name, config[curr_conf].dai_index); return ret; } - dai->dai_config = kmemdup(config, size, GFP_KERNEL); + + dai->number_configs = num_conf; + dai->current_config = curr_conf; + dai->dai_config = kmemdup(config, size * num_conf, GFP_KERNEL); if (!dai->dai_config) return -ENOMEM; @@ -2868,64 +2878,81 @@ static int sof_set_dai_config(struct snd_sof_dev *sdev, u32 size, return 0; } +static int sof_set_dai_config(struct snd_sof_dev *sdev, u32 size, + struct snd_soc_dai_link *link, + struct sof_ipc_dai_config *config) +{ + return sof_set_dai_config_multi(sdev, size, link, config, 1, 0); +} + static int sof_link_ssp_load(struct snd_soc_component *scomp, int index, struct snd_soc_dai_link *link, struct snd_soc_tplg_link_config *cfg, struct snd_soc_tplg_hw_config *hw_config, - struct sof_ipc_dai_config *config) + struct sof_ipc_dai_config *config, int curr_conf) { struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(scomp); struct snd_soc_tplg_private *private = &cfg->priv; + int num_conf = le32_to_cpu(cfg->num_hw_configs); u32 size = sizeof(*config); int ret; + int i; - /* handle master/slave and inverted clocks */ - sof_dai_set_format(hw_config, config); + /* + * Parse common data, we should have 1 common data per hw_config. + */ + ret = sof_parse_token_sets(scomp, &config->ssp, ssp_tokens, + ARRAY_SIZE(ssp_tokens), private->array, + le32_to_cpu(private->size), + num_conf, size); - /* init IPC */ - memset(&config->ssp, 0, sizeof(struct sof_ipc_dai_ssp_params)); - config->hdr.size = size; - - ret = sof_parse_tokens(scomp, &config->ssp, ssp_tokens, - ARRAY_SIZE(ssp_tokens), private->array, - le32_to_cpu(private->size)); if (ret != 0) { dev_err(scomp->dev, "error: parse ssp tokens failed %d\n", le32_to_cpu(private->size)); return ret; } - config->ssp.mclk_rate = le32_to_cpu(hw_config->mclk_rate); - config->ssp.bclk_rate = le32_to_cpu(hw_config->bclk_rate); - config->ssp.fsync_rate = le32_to_cpu(hw_config->fsync_rate); - config->ssp.tdm_slots = le32_to_cpu(hw_config->tdm_slots); - config->ssp.tdm_slot_width = le32_to_cpu(hw_config->tdm_slot_width); - config->ssp.mclk_direction = hw_config->mclk_direction; - config->ssp.rx_slots = le32_to_cpu(hw_config->rx_slots); - config->ssp.tx_slots = le32_to_cpu(hw_config->tx_slots); + /* process all possible hw configs */ + for (i = 0; i < num_conf; i++) { - dev_dbg(scomp->dev, "tplg: config SSP%d fmt 0x%x mclk %d bclk %d fclk %d width (%d)%d slots %d mclk id %d quirks %d\n", - config->dai_index, config->format, - config->ssp.mclk_rate, config->ssp.bclk_rate, - config->ssp.fsync_rate, config->ssp.sample_valid_bits, - config->ssp.tdm_slot_width, config->ssp.tdm_slots, - config->ssp.mclk_id, config->ssp.quirks); + /* handle master/slave and inverted clocks */ + sof_dai_set_format(&hw_config[i], &config[i]); - /* validate SSP fsync rate and channel count */ - if (config->ssp.fsync_rate < 8000 || config->ssp.fsync_rate > 192000) { - dev_err(scomp->dev, "error: invalid fsync rate for SSP%d\n", - config->dai_index); - return -EINVAL; - } + config[i].hdr.size = size; - if (config->ssp.tdm_slots < 1 || config->ssp.tdm_slots > 8) { - dev_err(scomp->dev, "error: invalid channel count for SSP%d\n", - config->dai_index); - return -EINVAL; + /* copy differentiating hw configs to ipc structs */ + config[i].ssp.mclk_rate = le32_to_cpu(hw_config[i].mclk_rate); + config[i].ssp.bclk_rate = le32_to_cpu(hw_config[i].bclk_rate); + config[i].ssp.fsync_rate = le32_to_cpu(hw_config[i].fsync_rate); + config[i].ssp.tdm_slots = le32_to_cpu(hw_config[i].tdm_slots); + config[i].ssp.tdm_slot_width = le32_to_cpu(hw_config[i].tdm_slot_width); + config[i].ssp.mclk_direction = hw_config[i].mclk_direction; + config[i].ssp.rx_slots = le32_to_cpu(hw_config[i].rx_slots); + config[i].ssp.tx_slots = le32_to_cpu(hw_config[i].tx_slots); + + dev_dbg(scomp->dev, "tplg: config SSP%d fmt 0x%x mclk %d bclk %d fclk %d width (%d)%d slots %d mclk id %d quirks %d\n", + config[i].dai_index, config[i].format, + config[i].ssp.mclk_rate, config[i].ssp.bclk_rate, + config[i].ssp.fsync_rate, config[i].ssp.sample_valid_bits, + config[i].ssp.tdm_slot_width, config[i].ssp.tdm_slots, + config[i].ssp.mclk_id, config[i].ssp.quirks); + + /* validate SSP fsync rate and channel count */ + if (config[i].ssp.fsync_rate < 8000 || config[i].ssp.fsync_rate > 192000) { + dev_err(scomp->dev, "error: invalid fsync rate for SSP%d\n", + config[i].dai_index); + return -EINVAL; + } + + if (config[i].ssp.tdm_slots < 1 || config[i].ssp.tdm_slots > 8) { + dev_err(scomp->dev, "error: invalid channel count for SSP%d\n", + config[i].dai_index); + return -EINVAL; + } } /* set config for all DAI's with name matching the link name */ - ret = sof_set_dai_config(sdev, size, link, config); + ret = sof_set_dai_config_multi(sdev, size, link, config, num_conf, curr_conf); if (ret < 0) dev_err(scomp->dev, "error: failed to save DAI config for SSP%d\n", config->dai_index); @@ -3216,11 +3243,13 @@ static int sof_link_load(struct snd_soc_component *scomp, int index, struct snd_soc_tplg_link_config *cfg) { struct snd_soc_tplg_private *private = &cfg->priv; - struct sof_ipc_dai_config config; struct snd_soc_tplg_hw_config *hw_config; - int num_hw_configs; + struct sof_ipc_dai_config common_config; + struct sof_ipc_dai_config *config; + int curr_conf; + int num_conf; int ret; - int i = 0; + int i; if (!link->platforms) { dev_err(scomp->dev, "error: no platforms\n"); @@ -3257,13 +3286,11 @@ static int sof_link_load(struct snd_soc_component *scomp, int index, return -EINVAL; } - /* Send BE DAI link configurations to DSP */ - memset(&config, 0, sizeof(config)); + memset(&common_config, 0, sizeof(common_config)); /* get any common DAI tokens */ - ret = sof_parse_tokens(scomp, &config, dai_link_tokens, - ARRAY_SIZE(dai_link_tokens), private->array, - le32_to_cpu(private->size)); + ret = sof_parse_tokens(scomp, &common_config, dai_link_tokens, ARRAY_SIZE(dai_link_tokens), + private->array, le32_to_cpu(private->size)); if (ret != 0) { dev_err(scomp->dev, "error: parse link tokens failed %d\n", le32_to_cpu(private->size)); @@ -3274,71 +3301,74 @@ static int sof_link_load(struct snd_soc_component *scomp, int index, * DAI links are expected to have at least 1 hw_config. * But some older topologies might have no hw_config for HDA dai links. */ - num_hw_configs = le32_to_cpu(cfg->num_hw_configs); - if (!num_hw_configs) { - if (config.type != SOF_DAI_INTEL_HDA) { + hw_config = cfg->hw_config; + num_conf = le32_to_cpu(cfg->num_hw_configs); + if (!num_conf) { + if (common_config.type != SOF_DAI_INTEL_HDA) { dev_err(scomp->dev, "error: unexpected DAI config count %d!\n", le32_to_cpu(cfg->num_hw_configs)); return -EINVAL; } + num_conf = 1; + curr_conf = 0; } else { dev_dbg(scomp->dev, "tplg: %d hw_configs found, default id: %d!\n", cfg->num_hw_configs, le32_to_cpu(cfg->default_hw_config_id)); - for (i = 0; i < num_hw_configs; i++) { - if (cfg->hw_config[i].id == cfg->default_hw_config_id) + for (curr_conf = 0; curr_conf < num_conf; curr_conf++) { + if (hw_config[curr_conf].id == cfg->default_hw_config_id) break; } - if (i == num_hw_configs) { + if (curr_conf == num_conf) { dev_err(scomp->dev, "error: default hw_config id: %d not found!\n", le32_to_cpu(cfg->default_hw_config_id)); return -EINVAL; } } - /* configure dai IPC message */ - hw_config = &cfg->hw_config[i]; + /* Reserve memory for all hw configs, eventually freed by widget */ + config = kcalloc(num_conf, sizeof(*config), GFP_KERNEL); + if (!config) + return -ENOMEM; - config.hdr.cmd = SOF_IPC_GLB_DAI_MSG | SOF_IPC_DAI_CONFIG; - config.format = le32_to_cpu(hw_config->fmt); + /* Copy common data to all config ipc structs */ + for (i = 0; i < num_conf; i++) { + config[i].hdr.cmd = SOF_IPC_GLB_DAI_MSG | SOF_IPC_DAI_CONFIG; + config[i].format = hw_config[i].fmt; + config[i].type = common_config.type; + config[i].dai_index = common_config.dai_index; + } /* now load DAI specific data and send IPC - type comes from token */ - switch (config.type) { + switch (common_config.type) { case SOF_DAI_INTEL_SSP: - ret = sof_link_ssp_load(scomp, index, link, cfg, hw_config, - &config); + ret = sof_link_ssp_load(scomp, index, link, cfg, hw_config, config, curr_conf); break; case SOF_DAI_INTEL_DMIC: - ret = sof_link_dmic_load(scomp, index, link, cfg, hw_config, - &config); + ret = sof_link_dmic_load(scomp, index, link, cfg, hw_config + curr_conf, config); break; case SOF_DAI_INTEL_HDA: - ret = sof_link_hda_load(scomp, index, link, cfg, hw_config, - &config); + ret = sof_link_hda_load(scomp, index, link, cfg, hw_config + curr_conf, config); break; case SOF_DAI_INTEL_ALH: - ret = sof_link_alh_load(scomp, index, link, cfg, hw_config, - &config); + ret = sof_link_alh_load(scomp, index, link, cfg, hw_config + curr_conf, config); break; case SOF_DAI_IMX_SAI: - ret = sof_link_sai_load(scomp, index, link, cfg, hw_config, - &config); + ret = sof_link_sai_load(scomp, index, link, cfg, hw_config + curr_conf, config); break; case SOF_DAI_IMX_ESAI: - ret = sof_link_esai_load(scomp, index, link, cfg, hw_config, - &config); + ret = sof_link_esai_load(scomp, index, link, cfg, hw_config + curr_conf, config); break; default: - dev_err(scomp->dev, "error: invalid DAI type %d\n", - config.type); + dev_err(scomp->dev, "error: invalid DAI type %d\n", common_config.type); ret = -EINVAL; break; } - if (ret < 0) - return ret; - return 0; + kfree(config); + + return ret; } static int sof_link_hda_unload(struct snd_sof_dev *sdev, From e12be9fbfb91173b3aa358466ce0474823be2695 Mon Sep 17 00:00:00 2001 From: Jaska Uimonen Date: Fri, 26 Mar 2021 18:51:49 +0200 Subject: [PATCH 343/587] ASoC: SOF: Intel: HDA: add hw params callback for SSP DAIs Currently SSP DAIs don't have hw params callback function as there wasn't anything to setup after initial topology loading. After enabling multiple DAI configs the current config can be sent in the callback. This patch changes the way SSP config ipc is sent to the dsp. Before it was only sent once in topology loading, but now it will be additionally sent always when stream is opened. Mechanism is similar as with HDA DAIs. Signed-off-by: Jaska Uimonen Reviewed-by: Ranjani Sridharan Reviewed-by: Pierre-Louis Bossart Reviewed-by: Guennadi Liakhovetski Signed-off-by: Kai Vehmanen Link: https://lore.kernel.org/r/20210326165150.255533-2-kai.vehmanen@linux.intel.com Signed-off-by: Mark Brown --- sound/soc/sof/intel/hda-dai.c | 44 +++++++++++++++++++++++++++++++++++ 1 file changed, 44 insertions(+) diff --git a/sound/soc/sof/intel/hda-dai.c b/sound/soc/sof/intel/hda-dai.c index c6cb8c212eca..8d7bab433fb3 100644 --- a/sound/soc/sof/intel/hda-dai.c +++ b/sound/soc/sof/intel/hda-dai.c @@ -414,6 +414,44 @@ static struct snd_soc_cdai_ops sof_probe_compr_ops = { #endif #endif +static int ssp_dai_hw_params(struct snd_pcm_substream *substream, + struct snd_pcm_hw_params *params, + struct snd_soc_dai *dai) +{ + struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream); + struct snd_soc_component *component = snd_soc_rtdcom_lookup(rtd, SOF_AUDIO_PCM_DRV_NAME); + struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(component); + struct sof_ipc_dai_config *config; + struct snd_sof_dai *sof_dai; + struct sof_ipc_reply reply; + int ret; + + list_for_each_entry(sof_dai, &sdev->dai_list, list) { + if (!sof_dai->cpu_dai_name || !sof_dai->dai_config) + continue; + + if (!strcmp(dai->name, sof_dai->cpu_dai_name) && + substream->stream == sof_dai->comp_dai.direction) { + config = &sof_dai->dai_config[sof_dai->current_config]; + + /* send IPC */ + ret = sof_ipc_tx_message(sdev->ipc, config->hdr.cmd, config, + config->hdr.size, &reply, sizeof(reply)); + + if (ret < 0) + dev_err(sdev->dev, "error: failed to set DAI config for %s\n", + sof_dai->name); + return ret; + } + } + + return 0; +} + +static const struct snd_soc_dai_ops ssp_dai_ops = { + .hw_params = ssp_dai_hw_params, +}; + /* * common dai driver for skl+ platforms. * some products who use this DAI array only physically have a subset of @@ -422,6 +460,7 @@ static struct snd_soc_cdai_ops sof_probe_compr_ops = { struct snd_soc_dai_driver skl_dai[] = { { .name = "SSP0 Pin", + .ops = &ssp_dai_ops, .playback = { .channels_min = 1, .channels_max = 8, @@ -433,6 +472,7 @@ struct snd_soc_dai_driver skl_dai[] = { }, { .name = "SSP1 Pin", + .ops = &ssp_dai_ops, .playback = { .channels_min = 1, .channels_max = 8, @@ -444,6 +484,7 @@ struct snd_soc_dai_driver skl_dai[] = { }, { .name = "SSP2 Pin", + .ops = &ssp_dai_ops, .playback = { .channels_min = 1, .channels_max = 8, @@ -455,6 +496,7 @@ struct snd_soc_dai_driver skl_dai[] = { }, { .name = "SSP3 Pin", + .ops = &ssp_dai_ops, .playback = { .channels_min = 1, .channels_max = 8, @@ -466,6 +508,7 @@ struct snd_soc_dai_driver skl_dai[] = { }, { .name = "SSP4 Pin", + .ops = &ssp_dai_ops, .playback = { .channels_min = 1, .channels_max = 8, @@ -477,6 +520,7 @@ struct snd_soc_dai_driver skl_dai[] = { }, { .name = "SSP5 Pin", + .ops = &ssp_dai_ops, .playback = { .channels_min = 1, .channels_max = 8, From c943a586f6e49998b323afbd7f788afabf6ed89b Mon Sep 17 00:00:00 2001 From: Jaska Uimonen Date: Fri, 26 Mar 2021 18:51:50 +0200 Subject: [PATCH 344/587] ASoC: SOF: match SSP config with pcm hw params This patch adds a function to find a match between pcm hw params and SSP DAI config. Config is matched against sample rate and if match is found current config is set. If match isn't found last matched config is left as current i.e. current config is not touched. Functionality for SSP DAIs with 1 config remains the same as before. Signed-off-by: Jaska Uimonen Reviewed-by: Ranjani Sridharan Reviewed-by: Pierre-Louis Bossart Reviewed-by: Guennadi Liakhovetski Signed-off-by: Kai Vehmanen Link: https://lore.kernel.org/r/20210326165150.255533-3-kai.vehmanen@linux.intel.com Signed-off-by: Mark Brown --- sound/soc/sof/pcm.c | 29 +++++++++++++++++++++++++++++ 1 file changed, 29 insertions(+) diff --git a/sound/soc/sof/pcm.c b/sound/soc/sof/pcm.c index c3dc533f2627..d6b1c8b7bdfb 100644 --- a/sound/soc/sof/pcm.c +++ b/sound/soc/sof/pcm.c @@ -619,6 +619,31 @@ capture: return 0; } +static void ssp_dai_config_pcm_params_match(struct snd_sof_dev *sdev, const char *link_name, + struct snd_pcm_hw_params *params) +{ + struct sof_ipc_dai_config *config; + struct snd_sof_dai *dai; + int i; + + /* + * Search for all matching DAIs as we can have both playback and capture DAI + * associated with the same link. + */ + list_for_each_entry(dai, &sdev->dai_list, list) { + if (!dai->name || strcmp(link_name, dai->name)) + continue; + for (i = 0; i < dai->number_configs; i++) { + config = &dai->dai_config[i]; + if (config->ssp.fsync_rate == params_rate(params)) { + dev_dbg(sdev->dev, "DAI config %d matches pcm hw params\n", i); + dai->current_config = i; + break; + } + } + } +} + /* fixup the BE DAI link to match any values from topology */ int sof_pcm_dai_link_fixup(struct snd_soc_pcm_runtime *rtd, struct snd_pcm_hw_params *params) { @@ -631,6 +656,7 @@ int sof_pcm_dai_link_fixup(struct snd_soc_pcm_runtime *rtd, struct snd_pcm_hw_pa snd_soc_rtdcom_lookup(rtd, SOF_AUDIO_PCM_DRV_NAME); struct snd_sof_dai *dai = snd_sof_find_dai(component, (char *)rtd->dai_link->name); + struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(component); struct snd_soc_dpcm *dpcm; /* no topology exists for this BE, try a common configuration */ @@ -673,6 +699,9 @@ int sof_pcm_dai_link_fixup(struct snd_soc_pcm_runtime *rtd, struct snd_pcm_hw_pa /* read rate and channels from topology */ switch (dai->dai_config->type) { case SOF_DAI_INTEL_SSP: + /* search for config to pcm params match, if not found use default */ + ssp_dai_config_pcm_params_match(sdev, (char *)rtd->dai_link->name, params); + rate->min = dai->dai_config[dai->current_config].ssp.fsync_rate; rate->max = dai->dai_config[dai->current_config].ssp.fsync_rate; channels->min = dai->dai_config[dai->current_config].ssp.tdm_slots; From f556de6087f0d19825ffcdddc4816f83ddfd35e3 Mon Sep 17 00:00:00 2001 From: Colin Ian King Date: Tue, 30 Mar 2021 09:47:10 +0100 Subject: [PATCH 345/587] ASoC: mediatek: mt6359: Fix spelling mistake "reate" -> "create" There is a spelling mistake in a dev_err error message. Fix it. Signed-off-by: Colin Ian King Link: https://lore.kernel.org/r/20210330084710.997731-1-colin.king@canonical.com Signed-off-by: Mark Brown --- sound/soc/codecs/mt6359-accdet.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sound/soc/codecs/mt6359-accdet.c b/sound/soc/codecs/mt6359-accdet.c index 0bef6eaad5ad..4222aed013f1 100644 --- a/sound/soc/codecs/mt6359-accdet.c +++ b/sound/soc/codecs/mt6359-accdet.c @@ -1019,7 +1019,7 @@ static int mt6359_accdet_probe(struct platform_device *pdev) priv->jd_workqueue = create_singlethread_workqueue("mt6359_accdet_jd"); INIT_WORK(&priv->jd_work, mt6359_accdet_jd_work); if (!priv->jd_workqueue) { - dev_err(&pdev->dev, "Failed to reate jack detect workqueue\n"); + dev_err(&pdev->dev, "Failed to create jack detect workqueue\n"); ret = -1; goto err_eint_wq; } From c7721e94279887f9dd8f4be303f2054bb5477c9e Mon Sep 17 00:00:00 2001 From: Mac Chiang Date: Fri, 26 Mar 2021 19:21:29 +0800 Subject: [PATCH 346/587] ASoC: Intel: add max98390 echo reference support load new topology file with speaker capture pipeline. Signed-off-by: Mac Chiang Acked-by: Pierre-Louis Bossart Link: https://lore.kernel.org/r/1616757689-22014-1-git-send-email-mac.chiang@intel.com Signed-off-by: Mark Brown --- sound/soc/intel/common/soc-acpi-intel-cml-match.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sound/soc/intel/common/soc-acpi-intel-cml-match.c b/sound/soc/intel/common/soc-acpi-intel-cml-match.c index 2161b3b85b4a..7f6ef8229969 100644 --- a/sound/soc/intel/common/soc-acpi-intel-cml-match.c +++ b/sound/soc/intel/common/soc-acpi-intel-cml-match.c @@ -79,7 +79,7 @@ struct snd_soc_acpi_mach snd_soc_acpi_intel_cml_machines[] = { .machine_quirk = snd_soc_acpi_codec_list, .quirk_data = &max98390_spk_codecs, .sof_fw_filename = "sof-cml.ri", - .sof_tplg_filename = "sof-cml-da7219-max98357a.tplg", + .sof_tplg_filename = "sof-cml-da7219-max98390.tplg", }, {}, }; From 96fadf7e8ff49fdb74754801228942b67c3eeebd Mon Sep 17 00:00:00 2001 From: Dmitry Baryshkov Date: Sat, 27 Mar 2021 12:28:57 +0300 Subject: [PATCH 347/587] ASoC: q6afe-clocks: fix reprobing of the driver Q6afe-clocks driver can get reprobed. For example if the APR services are restarted after the firmware crash. However currently Q6afe-clocks driver will oops because hw.init will get cleared during first _probe call. Rewrite the driver to fill the clock data at runtime rather than using big static array of clocks. Signed-off-by: Dmitry Baryshkov Reviewed-by: Srinivas Kandagatla Reviewed-by: Stephen Boyd Fixes: 520a1c396d19 ("ASoC: q6afe-clocks: add q6afe clock controller") Link: https://lore.kernel.org/r/20210327092857.3073879-1-dmitry.baryshkov@linaro.org Signed-off-by: Mark Brown --- sound/soc/qcom/qdsp6/q6afe-clocks.c | 209 ++++++++++++++-------------- sound/soc/qcom/qdsp6/q6afe.c | 2 +- sound/soc/qcom/qdsp6/q6afe.h | 2 +- 3 files changed, 108 insertions(+), 105 deletions(-) diff --git a/sound/soc/qcom/qdsp6/q6afe-clocks.c b/sound/soc/qcom/qdsp6/q6afe-clocks.c index f0362f061652..9431656283cd 100644 --- a/sound/soc/qcom/qdsp6/q6afe-clocks.c +++ b/sound/soc/qcom/qdsp6/q6afe-clocks.c @@ -11,33 +11,29 @@ #include #include "q6afe.h" -#define Q6AFE_CLK(id) &(struct q6afe_clk) { \ +#define Q6AFE_CLK(id) { \ .clk_id = id, \ .afe_clk_id = Q6AFE_##id, \ .name = #id, \ - .attributes = LPASS_CLK_ATTRIBUTE_COUPLE_NO, \ .rate = 19200000, \ - .hw.init = &(struct clk_init_data) { \ - .ops = &clk_q6afe_ops, \ - .name = #id, \ - }, \ } -#define Q6AFE_VOTE_CLK(id, blkid, n) &(struct q6afe_clk) { \ +#define Q6AFE_VOTE_CLK(id, blkid, n) { \ .clk_id = id, \ .afe_clk_id = blkid, \ - .name = #n, \ - .hw.init = &(struct clk_init_data) { \ - .ops = &clk_vote_q6afe_ops, \ - .name = #id, \ - }, \ + .name = n, \ } -struct q6afe_clk { - struct device *dev; +struct q6afe_clk_init { int clk_id; int afe_clk_id; char *name; + int rate; +}; + +struct q6afe_clk { + struct device *dev; + int afe_clk_id; int attributes; int rate; uint32_t handle; @@ -48,8 +44,7 @@ struct q6afe_clk { struct q6afe_cc { struct device *dev; - struct q6afe_clk **clks; - int num_clks; + struct q6afe_clk *clks[Q6AFE_MAX_CLK_ID]; }; static int clk_q6afe_prepare(struct clk_hw *hw) @@ -105,7 +100,7 @@ static int clk_vote_q6afe_block(struct clk_hw *hw) struct q6afe_clk *clk = to_q6afe_clk(hw); return q6afe_vote_lpass_core_hw(clk->dev, clk->afe_clk_id, - clk->name, &clk->handle); + clk_hw_get_name(&clk->hw), &clk->handle); } static void clk_unvote_q6afe_block(struct clk_hw *hw) @@ -120,84 +115,76 @@ static const struct clk_ops clk_vote_q6afe_ops = { .unprepare = clk_unvote_q6afe_block, }; -static struct q6afe_clk *q6afe_clks[Q6AFE_MAX_CLK_ID] = { - [LPASS_CLK_ID_PRI_MI2S_IBIT] = Q6AFE_CLK(LPASS_CLK_ID_PRI_MI2S_IBIT), - [LPASS_CLK_ID_PRI_MI2S_EBIT] = Q6AFE_CLK(LPASS_CLK_ID_PRI_MI2S_EBIT), - [LPASS_CLK_ID_SEC_MI2S_IBIT] = Q6AFE_CLK(LPASS_CLK_ID_SEC_MI2S_IBIT), - [LPASS_CLK_ID_SEC_MI2S_EBIT] = Q6AFE_CLK(LPASS_CLK_ID_SEC_MI2S_EBIT), - [LPASS_CLK_ID_TER_MI2S_IBIT] = Q6AFE_CLK(LPASS_CLK_ID_TER_MI2S_IBIT), - [LPASS_CLK_ID_TER_MI2S_EBIT] = Q6AFE_CLK(LPASS_CLK_ID_TER_MI2S_EBIT), - [LPASS_CLK_ID_QUAD_MI2S_IBIT] = Q6AFE_CLK(LPASS_CLK_ID_QUAD_MI2S_IBIT), - [LPASS_CLK_ID_QUAD_MI2S_EBIT] = Q6AFE_CLK(LPASS_CLK_ID_QUAD_MI2S_EBIT), - [LPASS_CLK_ID_SPEAKER_I2S_IBIT] = - Q6AFE_CLK(LPASS_CLK_ID_SPEAKER_I2S_IBIT), - [LPASS_CLK_ID_SPEAKER_I2S_EBIT] = - Q6AFE_CLK(LPASS_CLK_ID_SPEAKER_I2S_EBIT), - [LPASS_CLK_ID_SPEAKER_I2S_OSR] = - Q6AFE_CLK(LPASS_CLK_ID_SPEAKER_I2S_OSR), - [LPASS_CLK_ID_QUI_MI2S_IBIT] = Q6AFE_CLK(LPASS_CLK_ID_QUI_MI2S_IBIT), - [LPASS_CLK_ID_QUI_MI2S_EBIT] = Q6AFE_CLK(LPASS_CLK_ID_QUI_MI2S_EBIT), - [LPASS_CLK_ID_SEN_MI2S_IBIT] = Q6AFE_CLK(LPASS_CLK_ID_SEN_MI2S_IBIT), - [LPASS_CLK_ID_SEN_MI2S_EBIT] = Q6AFE_CLK(LPASS_CLK_ID_SEN_MI2S_EBIT), - [LPASS_CLK_ID_INT0_MI2S_IBIT] = Q6AFE_CLK(LPASS_CLK_ID_INT0_MI2S_IBIT), - [LPASS_CLK_ID_INT1_MI2S_IBIT] = Q6AFE_CLK(LPASS_CLK_ID_INT1_MI2S_IBIT), - [LPASS_CLK_ID_INT2_MI2S_IBIT] = Q6AFE_CLK(LPASS_CLK_ID_INT2_MI2S_IBIT), - [LPASS_CLK_ID_INT3_MI2S_IBIT] = Q6AFE_CLK(LPASS_CLK_ID_INT3_MI2S_IBIT), - [LPASS_CLK_ID_INT4_MI2S_IBIT] = Q6AFE_CLK(LPASS_CLK_ID_INT4_MI2S_IBIT), - [LPASS_CLK_ID_INT5_MI2S_IBIT] = Q6AFE_CLK(LPASS_CLK_ID_INT5_MI2S_IBIT), - [LPASS_CLK_ID_INT6_MI2S_IBIT] = Q6AFE_CLK(LPASS_CLK_ID_INT6_MI2S_IBIT), - [LPASS_CLK_ID_QUI_MI2S_OSR] = Q6AFE_CLK(LPASS_CLK_ID_QUI_MI2S_OSR), - [LPASS_CLK_ID_PRI_PCM_IBIT] = Q6AFE_CLK(LPASS_CLK_ID_PRI_PCM_IBIT), - [LPASS_CLK_ID_PRI_PCM_EBIT] = Q6AFE_CLK(LPASS_CLK_ID_PRI_PCM_EBIT), - [LPASS_CLK_ID_SEC_PCM_IBIT] = Q6AFE_CLK(LPASS_CLK_ID_SEC_PCM_IBIT), - [LPASS_CLK_ID_SEC_PCM_EBIT] = Q6AFE_CLK(LPASS_CLK_ID_SEC_PCM_EBIT), - [LPASS_CLK_ID_TER_PCM_IBIT] = Q6AFE_CLK(LPASS_CLK_ID_TER_PCM_IBIT), - [LPASS_CLK_ID_TER_PCM_EBIT] = Q6AFE_CLK(LPASS_CLK_ID_TER_PCM_EBIT), - [LPASS_CLK_ID_QUAD_PCM_IBIT] = Q6AFE_CLK(LPASS_CLK_ID_QUAD_PCM_IBIT), - [LPASS_CLK_ID_QUAD_PCM_EBIT] = Q6AFE_CLK(LPASS_CLK_ID_QUAD_PCM_EBIT), - [LPASS_CLK_ID_QUIN_PCM_IBIT] = Q6AFE_CLK(LPASS_CLK_ID_QUIN_PCM_IBIT), - [LPASS_CLK_ID_QUIN_PCM_EBIT] = Q6AFE_CLK(LPASS_CLK_ID_QUIN_PCM_EBIT), - [LPASS_CLK_ID_QUI_PCM_OSR] = Q6AFE_CLK(LPASS_CLK_ID_QUI_PCM_OSR), - [LPASS_CLK_ID_PRI_TDM_IBIT] = Q6AFE_CLK(LPASS_CLK_ID_PRI_TDM_IBIT), - [LPASS_CLK_ID_PRI_TDM_EBIT] = Q6AFE_CLK(LPASS_CLK_ID_PRI_TDM_EBIT), - [LPASS_CLK_ID_SEC_TDM_IBIT] = Q6AFE_CLK(LPASS_CLK_ID_SEC_TDM_IBIT), - [LPASS_CLK_ID_SEC_TDM_EBIT] = Q6AFE_CLK(LPASS_CLK_ID_SEC_TDM_EBIT), - [LPASS_CLK_ID_TER_TDM_IBIT] = Q6AFE_CLK(LPASS_CLK_ID_TER_TDM_IBIT), - [LPASS_CLK_ID_TER_TDM_EBIT] = Q6AFE_CLK(LPASS_CLK_ID_TER_TDM_EBIT), - [LPASS_CLK_ID_QUAD_TDM_IBIT] = Q6AFE_CLK(LPASS_CLK_ID_QUAD_TDM_IBIT), - [LPASS_CLK_ID_QUAD_TDM_EBIT] = Q6AFE_CLK(LPASS_CLK_ID_QUAD_TDM_EBIT), - [LPASS_CLK_ID_QUIN_TDM_IBIT] = Q6AFE_CLK(LPASS_CLK_ID_QUIN_TDM_IBIT), - [LPASS_CLK_ID_QUIN_TDM_EBIT] = Q6AFE_CLK(LPASS_CLK_ID_QUIN_TDM_EBIT), - [LPASS_CLK_ID_QUIN_TDM_OSR] = Q6AFE_CLK(LPASS_CLK_ID_QUIN_TDM_OSR), - [LPASS_CLK_ID_MCLK_1] = Q6AFE_CLK(LPASS_CLK_ID_MCLK_1), - [LPASS_CLK_ID_MCLK_2] = Q6AFE_CLK(LPASS_CLK_ID_MCLK_2), - [LPASS_CLK_ID_MCLK_3] = Q6AFE_CLK(LPASS_CLK_ID_MCLK_3), - [LPASS_CLK_ID_MCLK_4] = Q6AFE_CLK(LPASS_CLK_ID_MCLK_4), - [LPASS_CLK_ID_INTERNAL_DIGITAL_CODEC_CORE] = - Q6AFE_CLK(LPASS_CLK_ID_INTERNAL_DIGITAL_CODEC_CORE), - [LPASS_CLK_ID_INT_MCLK_0] = Q6AFE_CLK(LPASS_CLK_ID_INT_MCLK_0), - [LPASS_CLK_ID_INT_MCLK_1] = Q6AFE_CLK(LPASS_CLK_ID_INT_MCLK_1), - [LPASS_CLK_ID_WSA_CORE_MCLK] = Q6AFE_CLK(LPASS_CLK_ID_WSA_CORE_MCLK), - [LPASS_CLK_ID_WSA_CORE_NPL_MCLK] = - Q6AFE_CLK(LPASS_CLK_ID_WSA_CORE_NPL_MCLK), - [LPASS_CLK_ID_VA_CORE_MCLK] = Q6AFE_CLK(LPASS_CLK_ID_VA_CORE_MCLK), - [LPASS_CLK_ID_TX_CORE_MCLK] = Q6AFE_CLK(LPASS_CLK_ID_TX_CORE_MCLK), - [LPASS_CLK_ID_TX_CORE_NPL_MCLK] = - Q6AFE_CLK(LPASS_CLK_ID_TX_CORE_NPL_MCLK), - [LPASS_CLK_ID_RX_CORE_MCLK] = Q6AFE_CLK(LPASS_CLK_ID_RX_CORE_MCLK), - [LPASS_CLK_ID_RX_CORE_NPL_MCLK] = - Q6AFE_CLK(LPASS_CLK_ID_RX_CORE_NPL_MCLK), - [LPASS_CLK_ID_VA_CORE_2X_MCLK] = - Q6AFE_CLK(LPASS_CLK_ID_VA_CORE_2X_MCLK), - [LPASS_HW_AVTIMER_VOTE] = Q6AFE_VOTE_CLK(LPASS_HW_AVTIMER_VOTE, - Q6AFE_LPASS_CORE_AVTIMER_BLOCK, - "LPASS_AVTIMER_MACRO"), - [LPASS_HW_MACRO_VOTE] = Q6AFE_VOTE_CLK(LPASS_HW_MACRO_VOTE, - Q6AFE_LPASS_CORE_HW_MACRO_BLOCK, - "LPASS_HW_MACRO"), - [LPASS_HW_DCODEC_VOTE] = Q6AFE_VOTE_CLK(LPASS_HW_DCODEC_VOTE, - Q6AFE_LPASS_CORE_HW_DCODEC_BLOCK, - "LPASS_HW_DCODEC"), +static const struct q6afe_clk_init q6afe_clks[] = { + Q6AFE_CLK(LPASS_CLK_ID_PRI_MI2S_IBIT), + Q6AFE_CLK(LPASS_CLK_ID_PRI_MI2S_EBIT), + Q6AFE_CLK(LPASS_CLK_ID_SEC_MI2S_IBIT), + Q6AFE_CLK(LPASS_CLK_ID_SEC_MI2S_EBIT), + Q6AFE_CLK(LPASS_CLK_ID_TER_MI2S_IBIT), + Q6AFE_CLK(LPASS_CLK_ID_TER_MI2S_EBIT), + Q6AFE_CLK(LPASS_CLK_ID_QUAD_MI2S_IBIT), + Q6AFE_CLK(LPASS_CLK_ID_QUAD_MI2S_EBIT), + Q6AFE_CLK(LPASS_CLK_ID_SPEAKER_I2S_IBIT), + Q6AFE_CLK(LPASS_CLK_ID_SPEAKER_I2S_EBIT), + Q6AFE_CLK(LPASS_CLK_ID_SPEAKER_I2S_OSR), + Q6AFE_CLK(LPASS_CLK_ID_QUI_MI2S_IBIT), + Q6AFE_CLK(LPASS_CLK_ID_QUI_MI2S_EBIT), + Q6AFE_CLK(LPASS_CLK_ID_SEN_MI2S_IBIT), + Q6AFE_CLK(LPASS_CLK_ID_SEN_MI2S_EBIT), + Q6AFE_CLK(LPASS_CLK_ID_INT0_MI2S_IBIT), + Q6AFE_CLK(LPASS_CLK_ID_INT1_MI2S_IBIT), + Q6AFE_CLK(LPASS_CLK_ID_INT2_MI2S_IBIT), + Q6AFE_CLK(LPASS_CLK_ID_INT3_MI2S_IBIT), + Q6AFE_CLK(LPASS_CLK_ID_INT4_MI2S_IBIT), + Q6AFE_CLK(LPASS_CLK_ID_INT5_MI2S_IBIT), + Q6AFE_CLK(LPASS_CLK_ID_INT6_MI2S_IBIT), + Q6AFE_CLK(LPASS_CLK_ID_QUI_MI2S_OSR), + Q6AFE_CLK(LPASS_CLK_ID_PRI_PCM_IBIT), + Q6AFE_CLK(LPASS_CLK_ID_PRI_PCM_EBIT), + Q6AFE_CLK(LPASS_CLK_ID_SEC_PCM_IBIT), + Q6AFE_CLK(LPASS_CLK_ID_SEC_PCM_EBIT), + Q6AFE_CLK(LPASS_CLK_ID_TER_PCM_IBIT), + Q6AFE_CLK(LPASS_CLK_ID_TER_PCM_EBIT), + Q6AFE_CLK(LPASS_CLK_ID_QUAD_PCM_IBIT), + Q6AFE_CLK(LPASS_CLK_ID_QUAD_PCM_EBIT), + Q6AFE_CLK(LPASS_CLK_ID_QUIN_PCM_IBIT), + Q6AFE_CLK(LPASS_CLK_ID_QUIN_PCM_EBIT), + Q6AFE_CLK(LPASS_CLK_ID_QUI_PCM_OSR), + Q6AFE_CLK(LPASS_CLK_ID_PRI_TDM_IBIT), + Q6AFE_CLK(LPASS_CLK_ID_PRI_TDM_EBIT), + Q6AFE_CLK(LPASS_CLK_ID_SEC_TDM_IBIT), + Q6AFE_CLK(LPASS_CLK_ID_SEC_TDM_EBIT), + Q6AFE_CLK(LPASS_CLK_ID_TER_TDM_IBIT), + Q6AFE_CLK(LPASS_CLK_ID_TER_TDM_EBIT), + Q6AFE_CLK(LPASS_CLK_ID_QUAD_TDM_IBIT), + Q6AFE_CLK(LPASS_CLK_ID_QUAD_TDM_EBIT), + Q6AFE_CLK(LPASS_CLK_ID_QUIN_TDM_IBIT), + Q6AFE_CLK(LPASS_CLK_ID_QUIN_TDM_EBIT), + Q6AFE_CLK(LPASS_CLK_ID_QUIN_TDM_OSR), + Q6AFE_CLK(LPASS_CLK_ID_MCLK_1), + Q6AFE_CLK(LPASS_CLK_ID_MCLK_2), + Q6AFE_CLK(LPASS_CLK_ID_MCLK_3), + Q6AFE_CLK(LPASS_CLK_ID_MCLK_4), + Q6AFE_CLK(LPASS_CLK_ID_INTERNAL_DIGITAL_CODEC_CORE), + Q6AFE_CLK(LPASS_CLK_ID_INT_MCLK_0), + Q6AFE_CLK(LPASS_CLK_ID_INT_MCLK_1), + Q6AFE_CLK(LPASS_CLK_ID_WSA_CORE_MCLK), + Q6AFE_CLK(LPASS_CLK_ID_WSA_CORE_NPL_MCLK), + Q6AFE_CLK(LPASS_CLK_ID_VA_CORE_MCLK), + Q6AFE_CLK(LPASS_CLK_ID_TX_CORE_MCLK), + Q6AFE_CLK(LPASS_CLK_ID_TX_CORE_NPL_MCLK), + Q6AFE_CLK(LPASS_CLK_ID_RX_CORE_MCLK), + Q6AFE_CLK(LPASS_CLK_ID_RX_CORE_NPL_MCLK), + Q6AFE_CLK(LPASS_CLK_ID_VA_CORE_2X_MCLK), + Q6AFE_VOTE_CLK(LPASS_HW_AVTIMER_VOTE, + Q6AFE_LPASS_CORE_AVTIMER_BLOCK, + "LPASS_AVTIMER_MACRO"), + Q6AFE_VOTE_CLK(LPASS_HW_MACRO_VOTE, + Q6AFE_LPASS_CORE_HW_MACRO_BLOCK, + "LPASS_HW_MACRO"), + Q6AFE_VOTE_CLK(LPASS_HW_DCODEC_VOTE, + Q6AFE_LPASS_CORE_HW_DCODEC_BLOCK, + "LPASS_HW_DCODEC"), }; static struct clk_hw *q6afe_of_clk_hw_get(struct of_phandle_args *clkspec, @@ -207,7 +194,7 @@ static struct clk_hw *q6afe_of_clk_hw_get(struct of_phandle_args *clkspec, unsigned int idx = clkspec->args[0]; unsigned int attr = clkspec->args[1]; - if (idx >= cc->num_clks || attr > LPASS_CLK_ATTRIBUTE_COUPLE_DIVISOR) { + if (idx >= Q6AFE_MAX_CLK_ID || attr > LPASS_CLK_ATTRIBUTE_COUPLE_DIVISOR) { dev_err(cc->dev, "Invalid clk specifier (%d, %d)\n", idx, attr); return ERR_PTR(-EINVAL); } @@ -230,20 +217,36 @@ static int q6afe_clock_dev_probe(struct platform_device *pdev) if (!cc) return -ENOMEM; - cc->clks = &q6afe_clks[0]; - cc->num_clks = ARRAY_SIZE(q6afe_clks); + cc->dev = dev; for (i = 0; i < ARRAY_SIZE(q6afe_clks); i++) { - if (!q6afe_clks[i]) - continue; + unsigned int id = q6afe_clks[i].clk_id; + struct clk_init_data init = { + .name = q6afe_clks[i].name, + }; + struct q6afe_clk *clk; - q6afe_clks[i]->dev = dev; + clk = devm_kzalloc(dev, sizeof(*clk), GFP_KERNEL); + if (!clk) + return -ENOMEM; - ret = devm_clk_hw_register(dev, &q6afe_clks[i]->hw); + clk->dev = dev; + clk->afe_clk_id = q6afe_clks[i].afe_clk_id; + clk->rate = q6afe_clks[i].rate; + clk->hw.init = &init; + + if (clk->rate) + init.ops = &clk_q6afe_ops; + else + init.ops = &clk_vote_q6afe_ops; + + cc->clks[id] = clk; + + ret = devm_clk_hw_register(dev, &clk->hw); if (ret) return ret; } - ret = of_clk_add_hw_provider(dev->of_node, q6afe_of_clk_hw_get, cc); + ret = devm_of_clk_add_hw_provider(dev, q6afe_of_clk_hw_get, cc); if (ret) return ret; diff --git a/sound/soc/qcom/qdsp6/q6afe.c b/sound/soc/qcom/qdsp6/q6afe.c index 38f6042fe893..729d27da0447 100644 --- a/sound/soc/qcom/qdsp6/q6afe.c +++ b/sound/soc/qcom/qdsp6/q6afe.c @@ -1680,7 +1680,7 @@ int q6afe_unvote_lpass_core_hw(struct device *dev, uint32_t hw_block_id, EXPORT_SYMBOL(q6afe_unvote_lpass_core_hw); int q6afe_vote_lpass_core_hw(struct device *dev, uint32_t hw_block_id, - char *client_name, uint32_t *client_handle) + const char *client_name, uint32_t *client_handle) { struct q6afe *afe = dev_get_drvdata(dev->parent); struct afe_cmd_remote_lpass_core_hw_vote_request *vote_cfg; diff --git a/sound/soc/qcom/qdsp6/q6afe.h b/sound/soc/qcom/qdsp6/q6afe.h index 41133f8797c9..f9a1c04e38c2 100644 --- a/sound/soc/qcom/qdsp6/q6afe.h +++ b/sound/soc/qcom/qdsp6/q6afe.h @@ -236,7 +236,7 @@ int q6afe_port_set_sysclk(struct q6afe_port *port, int clk_id, int q6afe_set_lpass_clock(struct device *dev, int clk_id, int attri, int clk_root, unsigned int freq); int q6afe_vote_lpass_core_hw(struct device *dev, uint32_t hw_block_id, - char *client_name, uint32_t *client_handle); + const char *client_name, uint32_t *client_handle); int q6afe_unvote_lpass_core_hw(struct device *dev, uint32_t hw_block_id, uint32_t client_handle); #endif /* __Q6AFE_H__ */ From abc21649b3e5c34b143bf86f0c78e33d5815e250 Mon Sep 17 00:00:00 2001 From: Jia Zhou Date: Tue, 30 Mar 2021 13:19:23 +0200 Subject: [PATCH 348/587] ALSA: core: remove redundant spin_lock pair in snd_card_disconnect modification in commit 2a3f7221acdd ("ALSA: core: Fix card races between register and disconnect") resulting in this problem. Fixes: 2a3f7221acdd ("ALSA: core: Fix card races between register and disconnect") Signed-off-by: Jia Zhou Signed-off-by: Yi Wang Link: https://lore.kernel.org/r/1616989007-34429-1-git-send-email-wang.yi59@zte.com.cn Signed-off-by: Takashi Iwai --- sound/core/init.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/sound/core/init.c b/sound/core/init.c index 45f4b01de23f..ef41f5b3a240 100644 --- a/sound/core/init.c +++ b/sound/core/init.c @@ -398,10 +398,8 @@ int snd_card_disconnect(struct snd_card *card) return 0; } card->shutdown = 1; - spin_unlock(&card->files_lock); /* replace file->f_op with special dummy operations */ - spin_lock(&card->files_lock); list_for_each_entry(mfile, &card->files_list, list) { /* it's critical part, use endless loop */ /* we have no room to fail */ From 1fa4445f9adf19a3028ce0e8f375bac75214fc10 Mon Sep 17 00:00:00 2001 From: Jaroslav Kysela Date: Wed, 17 Mar 2021 18:29:40 +0100 Subject: [PATCH 349/587] ALSA: control - introduce snd_ctl_notify_one() helper This helper is required for the following generic LED mute patch. The helper also simplifies some other functions. Signed-off-by: Jaroslav Kysela Link: https://lore.kernel.org/r/20210317172945.842280-2-perex@perex.cz Signed-off-by: Takashi Iwai --- include/sound/control.h | 4 +-- sound/core/control.c | 68 +++++++++++++++++++++++++++-------------- 2 files changed, 47 insertions(+), 25 deletions(-) diff --git a/include/sound/control.h b/include/sound/control.h index 77d9fa10812d..22f3d48163ff 100644 --- a/include/sound/control.h +++ b/include/sound/control.h @@ -115,6 +115,7 @@ typedef int (*snd_kctl_ioctl_func_t) (struct snd_card * card, unsigned int cmd, unsigned long arg); void snd_ctl_notify(struct snd_card * card, unsigned int mask, struct snd_ctl_elem_id * id); +void snd_ctl_notify_one(struct snd_card * card, unsigned int mask, struct snd_kcontrol * kctl, unsigned int ioff); struct snd_kcontrol *snd_ctl_new1(const struct snd_kcontrol_new * kcontrolnew, void * private_data); void snd_ctl_free_one(struct snd_kcontrol * kcontrol); @@ -123,8 +124,7 @@ int snd_ctl_remove(struct snd_card * card, struct snd_kcontrol * kcontrol); int snd_ctl_replace(struct snd_card *card, struct snd_kcontrol *kcontrol, bool add_on_replace); int snd_ctl_remove_id(struct snd_card * card, struct snd_ctl_elem_id *id); int snd_ctl_rename_id(struct snd_card * card, struct snd_ctl_elem_id *src_id, struct snd_ctl_elem_id *dst_id); -int snd_ctl_activate_id(struct snd_card *card, struct snd_ctl_elem_id *id, - int active); +int snd_ctl_activate_id(struct snd_card *card, struct snd_ctl_elem_id *id, int active); struct snd_kcontrol *snd_ctl_find_numid(struct snd_card * card, unsigned int numid); struct snd_kcontrol *snd_ctl_find_id(struct snd_card * card, struct snd_ctl_elem_id *id); diff --git a/sound/core/control.c b/sound/core/control.c index 5165741a8400..8a5cedb0a4be 100644 --- a/sound/core/control.c +++ b/sound/core/control.c @@ -181,6 +181,27 @@ void snd_ctl_notify(struct snd_card *card, unsigned int mask, } EXPORT_SYMBOL(snd_ctl_notify); +/** + * snd_ctl_notify_one - Send notification to user-space for a control change + * @card: the card to send notification + * @mask: the event mask, SNDRV_CTL_EVENT_* + * @kctl: the pointer with the control instance + * @ioff: the additional offset to the control index + * + * This function calls snd_ctl_notify() and does additional jobs + * like LED state changes. + */ +void snd_ctl_notify_one(struct snd_card *card, unsigned int mask, + struct snd_kcontrol *kctl, unsigned int ioff) +{ + struct snd_ctl_elem_id id = kctl->id; + + id.index += ioff; + id.numid += ioff; + snd_ctl_notify(card, mask, &id); +} +EXPORT_SYMBOL(snd_ctl_notify_one); + /** * snd_ctl_new - create a new control instance with some elements * @kctl: the pointer to store new control instance @@ -342,7 +363,6 @@ static int __snd_ctl_add_replace(struct snd_card *card, { struct snd_ctl_elem_id id; unsigned int idx; - unsigned int count; struct snd_kcontrol *old; int err; @@ -376,10 +396,8 @@ static int __snd_ctl_add_replace(struct snd_card *card, kcontrol->id.numid = card->last_numid + 1; card->last_numid += kcontrol->count; - id = kcontrol->id; - count = kcontrol->count; - for (idx = 0; idx < count; idx++, id.index++, id.numid++) - snd_ctl_notify(card, SNDRV_CTL_EVENT_MASK_ADD, &id); + for (idx = 0; idx < kcontrol->count; idx++) + snd_ctl_notify_one(card, SNDRV_CTL_EVENT_MASK_ADD, kcontrol, idx); return 0; } @@ -462,16 +480,14 @@ EXPORT_SYMBOL(snd_ctl_replace); */ int snd_ctl_remove(struct snd_card *card, struct snd_kcontrol *kcontrol) { - struct snd_ctl_elem_id id; unsigned int idx; if (snd_BUG_ON(!card || !kcontrol)) return -EINVAL; list_del(&kcontrol->list); card->controls_count -= kcontrol->count; - id = kcontrol->id; - for (idx = 0; idx < kcontrol->count; idx++, id.index++, id.numid++) - snd_ctl_notify(card, SNDRV_CTL_EVENT_MASK_REMOVE, &id); + for (idx = 0; idx < kcontrol->count; idx++) + snd_ctl_notify_one(card, SNDRV_CTL_EVENT_MASK_REMOVE, kcontrol, idx); snd_ctl_free_one(kcontrol); return 0; } @@ -584,11 +600,13 @@ int snd_ctl_activate_id(struct snd_card *card, struct snd_ctl_elem_id *id, vd->access |= SNDRV_CTL_ELEM_ACCESS_INACTIVE; } snd_ctl_build_ioff(id, kctl, index_offset); - ret = 1; + downgrade_write(&card->controls_rwsem); + snd_ctl_notify_one(card, SNDRV_CTL_EVENT_MASK_INFO, kctl, index_offset); + up_read(&card->controls_rwsem); + return 1; + unlock: up_write(&card->controls_rwsem); - if (ret > 0) - snd_ctl_notify(card, SNDRV_CTL_EVENT_MASK_INFO, id); return ret; } EXPORT_SYMBOL_GPL(snd_ctl_activate_id); @@ -1110,25 +1128,34 @@ static int snd_ctl_elem_write(struct snd_card *card, struct snd_ctl_file *file, unsigned int index_offset; int result; + down_write(&card->controls_rwsem); kctl = snd_ctl_find_id(card, &control->id); - if (kctl == NULL) + if (kctl == NULL) { + up_write(&card->controls_rwsem); return -ENOENT; + } index_offset = snd_ctl_get_ioff(kctl, &control->id); vd = &kctl->vd[index_offset]; if (!(vd->access & SNDRV_CTL_ELEM_ACCESS_WRITE) || kctl->put == NULL || (file && vd->owner && vd->owner != file)) { + up_write(&card->controls_rwsem); return -EPERM; } snd_ctl_build_ioff(&control->id, kctl, index_offset); result = kctl->put(kctl, control); - if (result < 0) + if (result < 0) { + up_write(&card->controls_rwsem); return result; + } if (result > 0) { - struct snd_ctl_elem_id id = control->id; - snd_ctl_notify(card, SNDRV_CTL_EVENT_MASK_VALUE, &id); + downgrade_write(&card->controls_rwsem); + snd_ctl_notify_one(card, SNDRV_CTL_EVENT_MASK_VALUE, kctl, index_offset); + up_read(&card->controls_rwsem); + } else { + up_write(&card->controls_rwsem); } return 0; @@ -1150,9 +1177,7 @@ static int snd_ctl_elem_write_user(struct snd_ctl_file *file, if (result < 0) goto error; - down_write(&card->controls_rwsem); result = snd_ctl_elem_write(card, file, control); - up_write(&card->controls_rwsem); if (result < 0) goto error; @@ -1301,7 +1326,6 @@ static int replace_user_tlv(struct snd_kcontrol *kctl, unsigned int __user *buf, { struct user_element *ue = kctl->private_data; unsigned int *container; - struct snd_ctl_elem_id id; unsigned int mask = 0; int i; int change; @@ -1333,10 +1357,8 @@ static int replace_user_tlv(struct snd_kcontrol *kctl, unsigned int __user *buf, ue->tlv_data_size = size; mask |= SNDRV_CTL_EVENT_MASK_TLV; - for (i = 0; i < kctl->count; ++i) { - snd_ctl_build_ioff(&id, kctl, i); - snd_ctl_notify(ue->card, mask, &id); - } + for (i = 0; i < kctl->count; ++i) + snd_ctl_notify_one(ue->card, mask, kctl, i); return change; } From 3f0638a0333bfdd0549985aa620f2ab69737af47 Mon Sep 17 00:00:00 2001 From: Jaroslav Kysela Date: Wed, 17 Mar 2021 18:29:41 +0100 Subject: [PATCH 350/587] ALSA: control - add layer registration routines The layer registration allows to handle an extra functionality on top of the control API. It can be used for the audio LED control for example. Signed-off-by: Jaroslav Kysela Link: https://lore.kernel.org/r/20210317172945.842280-3-perex@perex.cz Signed-off-by: Takashi Iwai --- include/sound/control.h | 12 +++++ sound/core/control.c | 110 +++++++++++++++++++++++++++++++++++++++- 2 files changed, 120 insertions(+), 2 deletions(-) diff --git a/include/sound/control.h b/include/sound/control.h index 22f3d48163ff..175610bfa8c8 100644 --- a/include/sound/control.h +++ b/include/sound/control.h @@ -108,6 +108,14 @@ struct snd_ctl_file { struct list_head events; /* waiting events for read */ }; +struct snd_ctl_layer_ops { + struct snd_ctl_layer_ops *next; + const char *module_name; + void (*lregister)(struct snd_card *card); + void (*ldisconnect)(struct snd_card *card); + void (*lnotify)(struct snd_card *card, unsigned int mask, struct snd_kcontrol *kctl, unsigned int ioff); +}; + #define snd_ctl_file(n) list_entry(n, struct snd_ctl_file, list) typedef int (*snd_kctl_ioctl_func_t) (struct snd_card * card, @@ -140,6 +148,10 @@ int snd_ctl_unregister_ioctl_compat(snd_kctl_ioctl_func_t fcn); #define snd_ctl_unregister_ioctl_compat(fcn) #endif +int snd_ctl_request_layer(const char *module_name); +void snd_ctl_register_layer(struct snd_ctl_layer_ops *lops); +void snd_ctl_disconnect_layer(struct snd_ctl_layer_ops *lops); + int snd_ctl_get_preferred_subdevice(struct snd_card *card, int type); static inline unsigned int snd_ctl_get_ioffnum(struct snd_kcontrol *kctl, struct snd_ctl_elem_id *id) diff --git a/sound/core/control.c b/sound/core/control.c index 8a5cedb0a4be..87630021e434 100644 --- a/sound/core/control.c +++ b/sound/core/control.c @@ -28,10 +28,12 @@ struct snd_kctl_ioctl { }; static DECLARE_RWSEM(snd_ioctl_rwsem); +static DECLARE_RWSEM(snd_ctl_layer_rwsem); static LIST_HEAD(snd_control_ioctls); #ifdef CONFIG_COMPAT static LIST_HEAD(snd_control_compat_ioctls); #endif +static struct snd_ctl_layer_ops *snd_ctl_layer; static int snd_ctl_open(struct inode *inode, struct file *file) { @@ -195,10 +197,15 @@ void snd_ctl_notify_one(struct snd_card *card, unsigned int mask, struct snd_kcontrol *kctl, unsigned int ioff) { struct snd_ctl_elem_id id = kctl->id; + struct snd_ctl_layer_ops *lops; id.index += ioff; id.numid += ioff; snd_ctl_notify(card, mask, &id); + down_read(&snd_ctl_layer_rwsem); + for (lops = snd_ctl_layer; lops; lops = lops->next) + lops->lnotify(card, mask, kctl, ioff); + up_read(&snd_ctl_layer_rwsem); } EXPORT_SYMBOL(snd_ctl_notify_one); @@ -1997,6 +2004,86 @@ EXPORT_SYMBOL_GPL(snd_ctl_get_preferred_subdevice); #define snd_ctl_ioctl_compat NULL #endif +/* + * control layers (audio LED etc.) + */ + +/** + * snd_ctl_request_layer - request to use the layer + * @module_name: Name of the kernel module (NULL == build-in) + * + * Return an error code when the module cannot be loaded. + */ +int snd_ctl_request_layer(const char *module_name) +{ + struct snd_ctl_layer_ops *lops; + + if (module_name == NULL) + return 0; + down_read(&snd_ctl_layer_rwsem); + for (lops = snd_ctl_layer; lops; lops = lops->next) + if (strcmp(lops->module_name, module_name) == 0) + break; + up_read(&snd_ctl_layer_rwsem); + if (lops) + return 0; + return request_module(module_name); +} +EXPORT_SYMBOL_GPL(snd_ctl_request_layer); + +/** + * snd_ctl_register_layer - register new control layer + * @lops: operation structure + * + * The new layer can track all control elements and do additional + * operations on top (like audio LED handling). + */ +void snd_ctl_register_layer(struct snd_ctl_layer_ops *lops) +{ + struct snd_card *card; + int card_number; + + down_write(&snd_ctl_layer_rwsem); + lops->next = snd_ctl_layer; + snd_ctl_layer = lops; + up_write(&snd_ctl_layer_rwsem); + for (card_number = 0; card_number < SNDRV_CARDS; card_number++) { + card = snd_card_ref(card_number); + if (card) { + down_read(&card->controls_rwsem); + lops->lregister(card); + up_read(&card->controls_rwsem); + snd_card_unref(card); + } + } +} +EXPORT_SYMBOL_GPL(snd_ctl_register_layer); + +/** + * snd_ctl_disconnect_layer - disconnect control layer + * @lops: operation structure + * + * It is expected that the information about tracked cards + * is freed before this call (the disconnect callback is + * not called here). + */ +void snd_ctl_disconnect_layer(struct snd_ctl_layer_ops *lops) +{ + struct snd_ctl_layer_ops *lops2, *prev_lops2; + + down_write(&snd_ctl_layer_rwsem); + for (lops2 = snd_ctl_layer, prev_lops2 = NULL; lops2; lops2 = lops2->next) + if (lops2 == lops) { + if (!prev_lops2) + snd_ctl_layer = lops->next; + else + prev_lops2->next = lops->next; + break; + } + up_write(&snd_ctl_layer_rwsem); +} +EXPORT_SYMBOL_GPL(snd_ctl_disconnect_layer); + /* * INIT PART */ @@ -2020,9 +2107,20 @@ static const struct file_operations snd_ctl_f_ops = static int snd_ctl_dev_register(struct snd_device *device) { struct snd_card *card = device->device_data; + struct snd_ctl_layer_ops *lops; + int err; - return snd_register_device(SNDRV_DEVICE_TYPE_CONTROL, card, -1, - &snd_ctl_f_ops, card, &card->ctl_dev); + err = snd_register_device(SNDRV_DEVICE_TYPE_CONTROL, card, -1, + &snd_ctl_f_ops, card, &card->ctl_dev); + if (err < 0) + return err; + down_read(&card->controls_rwsem); + down_read(&snd_ctl_layer_rwsem); + for (lops = snd_ctl_layer; lops; lops = lops->next) + lops->lregister(card); + up_read(&snd_ctl_layer_rwsem); + up_read(&card->controls_rwsem); + return 0; } /* @@ -2032,6 +2130,7 @@ static int snd_ctl_dev_disconnect(struct snd_device *device) { struct snd_card *card = device->device_data; struct snd_ctl_file *ctl; + struct snd_ctl_layer_ops *lops; unsigned long flags; read_lock_irqsave(&card->ctl_files_rwlock, flags); @@ -2041,6 +2140,13 @@ static int snd_ctl_dev_disconnect(struct snd_device *device) } read_unlock_irqrestore(&card->ctl_files_rwlock, flags); + down_read(&card->controls_rwsem); + down_read(&snd_ctl_layer_rwsem); + for (lops = snd_ctl_layer; lops; lops = lops->next) + lops->ldisconnect(card); + up_read(&snd_ctl_layer_rwsem); + up_read(&card->controls_rwsem); + return snd_unregister_device(&card->ctl_dev); } From 22d8de62f11b287b279f1d4473a78c7d5e53e7bc Mon Sep 17 00:00:00 2001 From: Jaroslav Kysela Date: Wed, 17 Mar 2021 18:29:42 +0100 Subject: [PATCH 351/587] ALSA: control - add generic LED trigger module as the new control layer The recent laptops have usually two LEDs assigned to reflect the speaker and microphone mute state. This implementation adds a tiny layer on top of the control API which calculates the state for those LEDs using the driver callbacks. Two new access flags are introduced to describe the controls which affects the audio path settings (an easy code change for drivers). The LED resource can be shared with multiple sound cards with this code. The user space controls may be added to the state chain on demand, too. This code should replace the LED code in the HDA driver and add a possibility to easy extend the other drivers (ASoC codecs etc.). Signed-off-by: Jaroslav Kysela Link: https://lore.kernel.org/r/20210317172945.842280-4-perex@perex.cz Signed-off-by: Takashi Iwai --- include/sound/control.h | 19 ++- sound/core/Kconfig | 6 + sound/core/Makefile | 2 + sound/core/control.c | 4 +- sound/core/control_led.c | 278 +++++++++++++++++++++++++++++++++++++++ 5 files changed, 307 insertions(+), 2 deletions(-) create mode 100644 sound/core/control_led.c diff --git a/include/sound/control.h b/include/sound/control.h index 175610bfa8c8..985c51a8fb74 100644 --- a/include/sound/control.h +++ b/include/sound/control.h @@ -24,7 +24,7 @@ typedef int (snd_kcontrol_tlv_rw_t)(struct snd_kcontrol *kcontrol, /* internal flag for skipping validations */ #ifdef CONFIG_SND_CTL_VALIDATION -#define SNDRV_CTL_ELEM_ACCESS_SKIP_CHECK (1 << 27) +#define SNDRV_CTL_ELEM_ACCESS_SKIP_CHECK (1 << 24) #define snd_ctl_skip_validation(info) \ ((info)->access & SNDRV_CTL_ELEM_ACCESS_SKIP_CHECK) #else @@ -32,6 +32,12 @@ typedef int (snd_kcontrol_tlv_rw_t)(struct snd_kcontrol *kcontrol, #define snd_ctl_skip_validation(info) true #endif +/* kernel only - LED bits */ +#define SNDRV_CTL_ELEM_ACCESS_LED_SHIFT 25 +#define SNDRV_CTL_ELEM_ACCESS_LED_MASK (7<<25) /* kernel three bits - LED group */ +#define SNDRV_CTL_ELEM_ACCESS_SPK_LED (1<<25) /* kernel speaker (output) LED flag */ +#define SNDRV_CTL_ELEM_ACCESS_MIC_LED (2<<25) /* kernel microphone (input) LED flag */ + enum { SNDRV_CTL_TLV_OP_READ = 0, SNDRV_CTL_TLV_OP_WRITE = 1, @@ -265,6 +271,17 @@ int snd_ctl_apply_vmaster_followers(struct snd_kcontrol *kctl, void *arg), void *arg); +/* + * Control LED trigger layer + */ +#define SND_CTL_LAYER_MODULE_LED "snd-ctl-led" + +#if IS_MODULE(CONFIG_SND_CTL_LED) +static inline int snd_ctl_led_request(void) { return snd_ctl_request_layer(SND_CTL_LAYER_MODULE_LED); } +#else +static inline int snd_ctl_led_request(void) { return 0; } +#endif + /* * Helper functions for jack-detection controls */ diff --git a/sound/core/Kconfig b/sound/core/Kconfig index a4050f87f230..db2e3c63ff41 100644 --- a/sound/core/Kconfig +++ b/sound/core/Kconfig @@ -203,4 +203,10 @@ config SND_DMA_SGBUF def_bool y depends on X86 +config SND_CTL_LED + tristate + select NEW_LEDS if SND_CTL_LED + select LEDS_TRIGGERS if SND_CTL_LED + select LEDS_TRIGGER_AUDIO if SND_CTL_LED + source "sound/core/seq/Kconfig" diff --git a/sound/core/Makefile b/sound/core/Makefile index ee4a4a6b99ba..d774792850f3 100644 --- a/sound/core/Makefile +++ b/sound/core/Makefile @@ -27,6 +27,7 @@ CFLAGS_pcm_native.o := -I$(src) snd-pcm-dmaengine-objs := pcm_dmaengine.o +snd-ctl-led-objs := control_led.o snd-rawmidi-objs := rawmidi.o snd-timer-objs := timer.o snd-hrtimer-objs := hrtimer.o @@ -37,6 +38,7 @@ snd-seq-device-objs := seq_device.o snd-compress-objs := compress_offload.o obj-$(CONFIG_SND) += snd.o +obj-$(CONFIG_SND_CTL_LED) += snd-ctl-led.o obj-$(CONFIG_SND_HWDEP) += snd-hwdep.o obj-$(CONFIG_SND_TIMER) += snd-timer.o obj-$(CONFIG_SND_HRTIMER) += snd-hrtimer.o diff --git a/sound/core/control.c b/sound/core/control.c index 87630021e434..6825ca75daf5 100644 --- a/sound/core/control.c +++ b/sound/core/control.c @@ -278,6 +278,7 @@ struct snd_kcontrol *snd_ctl_new1(const struct snd_kcontrol_new *ncontrol, SNDRV_CTL_ELEM_ACCESS_TLV_READWRITE | SNDRV_CTL_ELEM_ACCESS_TLV_COMMAND | SNDRV_CTL_ELEM_ACCESS_TLV_CALLBACK | + SNDRV_CTL_ELEM_ACCESS_LED_MASK | SNDRV_CTL_ELEM_ACCESS_SKIP_CHECK); err = snd_ctl_new(&kctl, count, access, NULL); @@ -1047,7 +1048,8 @@ static int snd_ctl_elem_info_user(struct snd_ctl_file *ctl, if (result < 0) return result; /* drop internal access flags */ - info.access &= ~SNDRV_CTL_ELEM_ACCESS_SKIP_CHECK; + info.access &= ~(SNDRV_CTL_ELEM_ACCESS_SKIP_CHECK| + SNDRV_CTL_ELEM_ACCESS_LED_MASK); if (copy_to_user(_info, &info, sizeof(info))) return -EFAULT; return result; diff --git a/sound/core/control_led.c b/sound/core/control_led.c new file mode 100644 index 000000000000..3e2c3c485c5c --- /dev/null +++ b/sound/core/control_led.c @@ -0,0 +1,278 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * LED state routines for driver control interface + * Copyright (c) 2021 by Jaroslav Kysela + */ + +#include +#include +#include +#include +#include + +MODULE_AUTHOR("Jaroslav Kysela "); +MODULE_DESCRIPTION("ALSA control interface to LED trigger code."); +MODULE_LICENSE("GPL"); + +#define MAX_LED (((SNDRV_CTL_ELEM_ACCESS_MIC_LED - SNDRV_CTL_ELEM_ACCESS_SPK_LED) \ + >> SNDRV_CTL_ELEM_ACCESS_LED_SHIFT) + 1) + +struct snd_ctl_led { + struct list_head list; + struct snd_card *card; + unsigned int access; + struct snd_kcontrol *kctl; + unsigned int index_offset; +}; + +static DEFINE_MUTEX(snd_ctl_led_mutex); +static struct list_head snd_ctl_led_controls[MAX_LED]; +static bool snd_ctl_led_card_valid[SNDRV_CARDS]; + +#define UPDATE_ROUTE(route, cb) \ + do { \ + int route2 = (cb); \ + if (route2 >= 0) \ + route = route < 0 ? route2 : (route | route2); \ + } while (0) + +static inline unsigned int access_to_group(unsigned int access) +{ + return ((access & SNDRV_CTL_ELEM_ACCESS_LED_MASK) >> + SNDRV_CTL_ELEM_ACCESS_LED_SHIFT) - 1; +} + +static inline unsigned int group_to_access(unsigned int group) +{ + return (group + 1) << SNDRV_CTL_ELEM_ACCESS_LED_SHIFT; +} + +static struct list_head *snd_ctl_led_controls_by_access(unsigned int access) +{ + unsigned int group = access_to_group(access); + if (group >= MAX_LED) + return NULL; + return &snd_ctl_led_controls[group]; +} + +static int snd_ctl_led_get(struct snd_ctl_led *lctl) +{ + struct snd_kcontrol *kctl = lctl->kctl; + struct snd_ctl_elem_info info; + struct snd_ctl_elem_value value; + unsigned int i; + int result; + + memset(&info, 0, sizeof(info)); + info.id = kctl->id; + info.id.index += lctl->index_offset; + info.id.numid += lctl->index_offset; + result = kctl->info(kctl, &info); + if (result < 0) + return -1; + memset(&value, 0, sizeof(value)); + value.id = info.id; + result = kctl->get(kctl, &value); + if (result < 0) + return -1; + if (info.type == SNDRV_CTL_ELEM_TYPE_BOOLEAN || + info.type == SNDRV_CTL_ELEM_TYPE_INTEGER) { + for (i = 0; i < info.count; i++) + if (value.value.integer.value[i] != info.value.integer.min) + return 1; + } else if (info.type == SNDRV_CTL_ELEM_TYPE_INTEGER64) { + for (i = 0; i < info.count; i++) + if (value.value.integer64.value[i] != info.value.integer64.min) + return 1; + } + return 0; +} + +static void snd_ctl_led_set_state(struct snd_card *card, unsigned int access, + struct snd_kcontrol *kctl, unsigned int ioff) +{ + struct list_head *controls; + struct snd_ctl_led *lctl; + enum led_audio led_trigger_type; + int route; + bool found; + + controls = snd_ctl_led_controls_by_access(access); + if (!controls) + return; + if (access == SNDRV_CTL_ELEM_ACCESS_SPK_LED) { + led_trigger_type = LED_AUDIO_MUTE; + } else if (access == SNDRV_CTL_ELEM_ACCESS_MIC_LED) { + led_trigger_type = LED_AUDIO_MICMUTE; + } else { + return; + } + route = -1; + found = false; + mutex_lock(&snd_ctl_led_mutex); + /* the card may not be registered (active) at this point */ + if (card && !snd_ctl_led_card_valid[card->number]) { + mutex_unlock(&snd_ctl_led_mutex); + return; + } + list_for_each_entry(lctl, controls, list) { + if (lctl->kctl == kctl && lctl->index_offset == ioff) + found = true; + UPDATE_ROUTE(route, snd_ctl_led_get(lctl)); + } + if (!found && kctl && card) { + lctl = kzalloc(sizeof(*lctl), GFP_KERNEL); + if (lctl) { + lctl->card = card; + lctl->access = access; + lctl->kctl = kctl; + lctl->index_offset = ioff; + list_add(&lctl->list, controls); + UPDATE_ROUTE(route, snd_ctl_led_get(lctl)); + } + } + mutex_unlock(&snd_ctl_led_mutex); + if (route >= 0) + ledtrig_audio_set(led_trigger_type, route ? LED_OFF : LED_ON); +} + +static struct snd_ctl_led *snd_ctl_led_find(struct snd_kcontrol *kctl, unsigned int ioff) +{ + struct list_head *controls; + struct snd_ctl_led *lctl; + unsigned int group; + + for (group = 0; group < MAX_LED; group++) { + controls = &snd_ctl_led_controls[group]; + list_for_each_entry(lctl, controls, list) + if (lctl->kctl == kctl && lctl->index_offset == ioff) + return lctl; + } + return NULL; +} + +static unsigned int snd_ctl_led_remove(struct snd_kcontrol *kctl, unsigned int ioff, + unsigned int access) +{ + struct snd_ctl_led *lctl; + unsigned int ret = 0; + + mutex_lock(&snd_ctl_led_mutex); + lctl = snd_ctl_led_find(kctl, ioff); + if (lctl && (access == 0 || access != lctl->access)) { + ret = lctl->access; + list_del(&lctl->list); + kfree(lctl); + } + mutex_unlock(&snd_ctl_led_mutex); + return ret; +} + +static void snd_ctl_led_notify(struct snd_card *card, unsigned int mask, + struct snd_kcontrol *kctl, unsigned int ioff) +{ + struct snd_kcontrol_volatile *vd; + unsigned int access, access2; + + if (mask == SNDRV_CTL_EVENT_MASK_REMOVE) { + access = snd_ctl_led_remove(kctl, ioff, 0); + if (access) + snd_ctl_led_set_state(card, access, NULL, 0); + } else if (mask & SNDRV_CTL_EVENT_MASK_INFO) { + vd = &kctl->vd[ioff]; + access = vd->access & SNDRV_CTL_ELEM_ACCESS_LED_MASK; + access2 = snd_ctl_led_remove(kctl, ioff, access); + if (access2) + snd_ctl_led_set_state(card, access2, NULL, 0); + if (access) + snd_ctl_led_set_state(card, access, kctl, ioff); + } else if ((mask & (SNDRV_CTL_EVENT_MASK_ADD | + SNDRV_CTL_EVENT_MASK_VALUE)) != 0) { + vd = &kctl->vd[ioff]; + access = vd->access & SNDRV_CTL_ELEM_ACCESS_LED_MASK; + if (access) + snd_ctl_led_set_state(card, access, kctl, ioff); + } +} + +static void snd_ctl_led_refresh(void) +{ + unsigned int group; + + for (group = 0; group < MAX_LED; group++) + snd_ctl_led_set_state(NULL, group_to_access(group), NULL, 0); +} + +static void snd_ctl_led_clean(struct snd_card *card) +{ + unsigned int group; + struct list_head *controls; + struct snd_ctl_led *lctl; + + for (group = 0; group < MAX_LED; group++) { + controls = &snd_ctl_led_controls[group]; +repeat: + list_for_each_entry(lctl, controls, list) + if (!card || lctl->card == card) { + list_del(&lctl->list); + kfree(lctl); + goto repeat; + } + } +} + +static void snd_ctl_led_register(struct snd_card *card) +{ + struct snd_kcontrol *kctl; + unsigned int ioff; + + if (snd_BUG_ON(card->number < 0 || + card->number >= ARRAY_SIZE(snd_ctl_led_card_valid))) + return; + mutex_lock(&snd_ctl_led_mutex); + snd_ctl_led_card_valid[card->number] = true; + mutex_unlock(&snd_ctl_led_mutex); + /* the register callback is already called with held card->controls_rwsem */ + list_for_each_entry(kctl, &card->controls, list) + for (ioff = 0; ioff < kctl->count; ioff++) + snd_ctl_led_notify(card, SNDRV_CTL_EVENT_MASK_VALUE, kctl, ioff); + snd_ctl_led_refresh(); +} + +static void snd_ctl_led_disconnect(struct snd_card *card) +{ + mutex_lock(&snd_ctl_led_mutex); + snd_ctl_led_card_valid[card->number] = false; + snd_ctl_led_clean(card); + mutex_unlock(&snd_ctl_led_mutex); + snd_ctl_led_refresh(); +} + +/* + * Control layer registration + */ +static struct snd_ctl_layer_ops snd_ctl_led_lops = { + .module_name = SND_CTL_LAYER_MODULE_LED, + .lregister = snd_ctl_led_register, + .ldisconnect = snd_ctl_led_disconnect, + .lnotify = snd_ctl_led_notify, +}; + +static int __init snd_ctl_led_init(void) +{ + unsigned int group; + + for (group = 0; group < MAX_LED; group++) + INIT_LIST_HEAD(&snd_ctl_led_controls[group]); + snd_ctl_register_layer(&snd_ctl_led_lops); + return 0; +} + +static void __exit snd_ctl_led_exit(void) +{ + snd_ctl_disconnect_layer(&snd_ctl_led_lops); + snd_ctl_led_clean(NULL); +} + +module_init(snd_ctl_led_init) +module_exit(snd_ctl_led_exit) From e65bf99718b538c2f34e9444dfe1087789b58f94 Mon Sep 17 00:00:00 2001 From: Jaroslav Kysela Date: Wed, 17 Mar 2021 18:29:43 +0100 Subject: [PATCH 352/587] ALSA: HDA - remove the custom implementation for the audio LED trigger With the new snd-ctl-led module, we have a generic way to trigger audio LEDs based on the sound control changes. Remove the custom implementation from the HDA driver. Move the LED initialization before snd_hda_gen_parse_auto_config() call in all drivers to create marked controls there. Signed-off-by: Jaroslav Kysela Link: https://lore.kernel.org/r/20210317172945.842280-5-perex@perex.cz Signed-off-by: Takashi Iwai --- sound/pci/hda/Kconfig | 4 +- sound/pci/hda/hda_codec.c | 69 ++------------ sound/pci/hda/hda_generic.c | 162 +++++--------------------------- sound/pci/hda/hda_generic.h | 15 +-- sound/pci/hda/hda_local.h | 16 +--- sound/pci/hda/patch_ca0132.c | 4 +- sound/pci/hda/patch_realtek.c | 2 +- sound/pci/hda/patch_sigmatel.c | 6 +- sound/pci/hda/thinkpad_helper.c | 2 +- 9 files changed, 45 insertions(+), 235 deletions(-) diff --git a/sound/pci/hda/Kconfig b/sound/pci/hda/Kconfig index 90759391cbac..c4360cdbc728 100644 --- a/sound/pci/hda/Kconfig +++ b/sound/pci/hda/Kconfig @@ -221,10 +221,8 @@ comment "Set to Y if you want auto-loading the codec driver" config SND_HDA_GENERIC tristate "Enable generic HD-audio codec parser" - select NEW_LEDS if SND_HDA_GENERIC_LEDS + select SND_CTL_LED if SND_HDA_GENERIC_LEDS select LEDS_CLASS if SND_HDA_GENERIC_LEDS - select LEDS_TRIGGERS if SND_HDA_GENERIC_LEDS - select LEDS_TRIGGER_AUDIO if SND_HDA_GENERIC_LEDS help Say Y or M here to enable the generic HD-audio codec parser in snd-hda-intel driver. diff --git a/sound/pci/hda/hda_codec.c b/sound/pci/hda/hda_codec.c index 2026f1ccaf5a..e54e39b35709 100644 --- a/sound/pci/hda/hda_codec.c +++ b/sound/pci/hda/hda_codec.c @@ -1952,7 +1952,7 @@ static int add_follower(struct hda_codec *codec, int __snd_hda_add_vmaster(struct hda_codec *codec, char *name, unsigned int *tlv, const char * const *followers, const char *suffix, bool init_follower_vol, - struct snd_kcontrol **ctl_ret) + unsigned int access, struct snd_kcontrol **ctl_ret) { struct snd_kcontrol *kctl; int err; @@ -1968,6 +1968,7 @@ int __snd_hda_add_vmaster(struct hda_codec *codec, char *name, kctl = snd_ctl_make_virtual_master(name, tlv); if (!kctl) return -ENOMEM; + kctl->vd[0].access |= access; err = snd_hda_ctl_add(codec, 0, kctl); if (err < 0) return err; @@ -1994,87 +1995,29 @@ int __snd_hda_add_vmaster(struct hda_codec *codec, char *name, } EXPORT_SYMBOL_GPL(__snd_hda_add_vmaster); -/* - * mute-LED control using vmaster - */ -static int vmaster_mute_mode_info(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_info *uinfo) -{ - static const char * const texts[] = { - "On", "Off", "Follow Master" - }; - - return snd_ctl_enum_info(uinfo, 1, 3, texts); -} - -static int vmaster_mute_mode_get(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_value *ucontrol) -{ - struct hda_vmaster_mute_hook *hook = snd_kcontrol_chip(kcontrol); - ucontrol->value.enumerated.item[0] = hook->mute_mode; - return 0; -} - -static int vmaster_mute_mode_put(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_value *ucontrol) -{ - struct hda_vmaster_mute_hook *hook = snd_kcontrol_chip(kcontrol); - unsigned int old_mode = hook->mute_mode; - - hook->mute_mode = ucontrol->value.enumerated.item[0]; - if (hook->mute_mode > HDA_VMUTE_FOLLOW_MASTER) - hook->mute_mode = HDA_VMUTE_FOLLOW_MASTER; - if (old_mode == hook->mute_mode) - return 0; - snd_hda_sync_vmaster_hook(hook); - return 1; -} - -static const struct snd_kcontrol_new vmaster_mute_mode = { - .iface = SNDRV_CTL_ELEM_IFACE_MIXER, - .name = "Mute-LED Mode", - .info = vmaster_mute_mode_info, - .get = vmaster_mute_mode_get, - .put = vmaster_mute_mode_put, -}; - /* meta hook to call each driver's vmaster hook */ static void vmaster_hook(void *private_data, int enabled) { struct hda_vmaster_mute_hook *hook = private_data; - if (hook->mute_mode != HDA_VMUTE_FOLLOW_MASTER) - enabled = hook->mute_mode; hook->hook(hook->codec, enabled); } /** - * snd_hda_add_vmaster_hook - Add a vmaster hook for mute-LED + * snd_hda_add_vmaster_hook - Add a vmaster hw specific hook * @codec: the HDA codec * @hook: the vmaster hook object - * @expose_enum_ctl: flag to create an enum ctl * - * Add a mute-LED hook with the given vmaster switch kctl. - * When @expose_enum_ctl is set, "Mute-LED Mode" control is automatically - * created and associated with the given hook. + * Add a hw specific hook (like EAPD) with the given vmaster switch kctl. */ int snd_hda_add_vmaster_hook(struct hda_codec *codec, - struct hda_vmaster_mute_hook *hook, - bool expose_enum_ctl) + struct hda_vmaster_mute_hook *hook) { - struct snd_kcontrol *kctl; - if (!hook->hook || !hook->sw_kctl) return 0; hook->codec = codec; - hook->mute_mode = HDA_VMUTE_FOLLOW_MASTER; snd_ctl_add_vmaster_hook(hook->sw_kctl, vmaster_hook, hook); - if (!expose_enum_ctl) - return 0; - kctl = snd_ctl_new1(&vmaster_mute_mode, hook); - if (!kctl) - return -ENOMEM; - return snd_hda_ctl_add(codec, 0, kctl); + return 0; } EXPORT_SYMBOL_GPL(snd_hda_add_vmaster_hook); diff --git a/sound/pci/hda/hda_generic.c b/sound/pci/hda/hda_generic.c index f5cba7afd1c6..3998e1771805 100644 --- a/sound/pci/hda/hda_generic.c +++ b/sound/pci/hda/hda_generic.c @@ -981,6 +981,8 @@ add_control(struct hda_gen_spec *spec, int type, const char *name, knew->index = cidx; if (get_amp_nid_(val)) knew->subdevice = HDA_SUBDEV_AMP_FLAG; + if (knew->access == 0) + knew->access = SNDRV_CTL_ELEM_ACCESS_READWRITE; knew->private_value = val; return knew; } @@ -3618,8 +3620,11 @@ static int add_single_cap_ctl(struct hda_codec *codec, const char *label, amp_val_replace_channels(ctl, chs)); if (!knew) return -ENOMEM; - if (is_switch) + if (is_switch) { knew->put = cap_single_sw_put; + if (spec->mic_mute_led) + knew->access |= SNDRV_CTL_ELEM_ACCESS_MIC_LED; + } if (!inv_dmic) return 0; @@ -3634,8 +3639,11 @@ static int add_single_cap_ctl(struct hda_codec *codec, const char *label, amp_val_replace_channels(ctl, 2)); if (!knew) return -ENOMEM; - if (is_switch) + if (is_switch) { knew->put = cap_single_sw_put; + if (spec->mic_mute_led) + knew->access |= SNDRV_CTL_ELEM_ACCESS_MIC_LED; + } return 0; } @@ -3676,6 +3684,8 @@ static int create_bind_cap_vol_ctl(struct hda_codec *codec, int idx, knew->index = idx; knew->private_value = sw_ctl; knew->subdevice = HDA_SUBDEV_AMP_FLAG; + if (spec->mic_mute_led) + knew->access |= SNDRV_CTL_ELEM_ACCESS_MIC_LED; } return 0; } @@ -3917,11 +3927,6 @@ static int create_mute_led_cdev(struct hda_codec *codec, return devm_led_classdev_register(&codec->core.dev, cdev); } -static void vmaster_update_mute_led(void *private_data, int enabled) -{ - ledtrig_audio_set(LED_AUDIO_MUTE, enabled ? LED_OFF : LED_ON); -} - /** * snd_hda_gen_add_mute_led_cdev - Create a LED classdev and enable as vmaster mute LED * @codec: the HDA codec @@ -3945,134 +3950,11 @@ int snd_hda_gen_add_mute_led_cdev(struct hda_codec *codec, if (spec->vmaster_mute.hook) codec_err(codec, "vmaster hook already present before cdev!\n"); - spec->vmaster_mute.hook = vmaster_update_mute_led; - spec->vmaster_mute_enum = 1; + spec->vmaster_mute_led = 1; return 0; } EXPORT_SYMBOL_GPL(snd_hda_gen_add_mute_led_cdev); -/* - * mic mute LED hook helpers - */ -enum { - MICMUTE_LED_ON, - MICMUTE_LED_OFF, - MICMUTE_LED_FOLLOW_CAPTURE, - MICMUTE_LED_FOLLOW_MUTE, -}; - -static void call_micmute_led_update(struct hda_codec *codec) -{ - struct hda_gen_spec *spec = codec->spec; - unsigned int val; - - switch (spec->micmute_led.led_mode) { - case MICMUTE_LED_ON: - val = 1; - break; - case MICMUTE_LED_OFF: - val = 0; - break; - case MICMUTE_LED_FOLLOW_CAPTURE: - val = !!spec->micmute_led.capture; - break; - case MICMUTE_LED_FOLLOW_MUTE: - default: - val = !spec->micmute_led.capture; - break; - } - - if (val == spec->micmute_led.led_value) - return; - spec->micmute_led.led_value = val; - ledtrig_audio_set(LED_AUDIO_MICMUTE, - spec->micmute_led.led_value ? LED_ON : LED_OFF); -} - -static void update_micmute_led(struct hda_codec *codec, - struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_value *ucontrol) -{ - struct hda_gen_spec *spec = codec->spec; - unsigned int mask; - - if (spec->micmute_led.old_hook) - spec->micmute_led.old_hook(codec, kcontrol, ucontrol); - - if (!ucontrol) - return; - mask = 1U << snd_ctl_get_ioffidx(kcontrol, &ucontrol->id); - if (!strcmp("Capture Switch", ucontrol->id.name)) { - /* TODO: How do I verify if it's a mono or stereo here? */ - if (ucontrol->value.integer.value[0] || - ucontrol->value.integer.value[1]) - spec->micmute_led.capture |= mask; - else - spec->micmute_led.capture &= ~mask; - call_micmute_led_update(codec); - } -} - -static int micmute_led_mode_info(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_info *uinfo) -{ - static const char * const texts[] = { - "On", "Off", "Follow Capture", "Follow Mute", - }; - - return snd_ctl_enum_info(uinfo, 1, ARRAY_SIZE(texts), texts); -} - -static int micmute_led_mode_get(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_value *ucontrol) -{ - struct hda_codec *codec = snd_kcontrol_chip(kcontrol); - struct hda_gen_spec *spec = codec->spec; - - ucontrol->value.enumerated.item[0] = spec->micmute_led.led_mode; - return 0; -} - -static int micmute_led_mode_put(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_value *ucontrol) -{ - struct hda_codec *codec = snd_kcontrol_chip(kcontrol); - struct hda_gen_spec *spec = codec->spec; - unsigned int mode; - - mode = ucontrol->value.enumerated.item[0]; - if (mode > MICMUTE_LED_FOLLOW_MUTE) - mode = MICMUTE_LED_FOLLOW_MUTE; - if (mode == spec->micmute_led.led_mode) - return 0; - spec->micmute_led.led_mode = mode; - call_micmute_led_update(codec); - return 1; -} - -static const struct snd_kcontrol_new micmute_led_mode_ctl = { - .iface = SNDRV_CTL_ELEM_IFACE_MIXER, - .name = "Mic Mute-LED Mode", - .info = micmute_led_mode_info, - .get = micmute_led_mode_get, - .put = micmute_led_mode_put, -}; - -/* Set up the capture sync hook for controlling the mic-mute LED */ -static int add_micmute_led_hook(struct hda_codec *codec) -{ - struct hda_gen_spec *spec = codec->spec; - - spec->micmute_led.led_mode = MICMUTE_LED_FOLLOW_MUTE; - spec->micmute_led.capture = 0; - spec->micmute_led.led_value = -1; - spec->micmute_led.old_hook = spec->cap_sync_hook; - spec->cap_sync_hook = update_micmute_led; - if (!snd_hda_gen_add_kctl(spec, NULL, &micmute_led_mode_ctl)) - return -ENOMEM; - return 0; -} - /** * snd_hda_gen_add_micmute_led_cdev - Create a LED classdev and enable as mic-mute LED * @codec: the HDA codec @@ -4091,6 +3973,7 @@ int snd_hda_gen_add_micmute_led_cdev(struct hda_codec *codec, int (*callback)(struct led_classdev *, enum led_brightness)) { + struct hda_gen_spec *spec = codec->spec; int err; if (callback) { @@ -4101,7 +3984,8 @@ int snd_hda_gen_add_micmute_led_cdev(struct hda_codec *codec, } } - return add_micmute_led_hook(codec); + spec->mic_mute_led = 1; + return 0; } EXPORT_SYMBOL_GPL(snd_hda_gen_add_micmute_led_cdev); #endif /* CONFIG_SND_HDA_GENERIC_LEDS */ @@ -5060,6 +4944,9 @@ int snd_hda_gen_parse_auto_config(struct hda_codec *codec, parse_user_hints(codec); + if (spec->vmaster_mute_led || spec->mic_mute_led) + snd_ctl_led_request(); + if (spec->mixer_nid && !spec->mixer_merge_nid) spec->mixer_merge_nid = spec->mixer_nid; @@ -5291,7 +5178,7 @@ int snd_hda_gen_build_controls(struct hda_codec *codec) !snd_hda_find_mixer_ctl(codec, "Master Playback Volume")) { err = snd_hda_add_vmaster(codec, "Master Playback Volume", spec->vmaster_tlv, follower_pfxs, - "Playback Volume"); + "Playback Volume", 0); if (err < 0) return err; } @@ -5299,13 +5186,14 @@ int snd_hda_gen_build_controls(struct hda_codec *codec) !snd_hda_find_mixer_ctl(codec, "Master Playback Switch")) { err = __snd_hda_add_vmaster(codec, "Master Playback Switch", NULL, follower_pfxs, - "Playback Switch", - true, &spec->vmaster_mute.sw_kctl); + "Playback Switch", true, + spec->vmaster_mute_led ? + SNDRV_CTL_ELEM_ACCESS_SPK_LED : 0, + &spec->vmaster_mute.sw_kctl); if (err < 0) return err; if (spec->vmaster_mute.hook) { - snd_hda_add_vmaster_hook(codec, &spec->vmaster_mute, - spec->vmaster_mute_enum); + snd_hda_add_vmaster_hook(codec, &spec->vmaster_mute); snd_hda_sync_vmaster_hook(&spec->vmaster_mute); } } diff --git a/sound/pci/hda/hda_generic.h b/sound/pci/hda/hda_generic.h index 0886bc81f40b..d4dd1b8a2e7e 100644 --- a/sound/pci/hda/hda_generic.h +++ b/sound/pci/hda/hda_generic.h @@ -84,15 +84,6 @@ struct badness_table { extern const struct badness_table hda_main_out_badness; extern const struct badness_table hda_extra_out_badness; -struct hda_micmute_hook { - unsigned int led_mode; - unsigned int capture; - unsigned int led_value; - void (*old_hook)(struct hda_codec *codec, - struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_value *ucontrol); -}; - struct hda_gen_spec { char stream_name_analog[32]; /* analog PCM stream */ const struct hda_pcm_stream *stream_analog_playback; @@ -229,7 +220,8 @@ struct hda_gen_spec { unsigned int inv_dmic_split:1; /* inverted dmic w/a for conexant */ unsigned int own_eapd_ctl:1; /* set EAPD by own function */ unsigned int keep_eapd_on:1; /* don't turn off EAPD automatically */ - unsigned int vmaster_mute_enum:1; /* add vmaster mute mode enum */ + unsigned int vmaster_mute_led:1; /* add SPK-LED flag to vmaster mute switch */ + unsigned int mic_mute_led:1; /* add MIC-LED flag to capture mute switch */ unsigned int indep_hp:1; /* independent HP supported */ unsigned int prefer_hp_amp:1; /* enable HP amp for speaker if any */ unsigned int add_stereo_mix_input:2; /* add aamix as a capture src */ @@ -285,9 +277,6 @@ struct hda_gen_spec { struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol); - /* mic mute LED hook; called via cap_sync_hook */ - struct hda_micmute_hook micmute_led; - /* PCM hooks */ void (*pcm_playback_hook)(struct hda_pcm_stream *hinfo, struct hda_codec *codec, diff --git a/sound/pci/hda/hda_local.h b/sound/pci/hda/hda_local.h index 5beb8aa44ecd..06d4486a4961 100644 --- a/sound/pci/hda/hda_local.h +++ b/sound/pci/hda/hda_local.h @@ -131,21 +131,15 @@ struct snd_kcontrol *snd_hda_find_mixer_ctl(struct hda_codec *codec, int __snd_hda_add_vmaster(struct hda_codec *codec, char *name, unsigned int *tlv, const char * const *followers, const char *suffix, bool init_follower_vol, - struct snd_kcontrol **ctl_ret); -#define snd_hda_add_vmaster(codec, name, tlv, followers, suffix) \ - __snd_hda_add_vmaster(codec, name, tlv, followers, suffix, true, NULL) + unsigned int access, struct snd_kcontrol **ctl_ret); +#define snd_hda_add_vmaster(codec, name, tlv, followers, suffix, access) \ + __snd_hda_add_vmaster(codec, name, tlv, followers, suffix, true, access, NULL) int snd_hda_codec_reset(struct hda_codec *codec); void snd_hda_codec_register(struct hda_codec *codec); void snd_hda_codec_cleanup_for_unbind(struct hda_codec *codec); #define snd_hda_regmap_sync(codec) snd_hdac_regmap_sync(&(codec)->core) -enum { - HDA_VMUTE_OFF, - HDA_VMUTE_ON, - HDA_VMUTE_FOLLOW_MASTER, -}; - struct hda_vmaster_mute_hook { /* below two fields must be filled by the caller of * snd_hda_add_vmaster_hook() beforehand @@ -153,13 +147,11 @@ struct hda_vmaster_mute_hook { struct snd_kcontrol *sw_kctl; void (*hook)(void *, int); /* below are initialized automatically */ - unsigned int mute_mode; /* HDA_VMUTE_XXX */ struct hda_codec *codec; }; int snd_hda_add_vmaster_hook(struct hda_codec *codec, - struct hda_vmaster_mute_hook *hook, - bool expose_enum_ctl); + struct hda_vmaster_mute_hook *hook); void snd_hda_sync_vmaster_hook(struct hda_vmaster_mute_hook *hook); /* amp value bits */ diff --git a/sound/pci/hda/patch_ca0132.c b/sound/pci/hda/patch_ca0132.c index b2b620f6c832..49b4fdd2feab 100644 --- a/sound/pci/hda/patch_ca0132.c +++ b/sound/pci/hda/patch_ca0132.c @@ -7041,11 +7041,11 @@ static int ca0132_build_controls(struct hda_codec *codec) spec->tlv); snd_hda_add_vmaster(codec, "Master Playback Volume", spec->tlv, ca0132_alt_follower_pfxs, - "Playback Volume"); + "Playback Volume", 0); err = __snd_hda_add_vmaster(codec, "Master Playback Switch", NULL, ca0132_alt_follower_pfxs, "Playback Switch", - true, &spec->vmaster_mute.sw_kctl); + true, 0, &spec->vmaster_mute.sw_kctl); if (err < 0) return err; } diff --git a/sound/pci/hda/patch_realtek.c b/sound/pci/hda/patch_realtek.c index 316b9b4ccb32..2c35d2df09d6 100644 --- a/sound/pci/hda/patch_realtek.c +++ b/sound/pci/hda/patch_realtek.c @@ -292,7 +292,7 @@ static void alc_fixup_gpio4(struct hda_codec *codec, static void alc_fixup_micmute_led(struct hda_codec *codec, const struct hda_fixup *fix, int action) { - if (action == HDA_FIXUP_ACT_PROBE) + if (action == HDA_FIXUP_ACT_PRE_PROBE) snd_hda_gen_add_micmute_led_cdev(codec, NULL); } diff --git a/sound/pci/hda/patch_sigmatel.c b/sound/pci/hda/patch_sigmatel.c index c662431bf13a..3bd592e126a3 100644 --- a/sound/pci/hda/patch_sigmatel.c +++ b/sound/pci/hda/patch_sigmatel.c @@ -4277,6 +4277,9 @@ static int stac_parse_auto_config(struct hda_codec *codec) spec->gen.automute_hook = stac_update_outputs; + if (spec->gpio_led) + snd_hda_gen_add_mute_led_cdev(codec, stac_vmaster_hook); + err = snd_hda_gen_parse_auto_config(codec, &spec->gen.autocfg); if (err < 0) return err; @@ -4318,9 +4321,6 @@ static int stac_parse_auto_config(struct hda_codec *codec) } #endif - if (spec->gpio_led) - snd_hda_gen_add_mute_led_cdev(codec, stac_vmaster_hook); - if (spec->aloopback_ctl && snd_hda_get_bool_hint(codec, "loopback") == 1) { unsigned int wr_verb = diff --git a/sound/pci/hda/thinkpad_helper.c b/sound/pci/hda/thinkpad_helper.c index 6698ae241efc..de4d8deed102 100644 --- a/sound/pci/hda/thinkpad_helper.c +++ b/sound/pci/hda/thinkpad_helper.c @@ -18,7 +18,7 @@ static bool is_thinkpad(struct hda_codec *codec) static void hda_fixup_thinkpad_acpi(struct hda_codec *codec, const struct hda_fixup *fix, int action) { - if (action == HDA_FIXUP_ACT_PROBE) { + if (action == HDA_FIXUP_ACT_PRE_PROBE) { if (!is_thinkpad(codec)) return; snd_hda_gen_add_mute_led_cdev(codec, NULL); From cb17fe0045aaa74d1ce12c0ad0058a62a1ce0401 Mon Sep 17 00:00:00 2001 From: Jaroslav Kysela Date: Wed, 17 Mar 2021 18:29:44 +0100 Subject: [PATCH 353/587] ALSA: control - add sysfs support to the LED trigger module Create SYSFS/devices/virtual/sound/ctl-led tree (with SYSFS/class/sound/ctl-led symlink). speaker/ +-- mode +-- brightness mic/ +-- mode +-- brightness Copy the idea from the HDA driver and allow to set the audio LEDs based on the various modes: - follow mute - follow moute (inverted to follow mute) - off - on Also, the actual LED state is exposed. Signed-off-by: Jaroslav Kysela Link: https://lore.kernel.org/r/20210317172945.842280-6-perex@perex.cz Signed-off-by: Takashi Iwai --- sound/core/control_led.c | 192 +++++++++++++++++++++++++++++++++------ 1 file changed, 163 insertions(+), 29 deletions(-) diff --git a/sound/core/control_led.c b/sound/core/control_led.c index 3e2c3c485c5c..dfa51d8461e1 100644 --- a/sound/core/control_led.c +++ b/sound/core/control_led.c @@ -17,7 +17,23 @@ MODULE_LICENSE("GPL"); #define MAX_LED (((SNDRV_CTL_ELEM_ACCESS_MIC_LED - SNDRV_CTL_ELEM_ACCESS_SPK_LED) \ >> SNDRV_CTL_ELEM_ACCESS_LED_SHIFT) + 1) +enum snd_ctl_led_mode { + MODE_FOLLOW_MUTE = 0, + MODE_FOLLOW_ROUTE, + MODE_OFF, + MODE_ON, +}; + struct snd_ctl_led { + struct device dev; + struct list_head controls; + const char *name; + unsigned int group; + enum led_audio trigger_type; + enum snd_ctl_led_mode mode; +}; + +struct snd_ctl_led_ctl { struct list_head list; struct snd_card *card; unsigned int access; @@ -26,8 +42,21 @@ struct snd_ctl_led { }; static DEFINE_MUTEX(snd_ctl_led_mutex); -static struct list_head snd_ctl_led_controls[MAX_LED]; static bool snd_ctl_led_card_valid[SNDRV_CARDS]; +static struct snd_ctl_led snd_ctl_leds[MAX_LED] = { + { + .name = "speaker", + .group = (SNDRV_CTL_ELEM_ACCESS_SPK_LED >> SNDRV_CTL_ELEM_ACCESS_LED_SHIFT) - 1, + .trigger_type = LED_AUDIO_MUTE, + .mode = MODE_FOLLOW_MUTE, + }, + { + .name = "mic", + .group = (SNDRV_CTL_ELEM_ACCESS_MIC_LED >> SNDRV_CTL_ELEM_ACCESS_LED_SHIFT) - 1, + .trigger_type = LED_AUDIO_MICMUTE, + .mode = MODE_FOLLOW_MUTE, + }, +}; #define UPDATE_ROUTE(route, cb) \ do { \ @@ -47,15 +76,15 @@ static inline unsigned int group_to_access(unsigned int group) return (group + 1) << SNDRV_CTL_ELEM_ACCESS_LED_SHIFT; } -static struct list_head *snd_ctl_led_controls_by_access(unsigned int access) +static struct snd_ctl_led *snd_ctl_led_get_by_access(unsigned int access) { unsigned int group = access_to_group(access); if (group >= MAX_LED) return NULL; - return &snd_ctl_led_controls[group]; + return &snd_ctl_leds[group]; } -static int snd_ctl_led_get(struct snd_ctl_led *lctl) +static int snd_ctl_led_get(struct snd_ctl_led_ctl *lctl) { struct snd_kcontrol *kctl = lctl->kctl; struct snd_ctl_elem_info info; @@ -91,22 +120,14 @@ static int snd_ctl_led_get(struct snd_ctl_led *lctl) static void snd_ctl_led_set_state(struct snd_card *card, unsigned int access, struct snd_kcontrol *kctl, unsigned int ioff) { - struct list_head *controls; - struct snd_ctl_led *lctl; - enum led_audio led_trigger_type; + struct snd_ctl_led *led; + struct snd_ctl_led_ctl *lctl; int route; bool found; - controls = snd_ctl_led_controls_by_access(access); - if (!controls) + led = snd_ctl_led_get_by_access(access); + if (!led) return; - if (access == SNDRV_CTL_ELEM_ACCESS_SPK_LED) { - led_trigger_type = LED_AUDIO_MUTE; - } else if (access == SNDRV_CTL_ELEM_ACCESS_MIC_LED) { - led_trigger_type = LED_AUDIO_MICMUTE; - } else { - return; - } route = -1; found = false; mutex_lock(&snd_ctl_led_mutex); @@ -115,7 +136,7 @@ static void snd_ctl_led_set_state(struct snd_card *card, unsigned int access, mutex_unlock(&snd_ctl_led_mutex); return; } - list_for_each_entry(lctl, controls, list) { + list_for_each_entry(lctl, &led->controls, list) { if (lctl->kctl == kctl && lctl->index_offset == ioff) found = true; UPDATE_ROUTE(route, snd_ctl_led_get(lctl)); @@ -127,23 +148,29 @@ static void snd_ctl_led_set_state(struct snd_card *card, unsigned int access, lctl->access = access; lctl->kctl = kctl; lctl->index_offset = ioff; - list_add(&lctl->list, controls); + list_add(&lctl->list, &led->controls); UPDATE_ROUTE(route, snd_ctl_led_get(lctl)); } } mutex_unlock(&snd_ctl_led_mutex); + switch (led->mode) { + case MODE_OFF: route = 1; break; + case MODE_ON: route = 0; break; + case MODE_FOLLOW_ROUTE: if (route >= 0) route ^= 1; break; + case MODE_FOLLOW_MUTE: /* noop */ break; + } if (route >= 0) - ledtrig_audio_set(led_trigger_type, route ? LED_OFF : LED_ON); + ledtrig_audio_set(led->trigger_type, route ? LED_OFF : LED_ON); } -static struct snd_ctl_led *snd_ctl_led_find(struct snd_kcontrol *kctl, unsigned int ioff) +static struct snd_ctl_led_ctl *snd_ctl_led_find(struct snd_kcontrol *kctl, unsigned int ioff) { struct list_head *controls; - struct snd_ctl_led *lctl; + struct snd_ctl_led_ctl *lctl; unsigned int group; for (group = 0; group < MAX_LED; group++) { - controls = &snd_ctl_led_controls[group]; + controls = &snd_ctl_leds[group].controls; list_for_each_entry(lctl, controls, list) if (lctl->kctl == kctl && lctl->index_offset == ioff) return lctl; @@ -154,7 +181,7 @@ static struct snd_ctl_led *snd_ctl_led_find(struct snd_kcontrol *kctl, unsigned static unsigned int snd_ctl_led_remove(struct snd_kcontrol *kctl, unsigned int ioff, unsigned int access) { - struct snd_ctl_led *lctl; + struct snd_ctl_led_ctl *lctl; unsigned int ret = 0; mutex_lock(&snd_ctl_led_mutex); @@ -206,13 +233,13 @@ static void snd_ctl_led_refresh(void) static void snd_ctl_led_clean(struct snd_card *card) { unsigned int group; - struct list_head *controls; - struct snd_ctl_led *lctl; + struct snd_ctl_led *led; + struct snd_ctl_led_ctl *lctl; for (group = 0; group < MAX_LED; group++) { - controls = &snd_ctl_led_controls[group]; + led = &snd_ctl_leds[group]; repeat: - list_for_each_entry(lctl, controls, list) + list_for_each_entry(lctl, &led->controls, list) if (!card || lctl->card == card) { list_del(&lctl->list); kfree(lctl); @@ -248,6 +275,82 @@ static void snd_ctl_led_disconnect(struct snd_card *card) snd_ctl_led_refresh(); } +/* + * sysfs + */ + +static ssize_t show_mode(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct snd_ctl_led *led = container_of(dev, struct snd_ctl_led, dev); + const char *str; + + switch (led->mode) { + case MODE_FOLLOW_MUTE: str = "follow-mute"; break; + case MODE_FOLLOW_ROUTE: str = "follow-route"; break; + case MODE_ON: str = "on"; break; + case MODE_OFF: str = "off"; break; + } + return sprintf(buf, "%s\n", str); +} + +static ssize_t store_mode(struct device *dev, struct device_attribute *attr, + const char *buf, size_t count) +{ + struct snd_ctl_led *led = container_of(dev, struct snd_ctl_led, dev); + char _buf[16]; + size_t l = min(count, sizeof(_buf) - 1) + 1; + enum snd_ctl_led_mode mode; + + memcpy(_buf, buf, l); + _buf[l] = '\0'; + if (strstr(_buf, "mute")) + mode = MODE_FOLLOW_MUTE; + else if (strstr(_buf, "route")) + mode = MODE_FOLLOW_ROUTE; + else if (strncmp(_buf, "off", 3) == 0 || strncmp(_buf, "0", 1) == 0) + mode = MODE_OFF; + else if (strncmp(_buf, "on", 2) == 0 || strncmp(_buf, "1", 1) == 0) + mode = MODE_ON; + else + return count; + + mutex_lock(&snd_ctl_led_mutex); + led->mode = mode; + mutex_unlock(&snd_ctl_led_mutex); + + snd_ctl_led_set_state(NULL, group_to_access(led->group), NULL, 0); + return count; +} + +static ssize_t show_brightness(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct snd_ctl_led *led = container_of(dev, struct snd_ctl_led, dev); + + return sprintf(buf, "%u\n", ledtrig_audio_get(led->trigger_type)); +} + +static DEVICE_ATTR(mode, 0644, show_mode, store_mode); +static DEVICE_ATTR(brightness, 0444, show_brightness, NULL); + +static struct attribute *snd_ctl_led_dev_attrs[] = { + &dev_attr_mode.attr, + &dev_attr_brightness.attr, + NULL, +}; + +static const struct attribute_group snd_ctl_led_dev_attr_group = { + .attrs = snd_ctl_led_dev_attrs, +}; + +static const struct attribute_group *snd_ctl_led_dev_attr_groups[] = { + &snd_ctl_led_dev_attr_group, + NULL, +}; + +static struct device snd_ctl_led_dev; + /* * Control layer registration */ @@ -260,16 +363,47 @@ static struct snd_ctl_layer_ops snd_ctl_led_lops = { static int __init snd_ctl_led_init(void) { + struct snd_ctl_led *led; unsigned int group; - for (group = 0; group < MAX_LED; group++) - INIT_LIST_HEAD(&snd_ctl_led_controls[group]); + device_initialize(&snd_ctl_led_dev); + snd_ctl_led_dev.class = sound_class; + dev_set_name(&snd_ctl_led_dev, "ctl-led"); + if (device_add(&snd_ctl_led_dev)) { + put_device(&snd_ctl_led_dev); + return -ENOMEM; + } + for (group = 0; group < MAX_LED; group++) { + led = &snd_ctl_leds[group]; + INIT_LIST_HEAD(&led->controls); + device_initialize(&led->dev); + led->dev.parent = &snd_ctl_led_dev; + led->dev.groups = snd_ctl_led_dev_attr_groups; + dev_set_name(&led->dev, led->name); + if (device_add(&led->dev)) { + put_device(&led->dev); + for (; group > 0; group--) { + led = &snd_ctl_leds[group]; + device_del(&led->dev); + } + device_del(&snd_ctl_led_dev); + return -ENOMEM; + } + } snd_ctl_register_layer(&snd_ctl_led_lops); return 0; } static void __exit snd_ctl_led_exit(void) { + struct snd_ctl_led *led; + unsigned int group; + + for (group = 0; group < MAX_LED; group++) { + led = &snd_ctl_leds[group]; + device_del(&led->dev); + } + device_del(&snd_ctl_led_dev); snd_ctl_disconnect_layer(&snd_ctl_led_lops); snd_ctl_led_clean(NULL); } From a135dfb5de1501327895729b4f513370d2555b4d Mon Sep 17 00:00:00 2001 From: Jaroslav Kysela Date: Wed, 17 Mar 2021 18:29:45 +0100 Subject: [PATCH 354/587] ALSA: led control - add sysfs kcontrol LED marking layer We need to manage the kcontrol entries association for the LED trigger from the user space. This patch adds a layer to the sysfs tree like: /sys/devices/virtual/sound/ctl-led/mic + card0 | + attach | + detach | ... + card1 + attach ... Operations: attach and detach - amixer style ID is accepted and easy strings for numid and simple names reset - reset all associated kcontrol entries list - list associated kcontrol entries (numid values only) Additional symlinks: /sys/devices/virtual/sound/ctl-led/mic/card0/card -> /sys/class/sound/card0 /sys/class/sound/card0/controlC0/led-mic -> /sys/devices/virtual/sound/ctl-led/mic/card0 Signed-off-by: Jaroslav Kysela Link: https://lore.kernel.org/r/20210317172945.842280-7-perex@perex.cz Signed-off-by: Takashi Iwai --- sound/core/control_led.c | 366 ++++++++++++++++++++++++++++++++++++++- 1 file changed, 362 insertions(+), 4 deletions(-) diff --git a/sound/core/control_led.c b/sound/core/control_led.c index dfa51d8461e1..d4fb8b873f34 100644 --- a/sound/core/control_led.c +++ b/sound/core/control_led.c @@ -24,6 +24,12 @@ enum snd_ctl_led_mode { MODE_ON, }; +struct snd_ctl_led_card { + struct device dev; + int number; + struct snd_ctl_led *led; +}; + struct snd_ctl_led { struct device dev; struct list_head controls; @@ -31,6 +37,7 @@ struct snd_ctl_led { unsigned int group; enum led_audio trigger_type; enum snd_ctl_led_mode mode; + struct snd_ctl_led_card *cards[SNDRV_CARDS]; }; struct snd_ctl_led_ctl { @@ -58,6 +65,9 @@ static struct snd_ctl_led snd_ctl_leds[MAX_LED] = { }, }; +static void snd_ctl_led_sysfs_add(struct snd_card *card); +static void snd_ctl_led_sysfs_remove(struct snd_card *card); + #define UPDATE_ROUTE(route, cb) \ do { \ int route2 = (cb); \ @@ -222,6 +232,46 @@ static void snd_ctl_led_notify(struct snd_card *card, unsigned int mask, } } +static int snd_ctl_led_set_id(int card_number, struct snd_ctl_elem_id *id, + unsigned int group, bool set) +{ + struct snd_card *card; + struct snd_kcontrol *kctl; + struct snd_kcontrol_volatile *vd; + unsigned int ioff, access, new_access; + int err = 0; + + card = snd_card_ref(card_number); + if (card) { + down_write(&card->controls_rwsem); + kctl = snd_ctl_find_id(card, id); + if (kctl) { + ioff = snd_ctl_get_ioff(kctl, id); + vd = &kctl->vd[ioff]; + access = vd->access & SNDRV_CTL_ELEM_ACCESS_LED_MASK; + if (access != 0 && access != group_to_access(group)) { + err = -EXDEV; + goto unlock; + } + new_access = vd->access & ~SNDRV_CTL_ELEM_ACCESS_LED_MASK; + if (set) + new_access |= group_to_access(group); + if (new_access != vd->access) { + vd->access = new_access; + snd_ctl_led_notify(card, SNDRV_CTL_EVENT_MASK_INFO, kctl, ioff); + } + } else { + err = -ENOENT; + } +unlock: + up_write(&card->controls_rwsem); + snd_card_unref(card); + } else { + err = -ENXIO; + } + return err; +} + static void snd_ctl_led_refresh(void) { unsigned int group; @@ -230,6 +280,12 @@ static void snd_ctl_led_refresh(void) snd_ctl_led_set_state(NULL, group_to_access(group), NULL, 0); } +static void snd_ctl_led_ctl_destroy(struct snd_ctl_led_ctl *lctl) +{ + list_del(&lctl->list); + kfree(lctl); +} + static void snd_ctl_led_clean(struct snd_card *card) { unsigned int group; @@ -241,13 +297,47 @@ static void snd_ctl_led_clean(struct snd_card *card) repeat: list_for_each_entry(lctl, &led->controls, list) if (!card || lctl->card == card) { - list_del(&lctl->list); - kfree(lctl); + snd_ctl_led_ctl_destroy(lctl); goto repeat; } } } +static int snd_ctl_led_reset(int card_number, unsigned int group) +{ + struct snd_card *card; + struct snd_ctl_led *led; + struct snd_ctl_led_ctl *lctl; + struct snd_kcontrol_volatile *vd; + bool change = false; + + card = snd_card_ref(card_number); + if (!card) + return -ENXIO; + + mutex_lock(&snd_ctl_led_mutex); + if (!snd_ctl_led_card_valid[card_number]) { + mutex_unlock(&snd_ctl_led_mutex); + snd_card_unref(card); + return -ENXIO; + } + led = &snd_ctl_leds[group]; +repeat: + list_for_each_entry(lctl, &led->controls, list) + if (lctl->card == card) { + vd = &lctl->kctl->vd[lctl->index_offset]; + vd->access &= ~group_to_access(group); + snd_ctl_led_ctl_destroy(lctl); + change = true; + goto repeat; + } + mutex_unlock(&snd_ctl_led_mutex); + if (change) + snd_ctl_led_set_state(NULL, group_to_access(group), NULL, 0); + snd_card_unref(card); + return 0; +} + static void snd_ctl_led_register(struct snd_card *card) { struct snd_kcontrol *kctl; @@ -264,10 +354,12 @@ static void snd_ctl_led_register(struct snd_card *card) for (ioff = 0; ioff < kctl->count; ioff++) snd_ctl_led_notify(card, SNDRV_CTL_EVENT_MASK_VALUE, kctl, ioff); snd_ctl_led_refresh(); + snd_ctl_led_sysfs_add(card); } static void snd_ctl_led_disconnect(struct snd_card *card) { + snd_ctl_led_sysfs_remove(card); mutex_lock(&snd_ctl_led_mutex); snd_ctl_led_card_valid[card->number] = false; snd_ctl_led_clean(card); @@ -349,8 +441,264 @@ static const struct attribute_group *snd_ctl_led_dev_attr_groups[] = { NULL, }; +static char *find_eos(char *s) +{ + while (*s && *s != ',') + s++; + if (*s) + s++; + return s; +} + +static char *parse_uint(char *s, unsigned int *val) +{ + unsigned long long res; + if (kstrtoull(s, 10, &res)) + res = 0; + *val = res; + return find_eos(s); +} + +static char *parse_string(char *s, char *val, size_t val_size) +{ + if (*s == '"' || *s == '\'') { + char c = *s; + s++; + while (*s && *s != c) { + if (val_size > 1) { + *val++ = *s; + val_size--; + } + s++; + } + } else { + while (*s && *s != ',') { + if (val_size > 1) { + *val++ = *s; + val_size--; + } + s++; + } + } + *val = '\0'; + if (*s) + s++; + return s; +} + +static char *parse_iface(char *s, unsigned int *val) +{ + if (!strncasecmp(s, "card", 4)) + *val = SNDRV_CTL_ELEM_IFACE_CARD; + else if (!strncasecmp(s, "mixer", 5)) + *val = SNDRV_CTL_ELEM_IFACE_MIXER; + return find_eos(s); +} + +/* + * These types of input strings are accepted: + * + * unsigned integer - numid (equivaled to numid=UINT) + * string - basic mixer name (equivalent to iface=MIXER,name=STR) + * numid=UINT + * [iface=MIXER,][device=UINT,][subdevice=UINT,]name=STR[,index=UINT] + */ +static ssize_t set_led_id(struct snd_ctl_led_card *led_card, const char *buf, size_t count, + bool attach) +{ + char buf2[256], *s; + size_t len = max(sizeof(s) - 1, count); + struct snd_ctl_elem_id id; + int err; + + strncpy(buf2, buf, len); + buf2[len] = '\0'; + memset(&id, 0, sizeof(id)); + id.iface = SNDRV_CTL_ELEM_IFACE_MIXER; + s = buf2; + while (*s) { + if (!strncasecmp(s, "numid=", 6)) { + s = parse_uint(s + 6, &id.numid); + } else if (!strncasecmp(s, "iface=", 6)) { + s = parse_iface(s + 6, &id.iface); + } else if (!strncasecmp(s, "device=", 7)) { + s = parse_uint(s + 7, &id.device); + } else if (!strncasecmp(s, "subdevice=", 10)) { + s = parse_uint(s + 10, &id.subdevice); + } else if (!strncasecmp(s, "name=", 5)) { + s = parse_string(s + 5, id.name, sizeof(id.name)); + } else if (!strncasecmp(s, "index=", 6)) { + s = parse_uint(s + 6, &id.index); + } else if (s == buf2) { + while (*s) { + if (*s < '0' || *s > '9') + break; + s++; + } + if (*s == '\0') + parse_uint(buf2, &id.numid); + else { + for (; *s >= ' '; s++); + *s = '\0'; + strlcpy(id.name, buf2, sizeof(id.name)); + } + break; + } + if (*s == ',') + s++; + } + + err = snd_ctl_led_set_id(led_card->number, &id, led_card->led->group, attach); + if (err < 0) + return err; + + return count; +} + +static ssize_t parse_attach(struct device *dev, struct device_attribute *attr, + const char *buf, size_t count) +{ + struct snd_ctl_led_card *led_card = container_of(dev, struct snd_ctl_led_card, dev); + return set_led_id(led_card, buf, count, true); +} + +static ssize_t parse_detach(struct device *dev, struct device_attribute *attr, + const char *buf, size_t count) +{ + struct snd_ctl_led_card *led_card = container_of(dev, struct snd_ctl_led_card, dev); + return set_led_id(led_card, buf, count, false); +} + +static ssize_t ctl_reset(struct device *dev, struct device_attribute *attr, + const char *buf, size_t count) +{ + struct snd_ctl_led_card *led_card = container_of(dev, struct snd_ctl_led_card, dev); + int err; + + if (count > 0 && buf[0] == '1') { + err = snd_ctl_led_reset(led_card->number, led_card->led->group); + if (err < 0) + return err; + } + return count; +} + +static ssize_t ctl_list(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct snd_ctl_led_card *led_card = container_of(dev, struct snd_ctl_led_card, dev); + struct snd_card *card; + struct snd_ctl_led_ctl *lctl; + char *buf2 = buf; + size_t l; + + card = snd_card_ref(led_card->number); + if (!card) + return -ENXIO; + down_read(&card->controls_rwsem); + mutex_lock(&snd_ctl_led_mutex); + if (snd_ctl_led_card_valid[led_card->number]) { + list_for_each_entry(lctl, &led_card->led->controls, list) + if (lctl->card == card) { + if (buf2 - buf > PAGE_SIZE - 16) + break; + if (buf2 != buf) + *buf2++ = ' '; + l = scnprintf(buf2, 15, "%u", + lctl->kctl->id.numid + + lctl->index_offset); + buf2[l] = '\0'; + buf2 += l + 1; + } + } + mutex_unlock(&snd_ctl_led_mutex); + up_read(&card->controls_rwsem); + snd_card_unref(card); + return buf2 - buf; +} + +static DEVICE_ATTR(attach, 0200, NULL, parse_attach); +static DEVICE_ATTR(detach, 0200, NULL, parse_detach); +static DEVICE_ATTR(reset, 0200, NULL, ctl_reset); +static DEVICE_ATTR(list, 0444, ctl_list, NULL); + +static struct attribute *snd_ctl_led_card_attrs[] = { + &dev_attr_attach.attr, + &dev_attr_detach.attr, + &dev_attr_reset.attr, + &dev_attr_list.attr, + NULL, +}; + +static const struct attribute_group snd_ctl_led_card_attr_group = { + .attrs = snd_ctl_led_card_attrs, +}; + +static const struct attribute_group *snd_ctl_led_card_attr_groups[] = { + &snd_ctl_led_card_attr_group, + NULL, +}; + static struct device snd_ctl_led_dev; +static void snd_ctl_led_sysfs_add(struct snd_card *card) +{ + unsigned int group; + struct snd_ctl_led_card *led_card; + struct snd_ctl_led *led; + char link_name[32]; + + for (group = 0; group < MAX_LED; group++) { + led = &snd_ctl_leds[group]; + led_card = kzalloc(sizeof(*led_card), GFP_KERNEL); + if (!led_card) + goto cerr2; + led_card->number = card->number; + led_card->led = led; + device_initialize(&led_card->dev); + if (dev_set_name(&led_card->dev, "card%d", card->number) < 0) + goto cerr; + led_card->dev.parent = &led->dev; + led_card->dev.groups = snd_ctl_led_card_attr_groups; + if (device_add(&led_card->dev)) + goto cerr; + led->cards[card->number] = led_card; + snprintf(link_name, sizeof(link_name), "led-%s", led->name); + WARN(sysfs_create_link(&card->ctl_dev.kobj, &led_card->dev.kobj, link_name), + "can't create symlink to controlC%i device\n", card->number); + WARN(sysfs_create_link(&led_card->dev.kobj, &card->card_dev.kobj, "card"), + "can't create symlink to card%i\n", card->number); + + continue; +cerr: + put_device(&led_card->dev); +cerr2: + printk(KERN_ERR "snd_ctl_led: unable to add card%d", card->number); + kfree(led_card); + } +} + +static void snd_ctl_led_sysfs_remove(struct snd_card *card) +{ + unsigned int group; + struct snd_ctl_led_card *led_card; + struct snd_ctl_led *led; + char link_name[32]; + + for (group = 0; group < MAX_LED; group++) { + led = &snd_ctl_leds[group]; + led_card = led->cards[card->number]; + if (!led_card) + continue; + snprintf(link_name, sizeof(link_name), "led-%s", led->name); + sysfs_remove_link(&card->ctl_dev.kobj, link_name); + sysfs_remove_link(&led_card->dev.kobj, "card"); + device_del(&led_card->dev); + kfree(led_card); + led->cards[card->number] = NULL; + } +} + /* * Control layer registration */ @@ -397,14 +745,24 @@ static int __init snd_ctl_led_init(void) static void __exit snd_ctl_led_exit(void) { struct snd_ctl_led *led; - unsigned int group; + struct snd_card *card; + unsigned int group, card_number; + snd_ctl_disconnect_layer(&snd_ctl_led_lops); + for (card_number = 0; card_number < SNDRV_CARDS; card_number++) { + if (!snd_ctl_led_card_valid[card_number]) + continue; + card = snd_card_ref(card_number); + if (card) { + snd_ctl_led_sysfs_remove(card); + snd_card_unref(card); + } + } for (group = 0; group < MAX_LED; group++) { led = &snd_ctl_leds[group]; device_del(&led->dev); } device_del(&snd_ctl_led_dev); - snd_ctl_disconnect_layer(&snd_ctl_led_lops); snd_ctl_led_clean(NULL); } From 8b01a0d0b5c1327296b37a13c37ca7ab31841577 Mon Sep 17 00:00:00 2001 From: Rob Herring Date: Fri, 26 Mar 2021 13:50:03 -0600 Subject: [PATCH 355/587] ASoC: dt-bindings: nvidia, tegra210-ahub: Add missing child nodes The nvidia,tegra210-ahub binding is missing schema for child nodes. This results in warnings if 'additionalProperties: false' is set (or when the tools implement 'unevaluatedProperties' support). Add the child nodes and reference their schema if one exists. Cc: Liam Girdwood Cc: Mark Brown Cc: Thierry Reding Cc: Jonathan Hunter Cc: Sameer Pujar Cc: alsa-devel@alsa-project.org Cc: linux-tegra@vger.kernel.org Signed-off-by: Rob Herring Acked-by: Thierry Reding Acked-by: Sameer Pujar Link: https://lore.kernel.org/r/20210326195003.3756394-1-robh@kernel.org Signed-off-by: Mark Brown --- .../bindings/sound/nvidia,tegra210-ahub.yaml | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/Documentation/devicetree/bindings/sound/nvidia,tegra210-ahub.yaml b/Documentation/devicetree/bindings/sound/nvidia,tegra210-ahub.yaml index 31f3e51974bb..61d0c944e972 100644 --- a/Documentation/devicetree/bindings/sound/nvidia,tegra210-ahub.yaml +++ b/Documentation/devicetree/bindings/sound/nvidia,tegra210-ahub.yaml @@ -66,6 +66,22 @@ properties: number of port nodes depend on the number of clients that AHUB may have depending on the SoC revision. +patternProperties: + '^i2s@[0-9a-f]+$': + type: object + + '^dmic@[0-9a-f]+$': + type: object + $ref: nvidia,tegra210-dmic.yaml# + + '^admaif@[0-9a-f]+$': + type: object + $ref: nvidia,tegra210-admaif.yaml# + + '^dspk@[0-9a-f]+$': + type: object + $ref: nvidia,tegra186-dspk.yaml# + required: - compatible - reg From 89503d736e3631bda906c627d1092dc8e76ddfd9 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Fri, 26 Mar 2021 12:25:57 +0900 Subject: [PATCH 356/587] ASoC: simple-card-utils.c: remove old comment commit adb76b5b9c474 ("ASoC: soc-core: remove legacy style dai_link") removed snd_soc_init_multicodec(). The comment on asoc_simple_init_priv() is no longer needed. This patch removes it. Signed-off-by: Kuninori Morimoto Link: https://lore.kernel.org/r/87czvm1tq2.wl-kuninori.morimoto.gx@renesas.com Signed-off-by: Mark Brown --- sound/soc/generic/simple-card-utils.c | 5 ----- 1 file changed, 5 deletions(-) diff --git a/sound/soc/generic/simple-card-utils.c b/sound/soc/generic/simple-card-utils.c index 06c2512b6f2d..6897455219d1 100644 --- a/sound/soc/generic/simple-card-utils.c +++ b/sound/soc/generic/simple-card-utils.c @@ -617,11 +617,6 @@ int asoc_simple_init_priv(struct asoc_simple_priv *priv, } /* - * Use snd_soc_dai_link_component instead of legacy style - * It is codec only. but cpu/platform will be supported in the future. - * see - * soc-core.c :: snd_soc_init_multicodec() - * * "platform" might be removed * see * simple-card-utils.c :: asoc_simple_canonicalize_platform() From 050c7950fd706fec229af9f30e8ce254cea9b675 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Fri, 26 Mar 2021 12:26:06 +0900 Subject: [PATCH 357/587] ASoC: simple-card-utils: alloc dai_link information for CPU/Codec/Platform simple-card / audio-graph are assuming single CPU/Codec/Platform on dai_link. Because of it, it is difficult to support Multi-CPU/Codec. This patch allocs CPU/Codec/Platform dai_link imformation instead of using existing props information. It can update to multi-CPU/Codec, but is still assuming single-CPU/Codec for now. Signed-off-by: Kuninori Morimoto Link: https://lore.kernel.org/r/87blb61tpv.wl-kuninori.morimoto.gx@renesas.com Signed-off-by: Mark Brown --- include/sound/simple_card_utils.h | 7 ++++--- sound/soc/generic/simple-card-utils.c | 15 +++++++++++---- 2 files changed, 15 insertions(+), 7 deletions(-) diff --git a/include/sound/simple_card_utils.h b/include/sound/simple_card_utils.h index ba4a3e1897b9..86e46cbf9e14 100644 --- a/include/sound/simple_card_utils.h +++ b/include/sound/simple_card_utils.h @@ -43,9 +43,9 @@ struct asoc_simple_priv { struct simple_dai_props { struct asoc_simple_dai *cpu_dai; struct asoc_simple_dai *codec_dai; - struct snd_soc_dai_link_component cpus; /* single cpu */ - struct snd_soc_dai_link_component codecs; /* single codec */ - struct snd_soc_dai_link_component platforms; + struct snd_soc_dai_link_component *cpus; + struct snd_soc_dai_link_component *codecs; + struct snd_soc_dai_link_component *platforms; struct asoc_simple_data adata; struct snd_soc_codec_conf *codec_conf; unsigned int mclk_fs; @@ -54,6 +54,7 @@ struct asoc_simple_priv { struct asoc_simple_jack mic_jack; struct snd_soc_dai_link *dai_link; struct asoc_simple_dai *dais; + struct snd_soc_dai_link_component *dlcs; struct snd_soc_codec_conf *codec_conf; struct gpio_desc *pa_gpio; const struct snd_soc_ops *ops; diff --git a/sound/soc/generic/simple-card-utils.c b/sound/soc/generic/simple-card-utils.c index 6897455219d1..f05954529dfc 100644 --- a/sound/soc/generic/simple-card-utils.c +++ b/sound/soc/generic/simple-card-utils.c @@ -601,13 +601,15 @@ int asoc_simple_init_priv(struct asoc_simple_priv *priv, struct snd_soc_dai_link *dai_link; struct simple_dai_props *dai_props; struct asoc_simple_dai *dais; + struct snd_soc_dai_link_component *dlcs; struct snd_soc_codec_conf *cconf = NULL; int i; dai_props = devm_kcalloc(dev, li->link, sizeof(*dai_props), GFP_KERNEL); dai_link = devm_kcalloc(dev, li->link, sizeof(*dai_link), GFP_KERNEL); dais = devm_kcalloc(dev, li->dais, sizeof(*dais), GFP_KERNEL); - if (!dai_props || !dai_link || !dais) + dlcs = devm_kcalloc(dev, li->link * 3, sizeof(*dai_props), GFP_KERNEL); + if (!dai_props || !dai_link || !dais || !dlcs) return -ENOMEM; if (li->conf) { @@ -622,17 +624,22 @@ int asoc_simple_init_priv(struct asoc_simple_priv *priv, * simple-card-utils.c :: asoc_simple_canonicalize_platform() */ for (i = 0; i < li->link; i++) { - dai_link[i].cpus = &dai_props[i].cpus; + dai_props[i].cpus = dlcs + (3 * i) + 0; + dai_props[i].codecs = dlcs + (3 * i) + 1; + dai_props[i].platforms = dlcs + (3 * i) + 2; + + dai_link[i].cpus = dai_props[i].cpus; dai_link[i].num_cpus = 1; - dai_link[i].codecs = &dai_props[i].codecs; + dai_link[i].codecs = dai_props[i].codecs; dai_link[i].num_codecs = 1; - dai_link[i].platforms = &dai_props[i].platforms; + dai_link[i].platforms = dai_props[i].platforms; dai_link[i].num_platforms = 1; } priv->dai_props = dai_props; priv->dai_link = dai_link; priv->dais = dais; + priv->dlcs = dlcs; priv->codec_conf = cconf; card->dai_link = priv->dai_link; From 674b9438e2d4c44f45af2a38521767c06c46eacb Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Fri, 26 Mar 2021 12:26:11 +0900 Subject: [PATCH 358/587] ASoC: audio-graph: count DAI / link numbers as in order audio-graph checks DT links 2 times. 1st is for counting DAIs / links to allocating memory, 2nd is for detecting DAIs. To detecting DAIs as CPU-dummy -> dummy-Codec order when DPCM case, it uses loops 2 times at 2nd DT link check. But it doesn't do it at 1st DT link check. for (li.cpu = 1; li.cpu >= 0; li.cpu--) { /* * Detect all CPU first, and Detect all Codec 2n * * In Normal sound case, all DAIs are detected * as "CPU-Codec". * * In DPCM sound case, * all CPUs are detected as "CPU-dummy", and * all Codecs are detected as "dummy-Codec". * To avoid random sub-device numbering, * detect "dummy-Codec" in last; */ ret = graph_for_each_link(...); ... } To prepare supporting multi-CPU/Codec, and code cleanup, this patch use same loop for 1st DT link check, too. Signed-off-by: Kuninori Morimoto Link: https://lore.kernel.org/r/87a6qq1tpp.wl-kuninori.morimoto.gx@renesas.com Signed-off-by: Mark Brown --- sound/soc/generic/audio-graph-card.c | 29 ++++++++++++++++++++++------ 1 file changed, 23 insertions(+), 6 deletions(-) diff --git a/sound/soc/generic/audio-graph-card.c b/sound/soc/generic/audio-graph-card.c index 8c5cdcdc8713..3a967c520b01 100644 --- a/sound/soc/generic/audio-graph-card.c +++ b/sound/soc/generic/audio-graph-card.c @@ -617,6 +617,10 @@ static int graph_count_noml(struct asoc_simple_priv *priv, { struct device *dev = simple_priv_to_dev(priv); + /* Do it only CPU turn */ + if (!li->cpu) + return 0; + li->link += 1; /* 1xCPU-Codec */ li->dais += 2; /* 1xCPU + 1xCodec */ @@ -633,10 +637,22 @@ static int graph_count_dpcm(struct asoc_simple_priv *priv, { struct device *dev = simple_priv_to_dev(priv); - li->link++; /* 1xCPU-dummy */ - li->dais++; /* 1xCPU */ + /* + * Codec endpoint can be NULL for pluggable audio HW. + * Platform DT can populate the Codec endpoint depending on the + * plugged HW. + */ + if (!li->cpu && !codec_ep) + return 0; - if (!dup_codec && codec_ep) { + /* Do it all CPU endpoint, and 1st Codec endpoint */ + if (!li->cpu && dup_codec) + return 0; + + if (li->cpu) { + li->link++; /* 1xCPU-dummy */ + li->dais++; /* 1xCPU */ + } else if (!dup_codec && codec_ep) { li->link++; /* 1xdummy-Codec */ li->conf++; /* 1xdummy-Codec */ li->dais++; /* 1xCodec */ @@ -698,9 +714,10 @@ static void graph_get_dais_count(struct asoc_simple_priv *priv, * => 4 DAIs = 2xCPU + 2xCodec * => 1 ccnf = 1xdummy-Codec */ - graph_for_each_link(priv, li, - graph_count_noml, - graph_count_dpcm); + for (li->cpu = 1; li->cpu >= 0; li->cpu--) + graph_for_each_link(priv, li, + graph_count_noml, + graph_count_dpcm); dev_dbg(dev, "link %d, dais %d, ccnf %d\n", li->link, li->dais, li->conf); } From e9cbcf23a28b41a310a13d0b1b67501948b255fb Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Fri, 26 Mar 2021 12:26:20 +0900 Subject: [PATCH 359/587] ASoC: audio-graph: cleanup graph_for_each_link() audio-graph checks DT links 2 times. 1st is for counting DAIs / links to allocating memory, 2nd is for detecting DAIs. To detecting DAIs as CPU-dummy -> dummy-Codec order when DPCM case, it uses loops 2 times. Because of this kind of complex background, it needs to use local varuable for it, and each call-back functions need to care about it. Now, 1st and 2nd DT link check are using same order, thus we can share same code. This patch do it. Signed-off-by: Kuninori Morimoto Link: https://lore.kernel.org/r/878s6a1tpf.wl-kuninori.morimoto.gx@renesas.com Signed-off-by: Mark Brown --- sound/soc/generic/audio-graph-card.c | 129 +++++++++++++-------------- 1 file changed, 61 insertions(+), 68 deletions(-) diff --git a/sound/soc/generic/audio-graph-card.c b/sound/soc/generic/audio-graph-card.c index 3a967c520b01..ee1d924d68e5 100644 --- a/sound/soc/generic/audio-graph-card.c +++ b/sound/soc/generic/audio-graph-card.c @@ -212,8 +212,7 @@ static void graph_parse_mclk_fs(struct device_node *top, static int graph_dai_link_of_dpcm(struct asoc_simple_priv *priv, struct device_node *cpu_ep, struct device_node *codec_ep, - struct link_info *li, - int dup_codec) + struct link_info *li) { struct device *dev = simple_priv_to_dev(priv); struct snd_soc_card *card = simple_priv_to_card(priv); @@ -229,18 +228,6 @@ static int graph_dai_link_of_dpcm(struct asoc_simple_priv *priv, struct snd_soc_dai_link_component *codecs = dai_link->codecs; int ret; - /* - * Codec endpoint can be NULL for pluggable audio HW. - * Platform DT can populate the Codec endpoint depending on the - * plugged HW. - */ - if (!li->cpu && !codec_ep) - return 0; - - /* Do it all CPU endpoint, and 1st Codec endpoint */ - if (!li->cpu && dup_codec) - return 0; - port = of_get_parent(ep); ports = of_get_parent(port); node = of_graph_get_port_parent(ep); @@ -382,10 +369,6 @@ static int graph_dai_link_of(struct asoc_simple_priv *priv, struct asoc_simple_dai *codec_dai; int ret, single_cpu; - /* Do it only CPU turn */ - if (!li->cpu) - return 0; - dev_dbg(dev, "link_of (%pOF)\n", cpu_ep); li->link++; @@ -466,7 +449,7 @@ static inline bool parse_as_dpcm_link(struct asoc_simple_priv *priv, return false; } -static int graph_for_each_link(struct asoc_simple_priv *priv, +static int __graph_for_each_link(struct asoc_simple_priv *priv, struct link_info *li, int (*func_noml)(struct asoc_simple_priv *priv, struct device_node *cpu_ep, @@ -475,7 +458,7 @@ static int graph_for_each_link(struct asoc_simple_priv *priv, int (*func_dpcm)(struct asoc_simple_priv *priv, struct device_node *cpu_ep, struct device_node *codec_ep, - struct link_info *li, int dup_codec)) + struct link_info *li)) { struct of_phandle_iterator it; struct device *dev = simple_priv_to_dev(priv); @@ -486,7 +469,7 @@ static int graph_for_each_link(struct asoc_simple_priv *priv, struct device_node *codec_port; struct device_node *codec_port_old = NULL; struct asoc_simple_data adata; - int rc, ret; + int rc, ret = 0; /* loop for all listed CPU port */ of_for_each_phandle(&it, rc, node, "dais", NULL, 0) { @@ -509,12 +492,21 @@ static int graph_for_each_link(struct asoc_simple_priv *priv, graph_parse_convert(dev, cpu_ep, &adata); /* check if link requires DPCM parsing */ - if (parse_as_dpcm_link(priv, codec_port, &adata)) - ret = func_dpcm(priv, cpu_ep, codec_ep, li, - (codec_port_old == codec_port)); + if (parse_as_dpcm_link(priv, codec_port, &adata)) { + /* + * Codec endpoint can be NULL for pluggable audio HW. + * Platform DT can populate the Codec endpoint depending on the + * plugged HW. + */ + /* Do it all CPU endpoint, and 1st Codec endpoint */ + if (li->cpu || + ((codec_port_old != codec_port) && codec_ep)) + ret = func_dpcm(priv, cpu_ep, codec_ep, li); /* else normal sound */ - else - ret = func_noml(priv, cpu_ep, codec_ep, li); + } else { + if (li->cpu) + ret = func_noml(priv, cpu_ep, codec_ep, li); + } of_node_put(codec_ep); of_node_put(codec_port); @@ -529,6 +521,39 @@ static int graph_for_each_link(struct asoc_simple_priv *priv, return 0; } +static int graph_for_each_link(struct asoc_simple_priv *priv, + struct link_info *li, + int (*func_noml)(struct asoc_simple_priv *priv, + struct device_node *cpu_ep, + struct device_node *codec_ep, + struct link_info *li), + int (*func_dpcm)(struct asoc_simple_priv *priv, + struct device_node *cpu_ep, + struct device_node *codec_ep, + struct link_info *li)) +{ + int ret; + /* + * Detect all CPU first, and Detect all Codec 2nd. + * + * In Normal sound case, all DAIs are detected + * as "CPU-Codec". + * + * In DPCM sound case, + * all CPUs are detected as "CPU-dummy", and + * all Codecs are detected as "dummy-Codec". + * To avoid random sub-device numbering, + * detect "dummy-Codec" in last; + */ + for (li->cpu = 1; li->cpu >= 0; li->cpu--) { + ret = __graph_for_each_link(priv, li, func_noml, func_dpcm); + if (ret < 0) + break; + } + + return ret; +} + static void graph_get_dais_count(struct asoc_simple_priv *priv, struct link_info *li); @@ -566,25 +591,11 @@ int audio_graph_parse_of(struct asoc_simple_priv *priv, struct device *dev) return ret; memset(&li, 0, sizeof(li)); - for (li.cpu = 1; li.cpu >= 0; li.cpu--) { - /* - * Detect all CPU first, and Detect all Codec 2nd. - * - * In Normal sound case, all DAIs are detected - * as "CPU-Codec". - * - * In DPCM sound case, - * all CPUs are detected as "CPU-dummy", and - * all Codecs are detected as "dummy-Codec". - * To avoid random sub-device numbering, - * detect "dummy-Codec" in last; - */ - ret = graph_for_each_link(priv, &li, - graph_dai_link_of, - graph_dai_link_of_dpcm); - if (ret < 0) - goto err; - } + ret = graph_for_each_link(priv, &li, + graph_dai_link_of, + graph_dai_link_of_dpcm); + if (ret < 0) + goto err; ret = asoc_simple_parse_card_name(card, NULL); if (ret < 0) @@ -617,10 +628,6 @@ static int graph_count_noml(struct asoc_simple_priv *priv, { struct device *dev = simple_priv_to_dev(priv); - /* Do it only CPU turn */ - if (!li->cpu) - return 0; - li->link += 1; /* 1xCPU-Codec */ li->dais += 2; /* 1xCPU + 1xCodec */ @@ -632,27 +639,14 @@ static int graph_count_noml(struct asoc_simple_priv *priv, static int graph_count_dpcm(struct asoc_simple_priv *priv, struct device_node *cpu_ep, struct device_node *codec_ep, - struct link_info *li, - int dup_codec) + struct link_info *li) { struct device *dev = simple_priv_to_dev(priv); - /* - * Codec endpoint can be NULL for pluggable audio HW. - * Platform DT can populate the Codec endpoint depending on the - * plugged HW. - */ - if (!li->cpu && !codec_ep) - return 0; - - /* Do it all CPU endpoint, and 1st Codec endpoint */ - if (!li->cpu && dup_codec) - return 0; - if (li->cpu) { li->link++; /* 1xCPU-dummy */ li->dais++; /* 1xCPU */ - } else if (!dup_codec && codec_ep) { + } else { li->link++; /* 1xdummy-Codec */ li->conf++; /* 1xdummy-Codec */ li->dais++; /* 1xCodec */ @@ -714,10 +708,9 @@ static void graph_get_dais_count(struct asoc_simple_priv *priv, * => 4 DAIs = 2xCPU + 2xCodec * => 1 ccnf = 1xdummy-Codec */ - for (li->cpu = 1; li->cpu >= 0; li->cpu--) - graph_for_each_link(priv, li, - graph_count_noml, - graph_count_dpcm); + graph_for_each_link(priv, li, + graph_count_noml, + graph_count_dpcm); dev_dbg(dev, "link %d, dais %d, ccnf %d\n", li->link, li->dais, li->conf); } From a6e8798061bf0f33caea6fd47b0cb367309e34d0 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Fri, 26 Mar 2021 12:26:33 +0900 Subject: [PATCH 360/587] ASoC: simple-card: count DAI / link numbers as in order simple-card checks DT links 2 times. 1st is for counting DAIs / links to allocating memory, 2nd is for detecting DAIs. To detecting DAIs as CPU-dummy -> dummy-Codec order when DPCM case, it uses loops 2 times at 2nd DT link check. But it doesn't do it at 1st DT link check. for (li.cpu = 1; li.cpu >= 0; li.cpu--) { /* * Detect all CPU first, and Detect all Codec 2n * * In Normal sound case, all DAIs are detected * as "CPU-Codec". * * In DPCM sound case, * all CPUs are detected as "CPU-dummy", and * all Codecs are detected as "dummy-Codec". * To avoid random sub-device numbering, * detect "dummy-Codec" in last; */ ret = simple_for_each_link(...); ... } To prepare supporting multi-CPU/Codec, and code cleanup, this patch use same loop for 1st DT link check, too. Signed-off-by: Kuninori Morimoto Link: https://lore.kernel.org/r/877dlu1tp2.wl-kuninori.morimoto.gx@renesas.com Signed-off-by: Mark Brown --- sound/soc/generic/simple-card.c | 40 +++++++++++++++++++++++++-------- 1 file changed, 31 insertions(+), 9 deletions(-) diff --git a/sound/soc/generic/simple-card.c b/sound/soc/generic/simple-card.c index 75365c7bb393..f53f76ee0a8b 100644 --- a/sound/soc/generic/simple-card.c +++ b/sound/soc/generic/simple-card.c @@ -483,9 +483,17 @@ static int simple_count_noml(struct asoc_simple_priv *priv, struct device_node *codec, struct link_info *li, bool is_top) { - li->dais++; /* CPU or Codec */ - if (np != codec) - li->link++; /* CPU-Codec */ + /* + * |CPU |Codec : turn + * CPU |Pass |return + * Codec |return|return + * np + */ + if (!li->cpu || np == codec) + return 0; + + li->link += 1; + li->dais += 2; return 0; } @@ -495,10 +503,23 @@ static int simple_count_dpcm(struct asoc_simple_priv *priv, struct device_node *codec, struct link_info *li, bool is_top) { - li->dais++; /* CPU or Codec */ - li->link++; /* CPU-dummy or dummy-Codec */ - if (np == codec) + /* + * |CPU |Codec : turn + * CPU |Pass |return + * Codec |return|Pass + * np + */ + if (li->cpu == (np == codec)) + return 0; + + if (li->cpu) { + li->link++; /* CPU-dummy */ + li->dais++; + } else { + li->link++; /* dummy-Codec */ + li->dais++; li->conf++; + } return 0; } @@ -562,9 +583,10 @@ static void simple_get_dais_count(struct asoc_simple_priv *priv, return; } - simple_for_each_link(priv, li, - simple_count_noml, - simple_count_dpcm); + for (li->cpu = 1; li->cpu >= 0; li->cpu--) + simple_for_each_link(priv, li, + simple_count_noml, + simple_count_dpcm); dev_dbg(dev, "link %d, dais %d, ccnf %d\n", li->link, li->dais, li->conf); From 39af7f7a03d007e5590f0b852b3f2fed9e703d0f Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Fri, 26 Mar 2021 12:26:40 +0900 Subject: [PATCH 361/587] ASoC: simple-card: cleanup graph_for_each_link() simple-card checks DT links 2 times. 1st is for counting DAIs / links to allocating memory, 2nd is for detecting DAIs. To detecting DAIs as CPU-dummy -> dummy-Codec order when DPCM case, it uses loops 2 times. Because of this kind of complex background, it needs to use local varuable for it, and each call-back functions need to care about it. Now, 1st and 2nd DT link check are using same order, thus we can share same code. This patch do it. Signed-off-by: Kuninori Morimoto Link: https://lore.kernel.org/r/875z1e1tov.wl-kuninori.morimoto.gx@renesas.com Signed-off-by: Mark Brown --- sound/soc/generic/simple-card.c | 125 ++++++++++++++++---------------- 1 file changed, 61 insertions(+), 64 deletions(-) diff --git a/sound/soc/generic/simple-card.c b/sound/soc/generic/simple-card.c index f53f76ee0a8b..41aa40765a8d 100644 --- a/sound/soc/generic/simple-card.c +++ b/sound/soc/generic/simple-card.c @@ -129,15 +129,6 @@ static int simple_dai_link_of_dpcm(struct asoc_simple_priv *priv, char *prefix = ""; int ret; - /* - * |CPU |Codec : turn - * CPU |Pass |return - * Codec |return|Pass - * np - */ - if (li->cpu == (np == codec)) - return 0; - dev_dbg(dev, "link_of DPCM (%pOF)\n", np); li->link++; @@ -260,15 +251,6 @@ static int simple_dai_link_of(struct asoc_simple_priv *priv, char *prefix = ""; int ret, single_cpu; - /* - * |CPU |Codec : turn - * CPU |Pass |return - * Codec |return|return - * np - */ - if (!li->cpu || np == codec) - return 0; - cpu = np; node = of_get_parent(np); li->link++; @@ -342,7 +324,7 @@ dai_link_of_err: return ret; } -static int simple_for_each_link(struct asoc_simple_priv *priv, +static int __simple_for_each_link(struct asoc_simple_priv *priv, struct link_info *li, int (*func_noml)(struct asoc_simple_priv *priv, struct device_node *np, @@ -402,11 +384,26 @@ static int simple_for_each_link(struct asoc_simple_priv *priv, */ if (dpcm_selectable && (num > 2 || - adata.convert_rate || adata.convert_channels)) - ret = func_dpcm(priv, np, codec, li, is_top); + adata.convert_rate || adata.convert_channels)) { + /* + * np + * |1(CPU)|0(Codec) li->cpu + * CPU |Pass |return + * Codec |return|Pass + */ + if (li->cpu != (np == codec)) + ret = func_dpcm(priv, np, codec, li, is_top); /* else normal sound */ - else - ret = func_noml(priv, np, codec, li, is_top); + } else { + /* + * np + * |1(CPU)|0(Codec) li->cpu + * CPU |Pass |return + * Codec |return|return + */ + if (li->cpu && (np != codec)) + ret = func_noml(priv, np, codec, li, is_top); + } if (ret < 0) { of_node_put(codec); @@ -424,6 +421,39 @@ static int simple_for_each_link(struct asoc_simple_priv *priv, return ret; } +static int simple_for_each_link(struct asoc_simple_priv *priv, + struct link_info *li, + int (*func_noml)(struct asoc_simple_priv *priv, + struct device_node *np, + struct device_node *codec, + struct link_info *li, bool is_top), + int (*func_dpcm)(struct asoc_simple_priv *priv, + struct device_node *np, + struct device_node *codec, + struct link_info *li, bool is_top)) +{ + int ret; + /* + * Detect all CPU first, and Detect all Codec 2nd. + * + * In Normal sound case, all DAIs are detected + * as "CPU-Codec". + * + * In DPCM sound case, + * all CPUs are detected as "CPU-dummy", and + * all Codecs are detected as "dummy-Codec". + * To avoid random sub-device numbering, + * detect "dummy-Codec" in last; + */ + for (li->cpu = 1; li->cpu >= 0; li->cpu--) { + ret = __simple_for_each_link(priv, li, func_noml, func_dpcm); + if (ret < 0) + break; + } + + return ret; +} + static int simple_parse_of(struct asoc_simple_priv *priv) { struct device *dev = simple_priv_to_dev(priv); @@ -449,25 +479,11 @@ static int simple_parse_of(struct asoc_simple_priv *priv) /* Single/Muti DAI link(s) & New style of DT node */ memset(&li, 0, sizeof(li)); - for (li.cpu = 1; li.cpu >= 0; li.cpu--) { - /* - * Detect all CPU first, and Detect all Codec 2nd. - * - * In Normal sound case, all DAIs are detected - * as "CPU-Codec". - * - * In DPCM sound case, - * all CPUs are detected as "CPU-dummy", and - * all Codecs are detected as "dummy-Codec". - * To avoid random sub-device numbering, - * detect "dummy-Codec" in last; - */ - ret = simple_for_each_link(priv, &li, - simple_dai_link_of, - simple_dai_link_of_dpcm); - if (ret < 0) - return ret; - } + ret = simple_for_each_link(priv, &li, + simple_dai_link_of, + simple_dai_link_of_dpcm); + if (ret < 0) + return ret; ret = asoc_simple_parse_card_name(card, PREFIX); if (ret < 0) @@ -483,15 +499,6 @@ static int simple_count_noml(struct asoc_simple_priv *priv, struct device_node *codec, struct link_info *li, bool is_top) { - /* - * |CPU |Codec : turn - * CPU |Pass |return - * Codec |return|return - * np - */ - if (!li->cpu || np == codec) - return 0; - li->link += 1; li->dais += 2; @@ -503,15 +510,6 @@ static int simple_count_dpcm(struct asoc_simple_priv *priv, struct device_node *codec, struct link_info *li, bool is_top) { - /* - * |CPU |Codec : turn - * CPU |Pass |return - * Codec |return|Pass - * np - */ - if (li->cpu == (np == codec)) - return 0; - if (li->cpu) { li->link++; /* CPU-dummy */ li->dais++; @@ -583,10 +581,9 @@ static void simple_get_dais_count(struct asoc_simple_priv *priv, return; } - for (li->cpu = 1; li->cpu >= 0; li->cpu--) - simple_for_each_link(priv, li, - simple_count_noml, - simple_count_dpcm); + simple_for_each_link(priv, li, + simple_count_noml, + simple_count_dpcm); dev_dbg(dev, "link %d, dais %d, ccnf %d\n", li->link, li->dais, li->conf); From 875c40eadf6ac6644c0f71842a4f30dd9968d281 Mon Sep 17 00:00:00 2001 From: Hans de Goede Date: Thu, 25 Mar 2021 23:10:54 +0100 Subject: [PATCH 362/587] ASoC: Intel: bytcr_rt5640: Add quirk for the Chuwi Hi8 tablet The Chuwi Hi8 tablet is using an analog mic on IN1 and has its jack-detect connected to JD2_IN4N, instead of using the default IN3 for its internal mic and JD1_IN4P for jack-detect. It also only has 1 speaker. Add a quirk applying the correct settings for this configuration. Signed-off-by: Hans de Goede Link: https://lore.kernel.org/r/20210325221054.22714-1-hdegoede@redhat.com Signed-off-by: Mark Brown --- sound/soc/intel/boards/bytcr_rt5640.c | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/sound/soc/intel/boards/bytcr_rt5640.c b/sound/soc/intel/boards/bytcr_rt5640.c index 59d6d47c8d82..df2f5d55e8ff 100644 --- a/sound/soc/intel/boards/bytcr_rt5640.c +++ b/sound/soc/intel/boards/bytcr_rt5640.c @@ -518,6 +518,23 @@ static const struct dmi_system_id byt_rt5640_quirk_table[] = { BYT_RT5640_SSP0_AIF1 | BYT_RT5640_MCLK_EN), }, + { + /* Chuwi Hi8 (CWI509) */ + .matches = { + DMI_MATCH(DMI_BOARD_VENDOR, "Hampoo"), + DMI_MATCH(DMI_BOARD_NAME, "BYT-PA03C"), + DMI_MATCH(DMI_SYS_VENDOR, "ilife"), + DMI_MATCH(DMI_PRODUCT_NAME, "S806"), + }, + .driver_data = (void *)(BYT_RT5640_IN1_MAP | + BYT_RT5640_JD_SRC_JD2_IN4N | + BYT_RT5640_OVCD_TH_2000UA | + BYT_RT5640_OVCD_SF_0P75 | + BYT_RT5640_MONO_SPEAKER | + BYT_RT5640_DIFF_MIC | + BYT_RT5640_SSP0_AIF1 | + BYT_RT5640_MCLK_EN), + }, { .matches = { DMI_MATCH(DMI_SYS_VENDOR, "Circuitco"), From d8c5c82e4e5b641404c65bfc6cdf57b5d0a6c836 Mon Sep 17 00:00:00 2001 From: Viorel Suman Date: Wed, 31 Mar 2021 15:44:45 +0800 Subject: [PATCH 363/587] ASoC: ak5558: Add support for ak5552 AK5552 is a 32-bit 2ch ADC and has the same register map as AK5558. Signed-off-by: Viorel Suman Signed-off-by: Shengjiu Wang Link: https://lore.kernel.org/r/1617176686-25528-1-git-send-email-shengjiu.wang@nxp.com Signed-off-by: Mark Brown --- sound/soc/codecs/ak5558.c | 97 ++++++++++++++++++++++++++++++++++++--- 1 file changed, 90 insertions(+), 7 deletions(-) diff --git a/sound/soc/codecs/ak5558.c b/sound/soc/codecs/ak5558.c index 85bdd0534180..3ac62a281807 100644 --- a/sound/soc/codecs/ak5558.c +++ b/sound/soc/codecs/ak5558.c @@ -9,6 +9,7 @@ #include #include #include +#include #include #include #include @@ -23,6 +24,11 @@ #include "ak5558.h" +enum ak555x_type { + AK5558, + AK5552, +}; + #define AK5558_NUM_SUPPLIES 2 static const char *ak5558_supply_names[AK5558_NUM_SUPPLIES] = { "DVDD", @@ -59,6 +65,15 @@ static const struct soc_enum ak5558_mono_enum[] = { ARRAY_SIZE(mono_texts), mono_texts), }; +static const char * const mono_5552_texts[] = { + "2 Slot", "1 Slot (Fixed)", "2 Slot", "1 Slot (Optimal)", +}; + +static const struct soc_enum ak5552_mono_enum[] = { + SOC_ENUM_SINGLE(AK5558_01_POWER_MANAGEMENT2, 1, + ARRAY_SIZE(mono_5552_texts), mono_5552_texts), +}; + static const char * const digfil_texts[] = { "Sharp Roll-Off", "Show Roll-Off", "Short Delay Sharp Roll-Off", "Short Delay Show Roll-Off", @@ -70,8 +85,13 @@ static const struct soc_enum ak5558_adcset_enum[] = { }; static const struct snd_kcontrol_new ak5558_snd_controls[] = { - SOC_ENUM("AK5558 Monaural Mode", ak5558_mono_enum[0]), - SOC_ENUM("AK5558 Digital Filter", ak5558_adcset_enum[0]), + SOC_ENUM("Monaural Mode", ak5558_mono_enum[0]), + SOC_ENUM("Digital Filter", ak5558_adcset_enum[0]), +}; + +static const struct snd_kcontrol_new ak5552_snd_controls[] = { + SOC_ENUM("Monaural Mode", ak5552_mono_enum[0]), + SOC_ENUM("Digital Filter", ak5558_adcset_enum[0]), }; static const struct snd_soc_dapm_widget ak5558_dapm_widgets[] = { @@ -97,6 +117,17 @@ static const struct snd_soc_dapm_widget ak5558_dapm_widgets[] = { SND_SOC_DAPM_AIF_OUT("SDTO", "Capture", 0, SND_SOC_NOPM, 0, 0), }; +static const struct snd_soc_dapm_widget ak5552_dapm_widgets[] = { + /* Analog Input */ + SND_SOC_DAPM_INPUT("AIN1"), + SND_SOC_DAPM_INPUT("AIN2"), + + SND_SOC_DAPM_ADC("ADC Ch1", NULL, AK5558_00_POWER_MANAGEMENT1, 0, 0), + SND_SOC_DAPM_ADC("ADC Ch2", NULL, AK5558_00_POWER_MANAGEMENT1, 1, 0), + + SND_SOC_DAPM_AIF_OUT("SDTO", "Capture", 0, SND_SOC_NOPM, 0, 0), +}; + static const struct snd_soc_dapm_route ak5558_intercon[] = { {"ADC Ch1", NULL, "AIN1"}, {"SDTO", NULL, "ADC Ch1"}, @@ -123,6 +154,14 @@ static const struct snd_soc_dapm_route ak5558_intercon[] = { {"SDTO", NULL, "ADC Ch8"}, }; +static const struct snd_soc_dapm_route ak5552_intercon[] = { + {"ADC Ch1", NULL, "AIN1"}, + {"SDTO", NULL, "ADC Ch1"}, + + {"ADC Ch2", NULL, "AIN2"}, + {"SDTO", NULL, "ADC Ch2"}, +}; + static int ak5558_set_mcki(struct snd_soc_component *component) { return snd_soc_component_update_bits(component, AK5558_02_CONTROL1, AK5558_CKS, @@ -267,6 +306,18 @@ static struct snd_soc_dai_driver ak5558_dai = { .ops = &ak5558_dai_ops, }; +static struct snd_soc_dai_driver ak5552_dai = { + .name = "ak5558-aif", + .capture = { + .stream_name = "Capture", + .channels_min = 1, + .channels_max = 2, + .rates = SNDRV_PCM_RATE_KNOT, + .formats = AK5558_FORMATS, + }, + .ops = &ak5558_dai_ops, +}; + static void ak5558_power_off(struct ak5558_priv *ak5558) { if (!ak5558->reset_gpiod) @@ -354,6 +405,21 @@ static const struct snd_soc_component_driver soc_codec_dev_ak5558 = { .non_legacy_dai_naming = 1, }; +static const struct snd_soc_component_driver soc_codec_dev_ak5552 = { + .probe = ak5558_probe, + .remove = ak5558_remove, + .controls = ak5552_snd_controls, + .num_controls = ARRAY_SIZE(ak5552_snd_controls), + .dapm_widgets = ak5552_dapm_widgets, + .num_dapm_widgets = ARRAY_SIZE(ak5552_dapm_widgets), + .dapm_routes = ak5552_intercon, + .num_dapm_routes = ARRAY_SIZE(ak5552_intercon), + .idle_bias_on = 1, + .use_pmdown_time = 1, + .endianness = 1, + .non_legacy_dai_naming = 1, +}; + static const struct regmap_config ak5558_regmap = { .reg_bits = 8, .val_bits = 8, @@ -368,6 +434,7 @@ static int ak5558_i2c_probe(struct i2c_client *i2c) { struct ak5558_priv *ak5558; int ret = 0; + int dev_id; int i; ak5558 = devm_kzalloc(&i2c->dev, sizeof(*ak5558), GFP_KERNEL); @@ -396,11 +463,26 @@ static int ak5558_i2c_probe(struct i2c_client *i2c) return ret; } - ret = devm_snd_soc_register_component(&i2c->dev, - &soc_codec_dev_ak5558, - &ak5558_dai, 1); - if (ret) + dev_id = (uintptr_t)of_device_get_match_data(&i2c->dev); + switch (dev_id) { + case AK5552: + ret = devm_snd_soc_register_component(&i2c->dev, + &soc_codec_dev_ak5552, + &ak5552_dai, 1); + break; + case AK5558: + ret = devm_snd_soc_register_component(&i2c->dev, + &soc_codec_dev_ak5558, + &ak5558_dai, 1); + break; + default: + dev_err(&i2c->dev, "unexpected device type\n"); + return -EINVAL; + } + if (ret < 0) { + dev_err(&i2c->dev, "failed to register component: %d\n", ret); return ret; + } pm_runtime_enable(&i2c->dev); regcache_cache_only(ak5558->regmap, true); @@ -416,7 +498,8 @@ static int ak5558_i2c_remove(struct i2c_client *i2c) } static const struct of_device_id ak5558_i2c_dt_ids[] __maybe_unused = { - { .compatible = "asahi-kasei,ak5558"}, + { .compatible = "asahi-kasei,ak5558", .data = (void *) AK5558 }, + { .compatible = "asahi-kasei,ak5552", .data = (void *) AK5552 }, { } }; MODULE_DEVICE_TABLE(of, ak5558_i2c_dt_ids); From 8d246806d510c1bf7da9aab0473dc0f9c9f99308 Mon Sep 17 00:00:00 2001 From: Shengjiu Wang Date: Wed, 31 Mar 2021 15:44:46 +0800 Subject: [PATCH 364/587] ASoC: dt-bindings: ak5558: Add compatible string for ak5552 Add compatible string "asahi-kasei,ak5552" for ak5552 Signed-off-by: Shengjiu Wang Acked-by: Rob Herring Link: https://lore.kernel.org/r/1617176686-25528-2-git-send-email-shengjiu.wang@nxp.com Signed-off-by: Mark Brown --- Documentation/devicetree/bindings/sound/ak5558.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Documentation/devicetree/bindings/sound/ak5558.txt b/Documentation/devicetree/bindings/sound/ak5558.txt index 36934098170c..e28708db6686 100644 --- a/Documentation/devicetree/bindings/sound/ak5558.txt +++ b/Documentation/devicetree/bindings/sound/ak5558.txt @@ -4,7 +4,7 @@ This device supports I2C mode only. Required properties: -- compatible : "asahi-kasei,ak5558" +- compatible : "asahi-kasei,ak5558" or "asahi-kasei,ak5552". - reg : The I2C address of the device. Optional properties: From 50cbf945566b7cdb186c80c389bdfe22850d8d29 Mon Sep 17 00:00:00 2001 From: Bhaskar Chowdhury Date: Mon, 22 Mar 2021 12:19:09 +0530 Subject: [PATCH 365/587] ASoC: Intel: Fix a typo s/struture/structure/ Signed-off-by: Bhaskar Chowdhury Link: https://lore.kernel.org/r/20210322064909.4189290-1-unixbhaskar@gmail.com Signed-off-by: Mark Brown --- sound/soc/intel/atom/sst-mfld-dsp.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sound/soc/intel/atom/sst-mfld-dsp.h b/sound/soc/intel/atom/sst-mfld-dsp.h index 5795f98e04d4..102b0e7eafb0 100644 --- a/sound/soc/intel/atom/sst-mfld-dsp.h +++ b/sound/soc/intel/atom/sst-mfld-dsp.h @@ -358,7 +358,7 @@ struct snd_wma_params { u8 reserved; /* reserved */ } __packed; -/* Codec params struture */ +/* Codec params structure */ union snd_sst_codec_params { struct snd_pcm_params pcm_params; struct snd_mp3_params mp3_params; From 868d5c6340d878f44acf73c92923995b896b6454 Mon Sep 17 00:00:00 2001 From: Thierry Reding Date: Tue, 30 Mar 2021 20:06:57 +0200 Subject: [PATCH 366/587] ASoC: tegra: Set driver name explicitly The SoC sound core will generate a driver name by normalizing the card name. However, most of the time that name does not tell anything about the driver and is therefore useless for this purpose. Make the driver name more useful by setting it explicitly during card initialization. Signed-off-by: Thierry Reding Link: https://lore.kernel.org/r/20210330180657.1867971-1-thierry.reding@gmail.com Signed-off-by: Mark Brown --- sound/soc/tegra/tegra_audio_graph_card.c | 1 + 1 file changed, 1 insertion(+) diff --git a/sound/soc/tegra/tegra_audio_graph_card.c b/sound/soc/tegra/tegra_audio_graph_card.c index ddedf18adde1..47b319504c8c 100644 --- a/sound/soc/tegra/tegra_audio_graph_card.c +++ b/sound/soc/tegra/tegra_audio_graph_card.c @@ -198,6 +198,7 @@ static int tegra_audio_graph_probe(struct platform_device *pdev) return -ENOMEM; card = simple_priv_to_card(&priv->simple); + card->driver_name = "tegra-ape"; card->probe = tegra_audio_graph_card_probe; From e896ec390870287dcc92f3b46d80da88f3b4b1f8 Mon Sep 17 00:00:00 2001 From: Jack Yu Date: Wed, 31 Mar 2021 15:10:46 +0800 Subject: [PATCH 367/587] ASoC: rt1019: add address-cells and size-cells information Add address-cells and size-cells information to fix warnings for rt1019.yaml. Signed-off-by: Jack Yu Link: https://lore.kernel.org/r/20210331071046.12526-1-jack.yu@realtek.com Signed-off-by: Mark Brown --- Documentation/devicetree/bindings/sound/rt1019.yaml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/Documentation/devicetree/bindings/sound/rt1019.yaml b/Documentation/devicetree/bindings/sound/rt1019.yaml index c24c29eafa54..3d5a91a942f4 100644 --- a/Documentation/devicetree/bindings/sound/rt1019.yaml +++ b/Documentation/devicetree/bindings/sound/rt1019.yaml @@ -26,6 +26,8 @@ additionalProperties: false examples: - | i2c { + #address-cells = <1>; + #size-cells = <0>; rt1019: codec@28 { compatible = "realtek,rt1019"; reg = <0x28>; From 458c23c509f66c5950da7e5496ea952ad15128f7 Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Fri, 26 Mar 2021 17:16:18 -0500 Subject: [PATCH 368/587] ASoC: lm49453: fix useless assignment before return Cppcheck warning: sound/soc/codecs/lm49453.c:1210:11: style: Variable 'pll_clk' is assigned a value that is never used. [unreadVariable] pll_clk = BIT(4); ^ FIXME: What is the correct fix? /* fll clk slection */ pll_clk = BIT(4); return 0; is the assignment redundant or the 'return 0' a mistake? Signed-off-by: Pierre-Louis Bossart Link: https://lore.kernel.org/r/20210326221619.949961-2-pierre-louis.bossart@linux.intel.com Signed-off-by: Mark Brown --- sound/soc/codecs/lm49453.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/sound/soc/codecs/lm49453.c b/sound/soc/codecs/lm49453.c index eb3dd0bd80d9..fb0fb23537e7 100644 --- a/sound/soc/codecs/lm49453.c +++ b/sound/soc/codecs/lm49453.c @@ -1206,8 +1206,6 @@ static int lm49453_set_dai_sysclk(struct snd_soc_dai *dai, int clk_id, break; case 48000: case 32576: - /* fll clk slection */ - pll_clk = BIT(4); return 0; default: return -EINVAL; From 945b0b58c5d7c6640f9aad2096e4675bc7f5371c Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Fri, 26 Mar 2021 17:16:19 -0500 Subject: [PATCH 369/587] ASoC: da732x: simplify code cppcheck reports a false positive: sound/soc/codecs/da732x.c:1161:25: warning: Either the condition 'indiv<0' is redundant or there is division by zero at line 1161. [zerodivcond] fref = (da732x->sysclk / indiv); ^ sound/soc/codecs/da732x.c:1158:12: note: Assuming that condition 'indiv<0' is not redundant if (indiv < 0) ^ sound/soc/codecs/da732x.c:1161:25: note: Division by zero fref = (da732x->sysclk / indiv); ^ The code is awfully convoluted/confusing and can be simplified with a single variable and the BIT macro. Signed-off-by: Pierre-Louis Bossart Link: https://lore.kernel.org/r/20210326221619.949961-3-pierre-louis.bossart@linux.intel.com Signed-off-by: Mark Brown --- sound/soc/codecs/da732x.c | 17 ++++++----------- sound/soc/codecs/da732x.h | 12 ++++-------- 2 files changed, 10 insertions(+), 19 deletions(-) diff --git a/sound/soc/codecs/da732x.c b/sound/soc/codecs/da732x.c index d43ee7159ae0..42d6a3fc3af5 100644 --- a/sound/soc/codecs/da732x.c +++ b/sound/soc/codecs/da732x.c @@ -168,30 +168,25 @@ static const struct reg_default da732x_reg_cache[] = { static inline int da732x_get_input_div(struct snd_soc_component *component, int sysclk) { int val; - int ret; if (sysclk < DA732X_MCLK_10MHZ) { - val = DA732X_MCLK_RET_0_10MHZ; - ret = DA732X_MCLK_VAL_0_10MHZ; + val = DA732X_MCLK_VAL_0_10MHZ; } else if ((sysclk >= DA732X_MCLK_10MHZ) && (sysclk < DA732X_MCLK_20MHZ)) { - val = DA732X_MCLK_RET_10_20MHZ; - ret = DA732X_MCLK_VAL_10_20MHZ; + val = DA732X_MCLK_VAL_10_20MHZ; } else if ((sysclk >= DA732X_MCLK_20MHZ) && (sysclk < DA732X_MCLK_40MHZ)) { - val = DA732X_MCLK_RET_20_40MHZ; - ret = DA732X_MCLK_VAL_20_40MHZ; + val = DA732X_MCLK_VAL_20_40MHZ; } else if ((sysclk >= DA732X_MCLK_40MHZ) && (sysclk <= DA732X_MCLK_54MHZ)) { - val = DA732X_MCLK_RET_40_54MHZ; - ret = DA732X_MCLK_VAL_40_54MHZ; + val = DA732X_MCLK_VAL_40_54MHZ; } else { return -EINVAL; } snd_soc_component_write(component, DA732X_REG_PLL_CTRL, val); - return ret; + return val; } static void da732x_set_charge_pump(struct snd_soc_component *component, int state) @@ -1158,7 +1153,7 @@ static int da732x_set_dai_pll(struct snd_soc_component *component, int pll_id, if (indiv < 0) return indiv; - fref = (da732x->sysclk / indiv); + fref = da732x->sysclk / BIT(indiv); div_hi = freq_out / fref; frac_div = (u64)(freq_out % fref) * 8192ULL; do_div(frac_div, fref); diff --git a/sound/soc/codecs/da732x.h b/sound/soc/codecs/da732x.h index c5af17ee1516..c2f784c3f359 100644 --- a/sound/soc/codecs/da732x.h +++ b/sound/soc/codecs/da732x.h @@ -48,14 +48,10 @@ #define DA732X_MCLK_20MHZ 20000000 #define DA732X_MCLK_40MHZ 40000000 #define DA732X_MCLK_54MHZ 54000000 -#define DA732X_MCLK_RET_0_10MHZ 0 -#define DA732X_MCLK_VAL_0_10MHZ 1 -#define DA732X_MCLK_RET_10_20MHZ 1 -#define DA732X_MCLK_VAL_10_20MHZ 2 -#define DA732X_MCLK_RET_20_40MHZ 2 -#define DA732X_MCLK_VAL_20_40MHZ 4 -#define DA732X_MCLK_RET_40_54MHZ 3 -#define DA732X_MCLK_VAL_40_54MHZ 8 +#define DA732X_MCLK_VAL_0_10MHZ 0 +#define DA732X_MCLK_VAL_10_20MHZ 1 +#define DA732X_MCLK_VAL_20_40MHZ 2 +#define DA732X_MCLK_VAL_40_54MHZ 3 #define DA732X_DAI_ID1 0 #define DA732X_DAI_ID2 1 #define DA732X_SRCCLK_PLL 0 From 9c1e0439ada9973ec99cc1e0887eb84fd26444b8 Mon Sep 17 00:00:00 2001 From: Rob Herring Date: Wed, 31 Mar 2021 09:27:46 -0500 Subject: [PATCH 370/587] ASoC: dt-bindings: Move port/ports properties out of audio-graph-port.yaml Users of the audio-graph-port schema need to define how many ports and what each port is, so they need to define 'ports' and/or 'port' anyways. Let's drop 'ports' and 'port' from the schema and adjust users to reference audio-graph-port.yaml from a port property. Cc: Liam Girdwood Cc: Mark Brown Cc: Thierry Reding Cc: Jonathan Hunter Cc: Kuninori Morimoto Cc: Lubomir Rintel Cc: Sameer Pujar Cc: alsa-devel@alsa-project.org Cc: linux-tegra@vger.kernel.org Signed-off-by: Rob Herring Link: https://lore.kernel.org/r/20210331142748.2163272-2-robh@kernel.org Signed-off-by: Mark Brown --- .../bindings/sound/audio-graph-port.yaml | 101 ++++++++---------- .../bindings/sound/marvell,mmp-sspa.yaml | 6 +- .../bindings/sound/nvidia,tegra186-dspk.yaml | 11 +- .../sound/nvidia,tegra210-admaif.yaml | 11 +- .../bindings/sound/nvidia,tegra210-ahub.yaml | 11 +- .../bindings/sound/nvidia,tegra210-dmic.yaml | 11 +- .../bindings/sound/nvidia,tegra210-i2s.yaml | 11 +- .../bindings/sound/renesas,rsnd.yaml | 5 +- 8 files changed, 82 insertions(+), 85 deletions(-) diff --git a/Documentation/devicetree/bindings/sound/audio-graph-port.yaml b/Documentation/devicetree/bindings/sound/audio-graph-port.yaml index 766e9109b2f7..9f68142c9ae3 100644 --- a/Documentation/devicetree/bindings/sound/audio-graph-port.yaml +++ b/Documentation/devicetree/bindings/sound/audio-graph-port.yaml @@ -12,70 +12,59 @@ maintainers: select: false properties: - port: - description: single OF-Graph subnode + reg: + maxItems: 1 + prefix: + description: "device name prefix" + $ref: /schemas/types.yaml#/definitions/string + convert-rate: + description: CPU to Codec rate convert. + $ref: /schemas/types.yaml#/definitions/uint32 + convert-channels: + description: CPU to Codec rate channels. + $ref: /schemas/types.yaml#/definitions/uint32 +patternProperties: + "^endpoint(@[0-9a-f]+)?": type: object properties: - reg: + remote-endpoint: maxItems: 1 - prefix: - description: "device name prefix" - $ref: /schemas/types.yaml#/definitions/string + mclk-fs: + description: | + Multiplication factor between stream rate and codec mclk. + When defined, mclk-fs property defined in dai-link sub nodes are + ignored. + $ref: /schemas/types.yaml#/definitions/uint32 + frame-inversion: + description: dai-link uses frame clock inversion + $ref: /schemas/types.yaml#/definitions/flag + bitclock-inversion: + description: dai-link uses bit clock inversion + $ref: /schemas/types.yaml#/definitions/flag + frame-master: + description: Indicates dai-link frame master. + $ref: /schemas/types.yaml#/definitions/phandle + bitclock-master: + description: Indicates dai-link bit clock master + $ref: /schemas/types.yaml#/definitions/phandle + dai-format: + description: audio format. + items: + enum: + - i2s + - right_j + - left_j + - dsp_a + - dsp_b + - ac97 + - pdm + - msb + - lsb convert-rate: description: CPU to Codec rate convert. $ref: /schemas/types.yaml#/definitions/uint32 convert-channels: description: CPU to Codec rate channels. $ref: /schemas/types.yaml#/definitions/uint32 - patternProperties: - "^endpoint(@[0-9a-f]+)?": - type: object - properties: - remote-endpoint: - maxItems: 1 - mclk-fs: - description: | - Multiplication factor between stream rate and codec mclk. - When defined, mclk-fs property defined in dai-link sub nodes are - ignored. - $ref: /schemas/types.yaml#/definitions/uint32 - frame-inversion: - description: dai-link uses frame clock inversion - $ref: /schemas/types.yaml#/definitions/flag - bitclock-inversion: - description: dai-link uses bit clock inversion - $ref: /schemas/types.yaml#/definitions/flag - frame-master: - description: Indicates dai-link frame master. - $ref: /schemas/types.yaml#/definitions/phandle - bitclock-master: - description: Indicates dai-link bit clock master - $ref: /schemas/types.yaml#/definitions/phandle - dai-format: - description: audio format. - items: - enum: - - i2s - - right_j - - left_j - - dsp_a - - dsp_b - - ac97 - - pdm - - msb - - lsb - convert-rate: - description: CPU to Codec rate convert. - $ref: /schemas/types.yaml#/definitions/uint32 - convert-channels: - description: CPU to Codec rate channels. - $ref: /schemas/types.yaml#/definitions/uint32 - - ports: - description: multi OF-Graph subnode - type: object - patternProperties: - "^port(@[0-9a-f]+)?": - $ref: "#/properties/port" additionalProperties: true diff --git a/Documentation/devicetree/bindings/sound/marvell,mmp-sspa.yaml b/Documentation/devicetree/bindings/sound/marvell,mmp-sspa.yaml index 234f64a32184..81f266d66ec5 100644 --- a/Documentation/devicetree/bindings/sound/marvell,mmp-sspa.yaml +++ b/Documentation/devicetree/bindings/sound/marvell,mmp-sspa.yaml @@ -9,9 +9,6 @@ title: Marvel SSPA Digital Audio Interface Bindings maintainers: - Lubomir Rintel -allOf: - - $ref: audio-graph-port.yaml# - properties: $nodename: pattern: "^audio-controller(@.*)?$" @@ -54,7 +51,8 @@ properties: - const: rx port: - type: object + $ref: audio-graph-port.yaml# + unevaluatedProperties: false properties: endpoint: diff --git a/Documentation/devicetree/bindings/sound/nvidia,tegra186-dspk.yaml b/Documentation/devicetree/bindings/sound/nvidia,tegra186-dspk.yaml index b8645d9c38ac..5f6b37c251a8 100644 --- a/Documentation/devicetree/bindings/sound/nvidia,tegra186-dspk.yaml +++ b/Documentation/devicetree/bindings/sound/nvidia,tegra186-dspk.yaml @@ -17,9 +17,6 @@ maintainers: - Jon Hunter - Sameer Pujar -allOf: - - $ref: audio-graph-port.yaml# - properties: $nodename: pattern: "^dspk@[0-9a-f]*$" @@ -59,14 +56,18 @@ properties: available instances on a Tegra SoC. ports: - type: object + $ref: /schemas/graph.yaml#/properties/ports properties: port@0: + $ref: audio-graph-port.yaml# + unevaluatedProperties: false description: | DSPK ACIF (Audio Client Interface) port connected to the corresponding AHUB (Audio Hub) ACIF port. port@1: + $ref: audio-graph-port.yaml# + unevaluatedProperties: false description: | DSPK DAP (Digital Audio Port) interface which can be connected to external audio codec for playback. @@ -80,7 +81,7 @@ required: - assigned-clock-parents - sound-name-prefix -unevaluatedProperties: false +additionalProperties: false examples: - | diff --git a/Documentation/devicetree/bindings/sound/nvidia,tegra210-admaif.yaml b/Documentation/devicetree/bindings/sound/nvidia,tegra210-admaif.yaml index 7cee7722df41..19eaacc3f12a 100644 --- a/Documentation/devicetree/bindings/sound/nvidia,tegra210-admaif.yaml +++ b/Documentation/devicetree/bindings/sound/nvidia,tegra210-admaif.yaml @@ -17,9 +17,6 @@ maintainers: - Jon Hunter - Sameer Pujar -allOf: - - $ref: audio-graph-port.yaml# - properties: $nodename: pattern: "^admaif@[0-9a-f]*$" @@ -41,6 +38,7 @@ properties: dma-names: true ports: + $ref: /schemas/graph.yaml#/properties/ports description: | Contains list of ACIF (Audio CIF) port nodes for ADMAIF channels. The number of port nodes depends on the number of ADMAIF channels @@ -48,6 +46,11 @@ properties: in AHUB (Audio Hub). Each port is capable of data transfers in both directions. + patternProperties: + '^port@[0-9]': + $ref: audio-graph-port.yaml# + unevaluatedProperties: false + if: properties: compatible: @@ -92,7 +95,7 @@ required: - dmas - dma-names -unevaluatedProperties: false +additionalProperties: false examples: - | diff --git a/Documentation/devicetree/bindings/sound/nvidia,tegra210-ahub.yaml b/Documentation/devicetree/bindings/sound/nvidia,tegra210-ahub.yaml index 61d0c944e972..1118a9488345 100644 --- a/Documentation/devicetree/bindings/sound/nvidia,tegra210-ahub.yaml +++ b/Documentation/devicetree/bindings/sound/nvidia,tegra210-ahub.yaml @@ -17,9 +17,6 @@ maintainers: - Jon Hunter - Sameer Pujar -allOf: - - $ref: audio-graph-port.yaml# - properties: $nodename: pattern: "^ahub@[0-9a-f]*$" @@ -60,12 +57,18 @@ properties: ranges: true ports: + $ref: /schemas/graph.yaml#/properties/ports description: | Contains list of ACIF (Audio CIF) port nodes for AHUB (Audio Hub). These are connected to ACIF interfaces of AHUB clients. Thus the number of port nodes depend on the number of clients that AHUB may have depending on the SoC revision. + patternProperties: + '^port@[0-9]': + $ref: audio-graph-port.yaml# + unevaluatedProperties: false + patternProperties: '^i2s@[0-9a-f]+$': type: object @@ -93,7 +96,7 @@ required: - "#size-cells" - ranges -unevaluatedProperties: false +additionalProperties: false examples: - | diff --git a/Documentation/devicetree/bindings/sound/nvidia,tegra210-dmic.yaml b/Documentation/devicetree/bindings/sound/nvidia,tegra210-dmic.yaml index 89f4f471be24..fd275a575055 100644 --- a/Documentation/devicetree/bindings/sound/nvidia,tegra210-dmic.yaml +++ b/Documentation/devicetree/bindings/sound/nvidia,tegra210-dmic.yaml @@ -16,9 +16,6 @@ maintainers: - Jon Hunter - Sameer Pujar -allOf: - - $ref: audio-graph-port.yaml# - properties: $nodename: pattern: "^dmic@[0-9a-f]*$" @@ -60,14 +57,18 @@ properties: on the maximum available instances on a Tegra SoC. ports: - type: object + $ref: /schemas/graph.yaml#/properties/ports properties: port@0: + $ref: audio-graph-port.yaml# + unevaluatedProperties: false description: | DMIC ACIF (Audio Client Interface) port connected to the corresponding AHUB (Audio Hub) ACIF port. port@1: + $ref: audio-graph-port.yaml# + unevaluatedProperties: false description: | DMIC DAP (Digital Audio Port) interface which can be connected to external audio codec for capture. @@ -80,7 +81,7 @@ required: - assigned-clocks - assigned-clock-parents -unevaluatedProperties: false +additionalProperties: false examples: - | diff --git a/Documentation/devicetree/bindings/sound/nvidia,tegra210-i2s.yaml b/Documentation/devicetree/bindings/sound/nvidia,tegra210-i2s.yaml index 556460332ffb..38e52e7dbb40 100644 --- a/Documentation/devicetree/bindings/sound/nvidia,tegra210-i2s.yaml +++ b/Documentation/devicetree/bindings/sound/nvidia,tegra210-i2s.yaml @@ -16,9 +16,6 @@ maintainers: - Jon Hunter - Sameer Pujar -allOf: - - $ref: audio-graph-port.yaml# - properties: $nodename: pattern: "^i2s@[0-9a-f]*$" @@ -78,14 +75,18 @@ properties: on the maximum available instances on a Tegra SoC. ports: - type: object + $ref: /schemas/graph.yaml#/properties/ports properties: port@0: + $ref: audio-graph-port.yaml# + unevaluatedProperties: false description: | I2S ACIF (Audio Client Interface) port connected to the corresponding AHUB (Audio Hub) ACIF port. port@1: + $ref: audio-graph-port.yaml# + unevaluatedProperties: false description: | I2S DAP (Digital Audio Port) interface which can be connected to external audio codec for playback or capture. @@ -98,7 +99,7 @@ required: - assigned-clocks - assigned-clock-parents -unevaluatedProperties: false +additionalProperties: false examples: - | diff --git a/Documentation/devicetree/bindings/sound/renesas,rsnd.yaml b/Documentation/devicetree/bindings/sound/renesas,rsnd.yaml index 2e1046513603..1e0e14e88913 100644 --- a/Documentation/devicetree/bindings/sound/renesas,rsnd.yaml +++ b/Documentation/devicetree/bindings/sound/renesas,rsnd.yaml @@ -111,7 +111,9 @@ properties: - pattern: '^dvc\.[0-1]$' - pattern: '^clk_(a|b|c|i)$' - port: true + port: + $ref: audio-graph-port.yaml# + unevaluatedProperties: false # use patternProperties to avoid naming "xxx,yyy" issue patternProperties: @@ -257,7 +259,6 @@ required: allOf: - $ref: audio-graph.yaml# - - $ref: audio-graph-port.yaml# - if: properties: compatible: From ec1c8302178a946986bb7b52ac7bb9ccdcdf7d92 Mon Sep 17 00:00:00 2001 From: Rob Herring Date: Wed, 31 Mar 2021 09:27:47 -0500 Subject: [PATCH 371/587] ASoC: dt-bindings: Use OF graph schema Now that we have an OF graph schema, let's use it for the audio-graph-port schema. Cc: Liam Girdwood Cc: Mark Brown Cc: Kuninori Morimoto Cc: alsa-devel@alsa-project.org Signed-off-by: Rob Herring Link: https://lore.kernel.org/r/20210331142748.2163272-3-robh@kernel.org Signed-off-by: Mark Brown --- .../devicetree/bindings/sound/audio-graph-port.yaml | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/Documentation/devicetree/bindings/sound/audio-graph-port.yaml b/Documentation/devicetree/bindings/sound/audio-graph-port.yaml index 9f68142c9ae3..43e7f86e3b23 100644 --- a/Documentation/devicetree/bindings/sound/audio-graph-port.yaml +++ b/Documentation/devicetree/bindings/sound/audio-graph-port.yaml @@ -11,9 +11,10 @@ maintainers: select: false +allOf: + - $ref: /schemas/graph.yaml#/$defs/port-base + properties: - reg: - maxItems: 1 prefix: description: "device name prefix" $ref: /schemas/types.yaml#/definitions/string @@ -25,10 +26,8 @@ properties: $ref: /schemas/types.yaml#/definitions/uint32 patternProperties: "^endpoint(@[0-9a-f]+)?": - type: object + $ref: /schemas/graph.yaml#/$defs/endpoint-base properties: - remote-endpoint: - maxItems: 1 mclk-fs: description: | Multiplication factor between stream rate and codec mclk. From f1321c9766b2c9e79de268225e291dead0a8f969 Mon Sep 17 00:00:00 2001 From: Rob Herring Date: Wed, 31 Mar 2021 09:27:48 -0500 Subject: [PATCH 372/587] ASoC: dt-bindings: socionext: Use audio-graph-port schema Convert the Socionext audio schemas to use audio-graph-port.yaml schema for 'port' nodes. The number and numbering of port nodes should be documented, but is not. Leave a FIXME here so others don't copy. Cc: Masahiro Yamada Cc: Liam Girdwood Cc: Mark Brown Signed-off-by: Rob Herring Link: https://lore.kernel.org/r/20210331142748.2163272-4-robh@kernel.org Signed-off-by: Mark Brown --- .../devicetree/bindings/sound/socionext,uniphier-aio.yaml | 8 +++----- .../bindings/sound/socionext,uniphier-evea.yaml | 8 +++----- 2 files changed, 6 insertions(+), 10 deletions(-) diff --git a/Documentation/devicetree/bindings/sound/socionext,uniphier-aio.yaml b/Documentation/devicetree/bindings/sound/socionext,uniphier-aio.yaml index 4987eb91f2ab..55ae198220f4 100644 --- a/Documentation/devicetree/bindings/sound/socionext,uniphier-aio.yaml +++ b/Documentation/devicetree/bindings/sound/socionext,uniphier-aio.yaml @@ -46,11 +46,9 @@ properties: patternProperties: "^port@[0-9]$": - type: object - properties: - endpoint: true - required: - - endpoint + description: FIXME, Need to define what each port is. + $ref: audio-graph-port.yaml# + unevaluatedProperties: false additionalProperties: false diff --git a/Documentation/devicetree/bindings/sound/socionext,uniphier-evea.yaml b/Documentation/devicetree/bindings/sound/socionext,uniphier-evea.yaml index 228168f685cf..48ddfcbbcbae 100644 --- a/Documentation/devicetree/bindings/sound/socionext,uniphier-evea.yaml +++ b/Documentation/devicetree/bindings/sound/socionext,uniphier-evea.yaml @@ -40,11 +40,9 @@ properties: patternProperties: "^port@[0-9]$": - type: object - properties: - endpoint: true - required: - - endpoint + description: FIXME, Need to define what each port is. + $ref: audio-graph-port.yaml# + unevaluatedProperties: false additionalProperties: false From f1b3ee789f4b7a41ad93ff42d4efbae607622ae7 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Tue, 30 Mar 2021 14:26:28 +0900 Subject: [PATCH 373/587] ASoC: soc-core: add comment for rtd freeing We don't need to mind freeing for rtd, because it was created from devm_kzalloc(dev, xxx) which is rtd->dev. This means, if rtd->dev was freed, rtd will be also freed automatically. soc_new_pcm_runtime(...) { ... rtd = devm_kzalloc(dev, ...); rtd->dev = dev; ... } This explanation was missing at soc_free_pcm_runtime() comment. This patch indicates it. Signed-off-by: Kuninori Morimoto Link: https://lore.kernel.org/r/87sg4dxldn.wl-kuninori.morimoto.gx@renesas.com Signed-off-by: Mark Brown --- sound/soc/soc-core.c | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/sound/soc/soc-core.c b/sound/soc/soc-core.c index 522bae73640a..88694746dc11 100644 --- a/sound/soc/soc-core.c +++ b/sound/soc/soc-core.c @@ -413,6 +413,14 @@ static void soc_free_pcm_runtime(struct snd_soc_pcm_runtime *rtd) * it is alloced *before* rtd. * see * soc_new_pcm_runtime() + * + * We don't need to mind freeing for rtd, + * because it was created from dev (= rtd->dev) + * see + * soc_new_pcm_runtime() + * + * rtd = devm_kzalloc(dev, ...); + * rtd->dev = dev */ device_unregister(rtd->dev); } From 5fa7553dcd83c576c589fd3e617dc599e4fe15dc Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Tue, 30 Mar 2021 14:26:38 +0900 Subject: [PATCH 374/587] ASoC: soc-core: use device_unregister() if rtd allocation failed Because soc_free_pcm_runtime(rtd) checks rtd pointer and freeing rtd->xxx, it doesn't work correctly in case of rtd allocation failed. We need to use device_unregister(dev) in such case. This patch fixup it. Signed-off-by: Kuninori Morimoto Link: https://lore.kernel.org/r/87r1jxxldd.wl-kuninori.morimoto.gx@renesas.com Signed-off-by: Mark Brown --- sound/soc/soc-core.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/sound/soc/soc-core.c b/sound/soc/soc-core.c index 88694746dc11..236e075b9e57 100644 --- a/sound/soc/soc-core.c +++ b/sound/soc/soc-core.c @@ -470,8 +470,10 @@ static struct snd_soc_pcm_runtime *soc_new_pcm_runtime( dai_link->num_codecs + dai_link->num_platforms), GFP_KERNEL); - if (!rtd) - goto free_rtd; + if (!rtd) { + device_unregister(dev); + return NULL; + } rtd->dev = dev; INIT_LIST_HEAD(&rtd->list); From 2711a2d993036f26837e459ffb7b0d45c36b92a2 Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Fri, 26 Mar 2021 16:59:11 -0500 Subject: [PATCH 375/587] ASoC: amd: renoir: acp3x-pdm-dma: remove unnecessary assignments cppcheck warning: sound/soc/amd/renoir/acp3x-pdm-dma.c:132:17: style: Variable 'pdm_dma_enable' is assigned a value that is never used. [unreadVariable] pdm_dma_enable = 0x00; ^ sound/soc/amd/renoir/acp3x-pdm-dma.c:156:18: style: Variable 'pdm_dma_enable' is assigned a value that is never used. [unreadVariable] pdm_dma_enable = 0x00; ^ indeed those values are never used because the timeout is reset. Signed-off-by: Pierre-Louis Bossart Link: https://lore.kernel.org/r/20210326215927.936377-2-pierre-louis.bossart@linux.intel.com Signed-off-by: Mark Brown --- sound/soc/amd/renoir/acp3x-pdm-dma.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/sound/soc/amd/renoir/acp3x-pdm-dma.c b/sound/soc/amd/renoir/acp3x-pdm-dma.c index 7b14d9a81b97..1acd20439399 100644 --- a/sound/soc/amd/renoir/acp3x-pdm-dma.c +++ b/sound/soc/amd/renoir/acp3x-pdm-dma.c @@ -129,7 +129,6 @@ static int start_pdm_dma(void __iomem *acp_base) enable_pdm_clock(acp_base); rn_writel(pdm_enable, acp_base + ACP_WOV_PDM_ENABLE); rn_writel(pdm_dma_enable, acp_base + ACP_WOV_PDM_DMA_ENABLE); - pdm_dma_enable = 0x00; timeout = 0; while (++timeout < ACP_COUNTER) { pdm_dma_enable = rn_readl(acp_base + ACP_WOV_PDM_DMA_ENABLE); @@ -153,7 +152,6 @@ static int stop_pdm_dma(void __iomem *acp_base) if (pdm_dma_enable & 0x01) { pdm_dma_enable = 0x02; rn_writel(pdm_dma_enable, acp_base + ACP_WOV_PDM_DMA_ENABLE); - pdm_dma_enable = 0x00; timeout = 0; while (++timeout < ACP_COUNTER) { pdm_dma_enable = rn_readl(acp_base + From 86f3c05534bed54342ef6912b9da1d75f6b8d902 Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Fri, 26 Mar 2021 16:59:12 -0500 Subject: [PATCH 376/587] ASoC: atmel: fix shadowed variable Fix cppcheck warning: sound/soc/atmel/atmel-classd.c:51:14: style: Local variable 'pwm_type' shadows outer variable [shadowVariable] const char *pwm_type; ^ sound/soc/atmel/atmel-classd.c:226:27: note: Shadowed declaration static const char * const pwm_type[] = { ^ sound/soc/atmel/atmel-classd.c:51:14: note: Shadow variable const char *pwm_type; ^ Signed-off-by: Pierre-Louis Bossart Reviewed-by: Codrin Ciubotariu Link: https://lore.kernel.org/r/20210326215927.936377-3-pierre-louis.bossart@linux.intel.com Signed-off-by: Mark Brown --- sound/soc/atmel/atmel-classd.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/sound/soc/atmel/atmel-classd.c b/sound/soc/atmel/atmel-classd.c index b1a28a9382fb..6023369e0f1a 100644 --- a/sound/soc/atmel/atmel-classd.c +++ b/sound/soc/atmel/atmel-classd.c @@ -48,7 +48,7 @@ static struct atmel_classd_pdata *atmel_classd_dt_init(struct device *dev) { struct device_node *np = dev->of_node; struct atmel_classd_pdata *pdata; - const char *pwm_type; + const char *pwm_type_s; int ret; if (!np) { @@ -60,8 +60,8 @@ static struct atmel_classd_pdata *atmel_classd_dt_init(struct device *dev) if (!pdata) return ERR_PTR(-ENOMEM); - ret = of_property_read_string(np, "atmel,pwm-type", &pwm_type); - if ((ret == 0) && (strcmp(pwm_type, "diff") == 0)) + ret = of_property_read_string(np, "atmel,pwm-type", &pwm_type_s); + if ((ret == 0) && (strcmp(pwm_type_s, "diff") == 0)) pdata->pwm_type = CLASSD_MR_PWMTYP_DIFF; else pdata->pwm_type = CLASSD_MR_PWMTYP_SINGLE; From 6692dc07fa113939fc2c15d58dc3b27e28fc767c Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Fri, 26 Mar 2021 16:59:13 -0500 Subject: [PATCH 377/587] ASoC: atmel: atmel-i2s: remove useless initialization Cppcheck complains: sound/soc/atmel/atmel-i2s.c:628:6: style: Redundant initialization for 'err'. The initialized value is overwritten before it is read. [redundantInitialization] err = devm_request_irq(&pdev->dev, irq, atmel_i2s_interrupt, 0, ^ sound/soc/atmel/atmel-i2s.c:598:10: note: err is initialized int err = -ENXIO; ^ sound/soc/atmel/atmel-i2s.c:628:6: note: err is overwritten err = devm_request_irq(&pdev->dev, irq, atmel_i2s_interrupt, 0, ^ Signed-off-by: Pierre-Louis Bossart Reviewed-by: Codrin Ciubotariu Link: https://lore.kernel.org/r/20210326215927.936377-4-pierre-louis.bossart@linux.intel.com Signed-off-by: Mark Brown --- sound/soc/atmel/atmel-i2s.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sound/soc/atmel/atmel-i2s.c b/sound/soc/atmel/atmel-i2s.c index 7c6187e41f2b..584656cc7d3c 100644 --- a/sound/soc/atmel/atmel-i2s.c +++ b/sound/soc/atmel/atmel-i2s.c @@ -595,7 +595,7 @@ static int atmel_i2s_probe(struct platform_device *pdev) struct regmap *regmap; void __iomem *base; int irq; - int err = -ENXIO; + int err; unsigned int pcm_flags = 0; unsigned int version; From ce36242046f272c7656f7b4c91ff7b4387f514b0 Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Fri, 26 Mar 2021 16:59:14 -0500 Subject: [PATCH 378/587] ASoC: bcm: cygnus_ssp: remove useless initialization Cppcheck warning: sound/soc/bcm/cygnus-ssp.c:1364:6: style: Redundant initialization for 'err'. The initialized value is overwritten before it is read. [redundantInitialization] err = devm_snd_soc_register_component(dev, &cygnus_ssp_component, ^ sound/soc/bcm/cygnus-ssp.c:1313:10: note: err is initialized int err = -EINVAL; ^ sound/soc/bcm/cygnus-ssp.c:1364:6: note: err is overwritten err = devm_snd_soc_register_component(dev, &cygnus_ssp_component, ^ Signed-off-by: Pierre-Louis Bossart Link: https://lore.kernel.org/r/20210326215927.936377-5-pierre-louis.bossart@linux.intel.com Signed-off-by: Mark Brown --- sound/soc/bcm/cygnus-ssp.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sound/soc/bcm/cygnus-ssp.c b/sound/soc/bcm/cygnus-ssp.c index 6e634b448293..fea296b41a43 100644 --- a/sound/soc/bcm/cygnus-ssp.c +++ b/sound/soc/bcm/cygnus-ssp.c @@ -1310,7 +1310,7 @@ static int cygnus_ssp_probe(struct platform_device *pdev) struct device_node *child_node; struct resource *res; struct cygnus_audio *cygaud; - int err = -EINVAL; + int err; int node_count; int active_port_count; From 84d0493f67b856e5909c18e15b7ce78391565057 Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Fri, 26 Mar 2021 16:59:15 -0500 Subject: [PATCH 379/587] ASoC: meson: axg-tdmin: remove useless assignment cppcheck complains about potential null pointer dereference but it's rather an unnecessary assignment to NULL before walking through a list. Signed-off-by: Pierre-Louis Bossart Link: https://lore.kernel.org/r/20210326215927.936377-6-pierre-louis.bossart@linux.intel.com Signed-off-by: Mark Brown --- sound/soc/meson/axg-tdmin.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sound/soc/meson/axg-tdmin.c b/sound/soc/meson/axg-tdmin.c index b4faf9d5c1aa..49b613a1faf2 100644 --- a/sound/soc/meson/axg-tdmin.c +++ b/sound/soc/meson/axg-tdmin.c @@ -57,7 +57,7 @@ static const struct snd_kcontrol_new axg_tdmin_in_mux = static struct snd_soc_dai * axg_tdmin_get_be(struct snd_soc_dapm_widget *w) { - struct snd_soc_dapm_path *p = NULL; + struct snd_soc_dapm_path *p; struct snd_soc_dai *be; snd_soc_dapm_widget_for_each_source_path(w, p) { From 18efddee4f0a8820a4ba0215655bbafd479025bf Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Fri, 26 Mar 2021 16:59:16 -0500 Subject: [PATCH 380/587] ASoC: meson: axg-tdmout: remove useless assignment cppcheck complains about potential null pointer dereference but it's rather an unnecessary assignment to NULL before walking through a list. Signed-off-by: Pierre-Louis Bossart Link: https://lore.kernel.org/r/20210326215927.936377-7-pierre-louis.bossart@linux.intel.com Signed-off-by: Mark Brown --- sound/soc/meson/axg-tdmout.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sound/soc/meson/axg-tdmout.c b/sound/soc/meson/axg-tdmout.c index 3ceabddae629..22d519fc07b2 100644 --- a/sound/soc/meson/axg-tdmout.c +++ b/sound/soc/meson/axg-tdmout.c @@ -55,7 +55,7 @@ static const struct regmap_config axg_tdmout_regmap_cfg = { static struct snd_soc_dai * axg_tdmout_get_be(struct snd_soc_dapm_widget *w) { - struct snd_soc_dapm_path *p = NULL; + struct snd_soc_dapm_path *p; struct snd_soc_dai *be; snd_soc_dapm_widget_for_each_sink_path(w, p) { From 00a25480cca4a094765084964c753c8f28e0f6fd Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Fri, 26 Mar 2021 16:59:17 -0500 Subject: [PATCH 381/587] ASoC: pxa: remove useless assignment cppcheck warning: sound/soc/pxa/mmp-pcm.c:207:10: style: Variable 'ret' is assigned a value that is never used. [unreadVariable] int ret = 0, stream; ^ Signed-off-by: Pierre-Louis Bossart Link: https://lore.kernel.org/r/20210326215927.936377-8-pierre-louis.bossart@linux.intel.com Signed-off-by: Mark Brown --- sound/soc/pxa/mmp-pcm.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sound/soc/pxa/mmp-pcm.c b/sound/soc/pxa/mmp-pcm.c index 53fc49e32fbc..5d520e18e512 100644 --- a/sound/soc/pxa/mmp-pcm.c +++ b/sound/soc/pxa/mmp-pcm.c @@ -204,7 +204,7 @@ static int mmp_pcm_new(struct snd_soc_component *component, { struct snd_pcm_substream *substream; struct snd_pcm *pcm = rtd->pcm; - int ret = 0, stream; + int ret, stream; for (stream = 0; stream < 2; stream++) { substream = pcm->streams[stream].substream; From bf2a6b44d5e56a12dde6438a2d092475e54d1923 Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Fri, 26 Mar 2021 16:59:18 -0500 Subject: [PATCH 382/587] ASoC: sti: sti_uniperif: add missing error check cppcheck warning: sound/soc/sti/sti_uniperif.c:490:6: style: Variable 'ret' is reassigned a value before the old one has been used. [redundantAssignment] ret = devm_snd_soc_register_component(&pdev->dev, ^ sound/soc/sti/sti_uniperif.c:486:6: note: ret is assigned ret = sti_uniperiph_cpu_dai_of(node, priv); ^ sound/soc/sti/sti_uniperif.c:490:6: note: ret is overwritten ret = devm_snd_soc_register_component(&pdev->dev, ^ sti_uniperiph_cpu_dai_of() can return -EINVAL which seems like a good-enough reason to bail. Signed-off-by: Pierre-Louis Bossart Reviewed-by: Arnaud Pouliquen Link: https://lore.kernel.org/r/20210326215927.936377-9-pierre-louis.bossart@linux.intel.com Signed-off-by: Mark Brown --- sound/soc/sti/sti_uniperif.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/sound/soc/sti/sti_uniperif.c b/sound/soc/sti/sti_uniperif.c index 7b9169f04d6e..67315d9b352d 100644 --- a/sound/soc/sti/sti_uniperif.c +++ b/sound/soc/sti/sti_uniperif.c @@ -484,6 +484,8 @@ static int sti_uniperiph_probe(struct platform_device *pdev) priv->pdev = pdev; ret = sti_uniperiph_cpu_dai_of(node, priv); + if (ret < 0) + return ret; dev_set_drvdata(&pdev->dev, priv); From 00a820086ddd8c6f3eeeca3a034d234cebf084ba Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Fri, 26 Mar 2021 16:59:19 -0500 Subject: [PATCH 383/587] ASoC: sti: uniperif: align function prototypes cppcheck warning: sound/soc/sti/uniperif_player.c:1049:24: style:inconclusive: Function 'uni_player_init' argument 2 names different: declaration 'uni_player' definition 'player'. [funcArgNamesDifferent] struct uniperif *player) ^ sound/soc/sti/uniperif.h:1375:24: note: Function 'uni_player_init' argument 2 names different: declaration 'uni_player' definition 'player'. struct uniperif *uni_player); ^ sound/soc/sti/uniperif_player.c:1049:24: note: Function 'uni_player_init' argument 2 names different: declaration 'uni_player' definition 'player'. struct uniperif *player) ^ sound/soc/sti/uniperif_reader.c:411:24: style:inconclusive: Function 'uni_reader_init' argument 2 names different: declaration 'uni_reader' definition 'reader'. [funcArgNamesDifferent] struct uniperif *reader) ^ sound/soc/sti/uniperif.h:1380:24: note: Function 'uni_reader_init' argument 2 names different: declaration 'uni_reader' definition 'reader'. struct uniperif *uni_reader); ^ sound/soc/sti/uniperif_reader.c:411:24: note: Function 'uni_reader_init' argument 2 names different: declaration 'uni_reader' definition 'reader'. struct uniperif *reader) ^ Signed-off-by: Pierre-Louis Bossart Reviewed-by: Arnaud Pouliquen Link: https://lore.kernel.org/r/20210326215927.936377-10-pierre-louis.bossart@linux.intel.com Signed-off-by: Mark Brown --- sound/soc/sti/uniperif.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/sound/soc/sti/uniperif.h b/sound/soc/sti/uniperif.h index a16adeb7c1e9..2a5de328501c 100644 --- a/sound/soc/sti/uniperif.h +++ b/sound/soc/sti/uniperif.h @@ -1372,12 +1372,12 @@ static __maybe_unused const struct snd_pcm_hardware uni_tdm_hw = { /* uniperiph player*/ int uni_player_init(struct platform_device *pdev, - struct uniperif *uni_player); + struct uniperif *player); int uni_player_resume(struct uniperif *player); /* uniperiph reader */ int uni_reader_init(struct platform_device *pdev, - struct uniperif *uni_reader); + struct uniperif *reader); /* common */ int sti_uniperiph_dai_set_fmt(struct snd_soc_dai *dai, From 11033e51b31696fd7949f1abb558cba171ecf0f5 Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Fri, 26 Mar 2021 16:59:20 -0500 Subject: [PATCH 384/587] ASoC: stm: stm32_adfsdm: fix snprintf format string cppcheck warning: sound/soc/stm/stm32_adfsdm.c:120:2: warning: %d in format string (no. 1) requires 'int' but the argument type is 'unsigned int'. [invalidPrintfArgType_sint] snprintf(str_freq, sizeof(str_freq), "%d\n", freq); ^ Signed-off-by: Pierre-Louis Bossart Link: https://lore.kernel.org/r/20210326215927.936377-11-pierre-louis.bossart@linux.intel.com Signed-off-by: Mark Brown --- sound/soc/stm/stm32_adfsdm.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sound/soc/stm/stm32_adfsdm.c b/sound/soc/stm/stm32_adfsdm.c index 47fae8dd20b4..e6078f50e508 100644 --- a/sound/soc/stm/stm32_adfsdm.c +++ b/sound/soc/stm/stm32_adfsdm.c @@ -117,7 +117,7 @@ static int stm32_adfsdm_set_sysclk(struct snd_soc_dai *dai, int clk_id, /* Set IIO frequency if CODEC is master as clock comes from SPI_IN */ - snprintf(str_freq, sizeof(str_freq), "%d\n", freq); + snprintf(str_freq, sizeof(str_freq), "%u\n", freq); size = iio_write_channel_ext_info(priv->iio_ch, "spi_clk_freq", str_freq, sizeof(str_freq)); if (size != sizeof(str_freq)) { From 54f78aebe803b12e06d49988be88d87823ca16ab Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Fri, 26 Mar 2021 16:59:21 -0500 Subject: [PATCH 385/587] ASoC: sunxi: sun8i-codec: clarify expression cppcheck warning: sound/soc/sunxi/sun8i-codec.c:488:28: style: Clarify calculation precedence for '%' and '?'. [clarifyCalculation] return sample_rate % 4000 ? 22579200 : 24576000; ^ Signed-off-by: Pierre-Louis Bossart Acked-by: Maxime Ripard Link: https://lore.kernel.org/r/20210326215927.936377-12-pierre-louis.bossart@linux.intel.com Signed-off-by: Mark Brown --- sound/soc/sunxi/sun8i-codec.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sound/soc/sunxi/sun8i-codec.c b/sound/soc/sunxi/sun8i-codec.c index 460924fc173f..518bfb724a5b 100644 --- a/sound/soc/sunxi/sun8i-codec.c +++ b/sound/soc/sunxi/sun8i-codec.c @@ -485,7 +485,7 @@ static int sun8i_codec_get_lrck_div_order(unsigned int slots, static unsigned int sun8i_codec_get_sysclk_rate(unsigned int sample_rate) { - return sample_rate % 4000 ? 22579200 : 24576000; + return (sample_rate % 4000) ? 22579200 : 24576000; } static int sun8i_codec_hw_params(struct snd_pcm_substream *substream, From 1bc6d7a90b01e30123578761f5e70548ad894445 Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Fri, 26 Mar 2021 16:59:22 -0500 Subject: [PATCH 386/587] ASoC: tegra: tegra20_das: clarify expression cppcheck warning: sound/soc/tegra/tegra20_das.c:64:60: style: Boolean result is used in bitwise operation. Clarify expression with parentheses. [clarifyCondition] reg = otherdap << TEGRA20_DAS_DAP_CTRL_SEL_DAP_CTRL_SEL_P | ^ sound/soc/tegra/tegra20_das.c:65:61: style: Boolean result is used in bitwise operation. Clarify expression with parentheses. [clarifyCondition] !!sdata2rx << TEGRA20_DAS_DAP_CTRL_SEL_DAP_SDATA2_TX_RX_P | ^ sound/soc/tegra/tegra20_das.c:66:61: style: Boolean result is used in bitwise operation. Clarify expression with parentheses. [clarifyCondition] !!sdata1rx << TEGRA20_DAS_DAP_CTRL_SEL_DAP_SDATA1_TX_RX_P | ^ Signed-off-by: Pierre-Louis Bossart Acked-by: Thierry Reding Link: https://lore.kernel.org/r/20210326215927.936377-13-pierre-louis.bossart@linux.intel.com Signed-off-by: Mark Brown --- sound/soc/tegra/tegra20_das.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/sound/soc/tegra/tegra20_das.c b/sound/soc/tegra/tegra20_das.c index 79dba878d854..69c651274c12 100644 --- a/sound/soc/tegra/tegra20_das.c +++ b/sound/soc/tegra/tegra20_das.c @@ -61,10 +61,10 @@ int tegra20_das_connect_dap_to_dap(int dap, int otherdap, int master, addr = TEGRA20_DAS_DAP_CTRL_SEL + (dap * TEGRA20_DAS_DAP_CTRL_SEL_STRIDE); - reg = otherdap << TEGRA20_DAS_DAP_CTRL_SEL_DAP_CTRL_SEL_P | - !!sdata2rx << TEGRA20_DAS_DAP_CTRL_SEL_DAP_SDATA2_TX_RX_P | - !!sdata1rx << TEGRA20_DAS_DAP_CTRL_SEL_DAP_SDATA1_TX_RX_P | - !!master << TEGRA20_DAS_DAP_CTRL_SEL_DAP_MS_SEL_P; + reg = (otherdap << TEGRA20_DAS_DAP_CTRL_SEL_DAP_CTRL_SEL_P) | + (!!sdata2rx << TEGRA20_DAS_DAP_CTRL_SEL_DAP_SDATA2_TX_RX_P) | + (!!sdata1rx << TEGRA20_DAS_DAP_CTRL_SEL_DAP_SDATA1_TX_RX_P) | + (!!master << TEGRA20_DAS_DAP_CTRL_SEL_DAP_MS_SEL_P); tegra20_das_write(addr, reg); From 53567ebce407639e3657b5c232bd60970a66f82c Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Fri, 26 Mar 2021 16:59:23 -0500 Subject: [PATCH 387/587] ASoC: tegra: tegra20_das: align function prototypes cppcheck warnings: sound/soc/tegra/tegra20_das.c:35:40: style:inconclusive: Function 'tegra20_das_connect_dap_to_dac' argument 1 names different: declaration 'dap_id' definition 'dap'. [funcArgNamesDifferent] int tegra20_das_connect_dap_to_dac(int dap, int dac) ^ sound/soc/tegra/tegra20_das.h:98:47: note: Function 'tegra20_das_connect_dap_to_dac' argument 1 names different: declaration 'dap_id' definition 'dap'. extern int tegra20_das_connect_dap_to_dac(int dap_id, int dac_sel); ^ sound/soc/tegra/tegra20_das.c:35:40: note: Function 'tegra20_das_connect_dap_to_dac' argument 1 names different: declaration 'dap_id' definition 'dap'. int tegra20_das_connect_dap_to_dac(int dap, int dac) ^ sound/soc/tegra/tegra20_das.c:35:49: style:inconclusive: Function 'tegra20_das_connect_dap_to_dac' argument 2 names different: declaration 'dac_sel' definition 'dac'. [funcArgNamesDifferent] int tegra20_das_connect_dap_to_dac(int dap, int dac) ^ sound/soc/tegra/tegra20_das.h:98:59: note: Function 'tegra20_das_connect_dap_to_dac' argument 2 names different: declaration 'dac_sel' definition 'dac'. extern int tegra20_das_connect_dap_to_dac(int dap_id, int dac_sel); ^ sound/soc/tegra/tegra20_das.c:35:49: note: Function 'tegra20_das_connect_dap_to_dac' argument 2 names different: declaration 'dac_sel' definition 'dac'. int tegra20_das_connect_dap_to_dac(int dap, int dac) ^ sound/soc/tegra/tegra20_das.c:53:40: style:inconclusive: Function 'tegra20_das_connect_dap_to_dap' argument 1 names different: declaration 'dap_id' definition 'dap'. [funcArgNamesDifferent] int tegra20_das_connect_dap_to_dap(int dap, int otherdap, int master, ^ sound/soc/tegra/tegra20_das.h:108:47: note: Function 'tegra20_das_connect_dap_to_dap' argument 1 names different: declaration 'dap_id' definition 'dap'. extern int tegra20_das_connect_dap_to_dap(int dap_id, int other_dap_sel, ^ sound/soc/tegra/tegra20_das.c:53:40: note: Function 'tegra20_das_connect_dap_to_dap' argument 1 names different: declaration 'dap_id' definition 'dap'. int tegra20_das_connect_dap_to_dap(int dap, int otherdap, int master, ^ sound/soc/tegra/tegra20_das.c:53:49: style:inconclusive: Function 'tegra20_das_connect_dap_to_dap' argument 2 names different: declaration 'other_dap_sel' definition 'otherdap'. [funcArgNamesDifferent] int tegra20_das_connect_dap_to_dap(int dap, int otherdap, int master, ^ sound/soc/tegra/tegra20_das.h:108:59: note: Function 'tegra20_das_connect_dap_to_dap' argument 2 names different: declaration 'other_dap_sel' definition 'otherdap'. extern int tegra20_das_connect_dap_to_dap(int dap_id, int other_dap_sel, ^ sound/soc/tegra/tegra20_das.c:53:49: note: Function 'tegra20_das_connect_dap_to_dap' argument 2 names different: declaration 'other_dap_sel' definition 'otherdap'. int tegra20_das_connect_dap_to_dap(int dap, int otherdap, int master, ^ sound/soc/tegra/tegra20_das.c:75:40: style:inconclusive: Function 'tegra20_das_connect_dac_to_dap' argument 1 names different: declaration 'dac_id' definition 'dac'. [funcArgNamesDifferent] int tegra20_das_connect_dac_to_dap(int dac, int dap) ^ sound/soc/tegra/tegra20_das.h:118:47: note: Function 'tegra20_das_connect_dac_to_dap' argument 1 names different: declaration 'dac_id' definition 'dac'. extern int tegra20_das_connect_dac_to_dap(int dac_id, int dap_sel); ^ sound/soc/tegra/tegra20_das.c:75:40: note: Function 'tegra20_das_connect_dac_to_dap' argument 1 names different: declaration 'dac_id' definition 'dac'. int tegra20_das_connect_dac_to_dap(int dac, int dap) ^ sound/soc/tegra/tegra20_das.c:75:49: style:inconclusive: Function 'tegra20_das_connect_dac_to_dap' argument 2 names different: declaration 'dap_sel' definition 'dap'. [funcArgNamesDifferent] int tegra20_das_connect_dac_to_dap(int dac, int dap) ^ sound/soc/tegra/tegra20_das.h:118:59: note: Function 'tegra20_das_connect_dac_to_dap' argument 2 names different: declaration 'dap_sel' definition 'dap'. extern int tegra20_das_connect_dac_to_dap(int dac_id, int dap_sel); ^ sound/soc/tegra/tegra20_das.c:75:49: note: Function 'tegra20_das_connect_dac_to_dap' argument 2 names different: declaration 'dap_sel' definition 'dap'. int tegra20_das_connect_dac_to_dap(int dac, int dap) ^ Signed-off-by: Pierre-Louis Bossart Acked-by: Thierry Reding Link: https://lore.kernel.org/r/20210326215927.936377-14-pierre-louis.bossart@linux.intel.com Signed-off-by: Mark Brown --- sound/soc/tegra/tegra20_das.h | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/sound/soc/tegra/tegra20_das.h b/sound/soc/tegra/tegra20_das.h index d22abc4d08e6..18e832ded73a 100644 --- a/sound/soc/tegra/tegra20_das.h +++ b/sound/soc/tegra/tegra20_das.h @@ -95,7 +95,7 @@ struct tegra20_das { * dap_id: DAP to connect: TEGRA20_DAS_DAP_ID_* * dac_sel: DAC to connect to: TEGRA20_DAS_DAP_SEL_DAC* */ -extern int tegra20_das_connect_dap_to_dac(int dap_id, int dac_sel); +extern int tegra20_das_connect_dap_to_dac(int dap, int dac); /* * Connect a DAP to another DAP @@ -105,7 +105,7 @@ extern int tegra20_das_connect_dap_to_dac(int dap_id, int dac_sel); * sdata1rx: Is this DAP's SDATA1 pin RX (1) or TX (0) * sdata2rx: Is this DAP's SDATA2 pin RX (1) or TX (0) */ -extern int tegra20_das_connect_dap_to_dap(int dap_id, int other_dap_sel, +extern int tegra20_das_connect_dap_to_dap(int dap, int otherdap, int master, int sdata1rx, int sdata2rx); @@ -115,6 +115,6 @@ extern int tegra20_das_connect_dap_to_dap(int dap_id, int other_dap_sel, * dac_id: DAC ID to connect: TEGRA20_DAS_DAC_ID_* * dap_sel: DAP to receive input from: TEGRA20_DAS_DAC_SEL_DAP* */ -extern int tegra20_das_connect_dac_to_dap(int dac_id, int dap_sel); +extern int tegra20_das_connect_dac_to_dap(int dac, int dap); #endif From 248d4dc9c3b8ced2cb274581d1c306e7ec617aec Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Fri, 26 Mar 2021 16:59:24 -0500 Subject: [PATCH 388/587] ASoC: ti: omap-abe-twl6040: remove useless assignment cppcheck warning: sound/soc/ti/omap-abe-twl6040.c:173:10: style: Variable 'ret' is assigned a value that is never used. [unreadVariable] int ret = 0; ^ Signed-off-by: Pierre-Louis Bossart Acked-by: Peter Ujfalusi Link: https://lore.kernel.org/r/20210326215927.936377-15-pierre-louis.bossart@linux.intel.com Signed-off-by: Mark Brown --- sound/soc/ti/omap-abe-twl6040.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sound/soc/ti/omap-abe-twl6040.c b/sound/soc/ti/omap-abe-twl6040.c index 16ea039ff865..91cc9a4f44d7 100644 --- a/sound/soc/ti/omap-abe-twl6040.c +++ b/sound/soc/ti/omap-abe-twl6040.c @@ -170,7 +170,7 @@ static int omap_abe_twl6040_init(struct snd_soc_pcm_runtime *rtd) struct snd_soc_card *card = rtd->card; struct abe_twl6040 *priv = snd_soc_card_get_drvdata(card); int hs_trim; - int ret = 0; + int ret; /* * Configure McPDM offset cancellation based on the HSOTRIM value from From 3d37b27fffb311c521d61144e57ea4d40e31ab9b Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Fri, 26 Mar 2021 16:59:25 -0500 Subject: [PATCH 389/587] ASoC: ti: omap-mcsp: remove duplicate test cppcheck warning: sound/soc/ti/omap-mcbsp.c:379:11: style: The if condition is the same as the previous if condition [duplicateCondition] if (mcbsp->irq) { ^ sound/soc/ti/omap-mcbsp.c:376:11: note: First condition if (mcbsp->irq) ^ sound/soc/ti/omap-mcbsp.c:379:11: note: Second condition if (mcbsp->irq) { ^ Keeping two separate tests was probably intentional for clarity, but since this generates warnings we might as well make cppcheck happy so that we have fewer warnings. Signed-off-by: Pierre-Louis Bossart Acked-by: Peter Ujfalusi Link: https://lore.kernel.org/r/20210326215927.936377-16-pierre-louis.bossart@linux.intel.com Signed-off-by: Mark Brown --- sound/soc/ti/omap-mcbsp.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/sound/soc/ti/omap-mcbsp.c b/sound/soc/ti/omap-mcbsp.c index 6025b30bbe77..db47981768c5 100644 --- a/sound/soc/ti/omap-mcbsp.c +++ b/sound/soc/ti/omap-mcbsp.c @@ -373,10 +373,9 @@ static void omap_mcbsp_free(struct omap_mcbsp *mcbsp) MCBSP_WRITE(mcbsp, WAKEUPEN, 0); /* Disable interrupt requests */ - if (mcbsp->irq) + if (mcbsp->irq) { MCBSP_WRITE(mcbsp, IRQEN, 0); - if (mcbsp->irq) { free_irq(mcbsp->irq, (void *)mcbsp); } else { free_irq(mcbsp->rx_irq, (void *)mcbsp); From 5b920abeea03302e561b036181a6a5be4e53a584 Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Fri, 26 Mar 2021 16:59:26 -0500 Subject: [PATCH 390/587] ASoC: ux500: mop500: rename shadowing variable cppcheck warning: sound/soc/ux500/mop500.c:143:23: style: Local variable 'mop500_card' shadows outer variable [shadowVariable] struct snd_soc_card *mop500_card = platform_get_drvdata(pdev); ^ sound/soc/ux500/mop500.c:54:28: note: Shadowed declaration static struct snd_soc_card mop500_card = { ^ sound/soc/ux500/mop500.c:143:23: note: Shadow variable struct snd_soc_card *mop500_card = platform_get_drvdata(pdev); ^ Signed-off-by: Pierre-Louis Bossart Link: https://lore.kernel.org/r/20210326215927.936377-17-pierre-louis.bossart@linux.intel.com Signed-off-by: Mark Brown --- sound/soc/ux500/mop500.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/sound/soc/ux500/mop500.c b/sound/soc/ux500/mop500.c index cdae1190b930..4f41bb0ab2b0 100644 --- a/sound/soc/ux500/mop500.c +++ b/sound/soc/ux500/mop500.c @@ -140,12 +140,12 @@ static int mop500_probe(struct platform_device *pdev) static int mop500_remove(struct platform_device *pdev) { - struct snd_soc_card *mop500_card = platform_get_drvdata(pdev); + struct snd_soc_card *card = platform_get_drvdata(pdev); pr_debug("%s: Enter.\n", __func__); - snd_soc_unregister_card(mop500_card); - mop500_ab8500_remove(mop500_card); + snd_soc_unregister_card(card); + mop500_ab8500_remove(card); mop500_of_node_put(); return 0; From b4d09a01666fdcab8866f44b72f79e106f14a48d Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Fri, 26 Mar 2021 16:59:27 -0500 Subject: [PATCH 391/587] ASoC: ux500: mop500: align function prototype cppcheck warning: sound/soc/ux500/mop500_ab8500.c:360:60: style:inconclusive: Function 'mop500_ab8500_machine_init' argument 1 names different: declaration 'runtime' definition 'rtd'. [funcArgNamesDifferent] int mop500_ab8500_machine_init(struct snd_soc_pcm_runtime *rtd) ^ sound/soc/ux500/mop500_ab8500.h:16:60: note: Function 'mop500_ab8500_machine_init' argument 1 names different: declaration 'runtime' definition 'rtd'. int mop500_ab8500_machine_init(struct snd_soc_pcm_runtime *runtime); ^ sound/soc/ux500/mop500_ab8500.c:360:60: note: Function 'mop500_ab8500_machine_init' argument 1 names different: declaration 'runtime' definition 'rtd'. int mop500_ab8500_machine_init(struct snd_soc_pcm_runtime *rtd) ^ Signed-off-by: Pierre-Louis Bossart Link: https://lore.kernel.org/r/20210326215927.936377-18-pierre-louis.bossart@linux.intel.com Signed-off-by: Mark Brown --- sound/soc/ux500/mop500_ab8500.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sound/soc/ux500/mop500_ab8500.h b/sound/soc/ux500/mop500_ab8500.h index 99cfd972ea7a..8138a4e9aaf5 100644 --- a/sound/soc/ux500/mop500_ab8500.h +++ b/sound/soc/ux500/mop500_ab8500.h @@ -13,7 +13,7 @@ extern struct snd_soc_ops mop500_ab8500_ops[]; -int mop500_ab8500_machine_init(struct snd_soc_pcm_runtime *runtime); +int mop500_ab8500_machine_init(struct snd_soc_pcm_runtime *rtd); void mop500_ab8500_remove(struct snd_soc_card *card); #endif From bb0f78e59777d55e0065d16d070b5d43ae80b769 Mon Sep 17 00:00:00 2001 From: Bhaskar Chowdhury Date: Tue, 23 Mar 2021 02:31:05 +0530 Subject: [PATCH 392/587] ASoC: Intel: Fix a typo s/defintions/definitions/ Signed-off-by: Bhaskar Chowdhury Link: https://lore.kernel.org/r/20210322210105.1575758-1-unixbhaskar@gmail.com Signed-off-by: Mark Brown --- sound/soc/intel/skylake/skl.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sound/soc/intel/skylake/skl.h b/sound/soc/intel/skylake/skl.h index 857ea17e3c9f..33ed274fc0cb 100644 --- a/sound/soc/intel/skylake/skl.h +++ b/sound/soc/intel/skylake/skl.h @@ -1,6 +1,6 @@ /* SPDX-License-Identifier: GPL-2.0-only */ /* - * skl.h - HD Audio skylake defintions. + * skl.h - HD Audio skylake definitions. * * Copyright (C) 2015 Intel Corp * Author: Jeeja KP From 016c20506d5c30151196ab28c694ab10bc3604e6 Mon Sep 17 00:00:00 2001 From: Jaroslav Kysela Date: Wed, 31 Mar 2021 20:07:02 +0200 Subject: [PATCH 393/587] ALSA: control - add the missing prev_lops2 initialization As static analysis reported, the prev_lops2 should contain the previous lops2 pointer in snd_ctl_disconnect_layer(). Link: https://lore.kernel.org/alsa-devel/96e9bd5c-c8db-0db8-b393-fbf4a047dc80@canonical.com/ Fixes: 3f0638a0333b ("ALSA: control - add layer registration routines") Signed-off-by: Jaroslav Kysela Link: https://lore.kernel.org/r/20210331180702.663489-1-perex@perex.cz Signed-off-by: Takashi Iwai --- sound/core/control.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/sound/core/control.c b/sound/core/control.c index 6825ca75daf5..20d707d4ef40 100644 --- a/sound/core/control.c +++ b/sound/core/control.c @@ -2074,7 +2074,7 @@ void snd_ctl_disconnect_layer(struct snd_ctl_layer_ops *lops) struct snd_ctl_layer_ops *lops2, *prev_lops2; down_write(&snd_ctl_layer_rwsem); - for (lops2 = snd_ctl_layer, prev_lops2 = NULL; lops2; lops2 = lops2->next) + for (lops2 = snd_ctl_layer, prev_lops2 = NULL; lops2; lops2 = lops2->next) { if (lops2 == lops) { if (!prev_lops2) snd_ctl_layer = lops->next; @@ -2082,6 +2082,8 @@ void snd_ctl_disconnect_layer(struct snd_ctl_layer_ops *lops) prev_lops2->next = lops->next; break; } + prev_lops2 = lops2; + } up_write(&snd_ctl_layer_rwsem); } EXPORT_SYMBOL_GPL(snd_ctl_disconnect_layer); From 62327ebbdf0097cda25579522424b350c65422a4 Mon Sep 17 00:00:00 2001 From: Jaroslav Kysela Date: Wed, 31 Mar 2021 20:07:25 +0200 Subject: [PATCH 394/587] ALSA: control led - improve the set_led_id() parser It may be possible that the string pointer does not move when parsing. Add a code which detects this state and simply break the parser loop in this case. Signed-off-by: Jaroslav Kysela Link: https://lore.kernel.org/r/20210331180725.663623-1-perex@perex.cz Signed-off-by: Takashi Iwai --- sound/core/control_led.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/sound/core/control_led.c b/sound/core/control_led.c index d4fb8b873f34..788fd9e275e0 100644 --- a/sound/core/control_led.c +++ b/sound/core/control_led.c @@ -506,7 +506,7 @@ static char *parse_iface(char *s, unsigned int *val) static ssize_t set_led_id(struct snd_ctl_led_card *led_card, const char *buf, size_t count, bool attach) { - char buf2[256], *s; + char buf2[256], *s, *os; size_t len = max(sizeof(s) - 1, count); struct snd_ctl_elem_id id; int err; @@ -517,6 +517,7 @@ static ssize_t set_led_id(struct snd_ctl_led_card *led_card, const char *buf, si id.iface = SNDRV_CTL_ELEM_IFACE_MIXER; s = buf2; while (*s) { + os = s; if (!strncasecmp(s, "numid=", 6)) { s = parse_uint(s + 6, &id.numid); } else if (!strncasecmp(s, "iface=", 6)) { @@ -546,6 +547,8 @@ static ssize_t set_led_id(struct snd_ctl_led_card *led_card, const char *buf, si } if (*s == ',') s++; + if (s == os) + break; } err = snd_ctl_led_set_id(led_card->number, &id, led_card->led->group, attach); From ebf721fbbb6e077864783c8d0146021815bb1f24 Mon Sep 17 00:00:00 2001 From: Bhaskar Chowdhury Date: Mon, 22 Mar 2021 12:22:38 +0530 Subject: [PATCH 395/587] ASoC: Intel: Fix a typo s/struture/structure/ Signed-off-by: Bhaskar Chowdhury Link: https://lore.kernel.org/r/20210322065238.151920-1-unixbhaskar@gmail.com Signed-off-by: Mark Brown --- sound/soc/intel/atom/sst-mfld-dsp.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sound/soc/intel/atom/sst-mfld-dsp.h b/sound/soc/intel/atom/sst-mfld-dsp.h index 102b0e7eafb0..8d9e29b16e57 100644 --- a/sound/soc/intel/atom/sst-mfld-dsp.h +++ b/sound/soc/intel/atom/sst-mfld-dsp.h @@ -256,7 +256,7 @@ struct snd_sst_tstamp { u32 channel_peak[8]; } __packed; -/* Stream type params struture for Alloc stream */ +/* Stream type params structure for Alloc stream */ struct snd_sst_str_type { u8 codec_type; /* Codec type */ u8 str_type; /* 1 = voice 2 = music */ From 52cad756b777e82fabe05c728cc62b63b3c61fd3 Mon Sep 17 00:00:00 2001 From: Zhen Lei Date: Mon, 29 Mar 2021 16:14:35 +0800 Subject: [PATCH 396/587] ASoC: intel, keembay-i2s: Fix a dt_binding_check warning The property "dmas" contains two items: DMA "TX" and "RX" channel, Therefore, its value also needs to be written in two parts. Otherwise, below YAML check warning is reported: Documentation/devicetree/bindings/sound/intel,keembay-i2s.example.dt.yaml:\ i2s@20140000: dmas: [[4294967295, 29, 4294967295, 33]] is too short Signed-off-by: Zhen Lei Acked-by: Rob Herring Link: https://lore.kernel.org/r/20210329081435.2200-1-thunder.leizhen@huawei.com Signed-off-by: Mark Brown --- Documentation/devicetree/bindings/sound/intel,keembay-i2s.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Documentation/devicetree/bindings/sound/intel,keembay-i2s.yaml b/Documentation/devicetree/bindings/sound/intel,keembay-i2s.yaml index 6f71294909a5..803627e984f6 100644 --- a/Documentation/devicetree/bindings/sound/intel,keembay-i2s.yaml +++ b/Documentation/devicetree/bindings/sound/intel,keembay-i2s.yaml @@ -81,6 +81,6 @@ examples: interrupts = ; clock-names = "osc", "apb_clk"; clocks = <&scmi_clk KEEM_BAY_PSS_AUX_I2S3>, <&scmi_clk KEEM_BAY_PSS_I2S3>; - dmas = <&axi_dma0 29 &axi_dma0 33>; + dmas = <&axi_dma0 29>, <&axi_dma0 33>; dma-names = "tx", "rx"; }; From 628166c37c16250612da926c010fe6c84d086ac1 Mon Sep 17 00:00:00 2001 From: Mac Chiang Date: Thu, 1 Apr 2021 22:00:13 +0800 Subject: [PATCH 397/587] ASoC: Intel: Boards: cml_da7219_max98390: add capture stream for echo reference enable speaker capture dai link for feedback path Signed-off-by: Mac Chiang Acked-by: Pierre-Louis Bossart Link: https://lore.kernel.org/r/1617285613-29457-1-git-send-email-mac.chiang@intel.com Signed-off-by: Mark Brown --- sound/soc/intel/boards/bxt_da7219_max98357a.c | 1 + 1 file changed, 1 insertion(+) diff --git a/sound/soc/intel/boards/bxt_da7219_max98357a.c b/sound/soc/intel/boards/bxt_da7219_max98357a.c index 0c0a717823c4..9ffef396f8f2 100644 --- a/sound/soc/intel/boards/bxt_da7219_max98357a.c +++ b/sound/soc/intel/boards/bxt_da7219_max98357a.c @@ -813,6 +813,7 @@ static int broxton_audio_probe(struct platform_device *pdev) if (ctx->spkamp == SPKAMP_MAX98390) { broxton_dais[i].codecs = max98390_codec; broxton_dais[i].num_codecs = ARRAY_SIZE(max98390_codec); + broxton_dais[i].dpcm_capture = 1; } } /* DIALOG_CODEC is connected to SSP0 */ From ebbb165d2c0c44ffbf480e209f745ed4b0d5560a Mon Sep 17 00:00:00 2001 From: Hans de Goede Date: Fri, 2 Apr 2021 16:07:42 +0200 Subject: [PATCH 398/587] ASoC: Intel: Unify the thinkpad10 and aegex10 byt-match quirks There is no reason to have separate quirk-handlers / byt_machine_id-s for these. These are both cases of BYT devices with a 10EC5640 ACPI HID while using a rt5672 codec. The Dell Venue 10 Pro 5055 is another example of such a device, instead of adding a third byt_machine_id definition for this Dell model, make change the 2 existing cases into a generic BYT_RT5672 byt_machine_id in preparation for adding a quirk for the Dell Venue 10 Pro 5055. Signed-off-by: Hans de Goede Acked-by: Pierre-Louis Bossart Link: https://lore.kernel.org/r/20210402140747.174716-2-hdegoede@redhat.com Signed-off-by: Mark Brown --- .../intel/common/soc-acpi-intel-byt-match.c | 32 +++++++------------ 1 file changed, 12 insertions(+), 20 deletions(-) diff --git a/sound/soc/intel/common/soc-acpi-intel-byt-match.c b/sound/soc/intel/common/soc-acpi-intel-byt-match.c index d1febbb53b70..4596d128fff5 100644 --- a/sound/soc/intel/common/soc-acpi-intel-byt-match.c +++ b/sound/soc/intel/common/soc-acpi-intel-byt-match.c @@ -11,13 +11,12 @@ static unsigned long byt_machine_id; -#define BYT_THINKPAD_10 1 +#define BYT_RT5672 1 #define BYT_POV_P1006W 2 -#define BYT_AEGEX_10 3 -static int byt_thinkpad10_quirk_cb(const struct dmi_system_id *id) +static int byt_rt5672_quirk_cb(const struct dmi_system_id *id) { - byt_machine_id = BYT_THINKPAD_10; + byt_machine_id = BYT_RT5672; return 1; } @@ -27,36 +26,30 @@ static int byt_pov_p1006w_quirk_cb(const struct dmi_system_id *id) return 1; } -static int byt_aegex10_quirk_cb(const struct dmi_system_id *id) -{ - byt_machine_id = BYT_AEGEX_10; - return 1; -} - static const struct dmi_system_id byt_table[] = { { - .callback = byt_thinkpad10_quirk_cb, + .callback = byt_rt5672_quirk_cb, .matches = { DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"), DMI_MATCH(DMI_PRODUCT_VERSION, "ThinkPad 8"), }, }, { - .callback = byt_thinkpad10_quirk_cb, + .callback = byt_rt5672_quirk_cb, .matches = { DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"), DMI_MATCH(DMI_PRODUCT_VERSION, "ThinkPad 10"), }, }, { - .callback = byt_thinkpad10_quirk_cb, + .callback = byt_rt5672_quirk_cb, .matches = { DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"), DMI_MATCH(DMI_PRODUCT_VERSION, "ThinkPad Tablet B"), }, }, { - .callback = byt_thinkpad10_quirk_cb, + .callback = byt_rt5672_quirk_cb, .matches = { DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"), DMI_MATCH(DMI_PRODUCT_VERSION, "Lenovo Miix 2 10"), @@ -75,7 +68,7 @@ static const struct dmi_system_id byt_table[] = { }, { /* Aegex 10 tablet (RU2) */ - .callback = byt_aegex10_quirk_cb, + .callback = byt_rt5672_quirk_cb, .matches = { DMI_MATCH(DMI_SYS_VENDOR, "AEGEX"), DMI_MATCH(DMI_PRODUCT_VERSION, "RU2"), @@ -84,8 +77,8 @@ static const struct dmi_system_id byt_table[] = { { } }; -/* The Thinkapd 10 and Aegex 10 tablets have the same ID problem */ -static struct snd_soc_acpi_mach byt_thinkpad_10 = { +/* Various devices use an ACPI id of 10EC5640 while using a rt5672 codec */ +static struct snd_soc_acpi_mach byt_rt5672 = { .id = "10EC5640", .drv_name = "cht-bsw-rt5672", .fw_filename = "intel/fw_sst_0f28.bin", @@ -110,9 +103,8 @@ static struct snd_soc_acpi_mach *byt_quirk(void *arg) dmi_check_system(byt_table); switch (byt_machine_id) { - case BYT_THINKPAD_10: - case BYT_AEGEX_10: - return &byt_thinkpad_10; + case BYT_RT5672: + return &byt_rt5672; case BYT_POV_P1006W: return &byt_pov_p1006w; default: From 17d49b07a8bb3fdc630a44240c7d7e2a18e14b93 Mon Sep 17 00:00:00 2001 From: Hans de Goede Date: Fri, 2 Apr 2021 16:07:43 +0200 Subject: [PATCH 399/587] ASoC: Intel: Baytrail: Add quirk for the Dell Venue 10 Pro 5055 tablet The Dell Venue 10 Pro 5055 tablet uses an ACPI HID of 10EC5640 while using a rt5672 codec (instead of a rt5640 codec). Add a quirk for this. Signed-off-by: Hans de Goede Acked-by: Pierre-Louis Bossart Link: https://lore.kernel.org/r/20210402140747.174716-3-hdegoede@redhat.com Signed-off-by: Mark Brown --- sound/soc/intel/common/soc-acpi-intel-byt-match.c | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/sound/soc/intel/common/soc-acpi-intel-byt-match.c b/sound/soc/intel/common/soc-acpi-intel-byt-match.c index 4596d128fff5..510a5f38b7f1 100644 --- a/sound/soc/intel/common/soc-acpi-intel-byt-match.c +++ b/sound/soc/intel/common/soc-acpi-intel-byt-match.c @@ -74,6 +74,14 @@ static const struct dmi_system_id byt_table[] = { DMI_MATCH(DMI_PRODUCT_VERSION, "RU2"), }, }, + { + /* Dell Venue 10 Pro 5055 */ + .callback = byt_rt5672_quirk_cb, + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."), + DMI_MATCH(DMI_PRODUCT_NAME, "Venue 10 Pro 5055"), + }, + }, { } }; From c9b3c63392e578ea74411b29a720ace77ae9041f Mon Sep 17 00:00:00 2001 From: Hans de Goede Date: Fri, 2 Apr 2021 16:07:44 +0200 Subject: [PATCH 400/587] ASoC: Intel: cht_bsw_rt5672: Add support for Bay Trail CR / SSP0 The rt5672 codec is used on some Bay Trail CR boards, on these SoCs SSP2 is not available and SSP0 should be used instead. At support for this. This has been tested on a Dell Venue 10 Pro 5055. Signed-off-by: Hans de Goede Acked-by: Pierre-Louis Bossart Link: https://lore.kernel.org/r/20210402140747.174716-4-hdegoede@redhat.com Signed-off-by: Mark Brown --- sound/soc/intel/boards/cht_bsw_rt5672.c | 75 ++++++++++++++++++++----- 1 file changed, 61 insertions(+), 14 deletions(-) diff --git a/sound/soc/intel/boards/cht_bsw_rt5672.c b/sound/soc/intel/boards/cht_bsw_rt5672.c index 10c88ef2f85d..10d5ed20e4e8 100644 --- a/sound/soc/intel/boards/cht_bsw_rt5672.c +++ b/sound/soc/intel/boards/cht_bsw_rt5672.c @@ -21,6 +21,7 @@ #include #include "../../codecs/rt5670.h" #include "../atom/sst-atom-controls.h" +#include "../common/soc-intel-quirks.h" /* The platform clock #3 outputs 19.2Mhz clock to codec as I2S MCLK */ @@ -31,6 +32,7 @@ struct cht_mc_private { struct snd_soc_jack headset; char codec_name[SND_ACPI_I2C_ID_LEN]; struct clk *mclk; + bool use_ssp0; }; /* Headset jack detection DAPM pins */ @@ -121,16 +123,26 @@ static const struct snd_soc_dapm_route cht_audio_map[] = { {"Ext Spk", NULL, "SPOLN"}, {"Ext Spk", NULL, "SPORP"}, {"Ext Spk", NULL, "SPORN"}, + {"Headphone", NULL, "Platform Clock"}, + {"Headset Mic", NULL, "Platform Clock"}, + {"Int Mic", NULL, "Platform Clock"}, + {"Ext Spk", NULL, "Platform Clock"}, +}; + +static const struct snd_soc_dapm_route cht_audio_ssp0_map[] = { + {"AIF1 Playback", NULL, "ssp0 Tx"}, + {"ssp0 Tx", NULL, "modem_out"}, + {"modem_in", NULL, "ssp0 Rx"}, + {"ssp0 Rx", NULL, "AIF1 Capture"}, +}; + +static const struct snd_soc_dapm_route cht_audio_ssp2_map[] = { {"AIF1 Playback", NULL, "ssp2 Tx"}, {"ssp2 Tx", NULL, "codec_out0"}, {"ssp2 Tx", NULL, "codec_out1"}, {"codec_in0", NULL, "ssp2 Rx"}, {"codec_in1", NULL, "ssp2 Rx"}, {"ssp2 Rx", NULL, "AIF1 Capture"}, - {"Headphone", NULL, "Platform Clock"}, - {"Headset Mic", NULL, "Platform Clock"}, - {"Int Mic", NULL, "Platform Clock"}, - {"Ext Spk", NULL, "Platform Clock"}, }; static const struct snd_kcontrol_new cht_mc_controls[] = { @@ -197,6 +209,18 @@ static int cht_codec_init(struct snd_soc_pcm_runtime *runtime) | RT5670_AD_MONO_R_FILTER, RT5670_CLK_SEL_I2S1_ASRC); + if (ctx->use_ssp0) { + ret = snd_soc_dapm_add_routes(&runtime->card->dapm, + cht_audio_ssp0_map, + ARRAY_SIZE(cht_audio_ssp0_map)); + } else { + ret = snd_soc_dapm_add_routes(&runtime->card->dapm, + cht_audio_ssp2_map, + ARRAY_SIZE(cht_audio_ssp2_map)); + } + if (ret) + return ret; + ret = snd_soc_card_jack_new(runtime->card, "Headset", SND_JACK_HEADSET | SND_JACK_BTN_0 | SND_JACK_BTN_1 | SND_JACK_BTN_2, @@ -239,18 +263,26 @@ static int cht_codec_init(struct snd_soc_pcm_runtime *runtime) static int cht_codec_fixup(struct snd_soc_pcm_runtime *rtd, struct snd_pcm_hw_params *params) { + struct cht_mc_private *ctx = snd_soc_card_get_drvdata(rtd->card); struct snd_interval *rate = hw_param_interval(params, SNDRV_PCM_HW_PARAM_RATE); struct snd_interval *channels = hw_param_interval(params, SNDRV_PCM_HW_PARAM_CHANNELS); - int ret; + int ret, bits; /* The DSP will covert the FE rate to 48k, stereo, 24bits */ rate->min = rate->max = 48000; channels->min = channels->max = 2; - /* set SSP2 to 24-bit */ - params_set_format(params, SNDRV_PCM_FORMAT_S24_LE); + if (ctx->use_ssp0) { + /* set SSP0 to 16-bit */ + params_set_format(params, SNDRV_PCM_FORMAT_S16_LE); + bits = 16; + } else { + /* set SSP2 to 24-bit */ + params_set_format(params, SNDRV_PCM_FORMAT_S24_LE); + bits = 24; + } /* * The default mode for the cpu-dai is TDM 4 slot. The default mode @@ -274,6 +306,12 @@ static int cht_codec_fixup(struct snd_soc_pcm_runtime *rtd, return ret; } + ret = snd_soc_dai_set_tdm_slot(asoc_rtd_to_cpu(rtd, 0), 0x3, 0x3, 2, bits); + if (ret < 0) { + dev_err(rtd->dev, "can't set I2S config, err %d\n", ret); + return ret; + } + return 0; } @@ -414,6 +452,7 @@ static int snd_cht_mc_probe(struct platform_device *pdev) const char *platform_name; struct acpi_device *adev; bool sof_parent; + int dai_index = 0; int i; drv = devm_kzalloc(&pdev->dev, sizeof(*drv), GFP_KERNEL); @@ -422,19 +461,27 @@ static int snd_cht_mc_probe(struct platform_device *pdev) strcpy(drv->codec_name, RT5672_I2C_DEFAULT); + /* find index of codec dai */ + for (i = 0; i < ARRAY_SIZE(cht_dailink); i++) { + if (!strcmp(cht_dailink[i].codecs->name, RT5672_I2C_DEFAULT)) { + dai_index = i; + break; + } + } + /* fixup codec name based on HID */ adev = acpi_dev_get_first_match_dev(mach->id, NULL, -1); if (adev) { snprintf(drv->codec_name, sizeof(drv->codec_name), "i2c-%s", acpi_dev_name(adev)); put_device(&adev->dev); - for (i = 0; i < ARRAY_SIZE(cht_dailink); i++) { - if (!strcmp(cht_dailink[i].codecs->name, - RT5672_I2C_DEFAULT)) { - cht_dailink[i].codecs->name = drv->codec_name; - break; - } - } + cht_dailink[dai_index].codecs->name = drv->codec_name; + } + + /* Use SSP0 on Bay Trail CR devices */ + if (soc_intel_is_byt() && mach->mach_params.acpi_ipc_irq_index == 0) { + cht_dailink[dai_index].cpus->dai_name = "ssp0-port"; + drv->use_ssp0 = true; } /* override plaform name, if required */ From 84cb0d5581b6a7bd5d96013f67e9f2eb0c7b4378 Mon Sep 17 00:00:00 2001 From: Hans de Goede Date: Fri, 2 Apr 2021 16:07:45 +0200 Subject: [PATCH 401/587] ASoC: rt5670: Add a quirk for the Dell Venue 10 Pro 5055 Add a quirk with the jack-detect and dmic settings necessary to make jack-detect and the builtin mic work on Dell Venue 10 Pro 5055 tablets. Signed-off-by: Hans de Goede Acked-by: Pierre-Louis Bossart Link: https://lore.kernel.org/r/20210402140747.174716-5-hdegoede@redhat.com Signed-off-by: Mark Brown --- sound/soc/codecs/rt5670.c | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/sound/soc/codecs/rt5670.c b/sound/soc/codecs/rt5670.c index 8dcda24f3ceb..810d0e72eac7 100644 --- a/sound/soc/codecs/rt5670.c +++ b/sound/soc/codecs/rt5670.c @@ -2980,6 +2980,18 @@ static const struct dmi_system_id dmi_platform_intel_quirks[] = { RT5670_GPIO1_IS_IRQ | RT5670_JD_MODE3), }, + { + .callback = rt5670_quirk_cb, + .ident = "Dell Venue 10 Pro 5055", + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."), + DMI_MATCH(DMI_PRODUCT_NAME, "Venue 10 Pro 5055"), + }, + .driver_data = (unsigned long *)(RT5670_DMIC_EN | + RT5670_DMIC2_INR | + RT5670_GPIO1_IS_IRQ | + RT5670_JD_MODE1), + }, { .callback = rt5670_quirk_cb, .ident = "Aegex 10 tablet (RU2)", From 3d534537648bd7d7a82f2becc9ded99a4b228a6a Mon Sep 17 00:00:00 2001 From: Hans de Goede Date: Fri, 2 Apr 2021 16:07:46 +0200 Subject: [PATCH 402/587] ASoC: rt5670: Add a rt5670_components() helper The rt5670 codec driver uses DMI quirks to configure the DMIC data-pins, which means that it knows which DMIC interface is used on a specific device. ATM we duplicate this DMI matching inside the UCM profiles to select the right DMIC interface. Add a rt5670_components() helper which the machine-driver can use to set the components string of the card so that UCM can get the info from the components string. This way we only need to add new DMI quirks in one place. Signed-off-by: Hans de Goede Acked-by: Pierre-Louis Bossart Link: https://lore.kernel.org/r/20210402140747.174716-6-hdegoede@redhat.com Signed-off-by: Mark Brown --- sound/soc/codecs/rt5670.c | 39 +++++++++++++++++++++++++++++++++++++++ sound/soc/codecs/rt5670.h | 2 ++ 2 files changed, 41 insertions(+) diff --git a/sound/soc/codecs/rt5670.c b/sound/soc/codecs/rt5670.c index 810d0e72eac7..ecbaf129a6e3 100644 --- a/sound/soc/codecs/rt5670.c +++ b/sound/soc/codecs/rt5670.c @@ -3007,6 +3007,45 @@ static const struct dmi_system_id dmi_platform_intel_quirks[] = { {} }; +const char *rt5670_components(void) +{ + unsigned long quirk; + bool dmic1 = false; + bool dmic2 = false; + bool dmic3 = false; + + if (quirk_override) { + quirk = quirk_override; + } else { + dmi_check_system(dmi_platform_intel_quirks); + quirk = rt5670_quirk; + } + + if ((quirk & RT5670_DMIC1_IN2P) || + (quirk & RT5670_DMIC1_GPIO6) || + (quirk & RT5670_DMIC1_GPIO7)) + dmic1 = true; + + if ((quirk & RT5670_DMIC2_INR) || + (quirk & RT5670_DMIC2_GPIO8)) + dmic2 = true; + + if (quirk & RT5670_DMIC3_GPIO5) + dmic3 = true; + + if (dmic1 && dmic2) + return "cfg-spk:2 cfg-mic:dmics12"; + else if (dmic1) + return "cfg-spk:2 cfg-mic:dmic1"; + else if (dmic2) + return "cfg-spk:2 cfg-mic:dmic2"; + else if (dmic3) + return "cfg-spk:2 cfg-mic:dmic3"; + + return NULL; +} +EXPORT_SYMBOL_GPL(rt5670_components); + static int rt5670_i2c_probe(struct i2c_client *i2c, const struct i2c_device_id *id) { diff --git a/sound/soc/codecs/rt5670.h b/sound/soc/codecs/rt5670.h index 6fb3c369ee98..5b230897f630 100644 --- a/sound/soc/codecs/rt5670.h +++ b/sound/soc/codecs/rt5670.h @@ -2024,4 +2024,6 @@ void rt5670_jack_suspend(struct snd_soc_component *component); void rt5670_jack_resume(struct snd_soc_component *component); int rt5670_set_jack_detect(struct snd_soc_component *component, struct snd_soc_jack *jack); +const char *rt5670_components(void); + #endif /* __RT5670_H__ */ From e992a51b1d14317f414d4b9935966dca96ac0b36 Mon Sep 17 00:00:00 2001 From: Hans de Goede Date: Fri, 2 Apr 2021 16:07:47 +0200 Subject: [PATCH 403/587] ASoC: Intel: cht_bsw_rt5672: Set card.components string Set the card.components string using the new rt5670_components() helper which returns a components string based on the DMI quirks inside the rt5670 codec driver. Signed-off-by: Hans de Goede Acked-by: Pierre-Louis Bossart Link: https://lore.kernel.org/r/20210402140747.174716-7-hdegoede@redhat.com Signed-off-by: Mark Brown --- sound/soc/intel/boards/cht_bsw_rt5672.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/sound/soc/intel/boards/cht_bsw_rt5672.c b/sound/soc/intel/boards/cht_bsw_rt5672.c index 10d5ed20e4e8..e358632f50d7 100644 --- a/sound/soc/intel/boards/cht_bsw_rt5672.c +++ b/sound/soc/intel/boards/cht_bsw_rt5672.c @@ -493,6 +493,8 @@ static int snd_cht_mc_probe(struct platform_device *pdev) if (ret_val) return ret_val; + snd_soc_card_cht.components = rt5670_components(); + drv->mclk = devm_clk_get(&pdev->dev, "pmc_plt_clk_3"); if (IS_ERR(drv->mclk)) { dev_err(&pdev->dev, From 53cc2643c1498779c86ee8e038273c2b2d9c8126 Mon Sep 17 00:00:00 2001 From: Dan Carpenter Date: Fri, 2 Apr 2021 14:42:50 +0300 Subject: [PATCH 404/587] ALSA: control - off by one in store_mode() If count is 16 then this will put the NUL terminator one element beyond the end of the array. Fixes: cb17fe0045aa ("ALSA: control - add sysfs support to the LED trigger module") Signed-off-by: Dan Carpenter Reviewed-by: Jaroslav Kysela Link: https://lore.kernel.org/r/YGcDOtrimR46vr0k@mwanda Signed-off-by: Takashi Iwai --- sound/core/control_led.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sound/core/control_led.c b/sound/core/control_led.c index 788fd9e275e0..d756a52e58db 100644 --- a/sound/core/control_led.c +++ b/sound/core/control_led.c @@ -391,7 +391,7 @@ static ssize_t store_mode(struct device *dev, struct device_attribute *attr, { struct snd_ctl_led *led = container_of(dev, struct snd_ctl_led, dev); char _buf[16]; - size_t l = min(count, sizeof(_buf) - 1) + 1; + size_t l = min(count, sizeof(_buf) - 1); enum snd_ctl_led_mode mode; memcpy(_buf, buf, l); From 29654ed8384e9dbaf4cfba689dbcb664a6ab4bb7 Mon Sep 17 00:00:00 2001 From: Annaliese McDermond Date: Wed, 31 Mar 2021 18:21:45 +0000 Subject: [PATCH 405/587] ASoC: tlv320aic32x4: Increase maximum register in regmap AIC32X4_REFPOWERUP was added as a register, but the maximum register value in the regmap and regmap range was not correspondingly increased. This caused an error when this register was attempted to be written. Fixes: ec96690de82c ("ASoC: tlv320aic32x4: Enable fast charge") Cc: stable@vger.kernel.org Signed-off-by: Annaliese McDermond Link: https://lore.kernel.org/r/0101017889851cab-ce60cfdb-d88c-43d8-bbd2-7fbf34a0c912-000000@us-west-2.amazonses.com Signed-off-by: Mark Brown --- sound/soc/codecs/tlv320aic32x4.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/sound/soc/codecs/tlv320aic32x4.c b/sound/soc/codecs/tlv320aic32x4.c index f04f88c8d425..1ac3b3b12dc6 100644 --- a/sound/soc/codecs/tlv320aic32x4.c +++ b/sound/soc/codecs/tlv320aic32x4.c @@ -577,12 +577,12 @@ static const struct regmap_range_cfg aic32x4_regmap_pages[] = { .window_start = 0, .window_len = 128, .range_min = 0, - .range_max = AIC32X4_RMICPGAVOL, + .range_max = AIC32X4_REFPOWERUP, }, }; const struct regmap_config aic32x4_regmap_config = { - .max_register = AIC32X4_RMICPGAVOL, + .max_register = AIC32X4_REFPOWERUP, .ranges = aic32x4_regmap_pages, .num_ranges = ARRAY_SIZE(aic32x4_regmap_pages), }; From 1ca1156cfd69530e6b7cb99943baf90c8bd871a5 Mon Sep 17 00:00:00 2001 From: Annaliese McDermond Date: Wed, 31 Mar 2021 18:21:38 +0000 Subject: [PATCH 406/587] ASoC: tlv320aic32x4: Register clocks before registering component Clock registration must be performed before the component is registered. aic32x4_component_probe attempts to get all the clocks right off the bat. If the component is registered before the clocks there is a race condition where the clocks may not be registered by the time aic32x4_componet_probe actually runs. Fixes: d1c859d314d8 ("ASoC: codec: tlv3204: Increased maximum supported channels") Cc: stable@vger.kernel.org Signed-off-by: Annaliese McDermond Link: https://lore.kernel.org/r/0101017889850206-dcac4cce-8cc8-4a21-80e9-4e4bef44b981-000000@us-west-2.amazonses.com Signed-off-by: Mark Brown --- sound/soc/codecs/tlv320aic32x4.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/sound/soc/codecs/tlv320aic32x4.c b/sound/soc/codecs/tlv320aic32x4.c index 1ac3b3b12dc6..b689f26fc4be 100644 --- a/sound/soc/codecs/tlv320aic32x4.c +++ b/sound/soc/codecs/tlv320aic32x4.c @@ -1243,6 +1243,10 @@ int aic32x4_probe(struct device *dev, struct regmap *regmap) if (ret) goto err_disable_regulators; + ret = aic32x4_register_clocks(dev, aic32x4->mclk_name); + if (ret) + goto err_disable_regulators; + ret = devm_snd_soc_register_component(dev, &soc_component_dev_aic32x4, &aic32x4_dai, 1); if (ret) { @@ -1250,10 +1254,6 @@ int aic32x4_probe(struct device *dev, struct regmap *regmap) goto err_disable_regulators; } - ret = aic32x4_register_clocks(dev, aic32x4->mclk_name); - if (ret) - goto err_disable_regulators; - return 0; err_disable_regulators: From c7c19ec098b862a688291f5a1101f7de6e4b0a6c Mon Sep 17 00:00:00 2001 From: Vamshi Krishna Gopal Date: Mon, 5 Apr 2021 18:18:34 +0530 Subject: [PATCH 407/587] ASoC: Intel: kbl: Add MST route change to kbl machine drivers To support MST hdmi audio, modify the current routes to be based on port in kbl_da7219_max98357a, kbl_da7219_max98927 & kbl_rt5663_max98927. Signed-off-by: Vamshi Krishna Gopal Acked-by: Pierre-Louis Bossart Link: https://lore.kernel.org/r/20210405124835.71247-2-vamshi.krishna.gopal@intel.com Signed-off-by: Mark Brown --- sound/soc/intel/boards/kbl_da7219_max98357a.c | 10 ++++++---- sound/soc/intel/boards/kbl_da7219_max98927.c | 10 ++++++---- sound/soc/intel/boards/kbl_rt5663_max98927.c | 14 ++++++++++---- 3 files changed, 22 insertions(+), 12 deletions(-) diff --git a/sound/soc/intel/boards/kbl_da7219_max98357a.c b/sound/soc/intel/boards/kbl_da7219_max98357a.c index dc3d897ad280..0e689ec7e11b 100644 --- a/sound/soc/intel/boards/kbl_da7219_max98357a.c +++ b/sound/soc/intel/boards/kbl_da7219_max98357a.c @@ -90,8 +90,9 @@ static const struct snd_soc_dapm_widget kabylake_widgets[] = { SND_SOC_DAPM_MIC("Headset Mic", NULL), SND_SOC_DAPM_SPK("Spk", NULL), SND_SOC_DAPM_MIC("SoC DMIC", NULL), - SND_SOC_DAPM_SPK("DP", NULL), - SND_SOC_DAPM_SPK("HDMI", NULL), + SND_SOC_DAPM_SPK("HDMI1", NULL), + SND_SOC_DAPM_SPK("HDMI2", NULL), + SND_SOC_DAPM_SPK("HDMI3", NULL), SND_SOC_DAPM_SUPPLY("Platform Clock", SND_SOC_NOPM, 0, 0, platform_clock_control, SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD), @@ -108,8 +109,9 @@ static const struct snd_soc_dapm_route kabylake_map[] = { { "MIC", NULL, "Headset Mic" }, { "DMic", NULL, "SoC DMIC" }, - { "HDMI", NULL, "hif5 Output" }, - { "DP", NULL, "hif6 Output" }, + {"HDMI1", NULL, "hif5-0 Output"}, + {"HDMI2", NULL, "hif6-0 Output"}, + {"HDMI3", NULL, "hif7-0 Output"}, /* CODEC BE connections */ { "HiFi Playback", NULL, "ssp0 Tx" }, diff --git a/sound/soc/intel/boards/kbl_da7219_max98927.c b/sound/soc/intel/boards/kbl_da7219_max98927.c index cc9a2509ace2..9dfe5bd9180d 100644 --- a/sound/soc/intel/boards/kbl_da7219_max98927.c +++ b/sound/soc/intel/boards/kbl_da7219_max98927.c @@ -111,8 +111,9 @@ static const struct snd_soc_dapm_widget kabylake_widgets[] = { SND_SOC_DAPM_SPK("Left Spk", NULL), SND_SOC_DAPM_SPK("Right Spk", NULL), SND_SOC_DAPM_MIC("SoC DMIC", NULL), - SND_SOC_DAPM_SPK("DP", NULL), - SND_SOC_DAPM_SPK("HDMI", NULL), + SND_SOC_DAPM_SPK("HDMI1", NULL), + SND_SOC_DAPM_SPK("HDMI2", NULL), + SND_SOC_DAPM_SPK("HDMI3", NULL), SND_SOC_DAPM_SUPPLY("Platform Clock", SND_SOC_NOPM, 0, 0, platform_clock_control, SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD), @@ -126,8 +127,9 @@ static const struct snd_soc_dapm_route kabylake_map[] = { /* other jacks */ { "DMic", NULL, "SoC DMIC" }, - { "HDMI", NULL, "hif5 Output" }, - { "DP", NULL, "hif6 Output" }, + {"HDMI1", NULL, "hif5-0 Output"}, + {"HDMI2", NULL, "hif6-0 Output"}, + {"HDMI3", NULL, "hif7-0 Output"}, /* CODEC BE connections */ { "Left HiFi Playback", NULL, "ssp0 Tx" }, diff --git a/sound/soc/intel/boards/kbl_rt5663_max98927.c b/sound/soc/intel/boards/kbl_rt5663_max98927.c index 9a4b3d0973f6..a3de55a3b58d 100644 --- a/sound/soc/intel/boards/kbl_rt5663_max98927.c +++ b/sound/soc/intel/boards/kbl_rt5663_max98927.c @@ -151,6 +151,10 @@ static const struct snd_soc_dapm_route kabylake_map[] = { { "IN1N", NULL, "Headset Mic" }, { "DMic", NULL, "SoC DMIC" }, + {"HDMI1", NULL, "hif5-0 Output"}, + {"HDMI2", NULL, "hif6-0 Output"}, + {"HDMI3", NULL, "hif7-0 Output"}, + /* CODEC BE connections */ { "Left HiFi Playback", NULL, "ssp0 Tx" }, { "Right HiFi Playback", NULL, "ssp0 Tx" }, @@ -194,8 +198,9 @@ static const struct snd_kcontrol_new kabylake_5663_controls[] = { static const struct snd_soc_dapm_widget kabylake_5663_widgets[] = { SND_SOC_DAPM_HP("Headphone Jack", NULL), SND_SOC_DAPM_MIC("Headset Mic", NULL), - SND_SOC_DAPM_SPK("DP", NULL), - SND_SOC_DAPM_SPK("HDMI", NULL), + SND_SOC_DAPM_SPK("HDMI1", NULL), + SND_SOC_DAPM_SPK("HDMI2", NULL), + SND_SOC_DAPM_SPK("HDMI3", NULL), SND_SOC_DAPM_SUPPLY("Platform Clock", SND_SOC_NOPM, 0, 0, platform_clock_control, SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD), @@ -211,8 +216,9 @@ static const struct snd_soc_dapm_route kabylake_5663_map[] = { { "IN1P", NULL, "Headset Mic" }, { "IN1N", NULL, "Headset Mic" }, - { "HDMI", NULL, "hif5 Output" }, - { "DP", NULL, "hif6 Output" }, + {"HDMI1", NULL, "hif5-0 Output"}, + {"HDMI2", NULL, "hif6-0 Output"}, + {"HDMI3", NULL, "hif7-0 Output"}, /* CODEC BE connections */ { "AIF Playback", NULL, "ssp1 Tx" }, From 74ed9e9bfb7343b0a6710b651df66f3d68551110 Mon Sep 17 00:00:00 2001 From: Mac Chiang Date: Mon, 5 Apr 2021 18:18:35 +0530 Subject: [PATCH 408/587] ASoc: Intel: board: add BE DAI link for WoV create dai link in kbl_da7219_max98357a driver for wake on voice functionality. changes picked from broonie's tree commit 0c7941a63a0f ("ASoC: Intel: Skylake: Use refcap device for mono recording") commit 2154be362c90 ("ASoc: Intel: boards: Add WOV as sink for nau88l25_ssm4567 machine") Signed-off-by: Mac Chiang Signed-off-by: Vamshi Krishna Gopal Tested-by: Kaiyen Chang Tested-by: luke yang Tested-by: Grace Kao Tested-by: Kaiyen Chang Reviewed-by: Cheng-Yi Chiang Acked-by: Pierre-Louis Bossart Link: https://lore.kernel.org/r/20210405124835.71247-3-vamshi.krishna.gopal@intel.com Signed-off-by: Mark Brown --- sound/soc/intel/boards/kbl_da7219_max98357a.c | 48 +++++++++++++++++++ 1 file changed, 48 insertions(+) diff --git a/sound/soc/intel/boards/kbl_da7219_max98357a.c b/sound/soc/intel/boards/kbl_da7219_max98357a.c index 0e689ec7e11b..c0d8a73c6d21 100644 --- a/sound/soc/intel/boards/kbl_da7219_max98357a.c +++ b/sound/soc/intel/boards/kbl_da7219_max98357a.c @@ -44,6 +44,7 @@ struct kbl_codec_private { enum { KBL_DPCM_AUDIO_PB = 0, KBL_DPCM_AUDIO_CP, + KBL_DPCM_AUDIO_REF_CP, KBL_DPCM_AUDIO_DMIC_CP, KBL_DPCM_AUDIO_HDMI1_PB, KBL_DPCM_AUDIO_HDMI2_PB, @@ -338,12 +339,49 @@ static struct snd_soc_ops kabylake_dmic_ops = { .startup = kabylake_dmic_startup, }; +static unsigned int rates_16000[] = { + 16000, +}; + +static const struct snd_pcm_hw_constraint_list constraints_16000 = { + .count = ARRAY_SIZE(rates_16000), + .list = rates_16000, +}; + +static const unsigned int ch_mono[] = { + 1, +}; + +static const struct snd_pcm_hw_constraint_list constraints_refcap = { + .count = ARRAY_SIZE(ch_mono), + .list = ch_mono, +}; + +static int kabylake_refcap_startup(struct snd_pcm_substream *substream) +{ + substream->runtime->hw.channels_max = 1; + snd_pcm_hw_constraint_list(substream->runtime, 0, + SNDRV_PCM_HW_PARAM_CHANNELS, + &constraints_refcap); + + return snd_pcm_hw_constraint_list(substream->runtime, 0, + SNDRV_PCM_HW_PARAM_RATE, + &constraints_16000); +} + +static struct snd_soc_ops skylake_refcap_ops = { + .startup = kabylake_refcap_startup, +}; + SND_SOC_DAILINK_DEF(dummy, DAILINK_COMP_ARRAY(COMP_DUMMY())); SND_SOC_DAILINK_DEF(system, DAILINK_COMP_ARRAY(COMP_CPU("System Pin"))); +SND_SOC_DAILINK_DEF(reference, + DAILINK_COMP_ARRAY(COMP_CPU("Reference Pin"))); + SND_SOC_DAILINK_DEF(dmic, DAILINK_COMP_ARRAY(COMP_CPU("DMIC Pin"))); @@ -418,6 +456,16 @@ static struct snd_soc_dai_link kabylake_dais[] = { .ops = &kabylake_da7219_fe_ops, SND_SOC_DAILINK_REG(system, dummy, platform), }, + [KBL_DPCM_AUDIO_REF_CP] = { + .name = "Kbl Audio Reference cap", + .stream_name = "Wake on Voice", + .init = NULL, + .dpcm_capture = 1, + .nonatomic = 1, + .dynamic = 1, + .ops = &skylake_refcap_ops, + SND_SOC_DAILINK_REG(reference, dummy, platform), + }, [KBL_DPCM_AUDIO_DMIC_CP] = { .name = "Kbl Audio DMIC cap", .stream_name = "dmiccap", From a43508995a913893c5f303e56415d06432b15619 Mon Sep 17 00:00:00 2001 From: Shengjiu Wang Date: Sat, 3 Apr 2021 21:59:25 +0800 Subject: [PATCH 409/587] ASoC: ak5558: Fix s/show/slow/ typo s/show/slow/ Fixes: 920884777480 ("ASoC: ak5558: Add support for AK5558 ADC driver") Signed-off-by: Shengjiu Wang Link: https://lore.kernel.org/r/1617458365-23393-1-git-send-email-shengjiu.wang@nxp.com Signed-off-by: Mark Brown --- sound/soc/codecs/ak5558.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/sound/soc/codecs/ak5558.c b/sound/soc/codecs/ak5558.c index 3ac62a281807..8e4dca753f0b 100644 --- a/sound/soc/codecs/ak5558.c +++ b/sound/soc/codecs/ak5558.c @@ -75,8 +75,8 @@ static const struct soc_enum ak5552_mono_enum[] = { }; static const char * const digfil_texts[] = { - "Sharp Roll-Off", "Show Roll-Off", - "Short Delay Sharp Roll-Off", "Short Delay Show Roll-Off", + "Sharp Roll-Off", "Slow Roll-Off", + "Short Delay Sharp Roll-Off", "Short Delay Slow Roll-Off", }; static const struct soc_enum ak5558_adcset_enum[] = { From e5870bd0e40c749fd96a4e565497c789bee456bf Mon Sep 17 00:00:00 2001 From: Steve Lee Date: Mon, 5 Apr 2021 23:38:01 +0900 Subject: [PATCH 410/587] ASoC: max98390: Add support for tx slot configuration. Update voltage/current tx slot configuration support. Signed-off-by: Steve Lee Link: https://lore.kernel.org/r/20210405143801.29770-1-steves.lee@maximintegrated.com Signed-off-by: Mark Brown --- sound/soc/codecs/max98390.c | 62 +++++++++++++++++++++++++++++++++++++ sound/soc/codecs/max98390.h | 2 ++ 2 files changed, 64 insertions(+) diff --git a/sound/soc/codecs/max98390.c b/sound/soc/codecs/max98390.c index bb736c44e68a..94773ccee9d5 100644 --- a/sound/soc/codecs/max98390.c +++ b/sound/soc/codecs/max98390.c @@ -856,6 +856,48 @@ static void max98390_init_regs(struct snd_soc_component *component) regmap_write(max98390->regmap, MAX98390_ENV_TRACK_VOUT_HEADROOM, 0x0e); regmap_write(max98390->regmap, MAX98390_BOOST_BYPASS1, 0x46); regmap_write(max98390->regmap, MAX98390_FET_SCALING3, 0x03); + + /* voltage, current slot configuration */ + regmap_write(max98390->regmap, + MAX98390_PCM_CH_SRC_2, + (max98390->i_l_slot << 4 | + max98390->v_l_slot)&0xFF); + + if (max98390->v_l_slot < 8) { + regmap_update_bits(max98390->regmap, + MAX98390_PCM_TX_HIZ_CTRL_A, + 1 << max98390->v_l_slot, 0); + regmap_update_bits(max98390->regmap, + MAX98390_PCM_TX_EN_A, + 1 << max98390->v_l_slot, + 1 << max98390->v_l_slot); + } else { + regmap_update_bits(max98390->regmap, + MAX98390_PCM_TX_HIZ_CTRL_B, + 1 << (max98390->v_l_slot - 8), 0); + regmap_update_bits(max98390->regmap, + MAX98390_PCM_TX_EN_B, + 1 << (max98390->v_l_slot - 8), + 1 << (max98390->v_l_slot - 8)); + } + + if (max98390->i_l_slot < 8) { + regmap_update_bits(max98390->regmap, + MAX98390_PCM_TX_HIZ_CTRL_A, + 1 << max98390->i_l_slot, 0); + regmap_update_bits(max98390->regmap, + MAX98390_PCM_TX_EN_A, + 1 << max98390->i_l_slot, + 1 << max98390->i_l_slot); + } else { + regmap_update_bits(max98390->regmap, + MAX98390_PCM_TX_HIZ_CTRL_B, + 1 << (max98390->i_l_slot - 8), 0); + regmap_update_bits(max98390->regmap, + MAX98390_PCM_TX_EN_B, + 1 << (max98390->i_l_slot - 8), + 1 << (max98390->i_l_slot - 8)); + } } static int max98390_probe(struct snd_soc_component *component) @@ -946,6 +988,23 @@ static const struct regmap_config max98390_regmap = { .cache_type = REGCACHE_RBTREE, }; +static void max98390_slot_config(struct i2c_client *i2c, + struct max98390_priv *max98390) +{ + int value; + struct device *dev = &i2c->dev; + + if (!device_property_read_u32(dev, "maxim,vmon-slot-no", &value)) + max98390->v_l_slot = value & 0xF; + else + max98390->v_l_slot = 0; + + if (!device_property_read_u32(dev, "maxim,imon-slot-no", &value)) + max98390->i_l_slot = value & 0xF; + else + max98390->i_l_slot = 1; +} + static int max98390_i2c_probe(struct i2c_client *i2c, const struct i2c_device_id *id) { @@ -988,6 +1047,9 @@ static int max98390_i2c_probe(struct i2c_client *i2c, __func__, max98390->ref_rdc_value, max98390->ambient_temp_value); + /* voltage/current slot configuration */ + max98390_slot_config(i2c, max98390); + /* regmap initialization */ max98390->regmap = devm_regmap_init_i2c(i2c, &max98390_regmap); if (IS_ERR(max98390->regmap)) { diff --git a/sound/soc/codecs/max98390.h b/sound/soc/codecs/max98390.h index dff884f68e3e..e31516717d3b 100644 --- a/sound/soc/codecs/max98390.h +++ b/sound/soc/codecs/max98390.h @@ -658,6 +658,8 @@ struct max98390_priv { unsigned int sysclk; unsigned int master; unsigned int tdm_mode; + unsigned int v_l_slot; + unsigned int i_l_slot; unsigned int ref_rdc_value; unsigned int ambient_temp_value; }; From 5fb45414ae03421255593fd5556aa2d1d82303aa Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Tue, 6 Apr 2021 13:35:34 +0200 Subject: [PATCH 411/587] ALSA: usb-audio: Add error checks for usb_driver_claim_interface() calls There are a few calls of usb_driver_claim_interface() but all of those miss the proper error checks, as reported by Coverity. This patch adds those missing checks. Along with it, replace the magic pointer with -1 with a constant USB_AUDIO_IFACE_UNUSED for better readability. Reported-by: coverity-bot Addresses-Coverity-ID: 1475943 ("Error handling issues") Addresses-Coverity-ID: 1475944 ("Error handling issues") Addresses-Coverity-ID: 1475945 ("Error handling issues") Fixes: b1ce7ba619d9 ("ALSA: usb-audio: claim autodetected PCM interfaces all at once") Fixes: e5779998bf8b ("ALSA: usb-audio: refactor code") Link: https://lore.kernel.org/r/202104051059.FB7F3016@keescook Link: https://lore.kernel.org/r/20210406113534.30455-1-tiwai@suse.de Signed-off-by: Takashi Iwai --- sound/usb/card.c | 14 +++++++------- sound/usb/quirks.c | 16 ++++++++++++---- sound/usb/usbaudio.h | 2 ++ 3 files changed, 21 insertions(+), 11 deletions(-) diff --git a/sound/usb/card.c b/sound/usb/card.c index 0826a437f8fc..7b7526d3a56e 100644 --- a/sound/usb/card.c +++ b/sound/usb/card.c @@ -181,9 +181,8 @@ static int snd_usb_create_stream(struct snd_usb_audio *chip, int ctrlif, int int ctrlif, interface); return -EINVAL; } - usb_driver_claim_interface(&usb_audio_driver, iface, (void *)-1L); - - return 0; + return usb_driver_claim_interface(&usb_audio_driver, iface, + USB_AUDIO_IFACE_UNUSED); } if ((altsd->bInterfaceClass != USB_CLASS_AUDIO && @@ -203,7 +202,8 @@ static int snd_usb_create_stream(struct snd_usb_audio *chip, int ctrlif, int int if (! snd_usb_parse_audio_interface(chip, interface)) { usb_set_interface(dev, interface, 0); /* reset the current interface */ - usb_driver_claim_interface(&usb_audio_driver, iface, (void *)-1L); + return usb_driver_claim_interface(&usb_audio_driver, iface, + USB_AUDIO_IFACE_UNUSED); } return 0; @@ -862,7 +862,7 @@ static void usb_audio_disconnect(struct usb_interface *intf) struct snd_card *card; struct list_head *p; - if (chip == (void *)-1L) + if (chip == USB_AUDIO_IFACE_UNUSED) return; card = chip->card; @@ -992,7 +992,7 @@ static int usb_audio_suspend(struct usb_interface *intf, pm_message_t message) struct usb_mixer_interface *mixer; struct list_head *p; - if (chip == (void *)-1L) + if (chip == USB_AUDIO_IFACE_UNUSED) return 0; if (!chip->num_suspended_intf++) { @@ -1022,7 +1022,7 @@ static int __usb_audio_resume(struct usb_interface *intf, bool reset_resume) struct list_head *p; int err = 0; - if (chip == (void *)-1L) + if (chip == USB_AUDIO_IFACE_UNUSED) return 0; atomic_inc(&chip->active); /* avoid autopm */ diff --git a/sound/usb/quirks.c b/sound/usb/quirks.c index 9e5e37eff10e..232fbc0d37bd 100644 --- a/sound/usb/quirks.c +++ b/sound/usb/quirks.c @@ -55,8 +55,12 @@ static int create_composite_quirk(struct snd_usb_audio *chip, if (!iface) continue; if (quirk->ifnum != probed_ifnum && - !usb_interface_claimed(iface)) - usb_driver_claim_interface(driver, iface, (void *)-1L); + !usb_interface_claimed(iface)) { + err = usb_driver_claim_interface(driver, iface, + USB_AUDIO_IFACE_UNUSED); + if (err < 0) + return err; + } } return 0; @@ -426,8 +430,12 @@ static int create_autodetect_quirks(struct snd_usb_audio *chip, continue; err = create_autodetect_quirk(chip, iface, driver); - if (err >= 0) - usb_driver_claim_interface(driver, iface, (void *)-1L); + if (err >= 0) { + err = usb_driver_claim_interface(driver, iface, + USB_AUDIO_IFACE_UNUSED); + if (err < 0) + return err; + } } return 0; diff --git a/sound/usb/usbaudio.h b/sound/usb/usbaudio.h index 60b9dd7df6bb..8794c8658ab9 100644 --- a/sound/usb/usbaudio.h +++ b/sound/usb/usbaudio.h @@ -61,6 +61,8 @@ struct snd_usb_audio { struct media_intf_devnode *ctl_intf_media_devnode; }; +#define USB_AUDIO_IFACE_UNUSED ((void *)-1L) + #define usb_audio_err(chip, fmt, args...) \ dev_err(&(chip)->dev->dev, fmt, ##args) #define usb_audio_warn(chip, fmt, args...) \ From 884c7094a272fb674423bd5a473caa3c714045fe Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Tue, 6 Apr 2021 13:38:37 +0200 Subject: [PATCH 412/587] ALSA: usb-audio: Drop implicit fb quirk entries dubbed for capture The implicit feedback quirk table contains the entries that also appear in the capture quirks, and those are all handled to be skipped. For the code simplicity, drop the duped entries in the playback quirk table, and check the match with the capture quirk table instead. BugLink: https://bugzilla.kernel.org/show_bug.cgi?id=212519 Link: https://lore.kernel.org/r/20210406113837.32041-1-tiwai@suse.de Signed-off-by: Takashi Iwai --- sound/usb/implicit.c | 15 +++++---------- 1 file changed, 5 insertions(+), 10 deletions(-) diff --git a/sound/usb/implicit.c b/sound/usb/implicit.c index 11a85e66aa96..19622c58b72b 100644 --- a/sound/usb/implicit.c +++ b/sound/usb/implicit.c @@ -70,16 +70,6 @@ static const struct snd_usb_implicit_fb_match playback_implicit_fb_quirks[] = { .type = IMPLICIT_FB_FIXED, .ep_num = 0x84, .iface = 0 }, /* MOTU MicroBook II */ - /* No quirk for playback but with capture quirk (see below) */ - IMPLICIT_FB_SKIP_DEV(0x0582, 0x0130), /* BOSS BR-80 */ - IMPLICIT_FB_SKIP_DEV(0x0582, 0x0171), /* BOSS RC-505 */ - IMPLICIT_FB_SKIP_DEV(0x0582, 0x0185), /* BOSS GP-10 */ - IMPLICIT_FB_SKIP_DEV(0x0582, 0x0189), /* BOSS GT-100v2 */ - IMPLICIT_FB_SKIP_DEV(0x0582, 0x01d6), /* BOSS GT-1 */ - IMPLICIT_FB_SKIP_DEV(0x0582, 0x01d8), /* BOSS Katana */ - IMPLICIT_FB_SKIP_DEV(0x0582, 0x01e5), /* BOSS GT-001 */ - IMPLICIT_FB_SKIP_DEV(0x0582, 0x0203), /* BOSS AD-10 */ - {} /* terminator */ }; @@ -278,6 +268,11 @@ static int audioformat_implicit_fb_quirk(struct snd_usb_audio *chip, } } + /* Don't apply playback quirks for the devices with capture quirk */ + p = find_implicit_fb_entry(chip, capture_implicit_fb_quirks, alts); + if (p && p->type == IMPLICIT_FB_FIXED) + return 0; /* no quirk */ + /* Generic UAC2 implicit feedback */ if (attr == USB_ENDPOINT_SYNC_ASYNC && alts->desc.bInterfaceClass == USB_CLASS_AUDIO && From 6f68accaa8641b70b698da659216f82f87537869 Mon Sep 17 00:00:00 2001 From: Jerome Brunet Date: Wed, 7 Apr 2021 16:57:14 +0200 Subject: [PATCH 413/587] ASoC: meson: axg-frddr: set fifo depth according to the period When the period is small, using all the FRDDR fifo depth increases the latency of the playback because the following device won't start pulling data until the fifo reaches the depth set. We can adjust this depth so trim it down for small periods. Signed-off-by: Jerome Brunet Link: https://lore.kernel.org/r/20210407145714.311138-1-jbrunet@baylibre.com Signed-off-by: Mark Brown --- sound/soc/meson/axg-frddr.c | 26 ++++++++++++++++++++------ 1 file changed, 20 insertions(+), 6 deletions(-) diff --git a/sound/soc/meson/axg-frddr.c b/sound/soc/meson/axg-frddr.c index c3ae8ac30745..8ed114de0bdf 100644 --- a/sound/soc/meson/axg-frddr.c +++ b/sound/soc/meson/axg-frddr.c @@ -11,6 +11,7 @@ #include #include #include +#include #include #include @@ -46,11 +47,28 @@ static int g12a_frddr_dai_prepare(struct snd_pcm_substream *substream, return 0; } +static int axg_frddr_dai_hw_params(struct snd_pcm_substream *substream, + struct snd_pcm_hw_params *params, + struct snd_soc_dai *dai) +{ + struct axg_fifo *fifo = snd_soc_dai_get_drvdata(dai); + unsigned int period, depth, val; + + period = params_period_bytes(params); + + /* Trim the FIFO depth if the period is small to improve latency */ + depth = min(period, fifo->depth); + val = (depth / AXG_FIFO_BURST) - 1; + regmap_update_bits(fifo->map, FIFO_CTRL1, CTRL1_FRDDR_DEPTH_MASK, + CTRL1_FRDDR_DEPTH(val)); + + return 0; +} + static int axg_frddr_dai_startup(struct snd_pcm_substream *substream, struct snd_soc_dai *dai) { struct axg_fifo *fifo = snd_soc_dai_get_drvdata(dai); - unsigned int val; int ret; /* Enable pclk to access registers and clock the fifo ip */ @@ -61,11 +79,6 @@ static int axg_frddr_dai_startup(struct snd_pcm_substream *substream, /* Apply single buffer mode to the interface */ regmap_update_bits(fifo->map, FIFO_CTRL0, CTRL0_FRDDR_PP_MODE, 0); - /* Use all fifo depth */ - val = (fifo->depth / AXG_FIFO_BURST) - 1; - regmap_update_bits(fifo->map, FIFO_CTRL1, CTRL1_FRDDR_DEPTH_MASK, - CTRL1_FRDDR_DEPTH(val)); - return 0; } @@ -84,6 +97,7 @@ static int axg_frddr_pcm_new(struct snd_soc_pcm_runtime *rtd, } static const struct snd_soc_dai_ops axg_frddr_ops = { + .hw_params = axg_frddr_dai_hw_params, .startup = axg_frddr_dai_startup, .shutdown = axg_frddr_dai_shutdown, }; From 73a4808892b83c8336c3d913d44b8de68d881369 Mon Sep 17 00:00:00 2001 From: Jiri Prchal Date: Tue, 6 Apr 2021 16:24:36 +0200 Subject: [PATCH 414/587] ASoC: codecs: tlv320aic3x: move model definitions Model definitions moved to header file. Preparation for SPI and I2C separated files. Signed-off-by: Jiri Prchal Link: https://lore.kernel.org/r/20210406142439.102396-2-jiri.prchal@aksignal.cz Signed-off-by: Mark Brown --- sound/soc/codecs/tlv320aic3x.c | 4 ---- sound/soc/codecs/tlv320aic3x.h | 5 +++++ 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/sound/soc/codecs/tlv320aic3x.c b/sound/soc/codecs/tlv320aic3x.c index db1444127444..812f0f117fd3 100644 --- a/sound/soc/codecs/tlv320aic3x.c +++ b/sound/soc/codecs/tlv320aic3x.c @@ -82,10 +82,6 @@ struct aic3x_priv { int master; int gpio_reset; int power; -#define AIC3X_MODEL_3X 0 -#define AIC3X_MODEL_33 1 -#define AIC3X_MODEL_3007 2 -#define AIC3X_MODEL_3104 3 u16 model; /* Selects the micbias voltage */ diff --git a/sound/soc/codecs/tlv320aic3x.h b/sound/soc/codecs/tlv320aic3x.h index 66d3580cf2b1..21dd6edf1059 100644 --- a/sound/soc/codecs/tlv320aic3x.h +++ b/sound/soc/codecs/tlv320aic3x.h @@ -9,6 +9,11 @@ #ifndef _AIC3X_H #define _AIC3X_H +#define AIC3X_MODEL_3X 0 +#define AIC3X_MODEL_33 1 +#define AIC3X_MODEL_3007 2 +#define AIC3X_MODEL_3104 3 + /* AIC3X register space */ #define AIC3X_CACHEREGNUM 110 From b015df6ac03ee81b259dcb2f1a6faf4cf04ace5a Mon Sep 17 00:00:00 2001 From: Jiri Prchal Date: Tue, 6 Apr 2021 16:24:37 +0200 Subject: [PATCH 415/587] ASoC: codecs: tlv320aic3x: rename probe function Renamed function to have it free for generic probe. Signed-off-by: Jiri Prchal Link: https://lore.kernel.org/r/20210406142439.102396-3-jiri.prchal@aksignal.cz Signed-off-by: Mark Brown --- sound/soc/codecs/tlv320aic3x.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/sound/soc/codecs/tlv320aic3x.c b/sound/soc/codecs/tlv320aic3x.c index 812f0f117fd3..6549ad9296ce 100644 --- a/sound/soc/codecs/tlv320aic3x.c +++ b/sound/soc/codecs/tlv320aic3x.c @@ -1610,7 +1610,7 @@ static bool aic3x_is_shared_reset(struct aic3x_priv *aic3x) return false; } -static int aic3x_probe(struct snd_soc_component *component) +static int aic3x_component_probe(struct snd_soc_component *component) { struct aic3x_priv *aic3x = snd_soc_component_get_drvdata(component); int ret, i; @@ -1689,7 +1689,7 @@ static int aic3x_probe(struct snd_soc_component *component) static const struct snd_soc_component_driver soc_component_dev_aic3x = { .set_bias_level = aic3x_set_bias_level, - .probe = aic3x_probe, + .probe = aic3x_component_probe, .controls = aic3x_snd_controls, .num_controls = ARRAY_SIZE(aic3x_snd_controls), .dapm_widgets = aic3x_dapm_widgets, From a96d2ba2d8248d5e8170f2f44f98d4a33329b08a Mon Sep 17 00:00:00 2001 From: Jiri Prchal Date: Tue, 6 Apr 2021 16:24:38 +0200 Subject: [PATCH 416/587] ASoC: codecs: tlv320aic3x: move I2C to separated file Moved I2C related staff to separated source file. Signed-off-by: Jiri Prchal Link: https://lore.kernel.org/r/20210406142439.102396-4-jiri.prchal@aksignal.cz Signed-off-by: Mark Brown --- sound/soc/codecs/Kconfig | 9 ++- sound/soc/codecs/Makefile | 2 + sound/soc/codecs/tlv320aic3x-i2c.c | 70 ++++++++++++++++++++ sound/soc/codecs/tlv320aic3x.c | 100 ++++++++--------------------- sound/soc/codecs/tlv320aic3x.h | 7 ++ 5 files changed, 112 insertions(+), 76 deletions(-) create mode 100644 sound/soc/codecs/tlv320aic3x-i2c.c diff --git a/sound/soc/codecs/Kconfig b/sound/soc/codecs/Kconfig index 6d9cb00aa3d2..b0323dbabf11 100644 --- a/sound/soc/codecs/Kconfig +++ b/sound/soc/codecs/Kconfig @@ -218,7 +218,7 @@ config SND_SOC_ALL_CODECS imply SND_SOC_TLV320AIC31XX imply SND_SOC_TLV320AIC32X4_I2C imply SND_SOC_TLV320AIC32X4_SPI - imply SND_SOC_TLV320AIC3X + imply SND_SOC_TLV320AIC3X_I2C imply SND_SOC_TPA6130A2 imply SND_SOC_TLV320DAC33 imply SND_SOC_TSCS42XX @@ -1446,8 +1446,13 @@ config SND_SOC_TLV320AIC32X4_SPI select SND_SOC_TLV320AIC32X4 config SND_SOC_TLV320AIC3X - tristate "Texas Instruments TLV320AIC3x CODECs" + tristate + +config SND_SOC_TLV320AIC3X_I2C + tristate "Texas Instruments TLV320AIC3x audio CODECs - I2C" depends on I2C + select SND_SOC_TLV320AIC3X + select REGMAP_I2C config SND_SOC_TLV320DAC33 tristate diff --git a/sound/soc/codecs/Makefile b/sound/soc/codecs/Makefile index 1d8980be7019..f014ea9f2318 100644 --- a/sound/soc/codecs/Makefile +++ b/sound/soc/codecs/Makefile @@ -238,6 +238,7 @@ snd-soc-tlv320aic32x4-objs := tlv320aic32x4.o tlv320aic32x4-clk.o snd-soc-tlv320aic32x4-i2c-objs := tlv320aic32x4-i2c.o snd-soc-tlv320aic32x4-spi-objs := tlv320aic32x4-spi.o snd-soc-tlv320aic3x-objs := tlv320aic3x.o +snd-soc-tlv320aic3x-i2c-objs := tlv320aic3x-i2c.o snd-soc-tlv320dac33-objs := tlv320dac33.o snd-soc-tlv320adcx140-objs := tlv320adcx140.o snd-soc-tscs42xx-objs := tscs42xx.o @@ -558,6 +559,7 @@ obj-$(CONFIG_SND_SOC_TLV320AIC32X4) += snd-soc-tlv320aic32x4.o obj-$(CONFIG_SND_SOC_TLV320AIC32X4_I2C) += snd-soc-tlv320aic32x4-i2c.o obj-$(CONFIG_SND_SOC_TLV320AIC32X4_SPI) += snd-soc-tlv320aic32x4-spi.o obj-$(CONFIG_SND_SOC_TLV320AIC3X) += snd-soc-tlv320aic3x.o +obj-$(CONFIG_SND_SOC_TLV320AIC3X_I2C) += snd-soc-tlv320aic3x-i2c.o obj-$(CONFIG_SND_SOC_TLV320DAC33) += snd-soc-tlv320dac33.o obj-$(CONFIG_SND_SOC_TLV320ADCX140) += snd-soc-tlv320adcx140.o obj-$(CONFIG_SND_SOC_TSCS42XX) += snd-soc-tscs42xx.o diff --git a/sound/soc/codecs/tlv320aic3x-i2c.c b/sound/soc/codecs/tlv320aic3x-i2c.c new file mode 100644 index 000000000000..4535bb8dbadc --- /dev/null +++ b/sound/soc/codecs/tlv320aic3x-i2c.c @@ -0,0 +1,70 @@ +/* SPDX-License-Identifier: GPL-2.0-only + * + * ALSA SoC TLV320AIC3x codec driver I2C interface + * + * Author: Arun KS, + * Copyright: (C) 2008 Mistral Solutions Pvt Ltd., + * + * Based on sound/soc/codecs/wm8731.c by Richard Purdie + * + */ + +#include +#include +#include +#include +#include + +#include "tlv320aic3x.h" + +static int aic3x_i2c_probe(struct i2c_client *i2c, const struct i2c_device_id *id) +{ + struct regmap *regmap; + struct regmap_config config; + + config = aic3x_regmap; + config.reg_bits = 8; + config.val_bits = 8; + + regmap = devm_regmap_init_i2c(i2c, &config); + return aic3x_probe(&i2c->dev, regmap, id->driver_data); +} + +static int aic3x_i2c_remove(struct i2c_client *i2c) +{ + return aic3x_remove(&i2c->dev); +} + +static const struct i2c_device_id aic3x_i2c_id[] = { + { "tlv320aic3x", AIC3X_MODEL_3X }, + { "tlv320aic33", AIC3X_MODEL_33 }, + { "tlv320aic3007", AIC3X_MODEL_3007 }, + { "tlv320aic3104", AIC3X_MODEL_3104 }, + { } +}; +MODULE_DEVICE_TABLE(i2c, aic3x_i2c_id); + +static const struct of_device_id aic3x_of_id[] = { + { .compatible = "ti,tlv320aic3x", }, + { .compatible = "ti,tlv320aic33" }, + { .compatible = "ti,tlv320aic3007" }, + { .compatible = "ti,tlv320aic3104" }, + {}, +}; +MODULE_DEVICE_TABLE(of, aic3x_of_id); + +static struct i2c_driver aic3x_i2c_driver = { + .driver = { + .name = "tlv320aic3x", + .of_match_table = aic3x_of_id, + }, + .probe = aic3x_i2c_probe, + .remove = aic3x_i2c_remove, + .id_table = aic3x_i2c_id, +}; + +module_i2c_driver(aic3x_i2c_driver); + +MODULE_DESCRIPTION("ASoC TLV320AIC3x codec driver I2C"); +MODULE_AUTHOR("Arun KS "); +MODULE_LICENSE("GPL"); diff --git a/sound/soc/codecs/tlv320aic3x.c b/sound/soc/codecs/tlv320aic3x.c index 6549ad9296ce..2f351747b714 100644 --- a/sound/soc/codecs/tlv320aic3x.c +++ b/sound/soc/codecs/tlv320aic3x.c @@ -1,6 +1,5 @@ // SPDX-License-Identifier: GPL-2.0-only -/* - * ALSA SoC TLV320AIC3X codec driver +/* ALSA SoC TLV320AIC3X codec driver * * Author: Vladimir Barinov, * Copyright: (C) 2007 MontaVista Software, Inc., @@ -131,10 +130,7 @@ static bool aic3x_volatile_reg(struct device *dev, unsigned int reg) } } -static const struct regmap_config aic3x_regmap = { - .reg_bits = 8, - .val_bits = 8, - +const struct regmap_config aic3x_regmap = { .max_register = DAC_ICC_ADJ, .reg_defaults = aic3x_reg, .num_reg_defaults = ARRAY_SIZE(aic3x_reg), @@ -143,6 +139,7 @@ static const struct regmap_config aic3x_regmap = { .cache_type = REGCACHE_RBTREE, }; +EXPORT_SYMBOL_GPL(aic3x_regmap); #define SOC_DAPM_SINGLE_AIC3X(xname, reg, shift, mask, invert) \ SOC_SINGLE_EXT(xname, reg, shift, mask, invert, \ @@ -1701,10 +1698,9 @@ static const struct snd_soc_component_driver soc_component_dev_aic3x = { .non_legacy_dai_naming = 1, }; -static void aic3x_configure_ocmv(struct i2c_client *client) +static void aic3x_configure_ocmv(struct device *dev, struct aic3x_priv *aic3x) { - struct device_node *np = client->dev.of_node; - struct aic3x_priv *aic3x = i2c_get_clientdata(client); + struct device_node *np = dev->of_node; u32 value; int dvdd, avdd; @@ -1720,7 +1716,7 @@ static void aic3x_configure_ocmv(struct i2c_client *client) avdd = regulator_get_voltage(aic3x->supplies[2].consumer); if (avdd > 3600000 || dvdd > 1950000) { - dev_warn(&client->dev, + dev_warn(dev, "Too high supply voltage(s) AVDD: %d, DVDD: %d\n", avdd, dvdd); } else if (avdd == 3600000 && dvdd == 1950000) { @@ -1732,26 +1728,12 @@ static void aic3x_configure_ocmv(struct i2c_client *client) } else if (avdd >= 2700000 && dvdd >= 1525000) { aic3x->ocmv = HPOUT_SC_OCMV_1_35V; } else { - dev_warn(&client->dev, + dev_warn(dev, "Invalid supply voltage(s) AVDD: %d, DVDD: %d\n", avdd, dvdd); } } -/* - * AIC3X 2 wire address can be up to 4 devices with device addresses - * 0x18, 0x19, 0x1A, 0x1B - */ - -static const struct i2c_device_id aic3x_i2c_id[] = { - { "tlv320aic3x", AIC3X_MODEL_3X }, - { "tlv320aic33", AIC3X_MODEL_33 }, - { "tlv320aic3007", AIC3X_MODEL_3007 }, - { "tlv320aic3106", AIC3X_MODEL_3X }, - { "tlv320aic3104", AIC3X_MODEL_3104 }, - { } -}; -MODULE_DEVICE_TABLE(i2c, aic3x_i2c_id); static const struct reg_sequence aic3007_class_d[] = { /* Class-D speaker driver init; datasheet p. 46 */ @@ -1763,25 +1745,20 @@ static const struct reg_sequence aic3007_class_d[] = { { AIC3X_PAGE_SELECT, 0x00 }, }; -/* - * If the i2c layer weren't so broken, we could pass this kind of data - * around - */ -static int aic3x_i2c_probe(struct i2c_client *i2c, - const struct i2c_device_id *id) +int aic3x_probe(struct device *dev, struct regmap *regmap, kernel_ulong_t driver_data) { - struct aic3x_pdata *pdata = i2c->dev.platform_data; + struct aic3x_pdata *pdata = dev->platform_data; struct aic3x_priv *aic3x; struct aic3x_setup_data *ai3x_setup; - struct device_node *np = i2c->dev.of_node; + struct device_node *np = dev->of_node; int ret, i; u32 value; - aic3x = devm_kzalloc(&i2c->dev, sizeof(struct aic3x_priv), GFP_KERNEL); + aic3x = devm_kzalloc(dev, sizeof(struct aic3x_priv), GFP_KERNEL); if (!aic3x) return -ENOMEM; - aic3x->regmap = devm_regmap_init_i2c(i2c, &aic3x_regmap); + aic3x->regmap = regmap; if (IS_ERR(aic3x->regmap)) { ret = PTR_ERR(aic3x->regmap); return ret; @@ -1789,14 +1766,13 @@ static int aic3x_i2c_probe(struct i2c_client *i2c, regcache_cache_only(aic3x->regmap, true); - i2c_set_clientdata(i2c, aic3x); + dev_set_drvdata(dev, aic3x); if (pdata) { aic3x->gpio_reset = pdata->gpio_reset; aic3x->setup = pdata->setup; aic3x->micbias_vg = pdata->micbias_vg; } else if (np) { - ai3x_setup = devm_kzalloc(&i2c->dev, sizeof(*ai3x_setup), - GFP_KERNEL); + ai3x_setup = devm_kzalloc(dev, sizeof(*ai3x_setup), GFP_KERNEL); if (!ai3x_setup) return -ENOMEM; @@ -1806,7 +1782,7 @@ static int aic3x_i2c_probe(struct i2c_client *i2c, } else { ret = of_get_named_gpio(np, "gpio-reset", 0); if (ret > 0) { - dev_warn(&i2c->dev, "Using deprecated property \"gpio-reset\", please update your DT"); + dev_warn(dev, "Using deprecated property \"gpio-reset\", please update your DT"); aic3x->gpio_reset = ret; } else { aic3x->gpio_reset = -1; @@ -1831,7 +1807,7 @@ static int aic3x_i2c_probe(struct i2c_client *i2c, break; default : aic3x->micbias_vg = AIC3X_MICBIAS_OFF; - dev_err(&i2c->dev, "Unsuitable MicBias voltage " + dev_err(dev, "Unsuitable MicBias voltage " "found in DT\n"); } } else { @@ -1842,7 +1818,7 @@ static int aic3x_i2c_probe(struct i2c_client *i2c, aic3x->gpio_reset = -1; } - aic3x->model = id->driver_data; + aic3x->model = driver_data; if (gpio_is_valid(aic3x->gpio_reset) && !aic3x_is_shared_reset(aic3x)) { @@ -1855,25 +1831,24 @@ static int aic3x_i2c_probe(struct i2c_client *i2c, for (i = 0; i < ARRAY_SIZE(aic3x->supplies); i++) aic3x->supplies[i].supply = aic3x_supply_names[i]; - ret = devm_regulator_bulk_get(&i2c->dev, ARRAY_SIZE(aic3x->supplies), + ret = devm_regulator_bulk_get(dev, ARRAY_SIZE(aic3x->supplies), aic3x->supplies); if (ret != 0) { - dev_err(&i2c->dev, "Failed to request supplies: %d\n", ret); + dev_err(dev, "Failed to request supplies: %d\n", ret); goto err_gpio; } - aic3x_configure_ocmv(i2c); + aic3x_configure_ocmv(dev, aic3x); if (aic3x->model == AIC3X_MODEL_3007) { ret = regmap_register_patch(aic3x->regmap, aic3007_class_d, ARRAY_SIZE(aic3007_class_d)); if (ret != 0) - dev_err(&i2c->dev, "Failed to init class D: %d\n", + dev_err(dev, "Failed to init class D: %d\n", ret); } - ret = devm_snd_soc_register_component(&i2c->dev, - &soc_component_dev_aic3x, &aic3x_dai, 1); + ret = devm_snd_soc_register_component(dev, &soc_component_dev_aic3x, &aic3x_dai, 1); if (ret != 0) goto err_gpio; @@ -1890,10 +1865,11 @@ err_gpio: err: return ret; } +EXPORT_SYMBOL(aic3x_probe); -static int aic3x_i2c_remove(struct i2c_client *client) +int aic3x_remove(struct device *dev) { - struct aic3x_priv *aic3x = i2c_get_clientdata(client); + struct aic3x_priv *aic3x = dev_get_drvdata(dev); list_del(&aic3x->list); @@ -1904,31 +1880,7 @@ static int aic3x_i2c_remove(struct i2c_client *client) } return 0; } - -#if defined(CONFIG_OF) -static const struct of_device_id tlv320aic3x_of_match[] = { - { .compatible = "ti,tlv320aic3x", }, - { .compatible = "ti,tlv320aic33" }, - { .compatible = "ti,tlv320aic3007" }, - { .compatible = "ti,tlv320aic3106" }, - { .compatible = "ti,tlv320aic3104" }, - {}, -}; -MODULE_DEVICE_TABLE(of, tlv320aic3x_of_match); -#endif - -/* machine i2c codec control layer */ -static struct i2c_driver aic3x_i2c_driver = { - .driver = { - .name = "tlv320aic3x-codec", - .of_match_table = of_match_ptr(tlv320aic3x_of_match), - }, - .probe = aic3x_i2c_probe, - .remove = aic3x_i2c_remove, - .id_table = aic3x_i2c_id, -}; - -module_i2c_driver(aic3x_i2c_driver); +EXPORT_SYMBOL(aic3x_remove); MODULE_DESCRIPTION("ASoC TLV320AIC3X codec driver"); MODULE_AUTHOR("Vladimir Barinov"); diff --git a/sound/soc/codecs/tlv320aic3x.h b/sound/soc/codecs/tlv320aic3x.h index 21dd6edf1059..00908f1734a7 100644 --- a/sound/soc/codecs/tlv320aic3x.h +++ b/sound/soc/codecs/tlv320aic3x.h @@ -9,6 +9,13 @@ #ifndef _AIC3X_H #define _AIC3X_H +struct device; +struct regmap_config; + +extern const struct regmap_config aic3x_regmap; +int aic3x_probe(struct device *dev, struct regmap *regmap, kernel_ulong_t driver_data); +int aic3x_remove(struct device *dev); + #define AIC3X_MODEL_3X 0 #define AIC3X_MODEL_33 1 #define AIC3X_MODEL_3007 2 From fd4daab3b139a24e71cae5de4f0ca715dbb6634a Mon Sep 17 00:00:00 2001 From: Jiri Prchal Date: Tue, 6 Apr 2021 16:24:39 +0200 Subject: [PATCH 417/587] ASoC: codecs: tlv320aic3x: add SPI support Added SPI support. Signed-off-by: Jiri Prchal Link: https://lore.kernel.org/r/20210406142439.102396-5-jiri.prchal@aksignal.cz Signed-off-by: Mark Brown --- sound/soc/codecs/Kconfig | 7 +++ sound/soc/codecs/Makefile | 2 + sound/soc/codecs/tlv320aic3x-spi.c | 76 ++++++++++++++++++++++++++++++ 3 files changed, 85 insertions(+) create mode 100644 sound/soc/codecs/tlv320aic3x-spi.c diff --git a/sound/soc/codecs/Kconfig b/sound/soc/codecs/Kconfig index b0323dbabf11..2a7b3e363069 100644 --- a/sound/soc/codecs/Kconfig +++ b/sound/soc/codecs/Kconfig @@ -219,6 +219,7 @@ config SND_SOC_ALL_CODECS imply SND_SOC_TLV320AIC32X4_I2C imply SND_SOC_TLV320AIC32X4_SPI imply SND_SOC_TLV320AIC3X_I2C + imply SND_SOC_TLV320AIC3X_SPI imply SND_SOC_TPA6130A2 imply SND_SOC_TLV320DAC33 imply SND_SOC_TSCS42XX @@ -1454,6 +1455,12 @@ config SND_SOC_TLV320AIC3X_I2C select SND_SOC_TLV320AIC3X select REGMAP_I2C +config SND_SOC_TLV320AIC3X_SPI + tristate "Texas Instruments TLV320AIC3x audio CODECs - SPI" + depends on SPI_MASTER + select SND_SOC_TLV320AIC3X + select REGMAP_SPI + config SND_SOC_TLV320DAC33 tristate depends on I2C diff --git a/sound/soc/codecs/Makefile b/sound/soc/codecs/Makefile index f014ea9f2318..0efdba609048 100644 --- a/sound/soc/codecs/Makefile +++ b/sound/soc/codecs/Makefile @@ -239,6 +239,7 @@ snd-soc-tlv320aic32x4-i2c-objs := tlv320aic32x4-i2c.o snd-soc-tlv320aic32x4-spi-objs := tlv320aic32x4-spi.o snd-soc-tlv320aic3x-objs := tlv320aic3x.o snd-soc-tlv320aic3x-i2c-objs := tlv320aic3x-i2c.o +snd-soc-tlv320aic3x-spi-objs := tlv320aic3x-spi.o snd-soc-tlv320dac33-objs := tlv320dac33.o snd-soc-tlv320adcx140-objs := tlv320adcx140.o snd-soc-tscs42xx-objs := tscs42xx.o @@ -560,6 +561,7 @@ obj-$(CONFIG_SND_SOC_TLV320AIC32X4_I2C) += snd-soc-tlv320aic32x4-i2c.o obj-$(CONFIG_SND_SOC_TLV320AIC32X4_SPI) += snd-soc-tlv320aic32x4-spi.o obj-$(CONFIG_SND_SOC_TLV320AIC3X) += snd-soc-tlv320aic3x.o obj-$(CONFIG_SND_SOC_TLV320AIC3X_I2C) += snd-soc-tlv320aic3x-i2c.o +obj-$(CONFIG_SND_SOC_TLV320AIC3X_SPI) += snd-soc-tlv320aic3x-spi.o obj-$(CONFIG_SND_SOC_TLV320DAC33) += snd-soc-tlv320dac33.o obj-$(CONFIG_SND_SOC_TLV320ADCX140) += snd-soc-tlv320adcx140.o obj-$(CONFIG_SND_SOC_TSCS42XX) += snd-soc-tscs42xx.o diff --git a/sound/soc/codecs/tlv320aic3x-spi.c b/sound/soc/codecs/tlv320aic3x-spi.c new file mode 100644 index 000000000000..bd78ab0910da --- /dev/null +++ b/sound/soc/codecs/tlv320aic3x-spi.c @@ -0,0 +1,76 @@ +/* SPDX-License-Identifier: GPL-2.0 + * + * ALSA SoC TLV320AIC3x codec driver SPI interface + * + * Author: Arun KS, + * Copyright: (C) 2008 Mistral Solutions Pvt Ltd., + * + * Based on sound/soc/codecs/wm8731.c by Richard Purdie + * + */ + +#include +#include +#include +#include +#include + +#include "tlv320aic3x.h" + +static int aic3x_spi_probe(struct spi_device *spi) +{ + struct regmap *regmap; + struct regmap_config config; + const struct spi_device_id *id = spi_get_device_id(spi); + + config = aic3x_regmap; + config.reg_bits = 7; + config.pad_bits = 1; + config.val_bits = 8; + config.read_flag_mask = 0x01; + + dev_dbg(&spi->dev, "probing tlv320aic3x spi device\n"); + + regmap = devm_regmap_init_spi(spi, &config); + return aic3x_probe(&spi->dev, regmap, id->driver_data); +} + +static int aic3x_spi_remove(struct spi_device *spi) +{ + return aic3x_remove(&spi->dev); +} + +static const struct spi_device_id aic3x_spi_id[] = { + { "tlv320aic3x", AIC3X_MODEL_3X }, + { "tlv320aic33", AIC3X_MODEL_33 }, + { "tlv320aic3007", AIC3X_MODEL_3007 }, + { "tlv320aic3104", AIC3X_MODEL_3104 }, + { } +}; +MODULE_DEVICE_TABLE(spi, aic3x_spi_id); + +static const struct of_device_id aic3x_of_id[] = { + { .compatible = "ti,tlv320aic3x", }, + { .compatible = "ti,tlv320aic33" }, + { .compatible = "ti,tlv320aic3007" }, + { .compatible = "ti,tlv320aic3104" }, + {}, +}; +MODULE_DEVICE_TABLE(of, aic3x_of_id); + +static struct spi_driver aic3x_spi_driver = { + .driver = { + .name = "tlv320aic3x", + .owner = THIS_MODULE, + .of_match_table = aic3x_of_id, + }, + .probe = aic3x_spi_probe, + .remove = aic3x_spi_remove, + .id_table = aic3x_spi_id, +}; + +module_spi_driver(aic3x_spi_driver); + +MODULE_DESCRIPTION("ASoC TLV320AIC3x codec driver SPI"); +MODULE_AUTHOR("Arun KS "); +MODULE_LICENSE("GPL"); From af4b54127b2b8a69f0f50e54cf099f26b82c9244 Mon Sep 17 00:00:00 2001 From: Ye Bin Date: Wed, 7 Apr 2021 15:42:18 +0800 Subject: [PATCH 418/587] ASoC: codecs: lpass-va-macro: constify static struct snd_soc_dai_ops The snd_soc_dai_ops structures is only stored in the ops field of a snd_soc_dai_driver structure, so make the snd_soc_dai_ops structure const to allow the compiler to put it in read-only memory. Reported-by: Hulk Robot Signed-off-by: Ye Bin Link: https://lore.kernel.org/r/20210407074218.3051979-1-yebin10@huawei.com Signed-off-by: Mark Brown --- sound/soc/codecs/lpass-va-macro.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sound/soc/codecs/lpass-va-macro.c b/sound/soc/codecs/lpass-va-macro.c index 3d6976a3d9e4..5294c57b2cd4 100644 --- a/sound/soc/codecs/lpass-va-macro.c +++ b/sound/soc/codecs/lpass-va-macro.c @@ -894,7 +894,7 @@ static int va_macro_digital_mute(struct snd_soc_dai *dai, int mute, int stream) return 0; } -static struct snd_soc_dai_ops va_macro_dai_ops = { +static const struct snd_soc_dai_ops va_macro_dai_ops = { .hw_params = va_macro_hw_params, .get_channel_map = va_macro_get_channel_map, .mute_stream = va_macro_digital_mute, From fa74c223b6fd78a5314b4c61b9abdbed3c2185b4 Mon Sep 17 00:00:00 2001 From: Krzysztof Kozlowski Date: Wed, 7 Apr 2021 11:20:27 +0200 Subject: [PATCH 419/587] ASoC: simple-card: fix possible uninitialized single_cpu local variable The 'single_cpu' local variable is assigned by asoc_simple_parse_dai() and later used in a asoc_simple_canonicalize_cpu() call, assuming the entire function did not exit on errors. However the first function returns 0 if passed device_node is NULL, thus leaving the variable uninitialized and reporting success. Addresses-Coverity: Uninitialized scalar variable Fixes: 8f7f298a3337 ("ASoC: simple-card-utils: separate asoc_simple_card_parse_dai()") Signed-off-by: Krzysztof Kozlowski Acked-by: Sameer Pujar Link: https://lore.kernel.org/r/20210407092027.60769-1-krzysztof.kozlowski@canonical.com Signed-off-by: Mark Brown --- sound/soc/generic/audio-graph-card.c | 2 +- sound/soc/generic/simple-card.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/sound/soc/generic/audio-graph-card.c b/sound/soc/generic/audio-graph-card.c index ee1d924d68e5..76036ea377a9 100644 --- a/sound/soc/generic/audio-graph-card.c +++ b/sound/soc/generic/audio-graph-card.c @@ -367,7 +367,7 @@ static int graph_dai_link_of(struct asoc_simple_priv *priv, struct device_node *top = dev->of_node; struct asoc_simple_dai *cpu_dai; struct asoc_simple_dai *codec_dai; - int ret, single_cpu; + int ret, single_cpu = 0; dev_dbg(dev, "link_of (%pOF)\n", cpu_ep); diff --git a/sound/soc/generic/simple-card.c b/sound/soc/generic/simple-card.c index 41aa40765a8d..9a05f44fc3a9 100644 --- a/sound/soc/generic/simple-card.c +++ b/sound/soc/generic/simple-card.c @@ -249,7 +249,7 @@ static int simple_dai_link_of(struct asoc_simple_priv *priv, struct device_node *plat = NULL; char prop[128]; char *prefix = ""; - int ret, single_cpu; + int ret, single_cpu = 0; cpu = np; node = of_get_parent(np); From 9be701ec3493d3348723a38f0c19702d710758ce Mon Sep 17 00:00:00 2001 From: Jerome Brunet Date: Wed, 7 Apr 2021 16:59:14 +0200 Subject: [PATCH 420/587] ASoC: meson: axg-fifo: add NO_PERIOD_WAKEUP support On the AXG family, the fifo irq is not necessary for the HW to operate. It is just used to notify that a period has elapsed. If userpace does not care for these wakeups (such as pipewire), we are just wasting CPU cycles. Add support for NO_PERIOD_WAKEUP and disable irq when they are no needed. Signed-off-by: Jerome Brunet Link: https://lore.kernel.org/r/20210407145914.311479-1-jbrunet@baylibre.com Signed-off-by: Mark Brown --- sound/soc/meson/axg-fifo.c | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/sound/soc/meson/axg-fifo.c b/sound/soc/meson/axg-fifo.c index b2e867113226..b9af2d513e09 100644 --- a/sound/soc/meson/axg-fifo.c +++ b/sound/soc/meson/axg-fifo.c @@ -27,8 +27,8 @@ static struct snd_pcm_hardware axg_fifo_hw = { SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_MMAP_VALID | SNDRV_PCM_INFO_BLOCK_TRANSFER | - SNDRV_PCM_INFO_PAUSE), - + SNDRV_PCM_INFO_PAUSE | + SNDRV_PCM_INFO_NO_PERIOD_WAKEUP), .formats = AXG_FIFO_FORMATS, .rate_min = 5512, .rate_max = 192000, @@ -113,7 +113,7 @@ int axg_fifo_pcm_hw_params(struct snd_soc_component *component, { struct snd_pcm_runtime *runtime = ss->runtime; struct axg_fifo *fifo = axg_fifo_data(ss); - unsigned int burst_num, period, threshold; + unsigned int burst_num, period, threshold, irq_en; dma_addr_t end_ptr; period = params_period_bytes(params); @@ -142,10 +142,11 @@ int axg_fifo_pcm_hw_params(struct snd_soc_component *component, regmap_field_write(fifo->field_threshold, threshold ? threshold - 1 : 0); - /* Enable block count irq */ + /* Enable irq if necessary */ + irq_en = runtime->no_period_wakeup ? 0 : FIFO_INT_COUNT_REPEAT; regmap_update_bits(fifo->map, FIFO_CTRL0, CTRL0_INT_EN(FIFO_INT_COUNT_REPEAT), - CTRL0_INT_EN(FIFO_INT_COUNT_REPEAT)); + CTRL0_INT_EN(irq_en)); return 0; } From 66c6d1ef86ff3c1466e646d94c8eb3dcc9ccf873 Mon Sep 17 00:00:00 2001 From: Takashi Sakamoto Date: Thu, 8 Apr 2021 19:31:49 +0900 Subject: [PATCH 421/587] ALSA: control: Add memory consumption limit to user controls ALSA control interface allows users to add arbitrary control elements (called "user controls" or "user elements"), and its resource usage is limited just by the max number of control sets (currently 32). This limit, however, is quite loose: each allocation of control set may have 1028 elements, and each element may have up to 512 bytes (ILP32) or 1024 bytes (LP64) of value data. Moreover, each control set may contain the enum strings and TLV data, which can be up to 64kB and 128kB, respectively. Totally, the whole memory consumption may go over 38MB -- it's quite large, and we'd rather like to reduce the size. OTOH, there have been other requests even to increase the max number of user elements; e.g. ALSA firewire stack require the more user controls, hence we want to raise the bar, too. For satisfying both requirements, this patch changes the management of user controls: instead of setting the upper limit of the number of user controls, we check the actual memory allocation size and set the upper limit of the total allocation in bytes. As long as the memory consumption stays below the limit, more user controls are allowed than the current limit 32. At the same time, we set the lower limit (8MB) as default than the current theoretical limit, in order to lower the risk of DoS. As a compromise for lowering the default limit, now the actual memory limit is defined as a module option, 'max_user_ctl_alloc_size', so that user can increase/decrease the limit if really needed, too. Link: https://lore.kernel.org/r/s5htur3zl5e.wl-tiwai@suse.de Co-developed-by: Takashi Iwai Reviewed-by: Takashi Sakamoto Tested-by: Takashi Sakamoto Signed-off-by: Takashi Sakamoto Link: https://lore.kernel.org/r/20210408103149.40357-1-o-takashi@sakamocchi.jp Signed-off-by: Takashi Iwai --- include/sound/core.h | 2 +- sound/core/control.c | 75 ++++++++++++++++++++++++++++++-------------- 2 files changed, 52 insertions(+), 25 deletions(-) diff --git a/include/sound/core.h b/include/sound/core.h index 2e24f194ef70..1f9aef0adbc9 100644 --- a/include/sound/core.h +++ b/include/sound/core.h @@ -100,7 +100,7 @@ struct snd_card { struct rw_semaphore controls_rwsem; /* controls list lock */ rwlock_t ctl_files_rwlock; /* ctl_files list lock */ int controls_count; /* count of all controls */ - int user_ctl_count; /* count of all user controls */ + size_t user_ctl_alloc_size; // current memory allocation by user controls. struct list_head controls; /* all controls for this card */ struct list_head ctl_files; /* active control files */ diff --git a/sound/core/control.c b/sound/core/control.c index 20d707d4ef40..a076c08c21b6 100644 --- a/sound/core/control.c +++ b/sound/core/control.c @@ -7,6 +7,7 @@ #include #include #include +#include #include #include #include @@ -18,8 +19,11 @@ #include #include -/* max number of user-defined controls */ -#define MAX_USER_CONTROLS 32 +// Max allocation size for user controls. +static int max_user_ctl_alloc_size = 8 * 1024 * 1024; +module_param_named(max_user_ctl_alloc_size, max_user_ctl_alloc_size, int, 0444); +MODULE_PARM_DESC(max_user_ctl_alloc_size, "Max allocation size for user controls"); + #define MAX_CONTROL_COUNT 1028 struct snd_kctl_ioctl { @@ -561,9 +565,6 @@ static int snd_ctl_remove_user_ctl(struct snd_ctl_file * file, goto error; } ret = snd_ctl_remove(card, kctl); - if (ret < 0) - goto error; - card->user_ctl_count--; error: up_write(&card->controls_rwsem); return ret; @@ -1265,6 +1266,12 @@ struct user_element { void *priv_data; /* private data (like strings for enumerated type) */ }; +// check whether the addition (in bytes) of user ctl element may overflow the limit. +static bool check_user_elem_overflow(struct snd_card *card, ssize_t add) +{ + return (ssize_t)card->user_ctl_alloc_size + add > max_user_ctl_alloc_size; +} + static int snd_ctl_elem_user_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo) { @@ -1342,6 +1349,10 @@ static int replace_user_tlv(struct snd_kcontrol *kctl, unsigned int __user *buf, if (size > 1024 * 128) /* sane value */ return -EINVAL; + // does the TLV size change cause overflow? + if (check_user_elem_overflow(ue->card, (ssize_t)(size - ue->tlv_data_size))) + return -ENOMEM; + container = vmemdup_user(buf, size); if (IS_ERR(container)) return PTR_ERR(container); @@ -1359,11 +1370,16 @@ static int replace_user_tlv(struct snd_kcontrol *kctl, unsigned int __user *buf, for (i = 0; i < kctl->count; ++i) kctl->vd[i].access |= SNDRV_CTL_ELEM_ACCESS_TLV_READ; mask = SNDRV_CTL_EVENT_MASK_INFO; + } else { + ue->card->user_ctl_alloc_size -= ue->tlv_data_size; + ue->tlv_data_size = 0; + kvfree(ue->tlv_data); } - kvfree(ue->tlv_data); ue->tlv_data = container; ue->tlv_data_size = size; + // decremented at private_free. + ue->card->user_ctl_alloc_size += size; mask |= SNDRV_CTL_EVENT_MASK_TLV; for (i = 0; i < kctl->count; ++i) @@ -1405,16 +1421,17 @@ static int snd_ctl_elem_init_enum_names(struct user_element *ue) unsigned int i; const uintptr_t user_ptrval = ue->info.value.enumerated.names_ptr; - if (ue->info.value.enumerated.names_length > 64 * 1024) + buf_len = ue->info.value.enumerated.names_length; + if (buf_len > 64 * 1024) return -EINVAL; - names = vmemdup_user((const void __user *)user_ptrval, - ue->info.value.enumerated.names_length); + if (check_user_elem_overflow(ue->card, buf_len)) + return -ENOMEM; + names = vmemdup_user((const void __user *)user_ptrval, buf_len); if (IS_ERR(names)) return PTR_ERR(names); /* check that there are enough valid names */ - buf_len = ue->info.value.enumerated.names_length; p = names; for (i = 0; i < ue->info.value.enumerated.items; ++i) { name_len = strnlen(p, buf_len); @@ -1428,14 +1445,27 @@ static int snd_ctl_elem_init_enum_names(struct user_element *ue) ue->priv_data = names; ue->info.value.enumerated.names_ptr = 0; + // increment the allocation size; decremented again at private_free. + ue->card->user_ctl_alloc_size += ue->info.value.enumerated.names_length; return 0; } +static size_t compute_user_elem_size(size_t size, unsigned int count) +{ + return sizeof(struct user_element) + size * count; +} + static void snd_ctl_elem_user_free(struct snd_kcontrol *kcontrol) { struct user_element *ue = kcontrol->private_data; + // decrement the allocation size. + ue->card->user_ctl_alloc_size -= compute_user_elem_size(ue->elem_data_size, kcontrol->count); + ue->card->user_ctl_alloc_size -= ue->tlv_data_size; + if (ue->priv_data) + ue->card->user_ctl_alloc_size -= ue->info.value.enumerated.names_length; + kvfree(ue->tlv_data); kvfree(ue->priv_data); kfree(ue); @@ -1449,6 +1479,7 @@ static int snd_ctl_elem_add(struct snd_ctl_file *file, unsigned int count; unsigned int access; long private_size; + size_t alloc_size; struct user_element *ue; unsigned int offset; int err; @@ -1466,13 +1497,6 @@ static int snd_ctl_elem_add(struct snd_ctl_file *file, return err; } - /* - * The number of userspace controls are counted control by control, - * not element by element. - */ - if (card->user_ctl_count + 1 > MAX_USER_CONTROLS) - return -ENOMEM; - /* Check the number of elements for this userspace control. */ count = info->owner; if (count == 0) @@ -1503,6 +1527,10 @@ static int snd_ctl_elem_add(struct snd_ctl_file *file, if (info->count < 1) return -EINVAL; private_size = value_sizes[info->type] * info->count; + alloc_size = compute_user_elem_size(private_size, count); + + if (check_user_elem_overflow(card, alloc_size)) + return -ENOMEM; /* * Keep memory object for this userspace control. After passing this @@ -1514,16 +1542,18 @@ static int snd_ctl_elem_add(struct snd_ctl_file *file, if (err < 0) return err; memcpy(&kctl->id, &info->id, sizeof(kctl->id)); - kctl->private_data = kzalloc(sizeof(struct user_element) + private_size * count, - GFP_KERNEL); - if (kctl->private_data == NULL) { + ue = kzalloc(alloc_size, GFP_KERNEL); + if (!ue) { kfree(kctl); return -ENOMEM; } + kctl->private_data = ue; kctl->private_free = snd_ctl_elem_user_free; + // increment the allocated size; decremented again at private_free. + card->user_ctl_alloc_size += alloc_size; + /* Set private data for this userspace control. */ - ue = (struct user_element *)kctl->private_data; ue->card = card; ue->info = *info; ue->info.access = 0; @@ -1565,9 +1595,6 @@ static int snd_ctl_elem_add(struct snd_ctl_file *file, * applications because the field originally means PID of a process * which locks the element. */ - - card->user_ctl_count++; - unlock: up_write(&card->controls_rwsem); return err; From 44de8d80dba4e65f4fe7c17ea4be75e3cf9a902c Mon Sep 17 00:00:00 2001 From: Jack Yu Date: Thu, 8 Apr 2021 08:32:40 +0000 Subject: [PATCH 422/587] ASoC: rt1011: remove pack_id check in rt1011 For latest design, different package could use the same setting, therefore the check of pack_id will no longer be used. Signed-off-by: Jack Yu Link: https://lore.kernel.org/r/4cbe1cd3b8664140889132464c7dee7b@realtek.com Signed-off-by: Mark Brown --- sound/soc/codecs/rt1011.c | 16 ++-------------- sound/soc/codecs/rt1011.h | 1 - 2 files changed, 2 insertions(+), 15 deletions(-) diff --git a/sound/soc/codecs/rt1011.c b/sound/soc/codecs/rt1011.c index 098ecf13814d..bfe045367db3 100644 --- a/sound/soc/codecs/rt1011.c +++ b/sound/soc/codecs/rt1011.c @@ -2239,18 +2239,9 @@ static int rt1011_calibrate(struct rt1011_priv *rt1011, unsigned char cali_flag) dc_offset |= (value & 0xffff); dev_info(dev, "Gain1 offset=0x%x\n", dc_offset); - /* check the package info. */ - regmap_read(rt1011->regmap, RT1011_EFUSE_MATCH_DONE, &value); - if (value & 0x4) - rt1011->pack_id = 1; - if (cali_flag) { - if (rt1011->pack_id) - regmap_write(rt1011->regmap, RT1011_ADC_SET_1, 0x292c); - else - regmap_write(rt1011->regmap, RT1011_ADC_SET_1, 0x2925); - + regmap_write(rt1011->regmap, RT1011_ADC_SET_1, 0x2925); /* Class D on */ regmap_write(rt1011->regmap, RT1011_CLASS_D_POS, 0x010e); regmap_write(rt1011->regmap, @@ -2376,10 +2367,7 @@ static void rt1011_calibration_work(struct work_struct *work) rt1011_r0_load(rt1011); } - if (rt1011->pack_id) - snd_soc_component_write(component, RT1011_ADC_SET_1, 0x292c); - else - snd_soc_component_write(component, RT1011_ADC_SET_1, 0x2925); + snd_soc_component_write(component, RT1011_ADC_SET_1, 0x2925); } static int rt1011_parse_dp(struct rt1011_priv *rt1011, struct device *dev) diff --git a/sound/soc/codecs/rt1011.h b/sound/soc/codecs/rt1011.h index f3a9a96640f1..68fadc15fa8c 100644 --- a/sound/soc/codecs/rt1011.h +++ b/sound/soc/codecs/rt1011.h @@ -692,7 +692,6 @@ struct rt1011_priv { unsigned int r0_reg, cali_done; unsigned int r0_calib, temperature_calib; int recv_spk_mode; - unsigned int pack_id; /* 0: WLCSP; 1: QFN */ }; #endif /* end of _RT1011_H_ */ From 7b3f5b207da5116add56c335c5fb92cee140dc63 Mon Sep 17 00:00:00 2001 From: Dinghao Liu Date: Thu, 8 Apr 2021 14:40:34 +0800 Subject: [PATCH 423/587] ASoC: codecs: Fix runtime PM imbalance in tas2552_probe There is a rumtime PM imbalance between the error handling path after devm_snd_soc_register_component() and all other error handling paths. Add a PM runtime increment to balance refcount. Signed-off-by: Dinghao Liu Link: https://lore.kernel.org/r/20210408064036.6691-1-dinghao.liu@zju.edu.cn Signed-off-by: Mark Brown --- sound/soc/codecs/tas2552.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/sound/soc/codecs/tas2552.c b/sound/soc/codecs/tas2552.c index bd00c35116cd..700baa6314aa 100644 --- a/sound/soc/codecs/tas2552.c +++ b/sound/soc/codecs/tas2552.c @@ -730,8 +730,10 @@ static int tas2552_probe(struct i2c_client *client, ret = devm_snd_soc_register_component(&client->dev, &soc_component_dev_tas2552, tas2552_dai, ARRAY_SIZE(tas2552_dai)); - if (ret < 0) + if (ret < 0) { dev_err(&client->dev, "Failed to register component: %d\n", ret); + pm_runtime_get_noresume(&client->dev); + } return ret; } From f2138aed231c88d5c4fa8d06aa15ad19685087c2 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Thu, 1 Apr 2021 13:15:23 +0900 Subject: [PATCH 424/587] ASoC: simple-card-utils: enable flexible CPU/Codec/Platform Current simple-card / audio-graph are assuming fixed single-CPU/Codec/Platform. This patch prepares multi-CPU/Codec/Platform support. Note is that it is not yet full-multi-support. Signed-off-by: Kuninori Morimoto Link: https://lore.kernel.org/r/87v996od2c.wl-kuninori.morimoto.gx@renesas.com Signed-off-by: Mark Brown --- include/sound/simple_card_utils.h | 8 +++ sound/soc/generic/audio-graph-card.c | 22 ++++++++ sound/soc/generic/simple-card-utils.c | 72 +++++++++++++++++++-------- sound/soc/generic/simple-card.c | 30 +++++++++++ 4 files changed, 110 insertions(+), 22 deletions(-) diff --git a/include/sound/simple_card_utils.h b/include/sound/simple_card_utils.h index 86e46cbf9e14..475f8cb14492 100644 --- a/include/sound/simple_card_utils.h +++ b/include/sound/simple_card_utils.h @@ -38,6 +38,12 @@ struct asoc_simple_jack { struct snd_soc_jack_gpio gpio; }; +struct prop_nums { + int cpus; + int codecs; + int platforms; +}; + struct asoc_simple_priv { struct snd_soc_card snd_card; struct simple_dai_props { @@ -48,6 +54,7 @@ struct asoc_simple_priv { struct snd_soc_dai_link_component *platforms; struct asoc_simple_data adata; struct snd_soc_codec_conf *codec_conf; + struct prop_nums num; unsigned int mclk_fs; } *dai_props; struct asoc_simple_jack hp_jack; @@ -71,6 +78,7 @@ struct link_info { int link; /* number of link */ int conf; /* number of codec_conf */ int cpu; /* turn for CPU / Codec */ + struct prop_nums num[SNDRV_MINOR_DEVICES]; }; int asoc_simple_parse_daifmt(struct device *dev, diff --git a/sound/soc/generic/audio-graph-card.c b/sound/soc/generic/audio-graph-card.c index 76036ea377a9..5fe53c5efcbf 100644 --- a/sound/soc/generic/audio-graph-card.c +++ b/sound/soc/generic/audio-graph-card.c @@ -628,6 +628,15 @@ static int graph_count_noml(struct asoc_simple_priv *priv, { struct device *dev = simple_priv_to_dev(priv); + if (li->link >= SNDRV_MINOR_DEVICES) { + dev_err(dev, "too many links\n"); + return -EINVAL; + } + + li->num[li->link].cpus = 1; + li->num[li->link].codecs = 1; + li->num[li->link].platforms = 1; + li->link += 1; /* 1xCPU-Codec */ li->dais += 2; /* 1xCPU + 1xCodec */ @@ -643,10 +652,23 @@ static int graph_count_dpcm(struct asoc_simple_priv *priv, { struct device *dev = simple_priv_to_dev(priv); + if (li->link >= SNDRV_MINOR_DEVICES) { + dev_err(dev, "too many links\n"); + return -EINVAL; + } + if (li->cpu) { + li->num[li->link].cpus = 1; + li->num[li->link].codecs = 1; + li->num[li->link].platforms = 1; + li->link++; /* 1xCPU-dummy */ li->dais++; /* 1xCPU */ } else { + li->num[li->link].cpus = 1; + li->num[li->link].codecs = 1; + li->num[li->link].platforms = 1; + li->link++; /* 1xdummy-Codec */ li->conf++; /* 1xdummy-Codec */ li->dais++; /* 1xCodec */ diff --git a/sound/soc/generic/simple-card-utils.c b/sound/soc/generic/simple-card-utils.c index 3010ff63c71d..1606b9bc6b71 100644 --- a/sound/soc/generic/simple-card-utils.c +++ b/sound/soc/generic/simple-card-utils.c @@ -604,13 +604,27 @@ int asoc_simple_init_priv(struct asoc_simple_priv *priv, struct asoc_simple_dai *dais; struct snd_soc_dai_link_component *dlcs; struct snd_soc_codec_conf *cconf = NULL; - int i; + int i, dai_num = 0, dlc_num = 0; dai_props = devm_kcalloc(dev, li->link, sizeof(*dai_props), GFP_KERNEL); dai_link = devm_kcalloc(dev, li->link, sizeof(*dai_link), GFP_KERNEL); - dais = devm_kcalloc(dev, li->dais, sizeof(*dais), GFP_KERNEL); - dlcs = devm_kcalloc(dev, li->link * 3, sizeof(*dai_props), GFP_KERNEL); - if (!dai_props || !dai_link || !dais || !dlcs) + if (!dai_props || !dai_link) + return -ENOMEM; + + /* + * dais (= CPU+Codec) + * dlcs (= CPU+Codec+Platform) + */ + for (i = 0; i < li->link; i++) { + int cc = li->num[i].cpus + li->num[i].codecs; + + dai_num += cc; + dlc_num += cc + li->num[i].platforms; + } + + dais = devm_kcalloc(dev, dai_num, sizeof(*dais), GFP_KERNEL); + dlcs = devm_kcalloc(dev, dlc_num, sizeof(*dai_props), GFP_KERNEL); + if (!dais || !dlcs) return -ENOMEM; if (li->conf) { @@ -619,24 +633,6 @@ int asoc_simple_init_priv(struct asoc_simple_priv *priv, return -ENOMEM; } - /* - * "platform" might be removed - * see - * simple-card-utils.c :: asoc_simple_canonicalize_platform() - */ - for (i = 0; i < li->link; i++) { - dai_props[i].cpus = dlcs + (3 * i) + 0; - dai_props[i].codecs = dlcs + (3 * i) + 1; - dai_props[i].platforms = dlcs + (3 * i) + 2; - - dai_link[i].cpus = dai_props[i].cpus; - dai_link[i].num_cpus = 1; - dai_link[i].codecs = dai_props[i].codecs; - dai_link[i].num_codecs = 1; - dai_link[i].platforms = dai_props[i].platforms; - dai_link[i].num_platforms = 1; - } - priv->dai_props = dai_props; priv->dai_link = dai_link; priv->dais = dais; @@ -648,6 +644,38 @@ int asoc_simple_init_priv(struct asoc_simple_priv *priv, card->codec_conf = cconf; card->num_configs = li->conf; + for (i = 0; i < li->link; i++) { + if (li->num[i].cpus) { + /* Normal CPU */ + dai_props[i].cpus = + dai_link[i].cpus = dlcs; + dai_props[i].num.cpus = + dai_link[i].num_cpus = li->num[i].cpus; + + dlcs += li->num[i].cpus; + } + + if (li->num[i].codecs) { + /* Normal Codec */ + dai_props[i].codecs = + dai_link[i].codecs = dlcs; + dai_props[i].num.codecs = + dai_link[i].num_codecs = li->num[i].codecs; + + dlcs += li->num[i].codecs; + } + + if (li->num[i].platforms) { + /* Have Platform */ + dai_props[i].platforms = + dai_link[i].platforms = dlcs; + dai_props[i].num.platforms = + dai_link[i].num_platforms = li->num[i].platforms; + + dlcs += li->num[i].platforms; + } + } + return 0; } EXPORT_SYMBOL_GPL(asoc_simple_init_priv); diff --git a/sound/soc/generic/simple-card.c b/sound/soc/generic/simple-card.c index 9a05f44fc3a9..1fad570338b3 100644 --- a/sound/soc/generic/simple-card.c +++ b/sound/soc/generic/simple-card.c @@ -499,6 +499,17 @@ static int simple_count_noml(struct asoc_simple_priv *priv, struct device_node *codec, struct link_info *li, bool is_top) { + if (li->link >= SNDRV_MINOR_DEVICES) { + struct device *dev = simple_priv_to_dev(priv); + + dev_err(dev, "too many links\n"); + return -EINVAL; + } + + li->num[li->link].cpus = 1; + li->num[li->link].codecs = 1; + li->num[li->link].platforms = 1; + li->link += 1; li->dais += 2; @@ -510,10 +521,25 @@ static int simple_count_dpcm(struct asoc_simple_priv *priv, struct device_node *codec, struct link_info *li, bool is_top) { + if (li->link >= SNDRV_MINOR_DEVICES) { + struct device *dev = simple_priv_to_dev(priv); + + dev_err(dev, "too many links\n"); + return -EINVAL; + } + if (li->cpu) { + li->num[li->link].cpus = 1; + li->num[li->link].codecs = 1; + li->num[li->link].platforms = 1; + li->link++; /* CPU-dummy */ li->dais++; } else { + li->num[li->link].cpus = 1; + li->num[li->link].codecs = 1; + li->num[li->link].platforms = 1; + li->link++; /* dummy-Codec */ li->dais++; li->conf++; @@ -575,6 +601,10 @@ static void simple_get_dais_count(struct asoc_simple_priv *priv, * => 1 ccnf = 1xdummy-Codec */ if (!top) { + li->num[0].cpus = 1; + li->num[0].codecs = 1; + li->num[0].platforms = 1; + li->link = 1; li->dais = 2; li->conf = 0; From 205eb17eddb473c3159743c7d3aaf68db37b7231 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Thu, 1 Apr 2021 13:15:33 +0900 Subject: [PATCH 425/587] ASoC: simple-card-utils: share dummy DAI and reduce memory Current simple-card / audio-graph creates 1xCPU + 1xCodec + 1xPlatform for all dai_link, but some of them is not needed. For example Platform is not needed for DPCM BE case. Moreover, we can share snd-soc-dummy DAI for CPU-dummy / dummy-Codec in DPCM. This patch adds dummy DAI and share it when DPCM case, I beliave it can contribute to reduce memory. By this patch, CPU-dummy / dummy-CPU are set at asoc_simple_init_priv(), thus, its settings are no longer needed at DPCM detecting timing on simple-card / audio-graph. Moreover, we can remove triky Platform settings code for DPCM BE, because un-needed Platform is not created. Signed-off-by: Kuninori Morimoto Link: https://lore.kernel.org/r/87tuoqod22.wl-kuninori.morimoto.gx@renesas.com Signed-off-by: Mark Brown --- include/sound/simple_card_utils.h | 1 + sound/soc/generic/audio-graph-card.c | 12 +---------- sound/soc/generic/simple-card-utils.c | 30 ++++++++++++++++++++------- sound/soc/generic/simple-card.c | 12 +---------- 4 files changed, 26 insertions(+), 29 deletions(-) diff --git a/include/sound/simple_card_utils.h b/include/sound/simple_card_utils.h index 475f8cb14492..6635283a8160 100644 --- a/include/sound/simple_card_utils.h +++ b/include/sound/simple_card_utils.h @@ -62,6 +62,7 @@ struct asoc_simple_priv { struct snd_soc_dai_link *dai_link; struct asoc_simple_dai *dais; struct snd_soc_dai_link_component *dlcs; + struct snd_soc_dai_link_component dummy; struct snd_soc_codec_conf *codec_conf; struct gpio_desc *pa_gpio; const struct snd_soc_ops *ops; diff --git a/sound/soc/generic/audio-graph-card.c b/sound/soc/generic/audio-graph-card.c index 5fe53c5efcbf..7be2c2cb253e 100644 --- a/sound/soc/generic/audio-graph-card.c +++ b/sound/soc/generic/audio-graph-card.c @@ -240,9 +240,6 @@ static int graph_dai_link_of_dpcm(struct asoc_simple_priv *priv, int is_single_links = 0; /* Codec is dummy */ - codecs->of_node = NULL; - codecs->dai_name = "snd-soc-dummy-dai"; - codecs->name = "snd-soc-dummy"; /* FE settings */ dai_link->dynamic = 1; @@ -281,13 +278,11 @@ static int graph_dai_link_of_dpcm(struct asoc_simple_priv *priv, /* card->num_links includes Codec */ asoc_simple_canonicalize_cpu(dai_link, is_single_links); + asoc_simple_canonicalize_platform(dai_link); } else { struct snd_soc_codec_conf *cconf; /* CPU is dummy */ - cpus->of_node = NULL; - cpus->dai_name = "snd-soc-dummy-dai"; - cpus->name = "snd-soc-dummy"; /* BE settings */ dai_link->no_pcm = 1; @@ -328,8 +323,6 @@ static int graph_dai_link_of_dpcm(struct asoc_simple_priv *priv, graph_parse_convert(dev, ep, &dai_props->adata); graph_parse_mclk_fs(top, ep, dai_props); - asoc_simple_canonicalize_platform(dai_link); - ret = asoc_simple_parse_tdm(ep, dai); if (ret) goto out_put_node; @@ -659,15 +652,12 @@ static int graph_count_dpcm(struct asoc_simple_priv *priv, if (li->cpu) { li->num[li->link].cpus = 1; - li->num[li->link].codecs = 1; li->num[li->link].platforms = 1; li->link++; /* 1xCPU-dummy */ li->dais++; /* 1xCPU */ } else { - li->num[li->link].cpus = 1; li->num[li->link].codecs = 1; - li->num[li->link].platforms = 1; li->link++; /* 1xdummy-Codec */ li->conf++; /* 1xdummy-Codec */ diff --git a/sound/soc/generic/simple-card-utils.c b/sound/soc/generic/simple-card-utils.c index 1606b9bc6b71..64b1ff5bafda 100644 --- a/sound/soc/generic/simple-card-utils.c +++ b/sound/soc/generic/simple-card-utils.c @@ -404,13 +404,6 @@ void asoc_simple_canonicalize_platform(struct snd_soc_dai_link *dai_link) /* Assumes platform == cpu */ if (!dai_link->platforms->of_node) dai_link->platforms->of_node = dai_link->cpus->of_node; - - /* - * DPCM BE can be no platform. - * Alloced memory will be waste, but not leak. - */ - if (!dai_link->platforms->of_node) - dai_link->num_platforms = 0; } EXPORT_SYMBOL_GPL(asoc_simple_canonicalize_platform); @@ -633,6 +626,11 @@ int asoc_simple_init_priv(struct asoc_simple_priv *priv, return -ENOMEM; } + /* dummy CPU/Codec */ + priv->dummy.of_node = NULL; + priv->dummy.dai_name = "snd-soc-dummy-dai"; + priv->dummy.name = "snd-soc-dummy"; + priv->dai_props = dai_props; priv->dai_link = dai_link; priv->dais = dais; @@ -653,6 +651,12 @@ int asoc_simple_init_priv(struct asoc_simple_priv *priv, dai_link[i].num_cpus = li->num[i].cpus; dlcs += li->num[i].cpus; + } else { + /* DPCM Be's CPU = dummy */ + dai_props[i].cpus = + dai_link[i].cpus = &priv->dummy; + dai_props[i].num.cpus = + dai_link[i].num_cpus = 1; } if (li->num[i].codecs) { @@ -663,6 +667,12 @@ int asoc_simple_init_priv(struct asoc_simple_priv *priv, dai_link[i].num_codecs = li->num[i].codecs; dlcs += li->num[i].codecs; + } else { + /* DPCM Fe's Codec = dummy */ + dai_props[i].codecs = + dai_link[i].codecs = &priv->dummy; + dai_props[i].num.codecs = + dai_link[i].num_codecs = 1; } if (li->num[i].platforms) { @@ -673,6 +683,12 @@ int asoc_simple_init_priv(struct asoc_simple_priv *priv, dai_link[i].num_platforms = li->num[i].platforms; dlcs += li->num[i].platforms; + } else { + /* Doesn't have Platform */ + dai_props[i].platforms = + dai_link[i].platforms = NULL; + dai_props[i].num.platforms = + dai_link[i].num_platforms = 0; } } diff --git a/sound/soc/generic/simple-card.c b/sound/soc/generic/simple-card.c index 1fad570338b3..9132c0ea05af 100644 --- a/sound/soc/generic/simple-card.c +++ b/sound/soc/generic/simple-card.c @@ -141,9 +141,6 @@ static int simple_dai_link_of_dpcm(struct asoc_simple_priv *priv, int is_single_links = 0; /* Codec is dummy */ - codecs->of_node = NULL; - codecs->dai_name = "snd-soc-dummy-dai"; - codecs->name = "snd-soc-dummy"; /* FE settings */ dai_link->dynamic = 1; @@ -167,13 +164,11 @@ static int simple_dai_link_of_dpcm(struct asoc_simple_priv *priv, goto out_put_node; asoc_simple_canonicalize_cpu(dai_link, is_single_links); + asoc_simple_canonicalize_platform(dai_link); } else { struct snd_soc_codec_conf *cconf; /* CPU is dummy */ - cpus->of_node = NULL; - cpus->dai_name = "snd-soc-dummy-dai"; - cpus->name = "snd-soc-dummy"; /* BE settings */ dai_link->no_pcm = 1; @@ -211,8 +206,6 @@ static int simple_dai_link_of_dpcm(struct asoc_simple_priv *priv, simple_parse_convert(dev, np, &dai_props->adata); simple_parse_mclk_fs(top, np, codec, dai_props, prefix); - asoc_simple_canonicalize_platform(dai_link); - ret = asoc_simple_parse_tdm(np, dai); if (ret) goto out_put_node; @@ -530,15 +523,12 @@ static int simple_count_dpcm(struct asoc_simple_priv *priv, if (li->cpu) { li->num[li->link].cpus = 1; - li->num[li->link].codecs = 1; li->num[li->link].platforms = 1; li->link++; /* CPU-dummy */ li->dais++; } else { - li->num[li->link].cpus = 1; li->num[li->link].codecs = 1; - li->num[li->link].platforms = 1; li->link++; /* dummy-Codec */ li->dais++; From f985838003ee618daba7a38da3efe27c639575e2 Mon Sep 17 00:00:00 2001 From: Ye Bin Date: Thu, 8 Apr 2021 14:27:00 +0800 Subject: [PATCH 426/587] ASoC: codecs: wsa881x: constify static struct snd_soc_dai_ops The snd_soc_dai_ops structures is only stored in the ops field of a snd_soc_dai_driver structure, so make the snd_soc_dai_ops structure const to allow the compiler to put it in read-only memory. Reported-by: Hulk Robot Signed-off-by: Ye Bin Link: https://lore.kernel.org/r/20210408062700.803792-1-yebin10@huawei.com Signed-off-by: Mark Brown --- sound/soc/codecs/wsa881x.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sound/soc/codecs/wsa881x.c b/sound/soc/codecs/wsa881x.c index db87e07b11c9..2da4a5fa7a18 100644 --- a/sound/soc/codecs/wsa881x.c +++ b/sound/soc/codecs/wsa881x.c @@ -1014,7 +1014,7 @@ static int wsa881x_digital_mute(struct snd_soc_dai *dai, int mute, int stream) return 0; } -static struct snd_soc_dai_ops wsa881x_dai_ops = { +static const struct snd_soc_dai_ops wsa881x_dai_ops = { .hw_params = wsa881x_hw_params, .hw_free = wsa881x_hw_free, .mute_stream = wsa881x_digital_mute, From a0bc855ffdb55cbb9fbf7fa9611d17f19db889a8 Mon Sep 17 00:00:00 2001 From: Jiri Prchal Date: Thu, 8 Apr 2021 15:59:08 +0200 Subject: [PATCH 427/587] ASoC: codecs: tlv320aic3x: add AIC3106 In DT binding is mentioned that this driver is compatible with 3106. So added compatibility string and model number. Signed-off-by: Jiri Prchal Link: https://lore.kernel.org/r/20210408135908.125667-1-jiri.prchal@aksignal.cz Signed-off-by: Mark Brown --- sound/soc/codecs/tlv320aic3x-i2c.c | 2 ++ sound/soc/codecs/tlv320aic3x-spi.c | 2 ++ sound/soc/codecs/tlv320aic3x.c | 3 +++ sound/soc/codecs/tlv320aic3x.h | 1 + 4 files changed, 8 insertions(+) diff --git a/sound/soc/codecs/tlv320aic3x-i2c.c b/sound/soc/codecs/tlv320aic3x-i2c.c index 4535bb8dbadc..cd0558ed4dd4 100644 --- a/sound/soc/codecs/tlv320aic3x-i2c.c +++ b/sound/soc/codecs/tlv320aic3x-i2c.c @@ -40,6 +40,7 @@ static const struct i2c_device_id aic3x_i2c_id[] = { { "tlv320aic33", AIC3X_MODEL_33 }, { "tlv320aic3007", AIC3X_MODEL_3007 }, { "tlv320aic3104", AIC3X_MODEL_3104 }, + { "tlv320aic3106", AIC3X_MODEL_3106 }, { } }; MODULE_DEVICE_TABLE(i2c, aic3x_i2c_id); @@ -49,6 +50,7 @@ static const struct of_device_id aic3x_of_id[] = { { .compatible = "ti,tlv320aic33" }, { .compatible = "ti,tlv320aic3007" }, { .compatible = "ti,tlv320aic3104" }, + { .compatible = "ti,tlv320aic3106" }, {}, }; MODULE_DEVICE_TABLE(of, aic3x_of_id); diff --git a/sound/soc/codecs/tlv320aic3x-spi.c b/sound/soc/codecs/tlv320aic3x-spi.c index bd78ab0910da..8c7b6bb9223f 100644 --- a/sound/soc/codecs/tlv320aic3x-spi.c +++ b/sound/soc/codecs/tlv320aic3x-spi.c @@ -45,6 +45,7 @@ static const struct spi_device_id aic3x_spi_id[] = { { "tlv320aic33", AIC3X_MODEL_33 }, { "tlv320aic3007", AIC3X_MODEL_3007 }, { "tlv320aic3104", AIC3X_MODEL_3104 }, + { "tlv320aic3106", AIC3X_MODEL_3106 }, { } }; MODULE_DEVICE_TABLE(spi, aic3x_spi_id); @@ -54,6 +55,7 @@ static const struct of_device_id aic3x_of_id[] = { { .compatible = "ti,tlv320aic33" }, { .compatible = "ti,tlv320aic3007" }, { .compatible = "ti,tlv320aic3104" }, + { .compatible = "ti,tlv320aic3106" }, {}, }; MODULE_DEVICE_TABLE(of, aic3x_of_id); diff --git a/sound/soc/codecs/tlv320aic3x.c b/sound/soc/codecs/tlv320aic3x.c index 2f351747b714..7731593a5509 100644 --- a/sound/soc/codecs/tlv320aic3x.c +++ b/sound/soc/codecs/tlv320aic3x.c @@ -1003,6 +1003,7 @@ static int aic3x_add_widgets(struct snd_soc_component *component) switch (aic3x->model) { case AIC3X_MODEL_3X: case AIC3X_MODEL_33: + case AIC3X_MODEL_3106: snd_soc_dapm_new_controls(dapm, aic3x_extra_dapm_widgets, ARRAY_SIZE(aic3x_extra_dapm_widgets)); snd_soc_dapm_add_routes(dapm, intercon_extra, @@ -1580,6 +1581,7 @@ static int aic3x_init(struct snd_soc_component *component) switch (aic3x->model) { case AIC3X_MODEL_3X: case AIC3X_MODEL_33: + case AIC3X_MODEL_3106: aic3x_mono_init(component); break; case AIC3X_MODEL_3007: @@ -1646,6 +1648,7 @@ static int aic3x_component_probe(struct snd_soc_component *component) switch (aic3x->model) { case AIC3X_MODEL_3X: case AIC3X_MODEL_33: + case AIC3X_MODEL_3106: snd_soc_add_component_controls(component, aic3x_extra_snd_controls, ARRAY_SIZE(aic3x_extra_snd_controls)); snd_soc_add_component_controls(component, aic3x_mono_controls, diff --git a/sound/soc/codecs/tlv320aic3x.h b/sound/soc/codecs/tlv320aic3x.h index 00908f1734a7..7e0063913017 100644 --- a/sound/soc/codecs/tlv320aic3x.h +++ b/sound/soc/codecs/tlv320aic3x.h @@ -20,6 +20,7 @@ int aic3x_remove(struct device *dev); #define AIC3X_MODEL_33 1 #define AIC3X_MODEL_3007 2 #define AIC3X_MODEL_3104 3 +#define AIC3X_MODEL_3106 4 /* AIC3X register space */ #define AIC3X_CACHEREGNUM 110 From b186e7c17d9f2c2bc9cd0bd362402eddbea7749b Mon Sep 17 00:00:00 2001 From: Ye Bin Date: Thu, 8 Apr 2021 14:26:43 +0800 Subject: [PATCH 428/587] ASoC: tas2764: constify static struct snd_soc_dai_ops The snd_soc_dai_ops structures is only stored in the ops field of a snd_soc_dai_driver structure, so make the snd_soc_dai_ops structure const to allow the compiler to put it in read-only memory. Reported-by: Hulk Robot Signed-off-by: Ye Bin Link: https://lore.kernel.org/r/20210408062643.802908-1-yebin10@huawei.com Signed-off-by: Mark Brown --- sound/soc/codecs/tas2764.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sound/soc/codecs/tas2764.c b/sound/soc/codecs/tas2764.c index 8ff4d9e8d568..9265af41c235 100644 --- a/sound/soc/codecs/tas2764.c +++ b/sound/soc/codecs/tas2764.c @@ -457,7 +457,7 @@ static int tas2764_set_dai_tdm_slot(struct snd_soc_dai *dai, return 0; } -static struct snd_soc_dai_ops tas2764_dai_ops = { +static const struct snd_soc_dai_ops tas2764_dai_ops = { .mute_stream = tas2764_mute, .hw_params = tas2764_hw_params, .set_fmt = tas2764_set_fmt, From 38ec3006eccb46a6db6f4a36536f78db8e9042ac Mon Sep 17 00:00:00 2001 From: Jiri Prchal Date: Thu, 8 Apr 2021 08:07:41 +0200 Subject: [PATCH 429/587] ASoC: codecs: tlv320aic3x: add SPI to the DT binding Added note and example of SPI support. Signed-off-by: Jiri Prchal Link: https://lore.kernel.org/r/20210408060741.6879-1-jiri.prchal@aksignal.cz Signed-off-by: Mark Brown --- .../devicetree/bindings/sound/tlv320aic3x.txt | 21 +++++++++++++++++-- 1 file changed, 19 insertions(+), 2 deletions(-) diff --git a/Documentation/devicetree/bindings/sound/tlv320aic3x.txt b/Documentation/devicetree/bindings/sound/tlv320aic3x.txt index 9796c4639262..20931a63fd64 100644 --- a/Documentation/devicetree/bindings/sound/tlv320aic3x.txt +++ b/Documentation/devicetree/bindings/sound/tlv320aic3x.txt @@ -1,6 +1,6 @@ Texas Instruments - tlv320aic3x Codec module -The tlv320aic3x serial control bus communicates through I2C protocols +The tlv320aic3x serial control bus communicates through both I2C and SPI bus protocols Required properties: @@ -63,7 +63,7 @@ CODEC input pins for other compatible codecs: The pins can be used in referring sound node's audio-routing property. -Example: +I2C example: #include @@ -78,3 +78,20 @@ tlv320aic3x: tlv320aic3x@1b { DRVDD-supply = <®ulator>; DVDD-supply = <®ulator>; }; + +SPI example: + +spi0: spi@f0000000 { + tlv320aic3x: codec@0 { + compatible = "ti,tlv320aic3x"; + reg = <0>; /* CS number */ + #sound-dai-cells = <0>; + spi-max-frequency = <1000000>; + + AVDD-supply = <®ulator>; + IOVDD-supply = <®ulator>; + DRVDD-supply = <®ulator>; + DVDD-supply = <®ulator>; + ai3x-ocmv = <0>; + }; +}; From a93799d55fd479f540ed97066e69114aa7709787 Mon Sep 17 00:00:00 2001 From: Muhammad Usama Anjum Date: Wed, 7 Apr 2021 14:56:34 +0500 Subject: [PATCH 430/587] ASoC: fsl: sunxi: remove redundant dev_err call devm_ioremap_resource() prints error message in itself. Remove the dev_err call to avoid redundant error message. Signed-off-by: Muhammad Usama Anjum Link: https://lore.kernel.org/r/20210407095634.GA1379642@LEGION Signed-off-by: Mark Brown --- sound/soc/fsl/fsl_aud2htx.c | 4 +--- sound/soc/fsl/fsl_easrc.c | 4 +--- sound/soc/sunxi/sun4i-codec.c | 4 +--- 3 files changed, 3 insertions(+), 9 deletions(-) diff --git a/sound/soc/fsl/fsl_aud2htx.c b/sound/soc/fsl/fsl_aud2htx.c index d70d5e75a30c..a328697511f7 100644 --- a/sound/soc/fsl/fsl_aud2htx.c +++ b/sound/soc/fsl/fsl_aud2htx.c @@ -198,10 +198,8 @@ static int fsl_aud2htx_probe(struct platform_device *pdev) res = platform_get_resource(pdev, IORESOURCE_MEM, 0); regs = devm_ioremap_resource(&pdev->dev, res); - if (IS_ERR(regs)) { - dev_err(&pdev->dev, "failed ioremap\n"); + if (IS_ERR(regs)) return PTR_ERR(regs); - } aud2htx->regmap = devm_regmap_init_mmio(&pdev->dev, regs, &fsl_aud2htx_regmap_config); diff --git a/sound/soc/fsl/fsl_easrc.c b/sound/soc/fsl/fsl_easrc.c index 5e33afe87c4a..b1765c7d3bcd 100644 --- a/sound/soc/fsl/fsl_easrc.c +++ b/sound/soc/fsl/fsl_easrc.c @@ -1889,10 +1889,8 @@ static int fsl_easrc_probe(struct platform_device *pdev) res = platform_get_resource(pdev, IORESOURCE_MEM, 0); regs = devm_ioremap_resource(dev, res); - if (IS_ERR(regs)) { - dev_err(&pdev->dev, "failed ioremap\n"); + if (IS_ERR(regs)) return PTR_ERR(regs); - } easrc->paddr = res->start; diff --git a/sound/soc/sunxi/sun4i-codec.c b/sound/soc/sunxi/sun4i-codec.c index 6c13cc84b3fb..00b73b7444b7 100644 --- a/sound/soc/sunxi/sun4i-codec.c +++ b/sound/soc/sunxi/sun4i-codec.c @@ -1706,10 +1706,8 @@ static int sun4i_codec_probe(struct platform_device *pdev) res = platform_get_resource(pdev, IORESOURCE_MEM, 0); base = devm_ioremap_resource(&pdev->dev, res); - if (IS_ERR(base)) { - dev_err(&pdev->dev, "Failed to map the registers\n"); + if (IS_ERR(base)) return PTR_ERR(base); - } quirks = of_device_get_match_data(&pdev->dev); if (quirks == NULL) { From 5e71e9c14db4e49cca56354c95ce10e0e00214d1 Mon Sep 17 00:00:00 2001 From: Ye Bin Date: Thu, 8 Apr 2021 14:27:01 +0800 Subject: [PATCH 431/587] ASoC: rt1019: constify static struct snd_soc_dai_ops The snd_soc_dai_ops structures is only stored in the ops field of a snd_soc_dai_driver structure, so make the snd_soc_dai_ops structure const to allow the compiler to put it in read-only memory. Reported-by: Hulk Robot Signed-off-by: Ye Bin Link: https://lore.kernel.org/r/20210408062701.803865-1-yebin10@huawei.com Signed-off-by: Mark Brown --- sound/soc/codecs/rt1019.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sound/soc/codecs/rt1019.c b/sound/soc/codecs/rt1019.c index 5138f028d9f2..f64bb7302720 100644 --- a/sound/soc/codecs/rt1019.c +++ b/sound/soc/codecs/rt1019.c @@ -823,7 +823,7 @@ static int rt1019_probe(struct snd_soc_component *component) #define RT1019_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S20_3LE | \ SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S8) -static struct snd_soc_dai_ops rt1019_aif_dai_ops = { +static const struct snd_soc_dai_ops rt1019_aif_dai_ops = { .hw_params = rt1019_hw_params, .set_fmt = rt1019_set_dai_fmt, .set_sysclk = rt1019_set_dai_sysclk, From e9a216d8f14ac4d926078885e7e772db08e6aad9 Mon Sep 17 00:00:00 2001 From: Ye Bin Date: Thu, 8 Apr 2021 14:26:56 +0800 Subject: [PATCH 432/587] ASoC: cx2072x: constify static struct snd_soc_dai_ops The snd_soc_dai_ops structures is only stored in the ops field of a snd_soc_dai_driver structure, so make the snd_soc_dai_ops structure const to allow the compiler to put it in read-only memory. Reported-by: Hulk Robot Signed-off-by: Ye Bin Link: https://lore.kernel.org/r/20210408062656.803606-1-yebin10@huawei.com Signed-off-by: Mark Brown --- sound/soc/codecs/cx2072x.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sound/soc/codecs/cx2072x.c b/sound/soc/codecs/cx2072x.c index d924e3528029..1f5c57fab1d8 100644 --- a/sound/soc/codecs/cx2072x.c +++ b/sound/soc/codecs/cx2072x.c @@ -1532,7 +1532,7 @@ static const struct snd_soc_component_driver soc_codec_driver_cx2072x = { /* * DAI ops */ -static struct snd_soc_dai_ops cx2072x_dai_ops = { +static const struct snd_soc_dai_ops cx2072x_dai_ops = { .set_sysclk = cx2072x_set_dai_sysclk, .set_fmt = cx2072x_set_dai_fmt, .hw_params = cx2072x_hw_params, From f2ec1ebb257155fb534cad390575d696dfd567fb Mon Sep 17 00:00:00 2001 From: Ye Bin Date: Thu, 8 Apr 2021 14:26:46 +0800 Subject: [PATCH 433/587] ASoC: tas2770: Constify static struct snd_soc_dai_ops The snd_soc_dai_ops structures is only stored in the ops field of a snd_soc_dai_driver structure, so make the snd_soc_dai_ops structure const to allow the compiler to put it in read-only memory. Reported-by: Hulk Robot Signed-off-by: Ye Bin Link: https://lore.kernel.org/r/20210408062646.803053-1-yebin10@huawei.com Signed-off-by: Mark Brown --- sound/soc/codecs/tas2770.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sound/soc/codecs/tas2770.c b/sound/soc/codecs/tas2770.c index 781bf9cc4faa..172e79cbe0da 100644 --- a/sound/soc/codecs/tas2770.c +++ b/sound/soc/codecs/tas2770.c @@ -464,7 +464,7 @@ static int tas2770_set_dai_tdm_slot(struct snd_soc_dai *dai, return 0; } -static struct snd_soc_dai_ops tas2770_dai_ops = { +static const struct snd_soc_dai_ops tas2770_dai_ops = { .mute_stream = tas2770_mute, .hw_params = tas2770_hw_params, .set_fmt = tas2770_set_fmt, From d763145312582c08c4e9ed99d61276cde8488256 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Thu, 8 Apr 2021 09:56:56 +0200 Subject: [PATCH 434/587] ALSA: usb-audio: Skip probe of UA-101 devices UA-101 device and co are supported by another driver, snd-ua101, but the USB audio class driver (snd-usb-audio) catches all and this resulted in the lack of functionality like missing MIDI devices. This patch introduces a sort of deny-listing for those devices to just return -ENODEV at probe in snd-usb-audio driver, so that it falls back to the probe by snd-ua101. BugLink: https://bugzilla.kernel.org/show_bug.cgi?id=212477 Link: https://lore.kernel.org/r/20210408075656.30184-1-tiwai@suse.de Signed-off-by: Takashi Iwai --- sound/usb/card.c | 2 ++ sound/usb/quirks-table.h | 21 +++++++++++++++++++++ sound/usb/usbaudio.h | 1 + 3 files changed, 24 insertions(+) diff --git a/sound/usb/card.c b/sound/usb/card.c index 7b7526d3a56e..2f6a62416c05 100644 --- a/sound/usb/card.c +++ b/sound/usb/card.c @@ -713,6 +713,8 @@ static int usb_audio_probe(struct usb_interface *intf, quirk = get_alias_quirk(dev, id); if (quirk && quirk->ifnum >= 0 && ifnum != quirk->ifnum) return -ENXIO; + if (quirk && quirk->ifnum == QUIRK_NODEV_INTERFACE) + return -ENODEV; err = snd_usb_apply_boot_quirk(dev, intf, quirk, id); if (err < 0) diff --git a/sound/usb/quirks-table.h b/sound/usb/quirks-table.h index 9716a9f7c095..92f525b1c992 100644 --- a/sound/usb/quirks-table.h +++ b/sound/usb/quirks-table.h @@ -1674,6 +1674,27 @@ YAMAHA_DEVICE(0x7010, "UB99"), } } }, + +/* UA101 and co are supported by another driver */ +{ + USB_DEVICE(0x0582, 0x0044), /* UA-1000 high speed */ + .driver_info = (unsigned long) & (const struct snd_usb_audio_quirk) { + .ifnum = QUIRK_NODEV_INTERFACE + }, +}, +{ + USB_DEVICE(0x0582, 0x007d), /* UA-101 high speed */ + .driver_info = (unsigned long) & (const struct snd_usb_audio_quirk) { + .ifnum = QUIRK_NODEV_INTERFACE + }, +}, +{ + USB_DEVICE(0x0582, 0x008d), /* UA-101 full speed */ + .driver_info = (unsigned long) & (const struct snd_usb_audio_quirk) { + .ifnum = QUIRK_NODEV_INTERFACE + }, +}, + /* this catches most recent vendor-specific Roland devices */ { .match_flags = USB_DEVICE_ID_MATCH_VENDOR | diff --git a/sound/usb/usbaudio.h b/sound/usb/usbaudio.h index 8794c8658ab9..a536ee33d36e 100644 --- a/sound/usb/usbaudio.h +++ b/sound/usb/usbaudio.h @@ -77,6 +77,7 @@ struct snd_usb_audio { */ /* special values for .ifnum */ +#define QUIRK_NODEV_INTERFACE -3 /* return -ENODEV */ #define QUIRK_NO_INTERFACE -2 #define QUIRK_ANY_INTERFACE -1 From 64f40f9be14106e7df0098c427cb60be645bddb7 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Wed, 7 Apr 2021 16:45:49 +0200 Subject: [PATCH 435/587] ALSA: usb-audio: Add MIDI quirk for Vox ToneLab EX ToneLab EX guitar pedal device requires the same quirk like ToneLab ST for supporting the MIDI. BugLink: https://bugzilla.kernel.org/show_bug.cgi?id=212593 Cc: Link: https://lore.kernel.org/r/20210407144549.1530-1-tiwai@suse.de Signed-off-by: Takashi Iwai --- sound/usb/quirks-table.h | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/sound/usb/quirks-table.h b/sound/usb/quirks-table.h index 92f525b1c992..bdba37d0faab 100644 --- a/sound/usb/quirks-table.h +++ b/sound/usb/quirks-table.h @@ -2397,6 +2397,16 @@ YAMAHA_DEVICE(0x7010, "UB99"), } }, +{ + USB_DEVICE_VENDOR_SPEC(0x0944, 0x0204), + .driver_info = (unsigned long) & (const struct snd_usb_audio_quirk) { + .vendor_name = "KORG, Inc.", + /* .product_name = "ToneLab EX", */ + .ifnum = 3, + .type = QUIRK_MIDI_STANDARD_INTERFACE, + } +}, + /* AKAI devices */ { USB_DEVICE(0x09e8, 0x0062), From 3e075e842899779bd321520a3524a278442467d0 Mon Sep 17 00:00:00 2001 From: Ye Bin Date: Thu, 8 Apr 2021 14:26:51 +0800 Subject: [PATCH 436/587] ASoC: amd: raven: acp3x-i2s: Constify static struct snd_soc_dai_ops The snd_soc_dai_ops structures is only stored in the ops field of a snd_soc_dai_driver structure, so make the snd_soc_dai_ops structure const to allow the compiler to put it in read-only memory. Reported-by: Hulk Robot Signed-off-by: Ye Bin Link: https://lore.kernel.org/r/20210408062651.803413-1-yebin10@huawei.com Signed-off-by: Mark Brown --- sound/soc/amd/raven/acp3x-i2s.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sound/soc/amd/raven/acp3x-i2s.c b/sound/soc/amd/raven/acp3x-i2s.c index 5bc028692fcf..396cb7d619e2 100644 --- a/sound/soc/amd/raven/acp3x-i2s.c +++ b/sound/soc/amd/raven/acp3x-i2s.c @@ -249,7 +249,7 @@ static int acp3x_i2s_trigger(struct snd_pcm_substream *substream, return ret; } -static struct snd_soc_dai_ops acp3x_i2s_dai_ops = { +static const struct snd_soc_dai_ops acp3x_i2s_dai_ops = { .hw_params = acp3x_i2s_hwparams, .trigger = acp3x_i2s_trigger, .set_fmt = acp3x_i2s_set_fmt, From 45475bf60cc1d42da229a0aa757180c88bab8d22 Mon Sep 17 00:00:00 2001 From: Gyeongtaek Lee Date: Wed, 7 Apr 2021 13:14:04 +0900 Subject: [PATCH 437/587] ASoC: soc-compress: lock pcm_mutex to resolve lockdep error If panic_on_warn=1 is added in bootargs and compress offload playback with DPCM is started, kernel panic would be occurred because rtd->card->pcm_mutex isn't held in soc_compr_open_fe() and soc_compr_free_fe() and it generates lockdep warning in the following code. void snd_soc_runtime_action(struct snd_soc_pcm_runtime *rtd, int stream, int action) { struct snd_soc_dai *dai; int i; lockdep_assert_held(&rtd->card->pcm_mutex); To prevent lockdep warning but minimize side effect by adding mutex, pcm_mutex is held just before snd_soc_runtime_activate() and snd_soc_runtime_deactivate() and is released right after them. Signed-off-by: Gyeongtaek Lee Link: https://lore.kernel.org/r/1891546521.01617772502282.JavaMail.epsvc@epcpadp3 Signed-off-by: Mark Brown --- sound/soc/soc-compress.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/sound/soc/soc-compress.c b/sound/soc/soc-compress.c index 83b511f8b8c9..b4f59350a5a8 100644 --- a/sound/soc/soc-compress.c +++ b/sound/soc/soc-compress.c @@ -151,7 +151,9 @@ static int soc_compr_open_fe(struct snd_compr_stream *cstream) fe->dpcm[stream].state = SND_SOC_DPCM_STATE_OPEN; fe->dpcm[stream].runtime_update = SND_SOC_DPCM_UPDATE_NO; + mutex_lock_nested(&fe->card->pcm_mutex, fe->card->pcm_subclass); snd_soc_runtime_activate(fe, stream); + mutex_unlock(&fe->card->pcm_mutex); mutex_unlock(&fe->card->mutex); @@ -178,7 +180,9 @@ static int soc_compr_free_fe(struct snd_compr_stream *cstream) mutex_lock_nested(&fe->card->mutex, SND_SOC_CARD_CLASS_RUNTIME); + mutex_lock_nested(&fe->card->pcm_mutex, fe->card->pcm_subclass); snd_soc_runtime_deactivate(fe, stream); + mutex_unlock(&fe->card->pcm_mutex); fe->dpcm[stream].runtime_update = SND_SOC_DPCM_UPDATE_FE; From 857b602a3424a7d9ef875f8f137ddcb68de41c6f Mon Sep 17 00:00:00 2001 From: Ye Bin Date: Thu, 8 Apr 2021 14:26:50 +0800 Subject: [PATCH 438/587] ASoC: codecs: lpass-rx-macro: constify static struct snd_soc_dai_ops The snd_soc_dai_ops structures is only stored in the ops field of a snd_soc_dai_driver structure, so make the snd_soc_dai_ops structure const to allow the compiler to put it in read-only memory. Reported-by: Hulk Robot Signed-off-by: Ye Bin Link: https://lore.kernel.org/r/20210408062650.803309-1-yebin10@huawei.com Signed-off-by: Mark Brown --- sound/soc/codecs/lpass-rx-macro.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sound/soc/codecs/lpass-rx-macro.c b/sound/soc/codecs/lpass-rx-macro.c index c0f7b5ecbf9e..14c166506fb1 100644 --- a/sound/soc/codecs/lpass-rx-macro.c +++ b/sound/soc/codecs/lpass-rx-macro.c @@ -1767,7 +1767,7 @@ static int rx_macro_digital_mute(struct snd_soc_dai *dai, int mute, int stream) return 0; } -static struct snd_soc_dai_ops rx_macro_dai_ops = { +static const struct snd_soc_dai_ops rx_macro_dai_ops = { .hw_params = rx_macro_hw_params, .get_channel_map = rx_macro_get_channel_map, .mute_stream = rx_macro_digital_mute, From a457dd92d14acdf3dd64285f04ed9225d14d195a Mon Sep 17 00:00:00 2001 From: Ye Bin Date: Thu, 8 Apr 2021 14:26:53 +0800 Subject: [PATCH 439/587] ASoC: Intel: KMB: Constify static struct snd_soc_dai_ops The snd_soc_dai_ops structures is only stored in the ops field of a snd_soc_dai_driver structure, so make the snd_soc_dai_ops structure const to allow the compiler to put it in read-only memory. Reported-by: Hulk Robot Signed-off-by: Ye Bin Link: https://lore.kernel.org/r/20210408062653.803478-1-yebin10@huawei.com Signed-off-by: Mark Brown --- sound/soc/intel/keembay/kmb_platform.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sound/soc/intel/keembay/kmb_platform.c b/sound/soc/intel/keembay/kmb_platform.c index 0fd1e8f62c89..ef73392f8cff 100644 --- a/sound/soc/intel/keembay/kmb_platform.c +++ b/sound/soc/intel/keembay/kmb_platform.c @@ -729,7 +729,7 @@ static int kmb_dai_hw_free(struct snd_pcm_substream *substream, return 0; } -static struct snd_soc_dai_ops kmb_dai_ops = { +static const struct snd_soc_dai_ops kmb_dai_ops = { .startup = kmb_dai_startup, .trigger = kmb_dai_trigger, .hw_params = kmb_dai_hw_params, From 1f34084cc85d654a542c547df6714dae8a32d3c9 Mon Sep 17 00:00:00 2001 From: Ye Bin Date: Thu, 8 Apr 2021 14:26:54 +0800 Subject: [PATCH 440/587] ASoC: rt715-sdca: Constify static struct snd_soc_dai_ops The snd_soc_dai_ops structures is only stored in the ops field of a snd_soc_dai_driver structure, so make the snd_soc_dai_ops structure const to allow the compiler to put it in read-only memory. Reported-by: Hulk Robot Signed-off-by: Ye Bin Link: https://lore.kernel.org/r/20210408062654.803538-1-yebin10@huawei.com Signed-off-by: Mark Brown --- sound/soc/codecs/rt715-sdca.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sound/soc/codecs/rt715-sdca.c b/sound/soc/codecs/rt715-sdca.c index 20528afbdc57..7db76c19e048 100644 --- a/sound/soc/codecs/rt715-sdca.c +++ b/sound/soc/codecs/rt715-sdca.c @@ -935,7 +935,7 @@ static int rt715_sdca_pcm_hw_free(struct snd_pcm_substream *substream, #define RT715_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S20_3LE | \ SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S8) -static struct snd_soc_dai_ops rt715_sdca_ops = { +static const struct snd_soc_dai_ops rt715_sdca_ops = { .hw_params = rt715_sdca_pcm_hw_params, .hw_free = rt715_sdca_pcm_hw_free, .set_sdw_stream = rt715_sdca_set_sdw_stream, From e994cf82689465ddae2dfa9c9bc69616a0003649 Mon Sep 17 00:00:00 2001 From: Ye Bin Date: Thu, 8 Apr 2021 14:26:48 +0800 Subject: [PATCH 441/587] ASoC: wcd934x: constify static struct snd_soc_dai_ops The snd_soc_dai_ops structures is only stored in the ops field of a snd_soc_dai_driver structure, so make the snd_soc_dai_ops structure const to allow the compiler to put it in read-only memory. Reported-by: Hulk Robot Signed-off-by: Ye Bin Link: https://lore.kernel.org/r/20210408062648.803227-1-yebin10@huawei.com Signed-off-by: Mark Brown --- sound/soc/codecs/wcd934x.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sound/soc/codecs/wcd934x.c b/sound/soc/codecs/wcd934x.c index 2c4818dc2e6d..5fe403307b72 100644 --- a/sound/soc/codecs/wcd934x.c +++ b/sound/soc/codecs/wcd934x.c @@ -1946,7 +1946,7 @@ static int wcd934x_get_channel_map(struct snd_soc_dai *dai, return 0; } -static struct snd_soc_dai_ops wcd934x_dai_ops = { +static const struct snd_soc_dai_ops wcd934x_dai_ops = { .hw_params = wcd934x_hw_params, .hw_free = wcd934x_hw_free, .trigger = wcd934x_trigger, From 3cab801e8b94280264ba23ab0683cd3a9c13ca9f Mon Sep 17 00:00:00 2001 From: Ye Bin Date: Thu, 8 Apr 2021 14:26:47 +0800 Subject: [PATCH 442/587] ASoC: rt711-sdca: Constify static struct snd_soc_dai_ops The snd_soc_dai_ops structures is only stored in the ops field of a snd_soc_dai_driver structure, so make the snd_soc_dai_ops structure const to allow the compiler to put it in read-only memory. Reported-by: Hulk Robot Signed-off-by: Ye Bin Link: https://lore.kernel.org/r/20210408062647.803141-1-yebin10@huawei.com Signed-off-by: Mark Brown --- sound/soc/codecs/rt711-sdca.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sound/soc/codecs/rt711-sdca.c b/sound/soc/codecs/rt711-sdca.c index 381893b640c6..bfb7f1c8ec8f 100644 --- a/sound/soc/codecs/rt711-sdca.c +++ b/sound/soc/codecs/rt711-sdca.c @@ -1268,7 +1268,7 @@ static int rt711_sdca_pcm_hw_free(struct snd_pcm_substream *substream, #define RT711_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S20_3LE | \ SNDRV_PCM_FMTBIT_S24_LE) -static struct snd_soc_dai_ops rt711_sdca_ops = { +static const struct snd_soc_dai_ops rt711_sdca_ops = { .hw_params = rt711_sdca_pcm_hw_params, .hw_free = rt711_sdca_pcm_hw_free, .set_sdw_stream = rt711_sdca_set_sdw_stream, From 4f3b0f8e364029f2674875396f0e65a98ef84498 Mon Sep 17 00:00:00 2001 From: Jack Yu Date: Fri, 9 Apr 2021 08:52:29 +0000 Subject: [PATCH 443/587] ASoC: rt1019: remove registers to sync with rt1019 datasheet Remove some registers to synchronize with the latest rt1019 datasheet. Signed-off-by: Jack Yu Link: https://lore.kernel.org/r/01e6409f0db0451aa1e45ca7d82cca9c@realtek.com Signed-off-by: Mark Brown --- sound/soc/codecs/rt1019.c | 334 +------------------------------------- sound/soc/codecs/rt1019.h | 162 ------------------ 2 files changed, 1 insertion(+), 495 deletions(-) diff --git a/sound/soc/codecs/rt1019.c b/sound/soc/codecs/rt1019.c index f64bb7302720..10656a5927f1 100644 --- a/sound/soc/codecs/rt1019.c +++ b/sound/soc/codecs/rt1019.c @@ -32,210 +32,40 @@ static const struct reg_default rt1019_reg[] = { { 0x0000, 0x00 }, - { 0x0002, 0x55 }, - { 0x0003, 0x55 }, - { 0x0005, 0x54 }, - { 0x0006, 0x05 }, - { 0x0007, 0x01 }, - { 0x0008, 0x70 }, - { 0x0009, 0x28 }, - { 0x000a, 0x7f }, { 0x0011, 0x04 }, { 0x0013, 0x00 }, - { 0x0015, 0x00 }, - { 0x0017, 0x00 }, { 0x0019, 0x30 }, { 0x001b, 0x01 }, - { 0x001d, 0x18 }, - { 0x001f, 0x29 }, - { 0x0021, 0x09 }, - { 0x0023, 0x02 }, - { 0x0025, 0x00 }, - { 0x0026, 0x00 }, - { 0x0028, 0x03 }, - { 0x0053, 0x00 }, - { 0x0055, 0x00 }, - { 0x0056, 0x00 }, - { 0x0057, 0x00 }, - { 0x0058, 0x00 }, - { 0x005a, 0x00 }, { 0x005c, 0x00 }, - { 0x005d, 0x00 }, { 0x005e, 0x10 }, { 0x005f, 0xec }, { 0x0061, 0x10 }, { 0x0062, 0x19 }, - { 0x0064, 0x00 }, { 0x0066, 0x08 }, - { 0x0068, 0x00 }, - { 0x006a, 0x00 }, - { 0x006c, 0x00 }, - { 0x006e, 0x00 }, { 0x0100, 0x80 }, { 0x0100, 0x51 }, { 0x0102, 0x23 }, - { 0x0102, 0x0f }, - { 0x0104, 0x6c }, - { 0x0105, 0xec }, - { 0x0106, 0x00 }, - { 0x0107, 0x00 }, - { 0x0108, 0x00 }, - { 0x0200, 0x40 }, - { 0x0201, 0x00 }, - { 0x0202, 0x00 }, - { 0x0203, 0x00 }, - { 0x0301, 0x02 }, - { 0x0302, 0xaa }, - { 0x0303, 0x2a }, - { 0x0304, 0x6a }, - { 0x0306, 0xb0 }, - { 0x0308, 0x48 }, - { 0x030a, 0x0a }, - { 0x030b, 0x4b }, - { 0x030d, 0x7d }, - { 0x030e, 0xef }, - { 0x030f, 0x5a }, { 0x0311, 0x00 }, { 0x0312, 0x3e }, { 0x0313, 0x86 }, - { 0x0315, 0xa8 }, - { 0x0318, 0x1b }, - { 0x031a, 0x3d }, - { 0x031c, 0x40 }, - { 0x031d, 0x40 }, - { 0x031e, 0x30 }, - { 0x031f, 0xbb }, - { 0x0320, 0xa5 }, - { 0x0321, 0xa5 }, - { 0x0323, 0x5a }, - { 0x0324, 0xaa }, - { 0x0325, 0x80 }, - { 0x0326, 0xaa }, - { 0x0327, 0x66 }, - { 0x0328, 0x94 }, - { 0x0329, 0x00 }, - { 0x0330, 0x00 }, - { 0x0331, 0x30 }, - { 0x0332, 0x05 }, { 0x0400, 0x03 }, { 0x0401, 0x02 }, { 0x0402, 0x01 }, - { 0x0403, 0x23 }, - { 0x0404, 0x45 }, - { 0x0405, 0x67 }, - { 0x0500, 0x80 }, - { 0x0501, 0x00 }, - { 0x0502, 0x00 }, - { 0x0503, 0x00 }, { 0x0504, 0xff }, { 0x0505, 0x24 }, - { 0x0600, 0x75 }, - { 0x0601, 0x41 }, - { 0x0602, 0x60 }, - { 0x0603, 0x7f }, - { 0x0604, 0x65 }, - { 0x0605, 0x43 }, - { 0x0606, 0x00 }, - { 0x0607, 0x00 }, - { 0x0608, 0x00 }, - { 0x0609, 0x00 }, - { 0x060a, 0x00 }, - { 0x060b, 0x00 }, - { 0x060c, 0x00 }, - { 0x060d, 0x00 }, - { 0x060e, 0x00 }, - { 0x060f, 0x00 }, - { 0x0700, 0x15 }, - { 0x0701, 0xc8 }, - { 0x0704, 0x02 }, - { 0x0705, 0x00 }, - { 0x0706, 0x00 }, - { 0x0707, 0x80 }, - { 0x0708, 0x08 }, - { 0x0709, 0x00 }, - { 0x0800, 0x00 }, - { 0x0801, 0x00 }, - { 0x0802, 0x09 }, - { 0x0803, 0x00 }, - { 0x0900, 0x87 }, - { 0x0a01, 0x99 }, - { 0x0a02, 0x40 }, - { 0x0a03, 0x10 }, { 0x0b00, 0x50 }, { 0x0b01, 0xc3 }, - { 0x0c00, 0x84 }, - { 0x0c01, 0x00 }, - { 0x0c02, 0xbb }, - { 0x0c03, 0x80 }, - { 0x0c04, 0x10 }, - { 0x0c05, 0x30 }, - { 0x0c06, 0x00 }, - { 0x0d00, 0x80 }, - { 0x0d01, 0xbb }, - { 0x0d02, 0x80 }, - { 0x0d03, 0x00 }, - { 0x0d04, 0x00 }, - { 0x0d05, 0x00 }, - { 0x0e00, 0x80 }, - { 0x0e01, 0xbb }, - { 0x0e02, 0x80 }, - { 0x0e03, 0x00 }, - { 0x0e04, 0x10 }, - { 0x0e05, 0x30 }, - { 0x0f00, 0x80 }, - { 0x0f01, 0xbb }, - { 0x0f02, 0x80 }, - { 0x0f03, 0x00 }, - { 0x0f04, 0x10 }, - { 0x0f05, 0x30 }, - { 0x0f06, 0x88 }, - { 0x0f07, 0x88 }, - { 0x0f08, 0x00 }, - { 0x0f09, 0x00 }, }; static bool rt1019_volatile_register(struct device *dev, unsigned int reg) { switch (reg) { - case RT1019_PWR_STRP_1: case RT1019_PWR_STRP_2: - case RT1019_SIL_DET_GAT: - case RT1019_PHASE_SYNC: - case RT1019_STAT_MACH_2: - case RT1019_FS_DET_1: - case RT1019_FS_DET_2: - case RT1019_FS_DET_3: - case RT1019_FS_DET_4: - case RT1019_FS_DET_5: - case RT1019_FS_DET_6: - case RT1019_FS_DET_7: - case RT1019_ANA_READ: case RT1019_VER_ID: - case RT1019_CUSTOM_ID: case RT1019_VEND_ID_1: case RT1019_VEND_ID_2: case RT1019_DEV_ID_1: case RT1019_DEV_ID_2: - case RT1019_CAL_TOP_3: - case RT1019_CAL_TOP_7: - case RT1019_CAL_TOP_17: - case RT1019_CAL_TOP_18: - case RT1019_CAL_TOP_19: - case RT1019_CAL_TOP_20: - case RT1019_CAL_TOP_21: - case RT1019_CAL_TOP_22: - case RT1019_MDRE_CTRL_2: - case RT1019_MDRE_CTRL_3: - case RT1019_MDRE_CTRL_4: - case RT1019_SIL_DET_2: - case RT1019_PWM_DC_DET_1: - case RT1019_PMC_8: - case RT1019_PMC_9: - case RT1019_SPKDRC_7: - case RT1019_HALF_FREQ_7: - case RT1019_CUR_CTRL_11: - case RT1019_CUR_CTRL_12: - case RT1019_CUR_CTRL_13: return true; default: @@ -247,191 +77,29 @@ static bool rt1019_readable_register(struct device *dev, unsigned int reg) { switch (reg) { case RT1019_RESET: - case RT1019_PAD_DRV_1: - case RT1019_PAD_DRV_2: - case RT1019_PAD_PULL_1: - case RT1019_PAD_PULL_2: - case RT1019_PAD_PULL_3: - case RT1019_I2C_CTRL_1: - case RT1019_I2C_CTRL_2: - case RT1019_I2C_CTRL_3: case RT1019_IDS_CTRL: case RT1019_ASEL_CTRL: - case RT1019_PLL_RESET: - case RT1019_PWR_STRP_1: case RT1019_PWR_STRP_2: case RT1019_BEEP_TONE: - case RT1019_SIL_DET_GAT: - case RT1019_CLASSD_TIME: - case RT1019_CLASSD_OCP: - case RT1019_PHASE_SYNC: - case RT1019_STAT_MACH_1: - case RT1019_STAT_MACH_2: - case RT1019_EFF_CTRL: - case RT1019_FS_DET_1: - case RT1019_FS_DET_2: - case RT1019_FS_DET_3: - case RT1019_FS_DET_4: - case RT1019_FS_DET_5: - case RT1019_FS_DET_6: - case RT1019_FS_DET_7: - case RT1019_ANA_CTRL: - case RT1019_DUMMY_A: - case RT1019_DUMMY_B: - case RT1019_DUMMY_C: - case RT1019_DUMMY_D: - case RT1019_ANA_READ: case RT1019_VER_ID: - case RT1019_CUSTOM_ID: case RT1019_VEND_ID_1: case RT1019_VEND_ID_2: case RT1019_DEV_ID_1: case RT1019_DEV_ID_2: - case RT1019_TEST_PAD: case RT1019_SDB_CTRL: - case RT1019_TEST_CTRL_1: - case RT1019_TEST_CTRL_2: - case RT1019_TEST_CTRL_3: - case RT1019_SCAN_MODE: case RT1019_CLK_TREE_1: case RT1019_CLK_TREE_2: case RT1019_CLK_TREE_3: - case RT1019_CLK_TREE_4: - case RT1019_CLK_TREE_5: - case RT1019_CLK_TREE_6: - case RT1019_CLK_TREE_7: - case RT1019_CLK_TREE_8: - case RT1019_CLK_TREE_9: - case RT1019_ASRC_1: - case RT1019_ASRC_2: - case RT1019_ASRC_3: - case RT1019_ASRC_4: - case RT1019_SYS_CLK: - case RT1019_BIAS_CUR_1: - case RT1019_BIAS_CUR_2: - case RT1019_BIAS_CUR_3: - case RT1019_BIAS_CUR_4: - case RT1019_CHOP_CLK_DAC: - case RT1019_CHOP_CLK_ADC: - case RT1019_LDO_CTRL_1: - case RT1019_LDO_CTRL_2: - case RT1019_PM_ANA_1: - case RT1019_PM_ANA_2: - case RT1019_PM_ANA_3: case RT1019_PLL_1: case RT1019_PLL_2: case RT1019_PLL_3: - case RT1019_PLL_INT_1: - case RT1019_PLL_INT_3: - case RT1019_MIXER: - case RT1019_CLD_OUT_1: - case RT1019_CLD_OUT_2: - case RT1019_CLD_OUT_3: - case RT1019_CLD_OUT_4: - case RT1019_CLD_OUT_5: - case RT1019_CLD_OUT_6: - case RT1019_CLS_INT_REG_1: - case RT1019_CLS_INT_REG_2: - case RT1019_CLS_INT_REG_3: - case RT1019_CLS_INT_REG_4: - case RT1019_CLS_INT_REG_5: - case RT1019_CLS_INT_REG_6: - case RT1019_CLS_INT_REG_7: - case RT1019_CLS_INT_REG_8: - case RT1019_CLS_INT_REG_9: - case RT1019_CLS_INT_REG_10: case RT1019_TDM_1: case RT1019_TDM_2: case RT1019_TDM_3: - case RT1019_TDM_4: - case RT1019_TDM_5: - case RT1019_TDM_6: - case RT1019_DVOL_1: - case RT1019_DVOL_2: - case RT1019_DVOL_3: - case RT1019_DVOL_4: case RT1019_DMIX_MONO_1: case RT1019_DMIX_MONO_2: - case RT1019_CAL_TOP_1: - case RT1019_CAL_TOP_2: - case RT1019_CAL_TOP_3: - case RT1019_CAL_TOP_4: - case RT1019_CAL_TOP_5: - case RT1019_CAL_TOP_6: - case RT1019_CAL_TOP_7: - case RT1019_CAL_TOP_8: - case RT1019_CAL_TOP_9: - case RT1019_CAL_TOP_10: - case RT1019_CAL_TOP_11: - case RT1019_CAL_TOP_12: - case RT1019_CAL_TOP_13: - case RT1019_CAL_TOP_14: - case RT1019_CAL_TOP_15: - case RT1019_CAL_TOP_16: - case RT1019_CAL_TOP_17: - case RT1019_CAL_TOP_18: - case RT1019_CAL_TOP_19: - case RT1019_CAL_TOP_20: - case RT1019_CAL_TOP_21: - case RT1019_CAL_TOP_22: - case RT1019_MDRE_CTRL_1: - case RT1019_MDRE_CTRL_2: - case RT1019_MDRE_CTRL_3: - case RT1019_MDRE_CTRL_4: - case RT1019_MDRE_CTRL_5: - case RT1019_MDRE_CTRL_6: - case RT1019_MDRE_CTRL_7: - case RT1019_MDRE_CTRL_8: - case RT1019_MDRE_CTRL_9: - case RT1019_MDRE_CTRL_10: - case RT1019_SCC_CTRL_1: - case RT1019_SCC_CTRL_2: - case RT1019_SCC_CTRL_3: - case RT1019_SCC_DUMMY: - case RT1019_SIL_DET_1: - case RT1019_SIL_DET_2: - case RT1019_PWM_DC_DET_1: - case RT1019_PWM_DC_DET_2: - case RT1019_PWM_DC_DET_3: - case RT1019_PWM_DC_DET_4: case RT1019_BEEP_1: case RT1019_BEEP_2: - case RT1019_PMC_1: - case RT1019_PMC_2: - case RT1019_PMC_3: - case RT1019_PMC_4: - case RT1019_PMC_5: - case RT1019_PMC_6: - case RT1019_PMC_7: - case RT1019_PMC_8: - case RT1019_PMC_9: - case RT1019_SPKDRC_1: - case RT1019_SPKDRC_2: - case RT1019_SPKDRC_3: - case RT1019_SPKDRC_4: - case RT1019_SPKDRC_5: - case RT1019_SPKDRC_6: - case RT1019_SPKDRC_7: - case RT1019_HALF_FREQ_1: - case RT1019_HALF_FREQ_2: - case RT1019_HALF_FREQ_3: - case RT1019_HALF_FREQ_4: - case RT1019_HALF_FREQ_5: - case RT1019_HALF_FREQ_6: - case RT1019_HALF_FREQ_7: - case RT1019_CUR_CTRL_1: - case RT1019_CUR_CTRL_2: - case RT1019_CUR_CTRL_3: - case RT1019_CUR_CTRL_4: - case RT1019_CUR_CTRL_5: - case RT1019_CUR_CTRL_6: - case RT1019_CUR_CTRL_7: - case RT1019_CUR_CTRL_8: - case RT1019_CUR_CTRL_9: - case RT1019_CUR_CTRL_10: - case RT1019_CUR_CTRL_11: - case RT1019_CUR_CTRL_12: - case RT1019_CUR_CTRL_13: return true; default: return false; @@ -861,7 +529,7 @@ static const struct regmap_config rt1019_regmap = { .val_bits = 8, .use_single_read = true, .use_single_write = true, - .max_register = RT1019_CUR_CTRL_13, + .max_register = RT1019_BEEP_2, .volatile_reg = rt1019_volatile_register, .readable_reg = rt1019_readable_register, .cache_type = REGCACHE_RBTREE, diff --git a/sound/soc/codecs/rt1019.h b/sound/soc/codecs/rt1019.h index 46973e71c963..64df831eeb72 100644 --- a/sound/soc/codecs/rt1019.h +++ b/sound/soc/codecs/rt1019.h @@ -12,191 +12,29 @@ #define RT1019_DEVICE_ID_VAL2 0x6731 #define RT1019_RESET 0x0000 -#define RT1019_PAD_DRV_1 0x0002 -#define RT1019_PAD_DRV_2 0x0003 -#define RT1019_PAD_PULL_1 0x0005 -#define RT1019_PAD_PULL_2 0x0006 -#define RT1019_PAD_PULL_3 0x0007 -#define RT1019_I2C_CTRL_1 0x0008 -#define RT1019_I2C_CTRL_2 0x0009 -#define RT1019_I2C_CTRL_3 0x000a #define RT1019_IDS_CTRL 0x0011 #define RT1019_ASEL_CTRL 0x0013 -#define RT1019_PLL_RESET 0x0015 -#define RT1019_PWR_STRP_1 0x0017 #define RT1019_PWR_STRP_2 0x0019 #define RT1019_BEEP_TONE 0x001b -#define RT1019_SIL_DET_GAT 0x001d -#define RT1019_CLASSD_TIME 0x001f -#define RT1019_CLASSD_OCP 0x0021 -#define RT1019_PHASE_SYNC 0x0023 -#define RT1019_STAT_MACH_1 0x0025 -#define RT1019_STAT_MACH_2 0x0026 -#define RT1019_EFF_CTRL 0x0028 -#define RT1019_FS_DET_1 0x002a -#define RT1019_FS_DET_2 0x002b -#define RT1019_FS_DET_3 0x002c -#define RT1019_FS_DET_4 0x002d -#define RT1019_FS_DET_5 0x002e -#define RT1019_FS_DET_6 0x002f -#define RT1019_FS_DET_7 0x0030 -#define RT1019_ANA_CTRL 0x0053 -#define RT1019_DUMMY_A 0x0055 -#define RT1019_DUMMY_B 0x0056 -#define RT1019_DUMMY_C 0x0057 -#define RT1019_DUMMY_D 0x0058 -#define RT1019_ANA_READ 0x005a #define RT1019_VER_ID 0x005c -#define RT1019_CUSTOM_ID 0x005d #define RT1019_VEND_ID_1 0x005e #define RT1019_VEND_ID_2 0x005f #define RT1019_DEV_ID_1 0x0061 #define RT1019_DEV_ID_2 0x0062 -#define RT1019_TEST_PAD 0x0064 #define RT1019_SDB_CTRL 0x0066 -#define RT1019_TEST_CTRL_1 0x0068 -#define RT1019_TEST_CTRL_2 0x006a -#define RT1019_TEST_CTRL_3 0x006c -#define RT1019_SCAN_MODE 0x006e #define RT1019_CLK_TREE_1 0x0100 #define RT1019_CLK_TREE_2 0x0101 #define RT1019_CLK_TREE_3 0x0102 -#define RT1019_CLK_TREE_4 0x0103 -#define RT1019_CLK_TREE_5 0x0104 -#define RT1019_CLK_TREE_6 0x0105 -#define RT1019_CLK_TREE_7 0x0106 -#define RT1019_CLK_TREE_8 0x0107 -#define RT1019_CLK_TREE_9 0x0108 -#define RT1019_ASRC_1 0x0200 -#define RT1019_ASRC_2 0x0201 -#define RT1019_ASRC_3 0x0202 -#define RT1019_ASRC_4 0x0203 -#define RT1019_SYS_CLK 0x0300 -#define RT1019_BIAS_CUR_1 0x0301 -#define RT1019_BIAS_CUR_2 0x0302 -#define RT1019_BIAS_CUR_3 0x0303 -#define RT1019_BIAS_CUR_4 0x0304 -#define RT1019_CHOP_CLK_DAC 0x0306 -#define RT1019_CHOP_CLK_ADC 0x0308 -#define RT1019_LDO_CTRL_1 0x030a -#define RT1019_LDO_CTRL_2 0x030b -#define RT1019_PM_ANA_1 0x030d -#define RT1019_PM_ANA_2 0x030e -#define RT1019_PM_ANA_3 0x030f #define RT1019_PLL_1 0x0311 #define RT1019_PLL_2 0x0312 #define RT1019_PLL_3 0x0313 -#define RT1019_PLL_INT_1 0x0315 -#define RT1019_PLL_INT_3 0x0318 -#define RT1019_MIXER 0x031a -#define RT1019_CLD_OUT_1 0x031c -#define RT1019_CLD_OUT_2 0x031d -#define RT1019_CLD_OUT_3 0x031e -#define RT1019_CLD_OUT_4 0x031f -#define RT1019_CLD_OUT_5 0x0320 -#define RT1019_CLD_OUT_6 0x0321 -#define RT1019_CLS_INT_REG_1 0x0323 -#define RT1019_CLS_INT_REG_2 0x0324 -#define RT1019_CLS_INT_REG_3 0x0325 -#define RT1019_CLS_INT_REG_4 0x0326 -#define RT1019_CLS_INT_REG_5 0x0327 -#define RT1019_CLS_INT_REG_6 0x0328 -#define RT1019_CLS_INT_REG_7 0x0329 -#define RT1019_CLS_INT_REG_8 0x0330 -#define RT1019_CLS_INT_REG_9 0x0331 -#define RT1019_CLS_INT_REG_10 0x0332 #define RT1019_TDM_1 0x0400 #define RT1019_TDM_2 0x0401 #define RT1019_TDM_3 0x0402 -#define RT1019_TDM_4 0x0403 -#define RT1019_TDM_5 0x0404 -#define RT1019_TDM_6 0x0405 -#define RT1019_DVOL_1 0x0500 -#define RT1019_DVOL_2 0x0501 -#define RT1019_DVOL_3 0x0502 -#define RT1019_DVOL_4 0x0503 #define RT1019_DMIX_MONO_1 0x0504 #define RT1019_DMIX_MONO_2 0x0505 -#define RT1019_CAL_TOP_1 0x0600 -#define RT1019_CAL_TOP_2 0x0601 -#define RT1019_CAL_TOP_3 0x0602 -#define RT1019_CAL_TOP_4 0x0603 -#define RT1019_CAL_TOP_5 0x0604 -#define RT1019_CAL_TOP_6 0x0605 -#define RT1019_CAL_TOP_7 0x0606 -#define RT1019_CAL_TOP_8 0x0607 -#define RT1019_CAL_TOP_9 0x0608 -#define RT1019_CAL_TOP_10 0x0609 -#define RT1019_CAL_TOP_11 0x060a -#define RT1019_CAL_TOP_12 0x060b -#define RT1019_CAL_TOP_13 0x060c -#define RT1019_CAL_TOP_14 0x060d -#define RT1019_CAL_TOP_15 0x060e -#define RT1019_CAL_TOP_16 0x060f -#define RT1019_CAL_TOP_17 0x0610 -#define RT1019_CAL_TOP_18 0x0611 -#define RT1019_CAL_TOP_19 0x0612 -#define RT1019_CAL_TOP_20 0x0613 -#define RT1019_CAL_TOP_21 0x0614 -#define RT1019_CAL_TOP_22 0x0615 -#define RT1019_MDRE_CTRL_1 0x0700 -#define RT1019_MDRE_CTRL_2 0x0701 -#define RT1019_MDRE_CTRL_3 0x0702 -#define RT1019_MDRE_CTRL_4 0x0703 -#define RT1019_MDRE_CTRL_5 0x0704 -#define RT1019_MDRE_CTRL_6 0x0705 -#define RT1019_MDRE_CTRL_7 0x0706 -#define RT1019_MDRE_CTRL_8 0x0707 -#define RT1019_MDRE_CTRL_9 0x0708 -#define RT1019_MDRE_CTRL_10 0x0709 -#define RT1019_SCC_CTRL_1 0x0800 -#define RT1019_SCC_CTRL_2 0x0801 -#define RT1019_SCC_CTRL_3 0x0802 -#define RT1019_SCC_DUMMY 0x0803 -#define RT1019_SIL_DET_1 0x0900 -#define RT1019_SIL_DET_2 0x0901 -#define RT1019_PWM_DC_DET_1 0x0a00 -#define RT1019_PWM_DC_DET_2 0x0a01 -#define RT1019_PWM_DC_DET_3 0x0a02 -#define RT1019_PWM_DC_DET_4 0x0a03 #define RT1019_BEEP_1 0x0b00 #define RT1019_BEEP_2 0x0b01 -#define RT1019_PMC_1 0x0c00 -#define RT1019_PMC_2 0x0c01 -#define RT1019_PMC_3 0x0c02 -#define RT1019_PMC_4 0x0c03 -#define RT1019_PMC_5 0x0c04 -#define RT1019_PMC_6 0x0c05 -#define RT1019_PMC_7 0x0c06 -#define RT1019_PMC_8 0x0c07 -#define RT1019_PMC_9 0x0c08 -#define RT1019_SPKDRC_1 0x0d00 -#define RT1019_SPKDRC_2 0x0d01 -#define RT1019_SPKDRC_3 0x0d02 -#define RT1019_SPKDRC_4 0x0d03 -#define RT1019_SPKDRC_5 0x0d04 -#define RT1019_SPKDRC_6 0x0d05 -#define RT1019_SPKDRC_7 0x0d06 -#define RT1019_HALF_FREQ_1 0x0e00 -#define RT1019_HALF_FREQ_2 0x0e01 -#define RT1019_HALF_FREQ_3 0x0e02 -#define RT1019_HALF_FREQ_4 0x0e03 -#define RT1019_HALF_FREQ_5 0x0e04 -#define RT1019_HALF_FREQ_6 0x0e05 -#define RT1019_HALF_FREQ_7 0x0e06 -#define RT1019_CUR_CTRL_1 0x0f00 -#define RT1019_CUR_CTRL_2 0x0f01 -#define RT1019_CUR_CTRL_3 0x0f02 -#define RT1019_CUR_CTRL_4 0x0f03 -#define RT1019_CUR_CTRL_5 0x0f04 -#define RT1019_CUR_CTRL_6 0x0f05 -#define RT1019_CUR_CTRL_7 0x0f06 -#define RT1019_CUR_CTRL_8 0x0f07 -#define RT1019_CUR_CTRL_9 0x0f08 -#define RT1019_CUR_CTRL_10 0x0f09 -#define RT1019_CUR_CTRL_11 0x0f0a -#define RT1019_CUR_CTRL_12 0x0f0b -#define RT1019_CUR_CTRL_13 0x0f0c /* 0x0019 Power On Strap Control-2 */ #define RT1019_AUTO_BITS_SEL_MASK (0x1 << 5) From a893a666b5b9a8c9d331df4afa72f23f4d4f83fd Mon Sep 17 00:00:00 2001 From: Ye Bin Date: Thu, 8 Apr 2021 14:26:42 +0800 Subject: [PATCH 444/587] ASoC: codecs: lpass-wsa-macro: constify static struct snd_soc_dai_ops The snd_soc_dai_ops structures is only stored in the ops field of a snd_soc_dai_driver structure, so make the snd_soc_dai_ops structure const to allow the compiler to put it in read-only memory. Reported-by: Hulk Robot Signed-off-by: Ye Bin Link: https://lore.kernel.org/r/20210408062642.802846-1-yebin10@huawei.com Signed-off-by: Mark Brown --- sound/soc/codecs/lpass-wsa-macro.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sound/soc/codecs/lpass-wsa-macro.c b/sound/soc/codecs/lpass-wsa-macro.c index e37c8148c0de..e79a70386b4b 100644 --- a/sound/soc/codecs/lpass-wsa-macro.c +++ b/sound/soc/codecs/lpass-wsa-macro.c @@ -1031,7 +1031,7 @@ static int wsa_macro_get_channel_map(struct snd_soc_dai *dai, return 0; } -static struct snd_soc_dai_ops wsa_macro_dai_ops = { +static const struct snd_soc_dai_ops wsa_macro_dai_ops = { .hw_params = wsa_macro_hw_params, .get_channel_map = wsa_macro_get_channel_map, }; From 4150cc7306fa84577dd0c33f158949b0f085aea0 Mon Sep 17 00:00:00 2001 From: Ye Bin Date: Thu, 8 Apr 2021 14:26:58 +0800 Subject: [PATCH 445/587] ASoC: amd: renoir: acp3x-pdm-dma: constify static struct snd_soc_dai_ops The snd_soc_dai_ops structures is only stored in the ops field of a snd_soc_dai_driver structure, so make the snd_soc_dai_ops structure const to allow the compiler to put it in read-only memory. Reported-by: Hulk Robot Signed-off-by: Ye Bin Link: https://lore.kernel.org/r/20210408062658.803724-1-yebin10@huawei.com Signed-off-by: Mark Brown --- sound/soc/amd/renoir/acp3x-pdm-dma.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sound/soc/amd/renoir/acp3x-pdm-dma.c b/sound/soc/amd/renoir/acp3x-pdm-dma.c index 1acd20439399..4c2810e58dce 100644 --- a/sound/soc/amd/renoir/acp3x-pdm-dma.c +++ b/sound/soc/amd/renoir/acp3x-pdm-dma.c @@ -356,7 +356,7 @@ static int acp_pdm_dai_trigger(struct snd_pcm_substream *substream, return ret; } -static struct snd_soc_dai_ops acp_pdm_dai_ops = { +static const struct snd_soc_dai_ops acp_pdm_dai_ops = { .trigger = acp_pdm_dai_trigger, }; From 81df40a0807fed36f0f1f1eaeef2a780773934c2 Mon Sep 17 00:00:00 2001 From: Ye Bin Date: Thu, 8 Apr 2021 14:26:57 +0800 Subject: [PATCH 446/587] ASoC: codecs: lpass-tx-macro: constify static struct snd_soc_dai_ops The snd_soc_dai_ops structures is only stored in the ops field of a snd_soc_dai_driver structure, so make the snd_soc_dai_ops structure const to allow the compiler to put it in read-only memory. Reported-by: Hulk Robot Signed-off-by: Ye Bin Link: https://lore.kernel.org/r/20210408062657.803668-1-yebin10@huawei.com Signed-off-by: Mark Brown --- sound/soc/codecs/lpass-tx-macro.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sound/soc/codecs/lpass-tx-macro.c b/sound/soc/codecs/lpass-tx-macro.c index 36d7a6442cdb..4eede9ad57bf 100644 --- a/sound/soc/codecs/lpass-tx-macro.c +++ b/sound/soc/codecs/lpass-tx-macro.c @@ -1124,7 +1124,7 @@ static int tx_macro_digital_mute(struct snd_soc_dai *dai, int mute, int stream) return 0; } -static struct snd_soc_dai_ops tx_macro_dai_ops = { +static const struct snd_soc_dai_ops tx_macro_dai_ops = { .hw_params = tx_macro_hw_params, .get_channel_map = tx_macro_get_channel_map, .mute_stream = tx_macro_digital_mute, From 33e12dea130d4b0abbaa9ae944e696d1a9d5261b Mon Sep 17 00:00:00 2001 From: Ye Bin Date: Thu, 8 Apr 2021 14:26:44 +0800 Subject: [PATCH 447/587] ASoC: wcd9335: constify static struct snd_soc_dai_ops The snd_soc_dai_ops structures is only stored in the ops field of a snd_soc_dai_driver structure, so make the snd_soc_dai_ops structure const to allow the compiler to put it in read-only memory. Reported-by: Hulk Robot Signed-off-by: Ye Bin Link: https://lore.kernel.org/r/20210408062644.802988-1-yebin10@huawei.com Signed-off-by: Mark Brown --- sound/soc/codecs/wcd9335.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sound/soc/codecs/wcd9335.c b/sound/soc/codecs/wcd9335.c index adb325fac930..86c92e03ea5d 100644 --- a/sound/soc/codecs/wcd9335.c +++ b/sound/soc/codecs/wcd9335.c @@ -2058,7 +2058,7 @@ static int wcd9335_get_channel_map(struct snd_soc_dai *dai, return 0; } -static struct snd_soc_dai_ops wcd9335_dai_ops = { +static const struct snd_soc_dai_ops wcd9335_dai_ops = { .hw_params = wcd9335_hw_params, .trigger = wcd9335_trigger, .set_channel_map = wcd9335_set_channel_map, From 57b138dde3504b79358cd0d95d989bf5eba8280b Mon Sep 17 00:00:00 2001 From: Dan Carpenter Date: Fri, 9 Apr 2021 15:34:41 +0300 Subject: [PATCH 448/587] ALSA: control - double free in snd_ctl_led_init() "group - 1" was intended here instead of "group". The current error handling will double free the first item in the array and leak the last item. Fixes: cb17fe0045aa ("ALSA: control - add sysfs support to the LED trigger module") Signed-off-by: Dan Carpenter Reviewed-by: Jaroslav Kysela Link: https://lore.kernel.org/r/YHBJ4frGxErWB182@mwanda Signed-off-by: Takashi Iwai --- sound/core/control_led.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sound/core/control_led.c b/sound/core/control_led.c index d756a52e58db..93b201063c7d 100644 --- a/sound/core/control_led.c +++ b/sound/core/control_led.c @@ -734,7 +734,7 @@ static int __init snd_ctl_led_init(void) if (device_add(&led->dev)) { put_device(&led->dev); for (; group > 0; group--) { - led = &snd_ctl_leds[group]; + led = &snd_ctl_leds[group - 1]; device_del(&led->dev); } device_del(&snd_ctl_led_dev); From 26e33ed9f18475ebdc981d45150ac9a019e69f07 Mon Sep 17 00:00:00 2001 From: Vijendar Mukunda Date: Thu, 8 Apr 2021 18:32:36 +0530 Subject: [PATCH 449/587] ASoC: amd: Add support for ALC1015P codec in acp3x machine driver Add ALC1015p codec support for acp3x machine driver. Signed-off-by: Vijendar Mukunda Link: https://lore.kernel.org/r/1617886984-9500-1-git-send-email-Vijendar.Mukunda@amd.com Signed-off-by: Mark Brown --- sound/soc/amd/Kconfig | 1 + sound/soc/amd/acp3x-rt5682-max9836.c | 46 +++++++++++++++++++++++++++- 2 files changed, 46 insertions(+), 1 deletion(-) diff --git a/sound/soc/amd/Kconfig b/sound/soc/amd/Kconfig index 256c19275d45..ba5a85bf7412 100644 --- a/sound/soc/amd/Kconfig +++ b/sound/soc/amd/Kconfig @@ -35,6 +35,7 @@ config SND_SOC_AMD_RV_RT5682_MACH select SND_SOC_CROS_EC_CODEC select I2C_CROS_EC_TUNNEL select SND_SOC_RT1015 + select SND_SOC_RT1015P depends on SND_SOC_AMD_ACP3x && I2C && CROS_EC help This option enables machine driver for RT5682 and MAX9835. diff --git a/sound/soc/amd/acp3x-rt5682-max9836.c b/sound/soc/amd/acp3x-rt5682-max9836.c index cea320ad0e1c..d9980aba2910 100644 --- a/sound/soc/amd/acp3x-rt5682-max9836.c +++ b/sound/soc/amd/acp3x-rt5682-max9836.c @@ -275,6 +275,8 @@ SND_SOC_DAILINK_DEF(rt5682, DAILINK_COMP_ARRAY(COMP_CODEC("i2c-10EC5682:00", "rt5682-aif1"))); SND_SOC_DAILINK_DEF(max, DAILINK_COMP_ARRAY(COMP_CODEC("MX98357A:00", "HiFi"))); +SND_SOC_DAILINK_DEF(rt1015p, + DAILINK_COMP_ARRAY(COMP_CODEC("RTL1015:00", "HiFi"))); SND_SOC_DAILINK_DEF(rt1015, DAILINK_COMP_ARRAY(COMP_CODEC("i2c-10EC1015:00", "rt1015-aif"), COMP_CODEC("i2c-10EC1015:01", "rt1015-aif"))); @@ -419,6 +421,43 @@ static struct snd_soc_card acp3x_1015 = { .num_controls = ARRAY_SIZE(acp3x_mc_1015_controls), }; +static const struct snd_soc_dapm_widget acp3x_1015p_widgets[] = { + SND_SOC_DAPM_HP("Headphone Jack", NULL), + SND_SOC_DAPM_MIC("Headset Mic", NULL), + SND_SOC_DAPM_MUX("Dmic Mux", SND_SOC_NOPM, 0, 0, + &acp3x_dmic_mux_control), + SND_SOC_DAPM_SPK("Speakers", NULL), +}; + +static const struct snd_soc_dapm_route acp3x_1015p_route[] = { + {"Headphone Jack", NULL, "HPOL"}, + {"Headphone Jack", NULL, "HPOR"}, + {"IN1P", NULL, "Headset Mic"}, + {"Dmic Mux", "Front Mic", "DMIC"}, + {"Dmic Mux", "Rear Mic", "DMIC"}, + /* speaker */ + { "Speakers", NULL, "Speaker" }, +}; + +static const struct snd_kcontrol_new acp3x_mc_1015p_controls[] = { + SOC_DAPM_PIN_SWITCH("Speakers"), + SOC_DAPM_PIN_SWITCH("Headphone Jack"), + SOC_DAPM_PIN_SWITCH("Headset Mic"), +}; + +static struct snd_soc_card acp3x_1015p = { + .name = "acp3xalc56821015p", + .owner = THIS_MODULE, + .dai_link = acp3x_dai, + .num_links = ARRAY_SIZE(acp3x_dai), + .dapm_widgets = acp3x_1015p_widgets, + .num_dapm_widgets = ARRAY_SIZE(acp3x_1015p_widgets), + .dapm_routes = acp3x_1015p_route, + .num_dapm_routes = ARRAY_SIZE(acp3x_1015p_route), + .controls = acp3x_mc_1015p_controls, + .num_controls = ARRAY_SIZE(acp3x_mc_1015p_controls), +}; + void *soc_is_rltk_max(struct device *dev) { const struct acpi_device_id *match; @@ -435,6 +474,9 @@ static void card_spk_dai_link_present(struct snd_soc_dai_link *links, if (!strcmp(card_name, "acp3xalc56821015")) { links[1].codecs = rt1015; links[1].num_codecs = ARRAY_SIZE(rt1015); + } else if (!strcmp(card_name, "acp3xalc56821015p")) { + links[1].codecs = rt1015p; + links[1].num_codecs = ARRAY_SIZE(rt1015p); } else { links[1].codecs = max; links[1].num_codecs = ARRAY_SIZE(max); @@ -486,6 +528,7 @@ static int acp3x_probe(struct platform_device *pdev) static const struct acpi_device_id acp3x_audio_acpi_match[] = { { "AMDI5682", (unsigned long)&acp3x_5682}, { "AMDI1015", (unsigned long)&acp3x_1015}, + { "10021015", (unsigned long)&acp3x_1015p}, {}, }; MODULE_DEVICE_TABLE(acpi, acp3x_audio_acpi_match); @@ -503,5 +546,6 @@ module_platform_driver(acp3x_audio); MODULE_AUTHOR("akshu.agrawal@amd.com"); MODULE_AUTHOR("Vishnuvardhanrao.Ravulapati@amd.com"); -MODULE_DESCRIPTION("ALC5682 ALC1015 & MAX98357 audio support"); +MODULE_AUTHOR("Vijendar.Mukunda@amd.com"); +MODULE_DESCRIPTION("ALC5682 ALC1015, ALC1015P & MAX98357 audio support"); MODULE_LICENSE("GPL v2"); From 618fad3d921a781fe500bdf8cbecbf2c4ec1f696 Mon Sep 17 00:00:00 2001 From: Ranjani Sridharan Date: Fri, 9 Apr 2021 14:46:16 -0700 Subject: [PATCH 450/587] ALSA: HDA: Add access description in __snd_hda_add_vmaster Add description for access parameter in __snd_hda_add_vmaster() to prevent the compilation warning: warning: Function parameter or member 'access' not described in '__snd_hda_add_vmaster' Fixes: e65bf99718b5 ("ALSA: HDA - remove the custom implementation for the audio LED trigger") Signed-off-by: Ranjani Sridharan Link: https://lore.kernel.org/r/20210409214616.1539685-1-ranjani.sridharan@linux.intel.com Signed-off-by: Takashi Iwai --- sound/pci/hda/hda_codec.c | 1 + 1 file changed, 1 insertion(+) diff --git a/sound/pci/hda/hda_codec.c b/sound/pci/hda/hda_codec.c index e54e39b35709..a31009afc025 100644 --- a/sound/pci/hda/hda_codec.c +++ b/sound/pci/hda/hda_codec.c @@ -1938,6 +1938,7 @@ static int add_follower(struct hda_codec *codec, * @followers: follower control names (optional) * @suffix: suffix string to each follower name (optional) * @init_follower_vol: initialize followers to unmute/0dB + * @access: kcontrol access rights * @ctl_ret: store the vmaster kcontrol in return * * Create a virtual master control with the given name. The TLV data From d91cbe83d319e8923d36f974d8c9b1e1b56fea62 Mon Sep 17 00:00:00 2001 From: Chen Huang Date: Thu, 8 Apr 2021 12:54:29 +0000 Subject: [PATCH 451/587] ALSA: virtio: use module_virtio_driver() to simplify the code module_virtio_driver() makes the code simpler by eliminating boilerplate code. Signed-off-by: Chen Huang Reviewed-by: Anton Yakovlev Link: https://lore.kernel.org/r/20210408125429.1158703-1-chenhuang5@huawei.com Signed-off-by: Takashi Iwai --- sound/virtio/virtio_card.c | 12 +----------- 1 file changed, 1 insertion(+), 11 deletions(-) diff --git a/sound/virtio/virtio_card.c b/sound/virtio/virtio_card.c index ae9128063917..150ab3e37013 100644 --- a/sound/virtio/virtio_card.c +++ b/sound/virtio/virtio_card.c @@ -432,17 +432,7 @@ static struct virtio_driver virtsnd_driver = { #endif }; -static int __init init(void) -{ - return register_virtio_driver(&virtsnd_driver); -} -module_init(init); - -static void __exit fini(void) -{ - unregister_virtio_driver(&virtsnd_driver); -} -module_exit(fini); +module_virtio_driver(virtsnd_driver); MODULE_DEVICE_TABLE(virtio, id_table); MODULE_DESCRIPTION("Virtio sound card driver"); From 3bcae98e101727457c727b354c95c3ea8f074dce Mon Sep 17 00:00:00 2001 From: Peter Ujfalusi Date: Fri, 9 Apr 2021 15:09:58 -0700 Subject: [PATCH 452/587] ASoC: SOF: core: Add missing error prints to device probe operation Two error cases in snd_sof_device_probe() and sof_probe_continue() are missing error prints. If either of them happens it is not possible to identify the reason for the failure. Add dev_err() prints for the cases to aim debugging. Signed-off-by: Peter Ujfalusi Reviewed-by: Pierre-Louis Bossart Signed-off-by: Ranjani Sridharan Link: https://lore.kernel.org/r/20210409220959.1543456-2-ranjani.sridharan@linux.intel.com Signed-off-by: Mark Brown --- sound/soc/sof/core.c | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/sound/soc/sof/core.c b/sound/soc/sof/core.c index 495295a34c3a..f57e363b5974 100644 --- a/sound/soc/sof/core.c +++ b/sound/soc/sof/core.c @@ -232,8 +232,11 @@ static int sof_probe_continue(struct snd_sof_dev *sdev) } ret = snd_sof_machine_register(sdev, plat_data); - if (ret < 0) + if (ret < 0) { + dev_err(sdev->dev, + "error: failed to register machine driver %d\n", ret); goto fw_trace_err; + } /* * Some platforms in SOF, ex: BYT, may not have their platform PM @@ -309,8 +312,10 @@ int snd_sof_device_probe(struct device *dev, struct snd_sof_pdata *plat_data) !sof_ops(sdev)->block_read || !sof_ops(sdev)->block_write || !sof_ops(sdev)->send_msg || !sof_ops(sdev)->load_firmware || !sof_ops(sdev)->ipc_msg_data || !sof_ops(sdev)->ipc_pcm_params || - !sof_ops(sdev)->fw_ready) + !sof_ops(sdev)->fw_ready) { + dev_err(dev, "error: missing mandatory ops\n"); return -EINVAL; + } INIT_LIST_HEAD(&sdev->pcm_list); INIT_LIST_HEAD(&sdev->kcontrol_list); From 4d1284cd795296e4aa7be6db5fdce85f31374520 Mon Sep 17 00:00:00 2001 From: Peter Ujfalusi Date: Fri, 9 Apr 2021 15:09:59 -0700 Subject: [PATCH 453/587] ASoC: SOF: Simplify sof_probe_complete handling for acpi/pci/of Set the sof_data->sof_probe_complete callback unconditionally of CONFIG_SND_SOC_SOF_PROBE_WORK_QUEUE. The sof_probe_complete will be called when the sof_probe_continue() function is successfully executed, called either directly from snd_sof_device_probe() or from the scheduled work. Since all error cases within the call chain of snd_sof_device_probe() have error prints, there is no need to print again in the acpi/pci/of level. Signed-off-by: Peter Ujfalusi Reviewed-by: Pierre-Louis Bossart Signed-off-by: Ranjani Sridharan Link: https://lore.kernel.org/r/20210409220959.1543456-3-ranjani.sridharan@linux.intel.com Signed-off-by: Mark Brown --- sound/soc/sof/sof-acpi-dev.c | 18 +++--------------- sound/soc/sof/sof-of-dev.c | 18 +++--------------- sound/soc/sof/sof-pci-dev.c | 20 ++++---------------- 3 files changed, 10 insertions(+), 46 deletions(-) diff --git a/sound/soc/sof/sof-acpi-dev.c b/sound/soc/sof/sof-acpi-dev.c index 1fec0420f662..7fbf09f9f17e 100644 --- a/sound/soc/sof/sof-acpi-dev.c +++ b/sound/soc/sof/sof-acpi-dev.c @@ -61,7 +61,6 @@ int sof_acpi_probe(struct platform_device *pdev, const struct sof_dev_desc *desc struct device *dev = &pdev->dev; struct snd_sof_pdata *sof_pdata; const struct snd_sof_dsp_ops *ops; - int ret; dev_dbg(dev, "ACPI DSP detected"); @@ -93,22 +92,11 @@ int sof_acpi_probe(struct platform_device *pdev, const struct sof_dev_desc *desc sof_pdata->tplg_filename_prefix = sof_pdata->desc->default_tplg_path; -#if IS_ENABLED(CONFIG_SND_SOC_SOF_PROBE_WORK_QUEUE) - /* set callback to enable runtime_pm */ + /* set callback to be called on successful device probe to enable runtime_pm */ sof_pdata->sof_probe_complete = sof_acpi_probe_complete; -#endif + /* call sof helper for DSP hardware probe */ - ret = snd_sof_device_probe(dev, sof_pdata); - if (ret) { - dev_err(dev, "error: failed to probe DSP hardware!\n"); - return ret; - } - -#if !IS_ENABLED(CONFIG_SND_SOC_SOF_PROBE_WORK_QUEUE) - sof_acpi_probe_complete(dev); -#endif - - return ret; + return snd_sof_device_probe(dev, sof_pdata); } EXPORT_SYMBOL_NS(sof_acpi_probe, SND_SOC_SOF_ACPI_DEV); diff --git a/sound/soc/sof/sof-of-dev.c b/sound/soc/sof/sof-of-dev.c index 85ff0db88eb7..c9c70645b377 100644 --- a/sound/soc/sof/sof-of-dev.c +++ b/sound/soc/sof/sof-of-dev.c @@ -71,7 +71,6 @@ static int sof_of_probe(struct platform_device *pdev) const struct sof_dev_desc *desc; struct snd_sof_pdata *sof_pdata; const struct snd_sof_dsp_ops *ops; - int ret; dev_info(&pdev->dev, "DT DSP detected"); @@ -98,22 +97,11 @@ static int sof_of_probe(struct platform_device *pdev) sof_pdata->fw_filename_prefix = sof_pdata->desc->default_fw_path; sof_pdata->tplg_filename_prefix = sof_pdata->desc->default_tplg_path; -#if IS_ENABLED(CONFIG_SND_SOC_SOF_PROBE_WORK_QUEUE) - /* set callback to enable runtime_pm */ + /* set callback to be called on successful device probe to enable runtime_pm */ sof_pdata->sof_probe_complete = sof_of_probe_complete; -#endif - /* call sof helper for DSP hardware probe */ - ret = snd_sof_device_probe(dev, sof_pdata); - if (ret) { - dev_err(dev, "error: failed to probe DSP hardware\n"); - return ret; - } -#if !IS_ENABLED(CONFIG_SND_SOC_SOF_PROBE_WORK_QUEUE) - sof_of_probe_complete(dev); -#endif - - return ret; + /* call sof helper for DSP hardware probe */ + return snd_sof_device_probe(dev, sof_pdata); } static int sof_of_remove(struct platform_device *pdev) diff --git a/sound/soc/sof/sof-pci-dev.c b/sound/soc/sof/sof-pci-dev.c index b842a414e1df..3489dc1b48f6 100644 --- a/sound/soc/sof/sof-pci-dev.c +++ b/sound/soc/sof/sof-pci-dev.c @@ -184,25 +184,13 @@ int sof_pci_probe(struct pci_dev *pci, const struct pci_device_id *pci_id) if (sof_override_tplg_name) sof_pdata->tplg_filename = sof_override_tplg_name; -#if IS_ENABLED(CONFIG_SND_SOC_SOF_PROBE_WORK_QUEUE) - /* set callback to enable runtime_pm */ + /* set callback to be called on successful device probe to enable runtime_pm */ sof_pdata->sof_probe_complete = sof_pci_probe_complete; -#endif + /* call sof helper for DSP hardware probe */ ret = snd_sof_device_probe(dev, sof_pdata); - if (ret) { - dev_err(dev, "error: failed to probe DSP hardware!\n"); - goto release_regions; - } - -#if !IS_ENABLED(CONFIG_SND_SOC_SOF_PROBE_WORK_QUEUE) - sof_pci_probe_complete(dev); -#endif - - return ret; - -release_regions: - pci_release_regions(pci); + if (ret) + pci_release_regions(pci); return ret; } From e4330cae2a8cf4e4f3004947794bdd549e32cede Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Fri, 9 Apr 2021 15:01:16 -0700 Subject: [PATCH 454/587] ASoC: SOF: add Kconfig option for probe workqueues The probe workqueue is currently used in the HDaudio case, following the example of the snd-hda-intel driver. For development and validation, it's useful to enable the probe workqueue even with ACPI devices or NOCODEC mode. Signed-off-by: Pierre-Louis Bossart Reviewed-by: Daniel Baluta Reviewed-by: Kai Vehmanen Signed-off-by: Ranjani Sridharan Link: https://lore.kernel.org/r/20210409220121.1542362-2-ranjani.sridharan@linux.intel.com Signed-off-by: Mark Brown --- sound/soc/sof/Kconfig | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/sound/soc/sof/Kconfig b/sound/soc/sof/Kconfig index 8dfc165c3690..cd659493b5df 100644 --- a/sound/soc/sof/Kconfig +++ b/sound/soc/sof/Kconfig @@ -68,6 +68,17 @@ config SND_SOC_SOF_DEVELOPER_SUPPORT if SND_SOC_SOF_DEVELOPER_SUPPORT +config SND_SOC_SOF_FORCE_PROBE_WORKQUEUE + bool "SOF force probe workqueue" + select SND_SOC_SOF_PROBE_WORK_QUEUE + help + This option forces the use of a probe workqueue, which is only used + when HDaudio is enabled due to module dependencies. Forcing this + option is intended for debug only, but this should not add any + functional issues in nominal cases. + Say Y if you are involved in SOF development and need this option. + If not, select N. + config SND_SOC_SOF_NOCODEC tristate From ca6a0122557faa4fa01d6dbfa742870c33c46218 Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Fri, 9 Apr 2021 15:01:17 -0700 Subject: [PATCH 455/587] ASoC: soc-acpi: add new fields for mach_params We currently have an ugly way of handling the SOF nocodec mode, with blatant violations between layers. To create the nocodec card, let's add two new fields and the existing mach_params structure, that way there will be no differences with regular cards. Signed-off-by: Pierre-Louis Bossart Reviewed-by: Daniel Baluta Reviewed-by: Kai Vehmanen Signed-off-by: Ranjani Sridharan Link: https://lore.kernel.org/r/20210409220121.1542362-3-ranjani.sridharan@linux.intel.com Signed-off-by: Mark Brown --- include/sound/soc-acpi.h | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/include/sound/soc-acpi.h b/include/sound/soc-acpi.h index c45075024c30..2f3fa385c092 100644 --- a/include/sound/soc-acpi.h +++ b/include/sound/soc-acpi.h @@ -63,6 +63,8 @@ static inline struct snd_soc_acpi_mach *snd_soc_acpi_codec_list(void *arg) * @common_hdmi_codec_drv: use commom HDAudio HDMI codec driver * @link_mask: links enabled on the board * @links: array of link _ADR descriptors, null terminated + * @num_dai_drivers: number of elements in @dai_drivers + * @dai_drivers: pointer to dai_drivers, used e.g. in nocodec mode */ struct snd_soc_acpi_mach_params { u32 acpi_ipc_irq_index; @@ -72,6 +74,8 @@ struct snd_soc_acpi_mach_params { bool common_hdmi_codec_drv; u32 link_mask; const struct snd_soc_acpi_link_adr *links; + u32 num_dai_drivers; + struct snd_soc_dai_driver *dai_drivers; }; /** From 17e9d6b0a395a1d8973a9e1d20db88d791e157b1 Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Fri, 9 Apr 2021 15:01:18 -0700 Subject: [PATCH 456/587] ASoC: SOF: change signature of set_mach_params() callback To set additional parameters, we need to have access to sdev, not the plain vanilla struct device pointer. No functionality change. Signed-off-by: Pierre-Louis Bossart Reviewed-by: Daniel Baluta Reviewed-by: Kai Vehmanen Signed-off-by: Ranjani Sridharan Link: https://lore.kernel.org/r/20210409220121.1542362-4-ranjani.sridharan@linux.intel.com Signed-off-by: Mark Brown --- sound/soc/sof/intel/bdw.c | 4 ++-- sound/soc/sof/intel/byt.c | 18 +++++++++--------- sound/soc/sof/intel/hda.c | 4 ++-- sound/soc/sof/intel/hda.h | 2 +- sound/soc/sof/ops.h | 6 ++---- sound/soc/sof/sof-audio.c | 4 ++-- sound/soc/sof/sof-priv.h | 2 +- 7 files changed, 19 insertions(+), 21 deletions(-) diff --git a/sound/soc/sof/intel/bdw.c b/sound/soc/sof/intel/bdw.c index fd5ae628732d..28e049ac9c5e 100644 --- a/sound/soc/sof/intel/bdw.c +++ b/sound/soc/sof/intel/bdw.c @@ -559,12 +559,12 @@ static void bdw_machine_select(struct snd_sof_dev *sdev) } static void bdw_set_mach_params(const struct snd_soc_acpi_mach *mach, - struct device *dev) + struct snd_sof_dev *sdev) { struct snd_soc_acpi_mach_params *mach_params; mach_params = (struct snd_soc_acpi_mach_params *)&mach->mach_params; - mach_params->platform = dev_name(dev); + mach_params->platform = dev_name(sdev->dev); } /* Broadwell DAIs */ diff --git a/sound/soc/sof/intel/byt.c b/sound/soc/sof/intel/byt.c index 2846fdec9d95..bed26d96dc50 100644 --- a/sound/soc/sof/intel/byt.c +++ b/sound/soc/sof/intel/byt.c @@ -427,15 +427,6 @@ static void byt_machine_select(struct snd_sof_dev *sdev) sof_pdata->machine = mach; } -static void byt_set_mach_params(const struct snd_soc_acpi_mach *mach, - struct device *dev) -{ - struct snd_soc_acpi_mach_params *mach_params; - - mach_params = (struct snd_soc_acpi_mach_params *)&mach->mach_params; - mach_params->platform = dev_name(dev); -} - /* Baytrail DAIs */ static struct snd_soc_dai_driver byt_dai[] = { { @@ -506,6 +497,15 @@ static struct snd_soc_dai_driver byt_dai[] = { }, }; +static void byt_set_mach_params(const struct snd_soc_acpi_mach *mach, + struct snd_sof_dev *sdev) +{ + struct snd_soc_acpi_mach_params *mach_params; + + mach_params = (struct snd_soc_acpi_mach_params *)&mach->mach_params; + mach_params->platform = dev_name(sdev->dev); +} + /* * Probe and remove. */ diff --git a/sound/soc/sof/intel/hda.c b/sound/soc/sof/intel/hda.c index 5317dfa4a4bf..065b85285450 100644 --- a/sound/soc/sof/intel/hda.c +++ b/sound/soc/sof/intel/hda.c @@ -1213,12 +1213,12 @@ static int hda_sdw_machine_select(struct snd_sof_dev *sdev) #endif void hda_set_mach_params(const struct snd_soc_acpi_mach *mach, - struct device *dev) + struct snd_sof_dev *sdev) { struct snd_soc_acpi_mach_params *mach_params; mach_params = (struct snd_soc_acpi_mach_params *)&mach->mach_params; - mach_params->platform = dev_name(dev); + mach_params->platform = dev_name(sdev->dev); } void hda_machine_select(struct snd_sof_dev *sdev) diff --git a/sound/soc/sof/intel/hda.h b/sound/soc/sof/intel/hda.h index 7c7579daee7f..5ef29dcc052d 100644 --- a/sound/soc/sof/intel/hda.h +++ b/sound/soc/sof/intel/hda.h @@ -762,7 +762,7 @@ extern const struct sof_intel_dsp_desc adls_chip_info; /* machine driver select */ void hda_machine_select(struct snd_sof_dev *sdev); void hda_set_mach_params(const struct snd_soc_acpi_mach *mach, - struct device *dev); + struct snd_sof_dev *sdev); /* PCI driver selection and probe */ int hda_pci_intel_probe(struct pci_dev *pci, const struct pci_device_id *pci_id); diff --git a/sound/soc/sof/ops.h b/sound/soc/sof/ops.h index 5099ad03df72..323a0b3f561b 100644 --- a/sound/soc/sof/ops.h +++ b/sound/soc/sof/ops.h @@ -497,12 +497,10 @@ snd_sof_machine_select(struct snd_sof_dev *sdev) static inline void snd_sof_set_mach_params(const struct snd_soc_acpi_mach *mach, - struct device *dev) + struct snd_sof_dev *sdev) { - struct snd_sof_dev *sdev = dev_get_drvdata(dev); - if (sof_ops(sdev) && sof_ops(sdev)->set_mach_params) - sof_ops(sdev)->set_mach_params(mach, dev); + sof_ops(sdev)->set_mach_params(mach, sdev); } static inline const struct snd_sof_dsp_ops diff --git a/sound/soc/sof/sof-audio.c b/sound/soc/sof/sof-audio.c index 928d7a46d820..5d13bafd4736 100644 --- a/sound/soc/sof/sof-audio.c +++ b/sound/soc/sof/sof-audio.c @@ -475,7 +475,7 @@ int sof_machine_check(struct snd_sof_dev *sdev) /* find machine */ snd_sof_machine_select(sdev); if (sof_pdata->machine) { - snd_sof_set_mach_params(sof_pdata->machine, sdev->dev); + snd_sof_set_mach_params(sof_pdata->machine, sdev); return 0; } @@ -500,7 +500,7 @@ int sof_machine_check(struct snd_sof_dev *sdev) return ret; sof_pdata->machine = mach; - snd_sof_set_mach_params(sof_pdata->machine, sdev->dev); + snd_sof_set_mach_params(sof_pdata->machine, sdev); return 0; } diff --git a/sound/soc/sof/sof-priv.h b/sound/soc/sof/sof-priv.h index ad0d7ba2708c..fd8423172d8f 100644 --- a/sound/soc/sof/sof-priv.h +++ b/sound/soc/sof/sof-priv.h @@ -259,7 +259,7 @@ struct snd_sof_dsp_ops { void *pdata); /* optional */ void (*machine_select)(struct snd_sof_dev *sdev); /* optional */ void (*set_mach_params)(const struct snd_soc_acpi_mach *mach, - struct device *dev); /* optional */ + struct snd_sof_dev *sdev); /* optional */ /* DAI ops */ struct snd_soc_dai_driver *drv; From 974cccf490ebbc0c7ea0d19edd88542cef174d38 Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Fri, 9 Apr 2021 15:01:19 -0700 Subject: [PATCH 457/587] ASoC: SOF: Intel: update set_mach_params() Add information for num_dai_drivers and dai_drivers[], which will be used in the refactored nocodec implementation Signed-off-by: Pierre-Louis Bossart Reviewed-by: Daniel Baluta Reviewed-by: Kai Vehmanen Signed-off-by: Ranjani Sridharan Link: https://lore.kernel.org/r/20210409220121.1542362-5-ranjani.sridharan@linux.intel.com Signed-off-by: Mark Brown --- sound/soc/sof/intel/bdw.c | 4 ++++ sound/soc/sof/intel/byt.c | 4 ++++ sound/soc/sof/intel/hda.c | 4 ++++ 3 files changed, 12 insertions(+) diff --git a/sound/soc/sof/intel/bdw.c b/sound/soc/sof/intel/bdw.c index 28e049ac9c5e..89a6c1f04a55 100644 --- a/sound/soc/sof/intel/bdw.c +++ b/sound/soc/sof/intel/bdw.c @@ -561,10 +561,14 @@ static void bdw_machine_select(struct snd_sof_dev *sdev) static void bdw_set_mach_params(const struct snd_soc_acpi_mach *mach, struct snd_sof_dev *sdev) { + struct snd_sof_pdata *pdata = sdev->pdata; + const struct sof_dev_desc *desc = pdata->desc; struct snd_soc_acpi_mach_params *mach_params; mach_params = (struct snd_soc_acpi_mach_params *)&mach->mach_params; mach_params->platform = dev_name(sdev->dev); + mach_params->num_dai_drivers = desc->ops->num_drv; + mach_params->dai_drivers = desc->ops->drv; } /* Broadwell DAIs */ diff --git a/sound/soc/sof/intel/byt.c b/sound/soc/sof/intel/byt.c index bed26d96dc50..d9803e2ba67f 100644 --- a/sound/soc/sof/intel/byt.c +++ b/sound/soc/sof/intel/byt.c @@ -500,10 +500,14 @@ static struct snd_soc_dai_driver byt_dai[] = { static void byt_set_mach_params(const struct snd_soc_acpi_mach *mach, struct snd_sof_dev *sdev) { + struct snd_sof_pdata *pdata = sdev->pdata; + const struct sof_dev_desc *desc = pdata->desc; struct snd_soc_acpi_mach_params *mach_params; mach_params = (struct snd_soc_acpi_mach_params *)&mach->mach_params; mach_params->platform = dev_name(sdev->dev); + mach_params->num_dai_drivers = desc->ops->num_drv; + mach_params->dai_drivers = desc->ops->drv; } /* diff --git a/sound/soc/sof/intel/hda.c b/sound/soc/sof/intel/hda.c index 065b85285450..b00e8fcb2312 100644 --- a/sound/soc/sof/intel/hda.c +++ b/sound/soc/sof/intel/hda.c @@ -1215,10 +1215,14 @@ static int hda_sdw_machine_select(struct snd_sof_dev *sdev) void hda_set_mach_params(const struct snd_soc_acpi_mach *mach, struct snd_sof_dev *sdev) { + struct snd_sof_pdata *pdata = sdev->pdata; + const struct sof_dev_desc *desc = pdata->desc; struct snd_soc_acpi_mach_params *mach_params; mach_params = (struct snd_soc_acpi_mach_params *)&mach->mach_params; mach_params->platform = dev_name(sdev->dev); + mach_params->num_dai_drivers = desc->ops->num_drv; + mach_params->dai_drivers = desc->ops->drv; } void hda_machine_select(struct snd_sof_dev *sdev) From f3f3af1743350fdc7c373772fb3740dc223db8e5 Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Fri, 9 Apr 2021 15:01:20 -0700 Subject: [PATCH 458/587] ASoC: SOF: pcm: export snd_pcm_dai_link_fixup In preparation of the nocodec refactoring, export the dai-link fixup. This will also be required when we have more clients and platform drivers. Signed-off-by: Pierre-Louis Bossart Reviewed-by: Daniel Baluta Reviewed-by: Kai Vehmanen Signed-off-by: Ranjani Sridharan Link: https://lore.kernel.org/r/20210409220121.1542362-6-ranjani.sridharan@linux.intel.com Signed-off-by: Mark Brown --- sound/soc/sof/pcm.c | 1 + 1 file changed, 1 insertion(+) diff --git a/sound/soc/sof/pcm.c b/sound/soc/sof/pcm.c index d6b1c8b7bdfb..9893b182da43 100644 --- a/sound/soc/sof/pcm.c +++ b/sound/soc/sof/pcm.c @@ -775,6 +775,7 @@ int sof_pcm_dai_link_fixup(struct snd_soc_pcm_runtime *rtd, struct snd_pcm_hw_pa return 0; } +EXPORT_SYMBOL(sof_pcm_dai_link_fixup); static int sof_pcm_probe(struct snd_soc_component *component) { From 4c1cc83fcc7e02f6f6f76da2ea66af86a95fd675 Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Fri, 9 Apr 2021 15:01:21 -0700 Subject: [PATCH 459/587] ASOC: SOF: simplify nocodec mode Replace ugly #if (!IS_ENABLED) by if (!IS_ENABLED), remove cross-module dependencies and use classic mechanism to pass information to the machine driver. Signed-off-by: Pierre-Louis Bossart Reviewed-by: Daniel Baluta Reviewed-by: Kai Vehmanen Signed-off-by: Ranjani Sridharan Link: https://lore.kernel.org/r/20210409220121.1542362-7-ranjani.sridharan@linux.intel.com Signed-off-by: Mark Brown --- include/sound/sof.h | 3 --- sound/soc/sof/nocodec.c | 39 +++++++++++++++++++++------------------ sound/soc/sof/sof-audio.c | 32 ++++++++++++++------------------ 3 files changed, 35 insertions(+), 39 deletions(-) diff --git a/include/sound/sof.h b/include/sound/sof.h index b93bb8038080..502ed9b8d6a1 100644 --- a/include/sound/sof.h +++ b/include/sound/sof.h @@ -100,9 +100,6 @@ struct sof_dev_desc { const struct snd_sof_dsp_ops *ops; }; -int sof_nocodec_setup(struct device *dev, const struct snd_sof_dsp_ops *ops, - int (*pcm_dai_link_fixup)(struct snd_soc_pcm_runtime *rtd, - struct snd_pcm_hw_params *params)); int sof_dai_get_mclk(struct snd_soc_pcm_runtime *rtd); #endif diff --git a/sound/soc/sof/nocodec.c b/sound/soc/sof/nocodec.c index 3b9bb2e83a86..356497fe4f4c 100644 --- a/sound/soc/sof/nocodec.c +++ b/sound/soc/sof/nocodec.c @@ -20,16 +20,14 @@ static struct snd_soc_card sof_nocodec_card = { }; static int sof_nocodec_bes_setup(struct device *dev, - const struct snd_sof_dsp_ops *ops, + struct snd_soc_dai_driver *drv, struct snd_soc_dai_link *links, - int link_num, struct snd_soc_card *card, - int (*pcm_dai_link_fixup)(struct snd_soc_pcm_runtime *rtd, - struct snd_pcm_hw_params *params)) + int link_num, struct snd_soc_card *card) { struct snd_soc_dai_link_component *dlc; int i; - if (!ops || !links || !card) + if (!drv || !links || !card) return -EINVAL; /* set up BE dai_links */ @@ -55,16 +53,16 @@ static int sof_nocodec_bes_setup(struct device *dev, links[i].id = i; links[i].no_pcm = 1; - links[i].cpus->dai_name = ops->drv[i].name; - links[i].platforms->name = dev_name(dev); + links[i].cpus->dai_name = drv[i].name; + links[i].platforms->name = dev_name(dev->parent); links[i].codecs->dai_name = "snd-soc-dummy-dai"; links[i].codecs->name = "snd-soc-dummy"; - if (ops->drv[i].playback.channels_min) + if (drv[i].playback.channels_min) links[i].dpcm_playback = 1; - if (ops->drv[i].capture.channels_min) + if (drv[i].capture.channels_min) links[i].dpcm_capture = 1; - links[i].be_hw_params_fixup = pcm_dai_link_fixup; + links[i].be_hw_params_fixup = sof_pcm_dai_link_fixup; } card->dai_link = links; @@ -73,29 +71,34 @@ static int sof_nocodec_bes_setup(struct device *dev, return 0; } -int sof_nocodec_setup(struct device *dev, const struct snd_sof_dsp_ops *ops, - int (*pcm_dai_link_fixup)(struct snd_soc_pcm_runtime *rtd, - struct snd_pcm_hw_params *params)) +static int sof_nocodec_setup(struct device *dev, + u32 num_dai_drivers, + struct snd_soc_dai_driver *dai_drivers) { struct snd_soc_dai_link *links; /* create dummy BE dai_links */ - links = devm_kzalloc(dev, sizeof(struct snd_soc_dai_link) * - ops->num_drv, GFP_KERNEL); + links = devm_kzalloc(dev, sizeof(struct snd_soc_dai_link) * num_dai_drivers, GFP_KERNEL); if (!links) return -ENOMEM; - return sof_nocodec_bes_setup(dev, ops, links, ops->num_drv, - &sof_nocodec_card, pcm_dai_link_fixup); + return sof_nocodec_bes_setup(dev, dai_drivers, links, num_dai_drivers, &sof_nocodec_card); } -EXPORT_SYMBOL(sof_nocodec_setup); static int sof_nocodec_probe(struct platform_device *pdev) { struct snd_soc_card *card = &sof_nocodec_card; + struct snd_soc_acpi_mach *mach; + int ret; card->dev = &pdev->dev; card->topology_shortname_created = true; + mach = pdev->dev.platform_data; + + ret = sof_nocodec_setup(card->dev, mach->mach_params.num_dai_drivers, + mach->mach_params.dai_drivers); + if (ret < 0) + return ret; return devm_snd_soc_register_card(&pdev->dev, card); } diff --git a/sound/soc/sof/sof-audio.c b/sound/soc/sof/sof-audio.c index 5d13bafd4736..0d0d47dc0246 100644 --- a/sound/soc/sof/sof-audio.c +++ b/sound/soc/sof/sof-audio.c @@ -468,24 +468,24 @@ int sof_machine_check(struct snd_sof_dev *sdev) struct snd_sof_pdata *sof_pdata = sdev->pdata; const struct sof_dev_desc *desc = sof_pdata->desc; struct snd_soc_acpi_mach *mach; - int ret; -#if !IS_ENABLED(CONFIG_SND_SOC_SOF_FORCE_NOCODEC_MODE) + if (!IS_ENABLED(CONFIG_SND_SOC_SOF_FORCE_NOCODEC_MODE)) { - /* find machine */ - snd_sof_machine_select(sdev); - if (sof_pdata->machine) { - snd_sof_set_mach_params(sof_pdata->machine, sdev); - return 0; + /* find machine */ + snd_sof_machine_select(sdev); + if (sof_pdata->machine) { + snd_sof_set_mach_params(sof_pdata->machine, sdev); + return 0; + } + + if (!IS_ENABLED(CONFIG_SND_SOC_SOF_NOCODEC)) { + dev_err(sdev->dev, "error: no matching ASoC machine driver found - aborting probe\n"); + return -ENODEV; + } + } else { + dev_warn(sdev->dev, "Force to use nocodec mode\n"); } -#if !IS_ENABLED(CONFIG_SND_SOC_SOF_NOCODEC) - dev_err(sdev->dev, "error: no matching ASoC machine driver found - aborting probe\n"); - return -ENODEV; -#endif -#else - dev_warn(sdev->dev, "Force to use nocodec mode\n"); -#endif /* select nocodec mode */ dev_warn(sdev->dev, "Using nocodec machine driver\n"); mach = devm_kzalloc(sdev->dev, sizeof(*mach), GFP_KERNEL); @@ -495,10 +495,6 @@ int sof_machine_check(struct snd_sof_dev *sdev) mach->drv_name = "sof-nocodec"; sof_pdata->tplg_filename = desc->nocodec_tplg_filename; - ret = sof_nocodec_setup(sdev->dev, desc->ops, sof_pcm_dai_link_fixup); - if (ret < 0) - return ret; - sof_pdata->machine = mach; snd_sof_set_mach_params(sof_pdata->machine, sdev); From b2fe85790d8d67ae25af58ff94673afc6cb081d9 Mon Sep 17 00:00:00 2001 From: Libin Yang Date: Fri, 9 Apr 2021 15:13:08 -0700 Subject: [PATCH 460/587] ASoC: SOF: Kconfig: fix typo of SND_SOC_SOF_PCI It should be 'endif ## SND_SOC_SOF_PCI' instead of 'endif ## SND_SOC_SOF_INTEL_PCI' Signed-off-by: Libin Yang Reviewed-by: Kai Vehmanen Reviewed-by: Pierre-Louis Bossart Signed-off-by: Ranjani Sridharan Link: https://lore.kernel.org/r/20210409221308.1544000-1-ranjani.sridharan@linux.intel.com Signed-off-by: Mark Brown --- sound/soc/sof/intel/Kconfig | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sound/soc/sof/intel/Kconfig b/sound/soc/sof/intel/Kconfig index da1c396f529d..4bce89b5ea40 100644 --- a/sound/soc/sof/intel/Kconfig +++ b/sound/soc/sof/intel/Kconfig @@ -293,6 +293,6 @@ config SND_SOC_SOF_INTEL_SOUNDWIRE Say Y if you want to enable SoundWire links with SOF. If unsure select "N". -endif ## SND_SOC_SOF_INTEL_PCI +endif ## SND_SOC_SOF_PCI endif ## SND_SOC_SOF_INTEL_TOPLEVEL From 7459f8b703db589e1fa6482449cd681a6a612189 Mon Sep 17 00:00:00 2001 From: Ranjani Sridharan Date: Fri, 9 Apr 2021 15:05:22 -0700 Subject: [PATCH 461/587] ASoC: SOF: topology: remove useless code The patch "ASoC: SOF: Intel: hda: assign link DMA channel at run-time" fixed the sof_link_hda_unload() to remove the call to the BE hw_free op but left the rest of code that become redundant. So, remove sof_link_hda_unload() along with the link_unload() op entirely as it is not longer needed. Reported-by: Pierre-Louis Bossart Reviewed-by: Kai Vehmanen Reviewed-by: Pierre-Louis Bossart Signed-off-by: Ranjani Sridharan Link: https://lore.kernel.org/r/20210409220522.1542865-1-ranjani.sridharan@linux.intel.com Signed-off-by: Mark Brown --- sound/soc/sof/topology.c | 64 ---------------------------------------- 1 file changed, 64 deletions(-) diff --git a/sound/soc/sof/topology.c b/sound/soc/sof/topology.c index 036202768b75..59abcfc9bd55 100644 --- a/sound/soc/sof/topology.c +++ b/sound/soc/sof/topology.c @@ -3371,69 +3371,6 @@ static int sof_link_load(struct snd_soc_component *scomp, int index, return ret; } -static int sof_link_hda_unload(struct snd_sof_dev *sdev, - struct snd_soc_dai_link *link) -{ - struct snd_soc_dai *dai; - - dai = snd_soc_find_dai(link->cpus); - if (!dai) { - dev_err(sdev->dev, "error: failed to find dai %s in %s", - link->cpus->dai_name, __func__); - return -EINVAL; - } - - return 0; -} - -static int sof_link_unload(struct snd_soc_component *scomp, - struct snd_soc_dobj *dobj) -{ - struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(scomp); - struct snd_soc_dai_link *link = - container_of(dobj, struct snd_soc_dai_link, dobj); - - struct snd_sof_dai *sof_dai; - int ret = 0; - - /* only BE link is loaded by sof */ - if (!link->no_pcm) - return 0; - - list_for_each_entry(sof_dai, &sdev->dai_list, list) { - if (!sof_dai->name) - continue; - - if (strcmp(link->name, sof_dai->name) == 0) - goto found; - } - - dev_err(scomp->dev, "error: failed to find dai %s in %s", - link->name, __func__); - return -EINVAL; -found: - - switch (sof_dai->dai_config->type) { - case SOF_DAI_INTEL_SSP: - case SOF_DAI_INTEL_DMIC: - case SOF_DAI_INTEL_ALH: - case SOF_DAI_IMX_SAI: - case SOF_DAI_IMX_ESAI: - /* no resource needs to be released for all cases above */ - break; - case SOF_DAI_INTEL_HDA: - ret = sof_link_hda_unload(sdev, link); - break; - default: - dev_err(scomp->dev, "error: invalid DAI type %d\n", - sof_dai->dai_config->type); - ret = -EINVAL; - break; - } - - return ret; -} - /* DAI link - used for any driver specific init */ static int sof_route_load(struct snd_soc_component *scomp, int index, struct snd_soc_dapm_route *route) @@ -3734,7 +3671,6 @@ static struct snd_soc_tplg_ops sof_tplg_ops = { /* DAI link - used for any driver specific init */ .link_load = sof_link_load, - .link_unload = sof_link_unload, /* completion - called at completion of firmware loading */ .complete = sof_complete, From 1b9889974ce93dea50d010972a93c0eb529ac612 Mon Sep 17 00:00:00 2001 From: Libin Yang Date: Mon, 12 Apr 2021 11:15:18 -0500 Subject: [PATCH 462/587] ASoC: SOF: Intel: add missing use_acpi_target_states for TGL platforms All Intel TigerLake platforms should support the feature of getting the system state from acpi to deal with S0ix support. This was missed in previous commits, likely due to copy/paste from older code. Reviewed-by: Ranjani Sridharan Signed-off-by: Libin Yang Signed-off-by: Pierre-Louis Bossart Link: https://lore.kernel.org/r/20210412161519.13508-2-pierre-louis.bossart@linux.intel.com Signed-off-by: Mark Brown --- sound/soc/sof/intel/pci-tgl.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/sound/soc/sof/intel/pci-tgl.c b/sound/soc/sof/intel/pci-tgl.c index 485607471181..c2abb07fb7ff 100644 --- a/sound/soc/sof/intel/pci-tgl.c +++ b/sound/soc/sof/intel/pci-tgl.c @@ -39,6 +39,7 @@ static const struct sof_dev_desc tgl_desc = { static const struct sof_dev_desc tglh_desc = { .machines = snd_soc_acpi_intel_tgl_machines, .alt_machines = snd_soc_acpi_intel_tgl_sdw_machines, + .use_acpi_target_states = true, .resindex_lpe_base = 0, .resindex_pcicfg_base = -1, .resindex_imr_base = -1, @@ -71,6 +72,7 @@ static const struct sof_dev_desc ehl_desc = { static const struct sof_dev_desc adls_desc = { .machines = snd_soc_acpi_intel_adl_machines, .alt_machines = snd_soc_acpi_intel_adl_sdw_machines, + .use_acpi_target_states = true, .resindex_lpe_base = 0, .resindex_pcicfg_base = -1, .resindex_imr_base = -1, From 4ad03f894b3c96d77e51474f0c9731793fac412e Mon Sep 17 00:00:00 2001 From: Sathya Prakash M R Date: Mon, 12 Apr 2021 11:15:19 -0500 Subject: [PATCH 463/587] ASoC: SOF: Intel: Update ADL P to use its own descriptor ADL P has specific machines and hence having its own table will help separate the machines and FW Reviewed-by: Bard Liao Reviewed-by: Kai Vehmanen Signed-off-by: Sathya Prakash M R Signed-off-by: Pierre-Louis Bossart Link: https://lore.kernel.org/r/20210412161519.13508-3-pierre-louis.bossart@linux.intel.com Signed-off-by: Mark Brown --- sound/soc/sof/intel/pci-tgl.c | 18 +++++++++++++++++- sound/soc/sof/intel/tgl.c | 2 +- 2 files changed, 18 insertions(+), 2 deletions(-) diff --git a/sound/soc/sof/intel/pci-tgl.c b/sound/soc/sof/intel/pci-tgl.c index c2abb07fb7ff..21f69204d5ad 100644 --- a/sound/soc/sof/intel/pci-tgl.c +++ b/sound/soc/sof/intel/pci-tgl.c @@ -86,6 +86,22 @@ static const struct sof_dev_desc adls_desc = { .ops = &sof_tgl_ops, }; +static const struct sof_dev_desc adl_desc = { + .machines = snd_soc_acpi_intel_adl_machines, + .alt_machines = snd_soc_acpi_intel_adl_sdw_machines, + .resindex_lpe_base = 0, + .resindex_pcicfg_base = -1, + .resindex_imr_base = -1, + .irqindex_host_ipc = -1, + .resindex_dma_base = -1, + .chip_info = &tgl_chip_info, + .default_fw_path = "intel/sof", + .default_tplg_path = "intel/sof-tplg", + .default_fw_filename = "sof-adl.ri", + .nocodec_tplg_filename = "sof-adl-nocodec.tplg", + .ops = &sof_tgl_ops, +}; + /* PCI IDs */ static const struct pci_device_id sof_pci_ids[] = { { PCI_DEVICE(0x8086, 0xa0c8), /* TGL-LP */ @@ -99,7 +115,7 @@ static const struct pci_device_id sof_pci_ids[] = { { PCI_DEVICE(0x8086, 0x7ad0), /* ADL-S */ .driver_data = (unsigned long)&adls_desc}, { PCI_DEVICE(0x8086, 0x51c8), /* ADL-P */ - .driver_data = (unsigned long)&tgl_desc}, + .driver_data = (unsigned long)&adl_desc}, { 0, } }; MODULE_DEVICE_TABLE(pci, sof_pci_ids); diff --git a/sound/soc/sof/intel/tgl.c b/sound/soc/sof/intel/tgl.c index 419f05ba1920..940f169047a0 100644 --- a/sound/soc/sof/intel/tgl.c +++ b/sound/soc/sof/intel/tgl.c @@ -125,7 +125,7 @@ const struct snd_sof_dsp_ops sof_tgl_ops = { EXPORT_SYMBOL_NS(sof_tgl_ops, SND_SOC_SOF_INTEL_HDA_COMMON); const struct sof_intel_dsp_desc tgl_chip_info = { - /* Tigerlake */ + /* Tigerlake , Alderlake */ .cores_num = 4, .init_core_mask = 1, .host_managed_cores_mask = BIT(0), From d2e8f641257d0d3af6e45d6ac2d6f9d56b8ea964 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Tue, 13 Apr 2021 10:41:52 +0200 Subject: [PATCH 464/587] ALSA: usb-audio: Explicitly set up the clock selector In the current code, we have some assumption that the audio clock selector has been set up implicitly and don't want to touch it unless it's really needed for the fallback autoclock setup. This works for most devices but some seem having a problem. Partially this was covered for the devices with a single connector at the initialization phase (commit 086b957cc17f "ALSA: usb-audio: Skip the clock selector inquiry for single connections"), but also there are cases where the wrong clock set up is kept silently. The latter seems to be the cause of the noises on Behringer devices. In this patch, we explicitly set up the audio clock selector whenever the appropriate node is found. Reported-by: Geraldo Nascimento BugLink: https://bugzilla.kernel.org/show_bug.cgi?id=199327 Link: https://lore.kernel.org/r/CAEsQvcvF7LnO8PxyyCxuRCx=7jNeSCvFAd-+dE0g_rd1rOxxdw@mail.gmail.com Cc: Link: https://lore.kernel.org/r/20210413084152.32325-1-tiwai@suse.de Signed-off-by: Takashi Iwai --- sound/usb/clock.c | 18 ++++++++++++++---- 1 file changed, 14 insertions(+), 4 deletions(-) diff --git a/sound/usb/clock.c b/sound/usb/clock.c index a746802d0ac3..17bbde73d4d1 100644 --- a/sound/usb/clock.c +++ b/sound/usb/clock.c @@ -296,7 +296,7 @@ static int __uac_clock_find_source(struct snd_usb_audio *chip, selector = snd_usb_find_clock_selector(chip->ctrl_intf, entity_id); if (selector) { - int ret, i, cur; + int ret, i, cur, err; if (selector->bNrInPins == 1) { ret = 1; @@ -324,13 +324,17 @@ static int __uac_clock_find_source(struct snd_usb_audio *chip, ret = __uac_clock_find_source(chip, fmt, selector->baCSourceID[ret - 1], visited, validate); + if (ret > 0) { + err = uac_clock_selector_set_val(chip, entity_id, cur); + if (err < 0) + return err; + } + if (!validate || ret > 0 || !chip->autoclock) return ret; /* The current clock source is invalid, try others. */ for (i = 1; i <= selector->bNrInPins; i++) { - int err; - if (i == cur) continue; @@ -396,7 +400,7 @@ static int __uac3_clock_find_source(struct snd_usb_audio *chip, selector = snd_usb_find_clock_selector_v3(chip->ctrl_intf, entity_id); if (selector) { - int ret, i, cur; + int ret, i, cur, err; /* the entity ID we are looking for is a selector. * find out what it currently selects */ @@ -418,6 +422,12 @@ static int __uac3_clock_find_source(struct snd_usb_audio *chip, ret = __uac3_clock_find_source(chip, fmt, selector->baCSourceID[ret - 1], visited, validate); + if (ret > 0) { + err = uac_clock_selector_set_val(chip, entity_id, cur); + if (err < 0) + return err; + } + if (!validate || ret > 0 || !chip->autoclock) return ret; From 858066864a6383d1eecd2fa96a0b8e69935632f8 Mon Sep 17 00:00:00 2001 From: Jerome Brunet Date: Mon, 12 Apr 2021 15:22:56 +0200 Subject: [PATCH 465/587] ASoC: meson: axg-frddr: fix fifo depth on g12 and sm1 Previous fifo depth patch was only tested on axg, not g12 or sm1. Of course, while adding hw_params dai callback for the axg, I forgot to do the same for g12 and sm1, leaving the depth unset and breaking playback on these SoCs. Add hw_params callback to the g12 dai_ops to fix the problem. Fixes: 6f68accaa864 ("ASoC: meson: axg-frddr: set fifo depth according to the period") Reported-by: Christian Hewitt Tested-by: Christian Hewitt Signed-off-by: Jerome Brunet Link: https://lore.kernel.org/r/20210412132256.89920-1-jbrunet@baylibre.com Signed-off-by: Mark Brown --- sound/soc/meson/axg-frddr.c | 1 + 1 file changed, 1 insertion(+) diff --git a/sound/soc/meson/axg-frddr.c b/sound/soc/meson/axg-frddr.c index 8ed114de0bdf..37f4bb3469b5 100644 --- a/sound/soc/meson/axg-frddr.c +++ b/sound/soc/meson/axg-frddr.c @@ -171,6 +171,7 @@ static const struct axg_fifo_match_data axg_frddr_match_data = { static const struct snd_soc_dai_ops g12a_frddr_ops = { .prepare = g12a_frddr_dai_prepare, + .hw_params = axg_frddr_dai_hw_params, .startup = axg_frddr_dai_startup, .shutdown = axg_frddr_dai_shutdown, }; From 59f5cd96e9b9e1025ab0a9dc4ce9dd8633190794 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Mon, 12 Apr 2021 08:51:59 +0900 Subject: [PATCH 466/587] ASoC: simple-card-utils: setup dai_props cpu_dai/codec_dai at initial timing We couldn't setup dai_props cpu_dai/codec_dai at the initial timing, because "counting DAIs loop" and "detecting DAIs loop" were different. But we can do it now, because these are using same loops. This patch setups dai_props cpu_dai/codec_dai at the initial timing. It can removes triky code from simple-card / audio-graph. Signed-off-by: Kuninori Morimoto Link: https://lore.kernel.org/r/87tuocwfa8.wl-kuninori.morimoto.gx@renesas.com Signed-off-by: Mark Brown --- sound/soc/generic/audio-graph-card.c | 19 +++++-------------- sound/soc/generic/simple-card-utils.c | 10 ++++++++++ sound/soc/generic/simple-card.c | 24 +++++------------------- 3 files changed, 20 insertions(+), 33 deletions(-) diff --git a/sound/soc/generic/audio-graph-card.c b/sound/soc/generic/audio-graph-card.c index 7be2c2cb253e..5ce5b7d62ee0 100644 --- a/sound/soc/generic/audio-graph-card.c +++ b/sound/soc/generic/audio-graph-card.c @@ -245,8 +245,7 @@ static int graph_dai_link_of_dpcm(struct asoc_simple_priv *priv, dai_link->dynamic = 1; dai_link->dpcm_merged_format = 1; - dai = - dai_props->cpu_dai = &priv->dais[li->dais++]; + dai = dai_props->cpu_dai; ret = asoc_simple_parse_cpu(ep, dai_link, &is_single_links); if (ret) @@ -288,11 +287,8 @@ static int graph_dai_link_of_dpcm(struct asoc_simple_priv *priv, dai_link->no_pcm = 1; dai_link->be_hw_params_fixup = asoc_simple_be_hw_params_fixup; - dai = - dai_props->codec_dai = &priv->dais[li->dais++]; - - cconf = - dai_props->codec_conf = &priv->codec_conf[li->conf++]; + dai = dai_props->codec_dai; + cconf = dai_props->codec_conf; ret = asoc_simple_parse_codec(ep, dai_link); if (ret < 0) @@ -358,19 +354,14 @@ static int graph_dai_link_of(struct asoc_simple_priv *priv, struct snd_soc_dai_link *dai_link = simple_priv_to_link(priv, li->link); struct simple_dai_props *dai_props = simple_priv_to_props(priv, li->link); struct device_node *top = dev->of_node; - struct asoc_simple_dai *cpu_dai; - struct asoc_simple_dai *codec_dai; + struct asoc_simple_dai *cpu_dai = dai_props->cpu_dai; + struct asoc_simple_dai *codec_dai = dai_props->codec_dai; int ret, single_cpu = 0; dev_dbg(dev, "link_of (%pOF)\n", cpu_ep); li->link++; - cpu_dai = - dai_props->cpu_dai = &priv->dais[li->dais++]; - codec_dai = - dai_props->codec_dai = &priv->dais[li->dais++]; - /* Factor to mclk, used in hw_params() */ graph_parse_mclk_fs(top, cpu_ep, dai_props); graph_parse_mclk_fs(top, codec_ep, dai_props); diff --git a/sound/soc/generic/simple-card-utils.c b/sound/soc/generic/simple-card-utils.c index 64b1ff5bafda..ca74dfa58458 100644 --- a/sound/soc/generic/simple-card-utils.c +++ b/sound/soc/generic/simple-card-utils.c @@ -649,8 +649,10 @@ int asoc_simple_init_priv(struct asoc_simple_priv *priv, dai_link[i].cpus = dlcs; dai_props[i].num.cpus = dai_link[i].num_cpus = li->num[i].cpus; + dai_props[i].cpu_dai = dais; dlcs += li->num[i].cpus; + dais += li->num[i].cpus; } else { /* DPCM Be's CPU = dummy */ dai_props[i].cpus = @@ -665,8 +667,16 @@ int asoc_simple_init_priv(struct asoc_simple_priv *priv, dai_link[i].codecs = dlcs; dai_props[i].num.codecs = dai_link[i].num_codecs = li->num[i].codecs; + dai_props[i].codec_dai = dais; dlcs += li->num[i].codecs; + dais += li->num[i].codecs; + + if (!li->num[i].cpus) { + /* DPCM Be's Codec */ + dai_props[i].codec_conf = cconf; + cconf += li->num[i].codecs; + } } else { /* DPCM Fe's Codec = dummy */ dai_props[i].codecs = diff --git a/sound/soc/generic/simple-card.c b/sound/soc/generic/simple-card.c index 9132c0ea05af..30da8272fbc0 100644 --- a/sound/soc/generic/simple-card.c +++ b/sound/soc/generic/simple-card.c @@ -146,8 +146,7 @@ static int simple_dai_link_of_dpcm(struct asoc_simple_priv *priv, dai_link->dynamic = 1; dai_link->dpcm_merged_format = 1; - dai = - dai_props->cpu_dai = &priv->dais[li->dais++]; + dai = dai_props->cpu_dai; ret = asoc_simple_parse_cpu(np, dai_link, &is_single_links); if (ret) @@ -174,11 +173,8 @@ static int simple_dai_link_of_dpcm(struct asoc_simple_priv *priv, dai_link->no_pcm = 1; dai_link->be_hw_params_fixup = asoc_simple_be_hw_params_fixup; - dai = - dai_props->codec_dai = &priv->dais[li->dais++]; - - cconf = - dai_props->codec_conf = &priv->codec_conf[li->conf++]; + dai = dai_props->codec_dai; + cconf = dai_props->codec_conf; ret = asoc_simple_parse_codec(np, dai_link); if (ret < 0) @@ -234,8 +230,8 @@ static int simple_dai_link_of(struct asoc_simple_priv *priv, struct device *dev = simple_priv_to_dev(priv); struct snd_soc_dai_link *dai_link = simple_priv_to_link(priv, li->link); struct simple_dai_props *dai_props = simple_priv_to_props(priv, li->link); - struct asoc_simple_dai *cpu_dai; - struct asoc_simple_dai *codec_dai; + struct asoc_simple_dai *cpu_dai = dai_props->cpu_dai; + struct asoc_simple_dai *codec_dai = dai_props->codec_dai; struct device_node *top = dev->of_node; struct device_node *cpu = NULL; struct device_node *node = NULL; @@ -257,11 +253,6 @@ static int simple_dai_link_of(struct asoc_simple_priv *priv, snprintf(prop, sizeof(prop), "%splat", prefix); plat = of_get_child_by_name(node, prop); - cpu_dai = - dai_props->cpu_dai = &priv->dais[li->dais++]; - codec_dai = - dai_props->codec_dai = &priv->dais[li->dais++]; - ret = asoc_simple_parse_daifmt(dev, node, codec, prefix, &dai_link->dai_fmt); if (ret < 0) @@ -670,8 +661,6 @@ static int asoc_simple_probe(struct platform_device *pdev) struct snd_soc_dai_link *dai_link = priv->dai_link; struct simple_dai_props *dai_props = priv->dai_props; - int dai_idx = 0; - cinfo = dev->platform_data; if (!cinfo) { dev_err(dev, "no info for asoc-simple-card\n"); @@ -687,9 +676,6 @@ static int asoc_simple_probe(struct platform_device *pdev) return -EINVAL; } - dai_props->cpu_dai = &priv->dais[dai_idx++]; - dai_props->codec_dai = &priv->dais[dai_idx++]; - cpus = dai_link->cpus; cpus->dai_name = cinfo->cpu_dai.name; From f899006d558546a8ee39c93f816eb3847c5bc6c0 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Mon, 12 Apr 2021 08:52:04 +0900 Subject: [PATCH 467/587] ASoC: simple-card-utils: remove li->dais/li->conf li->dais is same as number of CPU + Codec, li->conf is same as number of Codec when dummy-Codec. li->dais/li->conf are no longer needed. This patch removes these. Signed-off-by: Kuninori Morimoto Link: https://lore.kernel.org/r/87sg3wwfa3.wl-kuninori.morimoto.gx@renesas.com Signed-off-by: Mark Brown --- include/sound/simple_card_utils.h | 2 -- sound/soc/generic/audio-graph-card.c | 10 +--------- sound/soc/generic/simple-card-utils.c | 14 ++++++++++---- sound/soc/generic/simple-card.c | 11 +---------- 4 files changed, 12 insertions(+), 25 deletions(-) diff --git a/include/sound/simple_card_utils.h b/include/sound/simple_card_utils.h index 6635283a8160..da9d7e3665a8 100644 --- a/include/sound/simple_card_utils.h +++ b/include/sound/simple_card_utils.h @@ -75,9 +75,7 @@ struct asoc_simple_priv { #define simple_priv_to_link(priv, i) (simple_priv_to_card(priv)->dai_link + (i)) struct link_info { - int dais; /* number of dai */ int link; /* number of link */ - int conf; /* number of codec_conf */ int cpu; /* turn for CPU / Codec */ struct prop_nums num[SNDRV_MINOR_DEVICES]; }; diff --git a/sound/soc/generic/audio-graph-card.c b/sound/soc/generic/audio-graph-card.c index 5ce5b7d62ee0..3a5bef2a91d3 100644 --- a/sound/soc/generic/audio-graph-card.c +++ b/sound/soc/generic/audio-graph-card.c @@ -552,7 +552,7 @@ int audio_graph_parse_of(struct asoc_simple_priv *priv, struct device *dev) memset(&li, 0, sizeof(li)); graph_get_dais_count(priv, &li); - if (!li.link || !li.dais) + if (!li.link) return -EINVAL; ret = asoc_simple_init_priv(priv, &li); @@ -622,7 +622,6 @@ static int graph_count_noml(struct asoc_simple_priv *priv, li->num[li->link].platforms = 1; li->link += 1; /* 1xCPU-Codec */ - li->dais += 2; /* 1xCPU + 1xCodec */ dev_dbg(dev, "Count As Normal\n"); @@ -646,13 +645,10 @@ static int graph_count_dpcm(struct asoc_simple_priv *priv, li->num[li->link].platforms = 1; li->link++; /* 1xCPU-dummy */ - li->dais++; /* 1xCPU */ } else { li->num[li->link].codecs = 1; li->link++; /* 1xdummy-Codec */ - li->conf++; /* 1xdummy-Codec */ - li->dais++; /* 1xCodec */ } dev_dbg(dev, "Count As DPCM\n"); @@ -663,8 +659,6 @@ static int graph_count_dpcm(struct asoc_simple_priv *priv, static void graph_get_dais_count(struct asoc_simple_priv *priv, struct link_info *li) { - struct device *dev = simple_priv_to_dev(priv); - /* * link_num : number of links. * CPU-Codec / CPU-dummy / dummy-Codec @@ -714,8 +708,6 @@ static void graph_get_dais_count(struct asoc_simple_priv *priv, graph_for_each_link(priv, li, graph_count_noml, graph_count_dpcm); - dev_dbg(dev, "link %d, dais %d, ccnf %d\n", - li->link, li->dais, li->conf); } int audio_graph_card_probe(struct snd_soc_card *card) diff --git a/sound/soc/generic/simple-card-utils.c b/sound/soc/generic/simple-card-utils.c index ca74dfa58458..59b4fb2bd586 100644 --- a/sound/soc/generic/simple-card-utils.c +++ b/sound/soc/generic/simple-card-utils.c @@ -597,7 +597,7 @@ int asoc_simple_init_priv(struct asoc_simple_priv *priv, struct asoc_simple_dai *dais; struct snd_soc_dai_link_component *dlcs; struct snd_soc_codec_conf *cconf = NULL; - int i, dai_num = 0, dlc_num = 0; + int i, dai_num = 0, dlc_num = 0, cnf_num = 0; dai_props = devm_kcalloc(dev, li->link, sizeof(*dai_props), GFP_KERNEL); dai_link = devm_kcalloc(dev, li->link, sizeof(*dai_link), GFP_KERNEL); @@ -613,6 +613,9 @@ int asoc_simple_init_priv(struct asoc_simple_priv *priv, dai_num += cc; dlc_num += cc + li->num[i].platforms; + + if (!li->num[i].cpus) + cnf_num += li->num[i].codecs; } dais = devm_kcalloc(dev, dai_num, sizeof(*dais), GFP_KERNEL); @@ -620,12 +623,15 @@ int asoc_simple_init_priv(struct asoc_simple_priv *priv, if (!dais || !dlcs) return -ENOMEM; - if (li->conf) { - cconf = devm_kcalloc(dev, li->conf, sizeof(*cconf), GFP_KERNEL); + if (cnf_num) { + cconf = devm_kcalloc(dev, cnf_num, sizeof(*cconf), GFP_KERNEL); if (!cconf) return -ENOMEM; } + dev_dbg(dev, "link %d, dais %d, ccnf %d\n", + li->link, dai_num, cnf_num); + /* dummy CPU/Codec */ priv->dummy.of_node = NULL; priv->dummy.dai_name = "snd-soc-dummy-dai"; @@ -640,7 +646,7 @@ int asoc_simple_init_priv(struct asoc_simple_priv *priv, card->dai_link = priv->dai_link; card->num_links = li->link; card->codec_conf = cconf; - card->num_configs = li->conf; + card->num_configs = cnf_num; for (i = 0; i < li->link; i++) { if (li->num[i].cpus) { diff --git a/sound/soc/generic/simple-card.c b/sound/soc/generic/simple-card.c index 30da8272fbc0..7665bbf2a6c0 100644 --- a/sound/soc/generic/simple-card.c +++ b/sound/soc/generic/simple-card.c @@ -495,7 +495,6 @@ static int simple_count_noml(struct asoc_simple_priv *priv, li->num[li->link].platforms = 1; li->link += 1; - li->dais += 2; return 0; } @@ -517,13 +516,10 @@ static int simple_count_dpcm(struct asoc_simple_priv *priv, li->num[li->link].platforms = 1; li->link++; /* CPU-dummy */ - li->dais++; } else { li->num[li->link].codecs = 1; li->link++; /* dummy-Codec */ - li->dais++; - li->conf++; } return 0; @@ -587,17 +583,12 @@ static void simple_get_dais_count(struct asoc_simple_priv *priv, li->num[0].platforms = 1; li->link = 1; - li->dais = 2; - li->conf = 0; return; } simple_for_each_link(priv, li, simple_count_noml, simple_count_dpcm); - - dev_dbg(dev, "link %d, dais %d, ccnf %d\n", - li->link, li->dais, li->conf); } static int simple_soc_probe(struct snd_soc_card *card) @@ -637,7 +628,7 @@ static int asoc_simple_probe(struct platform_device *pdev) memset(&li, 0, sizeof(li)); simple_get_dais_count(priv, &li); - if (!li.link || !li.dais) + if (!li.link) return -EINVAL; ret = asoc_simple_init_priv(priv, &li); From fafc05aadd4b6ce5c161135de9d3a653fc054543 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Mon, 12 Apr 2021 08:52:09 +0900 Subject: [PATCH 468/587] ASoC: simple-card-utils: use for_each_prop_xxx() ASoC is now supporting multi DAI, but, current simple-card / audio-graph are assuming fixed single DAI. This patch uses for_each_prop_xxx() to support multi DAI. Signed-off-by: Kuninori Morimoto Link: https://lore.kernel.org/r/87r1jgwf9y.wl-kuninori.morimoto.gx@renesas.com Signed-off-by: Mark Brown --- include/sound/simple_card_utils.h | 43 ++++++++- sound/soc/generic/simple-card-utils.c | 126 +++++++++++++++----------- 2 files changed, 113 insertions(+), 56 deletions(-) diff --git a/include/sound/simple_card_utils.h b/include/sound/simple_card_utils.h index da9d7e3665a8..de40f09d226f 100644 --- a/include/sound/simple_card_utils.h +++ b/include/sound/simple_card_utils.h @@ -74,6 +74,34 @@ struct asoc_simple_priv { #define simple_priv_to_dev(priv) (simple_priv_to_card(priv)->dev) #define simple_priv_to_link(priv, i) (simple_priv_to_card(priv)->dai_link + (i)) +#define for_each_prop_dlc_cpus(props, i, cpu) \ + for ((i) = 0; \ + ((i) < (props)->num.cpus) && ((cpu) = &(props)->cpus[i]); \ + (i)++) +#define for_each_prop_dlc_codecs(props, i, codec) \ + for ((i) = 0; \ + ((i) < (props)->num.codecs) && ((codec) = &(props)->codecs[i]); \ + (i)++) +#define for_each_prop_dlc_platforms(props, i, platform) \ + for ((i) = 0; \ + ((i) < (props)->num.platforms) && ((platform) = &(props)->platforms[i]); \ + (i)++) +#define for_each_prop_codec_conf(props, i, conf) \ + for ((i) = 0; \ + ((i) < (props)->num.codecs) && \ + (props)->codec_conf && \ + ((conf) = &(props)->codec_conf[i]); \ + (i)++) + +#define for_each_prop_dai_cpu(props, i, cpu) \ + for ((i) = 0; \ + ((i) < (props)->num.cpus) && ((cpu) = &(props)->cpu_dai[i]); \ + (i)++) +#define for_each_prop_dai_codec(props, i, codec) \ + for ((i) = 0; \ + ((i) < (props)->num.codecs) && ((codec) = &(props)->codec_dai[i]); \ + (i)++) + struct link_info { int link; /* number of link */ int cpu; /* turn for CPU / Codec */ @@ -192,11 +220,16 @@ static inline void asoc_simple_debug_info(struct asoc_simple_priv *priv) for (i = 0; i < card->num_links; i++) { struct simple_dai_props *props = simple_priv_to_props(priv, i); struct snd_soc_dai_link *link = simple_priv_to_link(priv, i); + struct asoc_simple_dai *dai; + struct snd_soc_codec_conf *cnf; + int j; dev_dbg(dev, "DAI%d\n", i); - asoc_simple_debug_dai(priv, "cpu", props->cpu_dai); - asoc_simple_debug_dai(priv, "codec", props->codec_dai); + for_each_prop_dai_cpu(props, j, dai) + asoc_simple_debug_dai(priv, "cpu", dai); + for_each_prop_dai_codec(props, j, dai) + asoc_simple_debug_dai(priv, "codec", dai); if (link->name) dev_dbg(dev, "dai name = %s\n", link->name); @@ -209,9 +242,9 @@ static inline void asoc_simple_debug_info(struct asoc_simple_priv *priv) if (props->adata.convert_channels) dev_dbg(dev, "convert_channels = %d\n", props->adata.convert_channels); - if (props->codec_conf && props->codec_conf->name_prefix) - dev_dbg(dev, "name prefix = %s\n", - props->codec_conf->name_prefix); + for_each_prop_codec_conf(props, j, cnf) + if (cnf->name_prefix) + dev_dbg(dev, "name prefix = %s\n", cnf->name_prefix); if (props->mclk_fs) dev_dbg(dev, "mclk-fs = %d\n", props->mclk_fs); diff --git a/sound/soc/generic/simple-card-utils.c b/sound/soc/generic/simple-card-utils.c index 59b4fb2bd586..fad9c7f37d2b 100644 --- a/sound/soc/generic/simple-card-utils.c +++ b/sound/soc/generic/simple-card-utils.c @@ -195,17 +195,37 @@ int asoc_simple_startup(struct snd_pcm_substream *substream) { struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream); struct asoc_simple_priv *priv = snd_soc_card_get_drvdata(rtd->card); - struct simple_dai_props *dai_props = simple_priv_to_props(priv, rtd->num); + struct simple_dai_props *props = simple_priv_to_props(priv, rtd->num); + struct asoc_simple_dai *dai; + int i1, i2, i; int ret; - ret = asoc_simple_clk_enable(dai_props->cpu_dai); - if (ret) - return ret; + for_each_prop_dai_cpu(props, i1, dai) { + ret = asoc_simple_clk_enable(dai); + if (ret) + goto cpu_err; + } - ret = asoc_simple_clk_enable(dai_props->codec_dai); - if (ret) - asoc_simple_clk_disable(dai_props->cpu_dai); + for_each_prop_dai_codec(props, i2, dai) { + ret = asoc_simple_clk_enable(dai); + if (ret) + goto codec_err; + } + return 0; + +codec_err: + for_each_prop_dai_codec(props, i, dai) { + if (i >= i2) + break; + asoc_simple_clk_disable(dai); + } +cpu_err: + for_each_prop_dai_cpu(props, i, dai) { + if (i >= i1) + break; + asoc_simple_clk_disable(dai); + } return ret; } EXPORT_SYMBOL_GPL(asoc_simple_startup); @@ -216,17 +236,19 @@ void asoc_simple_shutdown(struct snd_pcm_substream *substream) struct snd_soc_dai *codec_dai = asoc_rtd_to_codec(rtd, 0); struct snd_soc_dai *cpu_dai = asoc_rtd_to_cpu(rtd, 0); struct asoc_simple_priv *priv = snd_soc_card_get_drvdata(rtd->card); - struct simple_dai_props *dai_props = - simple_priv_to_props(priv, rtd->num); + struct simple_dai_props *props = simple_priv_to_props(priv, rtd->num); + struct asoc_simple_dai *dai; + int i; - if (dai_props->mclk_fs) { + if (props->mclk_fs) { snd_soc_dai_set_sysclk(codec_dai, 0, 0, SND_SOC_CLOCK_IN); snd_soc_dai_set_sysclk(cpu_dai, 0, 0, SND_SOC_CLOCK_OUT); } - asoc_simple_clk_disable(dai_props->cpu_dai); - - asoc_simple_clk_disable(dai_props->codec_dai); + for_each_prop_dai_cpu(props, i, dai) + asoc_simple_clk_disable(dai); + for_each_prop_dai_codec(props, i, dai) + asoc_simple_clk_disable(dai); } EXPORT_SYMBOL_GPL(asoc_simple_shutdown); @@ -249,41 +271,41 @@ int asoc_simple_hw_params(struct snd_pcm_substream *substream, struct snd_pcm_hw_params *params) { struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream); - struct snd_soc_dai *codec_dai = asoc_rtd_to_codec(rtd, 0); - struct snd_soc_dai *cpu_dai = asoc_rtd_to_cpu(rtd, 0); + struct asoc_simple_dai *pdai; + struct snd_soc_dai *sdai; struct asoc_simple_priv *priv = snd_soc_card_get_drvdata(rtd->card); - struct simple_dai_props *dai_props = - simple_priv_to_props(priv, rtd->num); + struct simple_dai_props *props = simple_priv_to_props(priv, rtd->num); unsigned int mclk, mclk_fs = 0; - int ret; + int i, ret; - if (dai_props->mclk_fs) - mclk_fs = dai_props->mclk_fs; + if (props->mclk_fs) + mclk_fs = props->mclk_fs; if (mclk_fs) { mclk = params_rate(params) * mclk_fs; - ret = asoc_simple_set_clk_rate(dai_props->codec_dai, mclk); - if (ret < 0) - return ret; - - ret = asoc_simple_set_clk_rate(dai_props->cpu_dai, mclk); - if (ret < 0) - return ret; - - ret = snd_soc_dai_set_sysclk(codec_dai, 0, mclk, - SND_SOC_CLOCK_IN); - if (ret && ret != -ENOTSUPP) - goto err; - - ret = snd_soc_dai_set_sysclk(cpu_dai, 0, mclk, - SND_SOC_CLOCK_OUT); - if (ret && ret != -ENOTSUPP) - goto err; + for_each_prop_dai_codec(props, i, pdai) { + ret = asoc_simple_set_clk_rate(pdai, mclk); + if (ret < 0) + return ret; + } + for_each_prop_dai_cpu(props, i, pdai) { + ret = asoc_simple_set_clk_rate(pdai, mclk); + if (ret < 0) + return ret; + } + for_each_rtd_codec_dais(rtd, i, sdai) { + ret = snd_soc_dai_set_sysclk(sdai, 0, mclk, SND_SOC_CLOCK_IN); + if (ret && ret != -ENOTSUPP) + return ret; + } + for_each_rtd_cpu_dais(rtd, i, sdai) { + ret = snd_soc_dai_set_sysclk(sdai, 0, mclk, SND_SOC_CLOCK_OUT); + if (ret && ret != -ENOTSUPP) + return ret; + } } return 0; -err: - return ret; } EXPORT_SYMBOL_GPL(asoc_simple_hw_params); @@ -378,20 +400,22 @@ static int asoc_simple_init_dai_link_params(struct snd_soc_pcm_runtime *rtd, int asoc_simple_dai_init(struct snd_soc_pcm_runtime *rtd) { struct asoc_simple_priv *priv = snd_soc_card_get_drvdata(rtd->card); - struct simple_dai_props *dai_props = simple_priv_to_props(priv, rtd->num); - int ret; + struct simple_dai_props *props = simple_priv_to_props(priv, rtd->num); + struct asoc_simple_dai *dai; + int i, ret; - ret = asoc_simple_init_dai(asoc_rtd_to_codec(rtd, 0), - dai_props->codec_dai); - if (ret < 0) - return ret; + for_each_prop_dai_codec(props, i, dai) { + ret = asoc_simple_init_dai(asoc_rtd_to_codec(rtd, i), dai); + if (ret < 0) + return ret; + } + for_each_prop_dai_cpu(props, i, dai) { + ret = asoc_simple_init_dai(asoc_rtd_to_cpu(rtd, i), dai); + if (ret < 0) + return ret; + } - ret = asoc_simple_init_dai(asoc_rtd_to_cpu(rtd, 0), - dai_props->cpu_dai); - if (ret < 0) - return ret; - - ret = asoc_simple_init_dai_link_params(rtd, dai_props); + ret = asoc_simple_init_dai_link_params(rtd, props); if (ret < 0) return ret; From e25704f84ca2b586e8e65d1b2ab686205b3076fe Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Mon, 12 Apr 2021 08:52:13 +0900 Subject: [PATCH 469/587] ASoC: simple-card-utils: remove asoc_simple_parse_xxx() ASoC is now supporting multi DAI, but, current simple-card / audio-graph are assuming fixed single DAI. Now, asoc_simple_parse_xxx() macro is assuming single DAI. To support multi-CPU/Codec, this patch unpack asoc_simple_parse_xxx() macro, and uses "&dai_link->cpus[i]" instead of "dai_link->cpus". Signed-off-by: Kuninori Morimoto Link: https://lore.kernel.org/r/87pmz0wf9u.wl-kuninori.morimoto.gx@renesas.com Signed-off-by: Mark Brown --- include/sound/simple_card_utils.h | 11 ----------- sound/soc/generic/audio-graph-card.c | 16 ++++++++-------- sound/soc/generic/simple-card.c | 18 +++++++++--------- 3 files changed, 17 insertions(+), 28 deletions(-) diff --git a/include/sound/simple_card_utils.h b/include/sound/simple_card_utils.h index de40f09d226f..23f17ccc7908 100644 --- a/include/sound/simple_card_utils.h +++ b/include/sound/simple_card_utils.h @@ -120,10 +120,6 @@ int asoc_simple_set_dailink_name(struct device *dev, int asoc_simple_parse_card_name(struct snd_soc_card *card, char *prefix); -#define asoc_simple_parse_clk_cpu(dev, node, dai_link, simple_dai) \ - asoc_simple_parse_clk(dev, node, simple_dai, dai_link->cpus) -#define asoc_simple_parse_clk_codec(dev, node, dai_link, simple_dai) \ - asoc_simple_parse_clk(dev, node, simple_dai, dai_link->codecs) int asoc_simple_parse_clk(struct device *dev, struct device_node *node, struct asoc_simple_dai *simple_dai, @@ -136,13 +132,6 @@ int asoc_simple_dai_init(struct snd_soc_pcm_runtime *rtd); int asoc_simple_be_hw_params_fixup(struct snd_soc_pcm_runtime *rtd, struct snd_pcm_hw_params *params); -#define asoc_simple_parse_cpu(node, dai_link, is_single_link) \ - asoc_simple_parse_dai(node, dai_link->cpus, is_single_link) -#define asoc_simple_parse_codec(node, dai_link) \ - asoc_simple_parse_dai(node, dai_link->codecs, NULL) -#define asoc_simple_parse_platform(node, dai_link) \ - asoc_simple_parse_dai(node, dai_link->platforms, NULL) - #define asoc_simple_parse_tdm(np, dai) \ snd_soc_of_parse_tdm_slot(np, &(dai)->tx_slot_mask, \ &(dai)->rx_slot_mask, \ diff --git a/sound/soc/generic/audio-graph-card.c b/sound/soc/generic/audio-graph-card.c index 3a5bef2a91d3..145f8a19c9e8 100644 --- a/sound/soc/generic/audio-graph-card.c +++ b/sound/soc/generic/audio-graph-card.c @@ -247,11 +247,11 @@ static int graph_dai_link_of_dpcm(struct asoc_simple_priv *priv, dai = dai_props->cpu_dai; - ret = asoc_simple_parse_cpu(ep, dai_link, &is_single_links); + ret = asoc_simple_parse_dai(ep, dai_link->cpus, &is_single_links); if (ret) goto out_put_node; - ret = asoc_simple_parse_clk_cpu(dev, ep, dai_link, dai); + ret = asoc_simple_parse_clk(dev, ep, dai, dai_link->cpus); if (ret < 0) goto out_put_node; @@ -290,11 +290,11 @@ static int graph_dai_link_of_dpcm(struct asoc_simple_priv *priv, dai = dai_props->codec_dai; cconf = dai_props->codec_conf; - ret = asoc_simple_parse_codec(ep, dai_link); + ret = asoc_simple_parse_dai(ep, dai_link->codecs, NULL); if (ret < 0) goto out_put_node; - ret = asoc_simple_parse_clk_codec(dev, ep, dai_link, dai); + ret = asoc_simple_parse_clk(dev, ep, dai, dai_link->codecs); if (ret < 0) goto out_put_node; @@ -371,11 +371,11 @@ static int graph_dai_link_of(struct asoc_simple_priv *priv, if (ret < 0) return ret; - ret = asoc_simple_parse_cpu(cpu_ep, dai_link, &single_cpu); + ret = asoc_simple_parse_dai(cpu_ep, dai_link->cpus, &single_cpu); if (ret < 0) return ret; - ret = asoc_simple_parse_codec(codec_ep, dai_link); + ret = asoc_simple_parse_dai(codec_ep, dai_link->codecs, NULL); if (ret < 0) return ret; @@ -387,11 +387,11 @@ static int graph_dai_link_of(struct asoc_simple_priv *priv, if (ret < 0) return ret; - ret = asoc_simple_parse_clk_cpu(dev, cpu_ep, dai_link, cpu_dai); + ret = asoc_simple_parse_clk(dev, cpu_ep, cpu_dai, dai_link->cpus); if (ret < 0) return ret; - ret = asoc_simple_parse_clk_codec(dev, codec_ep, dai_link, codec_dai); + ret = asoc_simple_parse_clk(dev, codec_ep, codec_dai, dai_link->codecs); if (ret < 0) return ret; diff --git a/sound/soc/generic/simple-card.c b/sound/soc/generic/simple-card.c index 7665bbf2a6c0..6a55b8672166 100644 --- a/sound/soc/generic/simple-card.c +++ b/sound/soc/generic/simple-card.c @@ -148,11 +148,11 @@ static int simple_dai_link_of_dpcm(struct asoc_simple_priv *priv, dai = dai_props->cpu_dai; - ret = asoc_simple_parse_cpu(np, dai_link, &is_single_links); + ret = asoc_simple_parse_dai(np, dai_link->cpus, &is_single_links); if (ret) goto out_put_node; - ret = asoc_simple_parse_clk_cpu(dev, np, dai_link, dai); + ret = asoc_simple_parse_clk(dev, np, dai, dai_link->cpus); if (ret < 0) goto out_put_node; @@ -176,11 +176,11 @@ static int simple_dai_link_of_dpcm(struct asoc_simple_priv *priv, dai = dai_props->codec_dai; cconf = dai_props->codec_conf; - ret = asoc_simple_parse_codec(np, dai_link); + ret = asoc_simple_parse_dai(np, dai_link->codecs, NULL); if (ret < 0) goto out_put_node; - ret = asoc_simple_parse_clk_codec(dev, np, dai_link, dai); + ret = asoc_simple_parse_clk(dev, np, dai, dai_link->codecs); if (ret < 0) goto out_put_node; @@ -260,15 +260,15 @@ static int simple_dai_link_of(struct asoc_simple_priv *priv, simple_parse_mclk_fs(top, cpu, codec, dai_props, prefix); - ret = asoc_simple_parse_cpu(cpu, dai_link, &single_cpu); + ret = asoc_simple_parse_dai(cpu, dai_link->cpus, &single_cpu); if (ret < 0) goto dai_link_of_err; - ret = asoc_simple_parse_codec(codec, dai_link); + ret = asoc_simple_parse_dai(codec, dai_link->codecs, NULL); if (ret < 0) goto dai_link_of_err; - ret = asoc_simple_parse_platform(plat, dai_link); + ret = asoc_simple_parse_dai(plat, dai_link->platforms, NULL); if (ret < 0) goto dai_link_of_err; @@ -280,11 +280,11 @@ static int simple_dai_link_of(struct asoc_simple_priv *priv, if (ret < 0) goto dai_link_of_err; - ret = asoc_simple_parse_clk_cpu(dev, cpu, dai_link, cpu_dai); + ret = asoc_simple_parse_clk(dev, cpu, cpu_dai, dai_link->cpus); if (ret < 0) goto dai_link_of_err; - ret = asoc_simple_parse_clk_codec(dev, codec, dai_link, codec_dai); + ret = asoc_simple_parse_clk(dev, codec, codec_dai, dai_link->codecs); if (ret < 0) goto dai_link_of_err; From 1cf6805700ecf25942468a01eff902ab8c32ce3c Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Mon, 12 Apr 2021 08:52:18 +0900 Subject: [PATCH 470/587] ASoC: simple-card-utils: care multi DAI at asoc_simple_clean_reference() ASoC is now supporting multi DAI, but, current simple-card / audio-graph are assuming fixed single DAI. This patch cares multi DAI at asoc_simple_clean_reference() for of_node_put(). Signed-off-by: Kuninori Morimoto Link: https://lore.kernel.org/r/87o8ekwf9p.wl-kuninori.morimoto.gx@renesas.com Signed-off-by: Mark Brown --- sound/soc/generic/simple-card-utils.c | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/sound/soc/generic/simple-card-utils.c b/sound/soc/generic/simple-card-utils.c index fad9c7f37d2b..6efe3757eff8 100644 --- a/sound/soc/generic/simple-card-utils.c +++ b/sound/soc/generic/simple-card-utils.c @@ -451,11 +451,15 @@ EXPORT_SYMBOL_GPL(asoc_simple_canonicalize_cpu); int asoc_simple_clean_reference(struct snd_soc_card *card) { struct snd_soc_dai_link *dai_link; - int i; + struct snd_soc_dai_link_component *cpu; + struct snd_soc_dai_link_component *codec; + int i, j; for_each_card_prelinks(card, i, dai_link) { - of_node_put(dai_link->cpus->of_node); - of_node_put(dai_link->codecs->of_node); + for_each_link_cpus(dai_link, j, cpu) + of_node_put(cpu->of_node); + for_each_link_codecs(dai_link, j, codec) + of_node_put(codec->of_node); } return 0; } From ac813c625ad5c3ee98a99e1b37659a0d85178978 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Mon, 12 Apr 2021 08:52:23 +0900 Subject: [PATCH 471/587] ASoC: simple-card-utils: indicate dai_fmt if exist link->dai_fmt might be 0. Don't indicate it in such case when debugging. Signed-off-by: Kuninori Morimoto Link: https://lore.kernel.org/r/87mtu4wf9k.wl-kuninori.morimoto.gx@renesas.com Signed-off-by: Mark Brown --- include/sound/simple_card_utils.h | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/include/sound/simple_card_utils.h b/include/sound/simple_card_utils.h index 23f17ccc7908..080fe7eb560f 100644 --- a/include/sound/simple_card_utils.h +++ b/include/sound/simple_card_utils.h @@ -222,9 +222,8 @@ static inline void asoc_simple_debug_info(struct asoc_simple_priv *priv) if (link->name) dev_dbg(dev, "dai name = %s\n", link->name); - - dev_dbg(dev, "dai format = %04x\n", link->dai_fmt); - + if (link->dai_fmt) + dev_dbg(dev, "dai format = %04x\n", link->dai_fmt); if (props->adata.convert_rate) dev_dbg(dev, "convert_rate = %d\n", props->adata.convert_rate); From 40d8cbe70e71be170e0a4fe6ab112d9aaa9cfb18 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Mon, 12 Apr 2021 08:52:27 +0900 Subject: [PATCH 472/587] ASoC: simple-card-utils: indicate missing CPU/Codec numbers for debug Now ALSA is supporting multi-CPU/Codec, thus, we want to know number of CPU/Codec when debugging. This patch indicates it. Signed-off-by: Kuninori Morimoto Link: https://lore.kernel.org/r/87lf9owf9g.wl-kuninori.morimoto.gx@renesas.com Signed-off-by: Mark Brown --- include/sound/simple_card_utils.h | 2 ++ 1 file changed, 2 insertions(+) diff --git a/include/sound/simple_card_utils.h b/include/sound/simple_card_utils.h index 080fe7eb560f..e366e432c475 100644 --- a/include/sound/simple_card_utils.h +++ b/include/sound/simple_card_utils.h @@ -215,8 +215,10 @@ static inline void asoc_simple_debug_info(struct asoc_simple_priv *priv) dev_dbg(dev, "DAI%d\n", i); + dev_dbg(dev, "cpu num = %d\n", link->num_cpus); for_each_prop_dai_cpu(props, j, dai) asoc_simple_debug_dai(priv, "cpu", dai); + dev_dbg(dev, "codec num = %d\n", link->num_codecs); for_each_prop_dai_codec(props, j, dai) asoc_simple_debug_dai(priv, "codec", dai); From 9830d3e99f51fc1c1c6ab8be7778fd205af198ad Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Mon, 12 Apr 2021 08:52:32 +0900 Subject: [PATCH 473/587] ASoC: simple-card-utils: add simple_props_to_xxx() macro We shouldn't use dai_props->cpus/codecs/cpu_dai/codec_dai/codec_conf directly, because these are array to supporting multi CPU/Codec/Platform. This patch adds asoc_link_to_xxx() macro for it. Signed-off-by: Kuninori Morimoto Link: https://lore.kernel.org/r/87k0p8wf9b.wl-kuninori.morimoto.gx@renesas.com Signed-off-by: Mark Brown --- include/sound/simple_card_utils.h | 27 ++++++++++++++++++++------- 1 file changed, 20 insertions(+), 7 deletions(-) diff --git a/include/sound/simple_card_utils.h b/include/sound/simple_card_utils.h index e366e432c475..78b6cf0194d2 100644 --- a/include/sound/simple_card_utils.h +++ b/include/sound/simple_card_utils.h @@ -74,32 +74,45 @@ struct asoc_simple_priv { #define simple_priv_to_dev(priv) (simple_priv_to_card(priv)->dev) #define simple_priv_to_link(priv, i) (simple_priv_to_card(priv)->dai_link + (i)) +#define simple_props_to_dlc_cpu(props, i) ((props)->cpus + i) +#define simple_props_to_dlc_codec(props, i) ((props)->codecs + i) +#define simple_props_to_dlc_platform(props, i) ((props)->platforms + i) + +#define simple_props_to_dai_cpu(props, i) ((props)->cpu_dai + i) +#define simple_props_to_dai_codec(props, i) ((props)->codec_dai + i) +#define simple_props_to_codec_conf(props, i) ((props)->codec_conf + i) + #define for_each_prop_dlc_cpus(props, i, cpu) \ for ((i) = 0; \ - ((i) < (props)->num.cpus) && ((cpu) = &(props)->cpus[i]); \ + ((i) < (props)->num.cpus) && \ + ((cpu) = simple_props_to_dlc_cpu(props, i)); \ (i)++) -#define for_each_prop_dlc_codecs(props, i, codec) \ +#define for_each_prop_dlc_codecs(props, i, codec) \ for ((i) = 0; \ - ((i) < (props)->num.codecs) && ((codec) = &(props)->codecs[i]); \ + ((i) < (props)->num.codecs) && \ + ((codec) = simple_props_to_dlc_codec(props, i)); \ (i)++) #define for_each_prop_dlc_platforms(props, i, platform) \ for ((i) = 0; \ - ((i) < (props)->num.platforms) && ((platform) = &(props)->platforms[i]); \ + ((i) < (props)->num.platforms) && \ + ((platform) = simple_props_to_dlc_platform(props, i)); \ (i)++) #define for_each_prop_codec_conf(props, i, conf) \ for ((i) = 0; \ ((i) < (props)->num.codecs) && \ (props)->codec_conf && \ - ((conf) = &(props)->codec_conf[i]); \ + ((conf) = simple_props_to_codec_conf(props, i)); \ (i)++) #define for_each_prop_dai_cpu(props, i, cpu) \ for ((i) = 0; \ - ((i) < (props)->num.cpus) && ((cpu) = &(props)->cpu_dai[i]); \ + ((i) < (props)->num.cpus) && \ + ((cpu) = simple_props_to_dai_cpu(props, i)); \ (i)++) #define for_each_prop_dai_codec(props, i, codec) \ for ((i) = 0; \ - ((i) < (props)->num.codecs) && ((codec) = &(props)->codec_dai[i]); \ + ((i) < (props)->num.codecs) && \ + ((codec) = simple_props_to_dai_codec(props, i)); \ (i)++) struct link_info { From c826ec0391c83f06354a4ebb25c7b2480c18f33a Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Mon, 12 Apr 2021 08:52:45 +0900 Subject: [PATCH 474/587] ASoC: simple-card-utils: multi support at asoc_simple_canonicalize_cpu/platform() Current asoc_simple_canonicalize_cpu/platform() is assuming single CPU, single Platform, but we want to support Multi support. This patch is prepare for it. Signed-off-by: Kuninori Morimoto Link: https://lore.kernel.org/r/87im4swf8y.wl-kuninori.morimoto.gx@renesas.com Signed-off-by: Mark Brown --- include/sound/simple_card_utils.h | 7 ++++--- sound/soc/generic/audio-graph-card.c | 9 +++++---- sound/soc/generic/simple-card-utils.c | 11 ++++++----- sound/soc/generic/simple-card.c | 9 +++++---- 4 files changed, 20 insertions(+), 16 deletions(-) diff --git a/include/sound/simple_card_utils.h b/include/sound/simple_card_utils.h index 78b6cf0194d2..cccd9987a1b4 100644 --- a/include/sound/simple_card_utils.h +++ b/include/sound/simple_card_utils.h @@ -151,9 +151,10 @@ int asoc_simple_be_hw_params_fixup(struct snd_soc_pcm_runtime *rtd, &(dai)->slots, \ &(dai)->slot_width); -void asoc_simple_canonicalize_platform(struct snd_soc_dai_link *dai_link); -void asoc_simple_canonicalize_cpu(struct snd_soc_dai_link *dai_link, - int is_single_links); +void asoc_simple_canonicalize_platform(struct snd_soc_dai_link_component *platforms, + struct snd_soc_dai_link_component *cpus); +void asoc_simple_canonicalize_cpu(struct snd_soc_dai_link_component *cpus, + int is_single_links); int asoc_simple_clean_reference(struct snd_soc_card *card); diff --git a/sound/soc/generic/audio-graph-card.c b/sound/soc/generic/audio-graph-card.c index 145f8a19c9e8..e6b64fdbdc76 100644 --- a/sound/soc/generic/audio-graph-card.c +++ b/sound/soc/generic/audio-graph-card.c @@ -226,6 +226,7 @@ static int graph_dai_link_of_dpcm(struct asoc_simple_priv *priv, struct asoc_simple_dai *dai; struct snd_soc_dai_link_component *cpus = dai_link->cpus; struct snd_soc_dai_link_component *codecs = dai_link->codecs; + struct snd_soc_dai_link_component *platforms = dai_link->platforms; int ret; port = of_get_parent(ep); @@ -276,8 +277,8 @@ static int graph_dai_link_of_dpcm(struct asoc_simple_priv *priv, dai_link->no_pcm = 1; /* card->num_links includes Codec */ - asoc_simple_canonicalize_cpu(dai_link, is_single_links); - asoc_simple_canonicalize_platform(dai_link); + asoc_simple_canonicalize_cpu(cpus, is_single_links); + asoc_simple_canonicalize_platform(platforms, cpus); } else { struct snd_soc_codec_conf *cconf; @@ -405,8 +406,8 @@ static int graph_dai_link_of(struct asoc_simple_priv *priv, dai_link->ops = &graph_ops; dai_link->init = asoc_simple_dai_init; - asoc_simple_canonicalize_cpu(dai_link, single_cpu); - asoc_simple_canonicalize_platform(dai_link); + asoc_simple_canonicalize_cpu(dai_link->cpus, single_cpu); + asoc_simple_canonicalize_platform(dai_link->platforms, dai_link->cpus); return 0; } diff --git a/sound/soc/generic/simple-card-utils.c b/sound/soc/generic/simple-card-utils.c index 6efe3757eff8..a15956c25858 100644 --- a/sound/soc/generic/simple-card-utils.c +++ b/sound/soc/generic/simple-card-utils.c @@ -423,15 +423,16 @@ int asoc_simple_dai_init(struct snd_soc_pcm_runtime *rtd) } EXPORT_SYMBOL_GPL(asoc_simple_dai_init); -void asoc_simple_canonicalize_platform(struct snd_soc_dai_link *dai_link) +void asoc_simple_canonicalize_platform(struct snd_soc_dai_link_component *platforms, + struct snd_soc_dai_link_component *cpus) { /* Assumes platform == cpu */ - if (!dai_link->platforms->of_node) - dai_link->platforms->of_node = dai_link->cpus->of_node; + if (!platforms->of_node) + platforms->of_node = cpus->of_node; } EXPORT_SYMBOL_GPL(asoc_simple_canonicalize_platform); -void asoc_simple_canonicalize_cpu(struct snd_soc_dai_link *dai_link, +void asoc_simple_canonicalize_cpu(struct snd_soc_dai_link_component *cpus, int is_single_links) { /* @@ -444,7 +445,7 @@ void asoc_simple_canonicalize_cpu(struct snd_soc_dai_link *dai_link, * fmt_multiple_name() */ if (is_single_links) - dai_link->cpus->dai_name = NULL; + cpus->dai_name = NULL; } EXPORT_SYMBOL_GPL(asoc_simple_canonicalize_cpu); diff --git a/sound/soc/generic/simple-card.c b/sound/soc/generic/simple-card.c index 6a55b8672166..06b2d6a7f48d 100644 --- a/sound/soc/generic/simple-card.c +++ b/sound/soc/generic/simple-card.c @@ -124,6 +124,7 @@ static int simple_dai_link_of_dpcm(struct asoc_simple_priv *priv, struct asoc_simple_dai *dai; struct snd_soc_dai_link_component *cpus = dai_link->cpus; struct snd_soc_dai_link_component *codecs = dai_link->codecs; + struct snd_soc_dai_link_component *platforms = dai_link->platforms; struct device_node *top = dev->of_node; struct device_node *node = of_get_parent(np); char *prefix = ""; @@ -162,8 +163,8 @@ static int simple_dai_link_of_dpcm(struct asoc_simple_priv *priv, if (ret < 0) goto out_put_node; - asoc_simple_canonicalize_cpu(dai_link, is_single_links); - asoc_simple_canonicalize_platform(dai_link); + asoc_simple_canonicalize_cpu(cpus, is_single_links); + asoc_simple_canonicalize_platform(platforms, cpus); } else { struct snd_soc_codec_conf *cconf; @@ -298,8 +299,8 @@ static int simple_dai_link_of(struct asoc_simple_priv *priv, dai_link->ops = &simple_ops; dai_link->init = asoc_simple_dai_init; - asoc_simple_canonicalize_cpu(dai_link, single_cpu); - asoc_simple_canonicalize_platform(dai_link); + asoc_simple_canonicalize_cpu(dai_link->cpus, single_cpu); + asoc_simple_canonicalize_platform(dai_link->platforms, dai_link->cpus); dai_link_of_err: of_node_put(plat); From 33cd6b191f1cdb5f332717a80ce26f661f53e924 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Mon, 12 Apr 2021 08:52:50 +0900 Subject: [PATCH 475/587] ASoC: simple-card-utils: tidyup debug info for clock simple-card / audio-graph can use clock as dai->clk or dai->sysclk. These related information should be indicated at same position. This patch tidyup it. Signed-off-by: Kuninori Morimoto Link: https://lore.kernel.org/r/87h7kcwf8t.wl-kuninori.morimoto.gx@renesas.com Signed-off-by: Mark Brown --- include/sound/simple_card_utils.h | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/include/sound/simple_card_utils.h b/include/sound/simple_card_utils.h index cccd9987a1b4..bf068803eb1f 100644 --- a/include/sound/simple_card_utils.h +++ b/include/sound/simple_card_utils.h @@ -191,12 +191,6 @@ static inline void asoc_simple_debug_dai(struct asoc_simple_priv *priv, if (dai->name) dev_dbg(dev, "%s dai name = %s\n", name, dai->name); - if (dai->sysclk) - dev_dbg(dev, "%s sysclk = %d\n", - name, dai->sysclk); - - dev_dbg(dev, "%s direction = %s\n", - name, dai->clk_direction ? "OUT" : "IN"); if (dai->slots) dev_dbg(dev, "%s slots = %d\n", name, dai->slots); @@ -208,6 +202,12 @@ static inline void asoc_simple_debug_dai(struct asoc_simple_priv *priv, dev_dbg(dev, "%s rx slot mask = %d\n", name, dai->rx_slot_mask); if (dai->clk) dev_dbg(dev, "%s clk %luHz\n", name, clk_get_rate(dai->clk)); + if (dai->sysclk) + dev_dbg(dev, "%s sysclk = %dHz\n", + name, dai->sysclk); + if (dai->clk || dai->sysclk) + dev_dbg(dev, "%s direction = %s\n", + name, dai->clk_direction ? "OUT" : "IN"); } static inline void asoc_simple_debug_info(struct asoc_simple_priv *priv) From 3919249e80995ed5f125f94d05fcb6171f79e732 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Mon, 12 Apr 2021 08:52:55 +0900 Subject: [PATCH 476/587] ASoC: simple-card-utils: tidyup dev_dbg() to use 1 line We can use 100 char now for 1 line. This patch tidyup unreadable dev_dbg() message. Signed-off-by: Kuninori Morimoto Link: https://lore.kernel.org/r/87fszwwf8o.wl-kuninori.morimoto.gx@renesas.com Signed-off-by: Mark Brown --- include/sound/simple_card_utils.h | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/include/sound/simple_card_utils.h b/include/sound/simple_card_utils.h index bf068803eb1f..20c22bffe091 100644 --- a/include/sound/simple_card_utils.h +++ b/include/sound/simple_card_utils.h @@ -241,17 +241,14 @@ static inline void asoc_simple_debug_info(struct asoc_simple_priv *priv) if (link->dai_fmt) dev_dbg(dev, "dai format = %04x\n", link->dai_fmt); if (props->adata.convert_rate) - dev_dbg(dev, "convert_rate = %d\n", - props->adata.convert_rate); + dev_dbg(dev, "convert_rate = %d\n", props->adata.convert_rate); if (props->adata.convert_channels) - dev_dbg(dev, "convert_channels = %d\n", - props->adata.convert_channels); + dev_dbg(dev, "convert_channels = %d\n", props->adata.convert_channels); for_each_prop_codec_conf(props, j, cnf) if (cnf->name_prefix) dev_dbg(dev, "name prefix = %s\n", cnf->name_prefix); if (props->mclk_fs) - dev_dbg(dev, "mclk-fs = %d\n", - props->mclk_fs); + dev_dbg(dev, "mclk-fs = %d\n", props->mclk_fs); } } #else From fcfd763bef4ff7f6371790979a6ceac9c4ac425a Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Mon, 12 Apr 2021 08:53:00 +0900 Subject: [PATCH 477/587] ASoC: simple-card-utils: tidyup asoc_simple_parse_convert() dev is not used. This patch removes it. Signed-off-by: Kuninori Morimoto Link: https://lore.kernel.org/r/87eefgwf8j.wl-kuninori.morimoto.gx@renesas.com Signed-off-by: Mark Brown --- include/sound/simple_card_utils.h | 3 +-- sound/soc/generic/audio-graph-card.c | 10 +++++----- sound/soc/generic/simple-card-utils.c | 3 +-- sound/soc/generic/simple-card.c | 8 ++++---- 4 files changed, 11 insertions(+), 13 deletions(-) diff --git a/include/sound/simple_card_utils.h b/include/sound/simple_card_utils.h index 20c22bffe091..fac3b832d982 100644 --- a/include/sound/simple_card_utils.h +++ b/include/sound/simple_card_utils.h @@ -160,8 +160,7 @@ int asoc_simple_clean_reference(struct snd_soc_card *card); void asoc_simple_convert_fixup(struct asoc_simple_data *data, struct snd_pcm_hw_params *params); -void asoc_simple_parse_convert(struct device *dev, - struct device_node *np, char *prefix, +void asoc_simple_parse_convert(struct device_node *np, char *prefix, struct asoc_simple_data *data); int asoc_simple_parse_routing(struct snd_soc_card *card, diff --git a/sound/soc/generic/audio-graph-card.c b/sound/soc/generic/audio-graph-card.c index e6b64fdbdc76..0582fe296471 100644 --- a/sound/soc/generic/audio-graph-card.c +++ b/sound/soc/generic/audio-graph-card.c @@ -180,11 +180,11 @@ static void graph_parse_convert(struct device *dev, struct device_node *ports = of_get_parent(port); struct device_node *node = of_graph_get_port_parent(ep); - asoc_simple_parse_convert(dev, top, NULL, adata); - asoc_simple_parse_convert(dev, node, PREFIX, adata); - asoc_simple_parse_convert(dev, ports, NULL, adata); - asoc_simple_parse_convert(dev, port, NULL, adata); - asoc_simple_parse_convert(dev, ep, NULL, adata); + asoc_simple_parse_convert(top, NULL, adata); + asoc_simple_parse_convert(node, PREFIX, adata); + asoc_simple_parse_convert(ports, NULL, adata); + asoc_simple_parse_convert(port, NULL, adata); + asoc_simple_parse_convert(ep, NULL, adata); of_node_put(port); of_node_put(ports); diff --git a/sound/soc/generic/simple-card-utils.c b/sound/soc/generic/simple-card-utils.c index a15956c25858..e1b7b30a4c8c 100644 --- a/sound/soc/generic/simple-card-utils.c +++ b/sound/soc/generic/simple-card-utils.c @@ -32,8 +32,7 @@ void asoc_simple_convert_fixup(struct asoc_simple_data *data, } EXPORT_SYMBOL_GPL(asoc_simple_convert_fixup); -void asoc_simple_parse_convert(struct device *dev, - struct device_node *np, +void asoc_simple_parse_convert(struct device_node *np, char *prefix, struct asoc_simple_data *data) { diff --git a/sound/soc/generic/simple-card.c b/sound/soc/generic/simple-card.c index 06b2d6a7f48d..bf5ddf1ea65f 100644 --- a/sound/soc/generic/simple-card.c +++ b/sound/soc/generic/simple-card.c @@ -84,10 +84,10 @@ static void simple_parse_convert(struct device *dev, struct device_node *top = dev->of_node; struct device_node *node = of_get_parent(np); - asoc_simple_parse_convert(dev, top, PREFIX, adata); - asoc_simple_parse_convert(dev, node, PREFIX, adata); - asoc_simple_parse_convert(dev, node, NULL, adata); - asoc_simple_parse_convert(dev, np, NULL, adata); + asoc_simple_parse_convert(top, PREFIX, adata); + asoc_simple_parse_convert(node, PREFIX, adata); + asoc_simple_parse_convert(node, NULL, adata); + asoc_simple_parse_convert(np, NULL, adata); of_node_put(node); } From 462c47c2fcc26d838c82646a31d6e3e8fc01ce68 Mon Sep 17 00:00:00 2001 From: Chen Lifu Date: Fri, 9 Apr 2021 09:59:53 +0800 Subject: [PATCH 478/587] ASoC: sti: sti_uniperif: add missing MODULE_DEVICE_TABLE This patch adds missing MODULE_DEVICE_TABLE definition which generates correct modalias for automatic loading of this driver when it is built as an external module. Reported-by: Hulk Robot Signed-off-by: Chen Lifu Reviewed-by: Arnaud Pouliquen Link: https://lore.kernel.org/r/20210409015953.259688-1-chenlifu@huawei.com Signed-off-by: Mark Brown --- sound/soc/sti/sti_uniperif.c | 1 + 1 file changed, 1 insertion(+) diff --git a/sound/soc/sti/sti_uniperif.c b/sound/soc/sti/sti_uniperif.c index 67315d9b352d..e3561f00ed40 100644 --- a/sound/soc/sti/sti_uniperif.c +++ b/sound/soc/sti/sti_uniperif.c @@ -97,6 +97,7 @@ static const struct of_device_id snd_soc_sti_match[] = { }, {}, }; +MODULE_DEVICE_TABLE(of, snd_soc_sti_match); int sti_uniperiph_reset(struct uniperif *uni) { From 38c694e98f6a6c8dfa48f2ba6f442363ed836efb Mon Sep 17 00:00:00 2001 From: Christophe JAILLET Date: Sun, 11 Apr 2021 14:51:06 +0200 Subject: [PATCH 479/587] ASoC: cs35l35: Fix an error handling path in 'cs35l35_i2c_probe()' If 'devm_regmap_init_i2c()' fails, there is no need to goto err. We should return directly as already done by the surrounding error handling paths. Signed-off-by: Christophe JAILLET Link: https://lore.kernel.org/r/15720439769ba94ffb65c90217392b0758b08f61.1618145369.git.christophe.jaillet@wanadoo.fr Signed-off-by: Mark Brown --- sound/soc/codecs/cs35l35.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sound/soc/codecs/cs35l35.c b/sound/soc/codecs/cs35l35.c index 55d529aa0011..7b9f5498f8a7 100644 --- a/sound/soc/codecs/cs35l35.c +++ b/sound/soc/codecs/cs35l35.c @@ -1488,7 +1488,7 @@ static int cs35l35_i2c_probe(struct i2c_client *i2c_client, if (IS_ERR(cs35l35->regmap)) { ret = PTR_ERR(cs35l35->regmap); dev_err(dev, "regmap_init() failed: %d\n", ret); - goto err; + return ret; } for (i = 0; i < ARRAY_SIZE(cs35l35_supplies); i++) From cdf20c3ef0e90b962e62ae7d835d7f46333285bc Mon Sep 17 00:00:00 2001 From: Christophe JAILLET Date: Sun, 11 Apr 2021 14:57:13 +0200 Subject: [PATCH 480/587] ASoC: cs35l36: Fix an error handling path in 'cs35l36_i2c_probe()' If 'devm_regmap_init_i2c()' fails, there is no need to goto err. We should return directly as already done by the surrounding error handling paths. Signed-off-by: Christophe JAILLET Link: https://lore.kernel.org/r/9fec48e75bc1d3c92626e6f6aca2344bda223379.1618145790.git.christophe.jaillet@wanadoo.fr Signed-off-by: Mark Brown --- sound/soc/codecs/cs35l36.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sound/soc/codecs/cs35l36.c b/sound/soc/codecs/cs35l36.c index 4451ca9f4916..a038bcec2d17 100644 --- a/sound/soc/codecs/cs35l36.c +++ b/sound/soc/codecs/cs35l36.c @@ -1721,7 +1721,7 @@ static int cs35l36_i2c_probe(struct i2c_client *i2c_client, if (IS_ERR(cs35l36->regmap)) { ret = PTR_ERR(cs35l36->regmap); dev_err(dev, "regmap_init() failed: %d\n", ret); - goto err; + return ret; } cs35l36->num_supplies = ARRAY_SIZE(cs35l36_supplies); From 543f8d780867bdbd8b0792487fa1644d89faa19c Mon Sep 17 00:00:00 2001 From: Jaroslav Kysela Date: Wed, 14 Apr 2021 12:58:58 +0200 Subject: [PATCH 481/587] ALSA: control_led - fix the stack usage (control element ops) It's a bad idea to allocate big structures on the stack. Mark the variables as static and add a note for the locking. Fixes: 22d8de62f11b ("ALSA: control - add generic LED trigger module as the new control layer") Cc: Nathan Chancellor Cc: Takashi Sakamoto Signed-off-by: Jaroslav Kysela Link: https://lore.kernel.org/r/20210414105858.1937710-1-perex@perex.cz Signed-off-by: Takashi Iwai --- sound/core/control_led.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/sound/core/control_led.c b/sound/core/control_led.c index 93b201063c7d..25f57c14f294 100644 --- a/sound/core/control_led.c +++ b/sound/core/control_led.c @@ -94,11 +94,15 @@ static struct snd_ctl_led *snd_ctl_led_get_by_access(unsigned int access) return &snd_ctl_leds[group]; } +/* + * A note for callers: + * The two static variables info and value are protected using snd_ctl_led_mutex. + */ static int snd_ctl_led_get(struct snd_ctl_led_ctl *lctl) { + static struct snd_ctl_elem_info info; + static struct snd_ctl_elem_value value; struct snd_kcontrol *kctl = lctl->kctl; - struct snd_ctl_elem_info info; - struct snd_ctl_elem_value value; unsigned int i; int result; From ebe8dc5afb3912e2d4f5c62cf7c492a13143a77a Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Wed, 14 Apr 2021 10:32:55 +0200 Subject: [PATCH 482/587] ALSA: usb-audio: Apply implicit feedback mode for BOSS devices During the recent rewrite of the implicit feedback support, we've tested to apply the implicit fb on BOSS devices, but it failed, as the capture stream didn't start without the playback. As the end result, it got another type of quirk for tying both streams but starts playback always (commit 6234fdc1cede "ALSA: usb-audio: Quirk for BOSS GT-001"). Meanwhile, Mike Oliphant has tested the real implicit feedback mode for the playback again with the latest code, and found out that it actually works if the initial feedback sync is skipped; that is, on those BOSS devices, the playback stream has to be started at first without waiting for the capture URB completions. Otherwise it gets stuck. In the rest operations after the capture stream processed, we can take them as the implicit feedback source. This patch is an attempt to improve the support for BOSS devices with the implicit feedback mode in the way described above. It adds a new flag to snd_usb_audio, playback_first, indicating that the playback stream starts without sync with the initial capture completion. This flag is set in the quirk table with the new IMPLICIT_FB_BOTH type. Reported-and-tested-by: Mike Oliphant Link: https://lore.kernel.org/r/20210414083255.9527-1-tiwai@suse.de Signed-off-by: Takashi Iwai --- sound/usb/endpoint.c | 3 ++- sound/usb/implicit.c | 35 +++++++++++++++++++++++------------ sound/usb/usbaudio.h | 1 + 3 files changed, 26 insertions(+), 13 deletions(-) diff --git a/sound/usb/endpoint.c b/sound/usb/endpoint.c index 102d53515a76..f4c3d2b38abb 100644 --- a/sound/usb/endpoint.c +++ b/sound/usb/endpoint.c @@ -1375,7 +1375,8 @@ int snd_usb_endpoint_start(struct snd_usb_endpoint *ep) if (!ep_state_update(ep, EP_STATE_STOPPED, EP_STATE_RUNNING)) goto __error; - if (snd_usb_endpoint_implicit_feedback_sink(ep)) { + if (snd_usb_endpoint_implicit_feedback_sink(ep) && + !ep->chip->playback_first) { for (i = 0; i < ep->nurbs; i++) { struct snd_urb_ctx *ctx = ep->urb + i; list_add_tail(&ctx->ready_list, &ep->ready_playback_urbs); diff --git a/sound/usb/implicit.c b/sound/usb/implicit.c index 19622c58b72b..4bd9c105a529 100644 --- a/sound/usb/implicit.c +++ b/sound/usb/implicit.c @@ -21,6 +21,7 @@ enum { IMPLICIT_FB_NONE, IMPLICIT_FB_GENERIC, IMPLICIT_FB_FIXED, + IMPLICIT_FB_BOTH, /* generic playback + capture (for BOSS) */ }; struct snd_usb_implicit_fb_match { @@ -36,6 +37,9 @@ struct snd_usb_implicit_fb_match { #define IMPLICIT_FB_FIXED_DEV(vend, prod, ep, ifnum) \ { .id = USB_ID(vend, prod), .type = IMPLICIT_FB_FIXED, .ep_num = (ep),\ .iface = (ifnum) } +#define IMPLICIT_FB_BOTH_DEV(vend, prod, ep, ifnum) \ + { .id = USB_ID(vend, prod), .type = IMPLICIT_FB_BOTH, .ep_num = (ep),\ + .iface = (ifnum) } #define IMPLICIT_FB_SKIP_DEV(vend, prod) \ { .id = USB_ID(vend, prod), .type = IMPLICIT_FB_NONE } @@ -75,14 +79,14 @@ static const struct snd_usb_implicit_fb_match playback_implicit_fb_quirks[] = { /* Implicit feedback quirk table for capture: only FIXED type */ static const struct snd_usb_implicit_fb_match capture_implicit_fb_quirks[] = { - IMPLICIT_FB_FIXED_DEV(0x0582, 0x0130, 0x0d, 0x01), /* BOSS BR-80 */ - IMPLICIT_FB_FIXED_DEV(0x0582, 0x0171, 0x0d, 0x01), /* BOSS RC-505 */ - IMPLICIT_FB_FIXED_DEV(0x0582, 0x0185, 0x0d, 0x01), /* BOSS GP-10 */ - IMPLICIT_FB_FIXED_DEV(0x0582, 0x0189, 0x0d, 0x01), /* BOSS GT-100v2 */ - IMPLICIT_FB_FIXED_DEV(0x0582, 0x01d6, 0x0d, 0x01), /* BOSS GT-1 */ - IMPLICIT_FB_FIXED_DEV(0x0582, 0x01d8, 0x0d, 0x01), /* BOSS Katana */ - IMPLICIT_FB_FIXED_DEV(0x0582, 0x01e5, 0x0d, 0x01), /* BOSS GT-001 */ - IMPLICIT_FB_FIXED_DEV(0x0582, 0x0203, 0x0d, 0x01), /* BOSS AD-10 */ + IMPLICIT_FB_BOTH_DEV(0x0582, 0x0130, 0x0d, 0x01), /* BOSS BR-80 */ + IMPLICIT_FB_BOTH_DEV(0x0582, 0x0171, 0x0d, 0x01), /* BOSS RC-505 */ + IMPLICIT_FB_BOTH_DEV(0x0582, 0x0185, 0x0d, 0x01), /* BOSS GP-10 */ + IMPLICIT_FB_BOTH_DEV(0x0582, 0x0189, 0x0d, 0x01), /* BOSS GT-100v2 */ + IMPLICIT_FB_BOTH_DEV(0x0582, 0x01d6, 0x0d, 0x01), /* BOSS GT-1 */ + IMPLICIT_FB_BOTH_DEV(0x0582, 0x01d8, 0x0d, 0x01), /* BOSS Katana */ + IMPLICIT_FB_BOTH_DEV(0x0582, 0x01e5, 0x0d, 0x01), /* BOSS GT-001 */ + IMPLICIT_FB_BOTH_DEV(0x0582, 0x0203, 0x0d, 0x01), /* BOSS AD-10 */ {} /* terminator */ }; @@ -268,10 +272,17 @@ static int audioformat_implicit_fb_quirk(struct snd_usb_audio *chip, } } - /* Don't apply playback quirks for the devices with capture quirk */ + /* Special handling for devices with capture quirks */ p = find_implicit_fb_entry(chip, capture_implicit_fb_quirks, alts); - if (p && p->type == IMPLICIT_FB_FIXED) - return 0; /* no quirk */ + if (p) { + switch (p->type) { + case IMPLICIT_FB_FIXED: + return 0; /* no quirk */ + case IMPLICIT_FB_BOTH: + chip->playback_first = 1; + return add_generic_implicit_fb(chip, fmt, alts); + } + } /* Generic UAC2 implicit feedback */ if (attr == USB_ENDPOINT_SYNC_ASYNC && @@ -321,7 +332,7 @@ static int audioformat_capture_quirk(struct snd_usb_audio *chip, const struct snd_usb_implicit_fb_match *p; p = find_implicit_fb_entry(chip, capture_implicit_fb_quirks, alts); - if (p && p->type == IMPLICIT_FB_FIXED) + if (p && (p->type == IMPLICIT_FB_FIXED || p->type == IMPLICIT_FB_BOTH)) return add_implicit_fb_sync_ep(chip, fmt, p->ep_num, 0, p->iface, NULL); return 0; diff --git a/sound/usb/usbaudio.h b/sound/usb/usbaudio.h index a536ee33d36e..538831cbd925 100644 --- a/sound/usb/usbaudio.h +++ b/sound/usb/usbaudio.h @@ -37,6 +37,7 @@ struct snd_usb_audio { unsigned int txfr_quirk:1; /* Subframe boundaries on transfers */ unsigned int tx_length_quirk:1; /* Put length specifier in transfers */ unsigned int need_delayed_register:1; /* warn for delayed registration */ + unsigned int playback_first:1; /* for implicit fb: don't wait for the first capture URBs */ int num_interfaces; int num_suspended_intf; int sample_rate_read_error; From a122a116fc6d8fcf2f202dcd185173a54268f239 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Thu, 8 Apr 2021 13:28:38 +0900 Subject: [PATCH 483/587] ASoC: rsnd: call rsnd_ssi_master_clk_start() from rsnd_ssi_init() Current rsnd needs to call .prepare (P) for clock settings, .trigger for playback start (S) and stop (E). It should be called as below from SSI point of view. P -> S -> E -> P -> S -> E -> ... But, if you used MIXer, below case might happen (2) 1: P -> S ---> E -> ... 2: P ----> S -> ... (1) (3) P(1) setups clock, but E(2) resets it. and starts playback (3). In such case, it will reports "SSI parent/child should use same rate". rsnd_ssi_master_clk_start() which is the main function at (P) was called from rsnd_ssi_init() (= S) before, but was moved by below patch to rsnd_soc_dai_prepare() (= P) to avoid using clk_get_rate() which shouldn't be used under atomic context. commit 4d230d1271064 ("ASoC: rsnd: fixup not to call clk_get/set under non-atomic") Because of above patch, rsnd_ssi_master_clk_start() is now called at (P) which is for non atomic context. But (P) is assuming that spin lock is *not* used. One issue now is rsnd_ssi_master_clk_start() is checking ssi->xxx which should be protected by spin lock. After above patch, adg.c had below patch for other reasons. commit 06e8f5c842f2d ("ASoC: rsnd: don't call clk_get_rate() under atomic context") clk_get_rate() is used at probe() timing by this patch. In other words, rsnd_ssi_master_clk_start() is no longer using clk_get_rate() any more. This means we can call it from rsnd_ssi_init() (= S) again which is protected by spin lock. This patch re-move it to under spin lock, and solves 1. checking ssi->xxx without spin lock issue. 2. clk setting / device start / device stop race condition. Reported-by: Linh Phung T. Y. Signed-off-by: Kuninori Morimoto Link: https://lore.kernel.org/r/875z0x1jt5.wl-kuninori.morimoto.gx@renesas.com Signed-off-by: Mark Brown --- sound/soc/sh/rcar/ssi.c | 14 +++++--------- 1 file changed, 5 insertions(+), 9 deletions(-) diff --git a/sound/soc/sh/rcar/ssi.c b/sound/soc/sh/rcar/ssi.c index d071cec25f71..048d53566127 100644 --- a/sound/soc/sh/rcar/ssi.c +++ b/sound/soc/sh/rcar/ssi.c @@ -506,10 +506,15 @@ static int rsnd_ssi_init(struct rsnd_mod *mod, struct rsnd_priv *priv) { struct rsnd_ssi *ssi = rsnd_mod_to_ssi(mod); + int ret; if (!rsnd_ssi_is_run_mods(mod, io)) return 0; + ret = rsnd_ssi_master_clk_start(mod, io); + if (ret < 0) + return ret; + ssi->usrcnt++; rsnd_mod_power_on(mod); @@ -1060,13 +1065,6 @@ static int rsnd_ssi_pio_pointer(struct rsnd_mod *mod, return 0; } -static int rsnd_ssi_prepare(struct rsnd_mod *mod, - struct rsnd_dai_stream *io, - struct rsnd_priv *priv) -{ - return rsnd_ssi_master_clk_start(mod, io); -} - static struct rsnd_mod_ops rsnd_ssi_pio_ops = { .name = SSI_NAME, .probe = rsnd_ssi_common_probe, @@ -1079,7 +1077,6 @@ static struct rsnd_mod_ops rsnd_ssi_pio_ops = { .pointer = rsnd_ssi_pio_pointer, .pcm_new = rsnd_ssi_pcm_new, .hw_params = rsnd_ssi_hw_params, - .prepare = rsnd_ssi_prepare, .get_status = rsnd_ssi_get_status, }; @@ -1166,7 +1163,6 @@ static struct rsnd_mod_ops rsnd_ssi_dma_ops = { .pcm_new = rsnd_ssi_pcm_new, .fallback = rsnd_ssi_fallback, .hw_params = rsnd_ssi_hw_params, - .prepare = rsnd_ssi_prepare, .get_status = rsnd_ssi_get_status, }; From a4856e15e58b54977f1c0c0299309ad4d1f13365 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Thu, 8 Apr 2021 13:28:47 +0900 Subject: [PATCH 484/587] ASoC: rsnd: check all BUSIF status when error commit 66c705d07d784 ("SoC: rsnd: add interrupt support for SSI BUSIF buffer") adds __rsnd_ssi_interrupt() checks for BUSIF status, but is using "break" at for loop. This means it is not checking all status. Let's check all BUSIF status. Fixes: commit 66c705d07d784 ("SoC: rsnd: add interrupt support for SSI BUSIF buffer") Signed-off-by: Kuninori Morimoto Link: https://lore.kernel.org/r/874kgh1jsw.wl-kuninori.morimoto.gx@renesas.com Signed-off-by: Mark Brown --- sound/soc/sh/rcar/ssi.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/sound/soc/sh/rcar/ssi.c b/sound/soc/sh/rcar/ssi.c index 048d53566127..9a3310393989 100644 --- a/sound/soc/sh/rcar/ssi.c +++ b/sound/soc/sh/rcar/ssi.c @@ -797,7 +797,6 @@ static void __rsnd_ssi_interrupt(struct rsnd_mod *mod, SSI_SYS_STATUS(i * 2), 0xf << (id * 4)); stop = true; - break; } } break; @@ -815,7 +814,6 @@ static void __rsnd_ssi_interrupt(struct rsnd_mod *mod, SSI_SYS_STATUS((i * 2) + 1), 0xf << 4); stop = true; - break; } } break; From 691b379cbe348fbead33e49d1c1d0f045a2e3446 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Thu, 8 Apr 2021 13:28:55 +0900 Subject: [PATCH 485/587] ASoC: rsnd: add rsnd_ssi_busif_err_status_clear() Current ssi.c clears BUSIF error status at __rsnd_ssi_interrupt(), but its code is verbose. This patch off-load it to rsnd_ssi_busif_err_status_clear(). Signed-off-by: Kuninori Morimoto Link: https://lore.kernel.org/r/8735w11jso.wl-kuninori.morimoto.gx@renesas.com Signed-off-by: Mark Brown --- sound/soc/sh/rcar/ssi.c | 97 ++++++++++++++++++++++------------------- 1 file changed, 51 insertions(+), 46 deletions(-) diff --git a/sound/soc/sh/rcar/ssi.c b/sound/soc/sh/rcar/ssi.c index 9a3310393989..4af024917f03 100644 --- a/sound/soc/sh/rcar/ssi.c +++ b/sound/soc/sh/rcar/ssi.c @@ -359,6 +359,55 @@ static void rsnd_ssi_master_clk_stop(struct rsnd_mod *mod, rsnd_adg_ssi_clk_stop(mod); } +static bool rsnd_ssi_busif_err_status_clear(struct rsnd_mod *mod) +{ + struct rsnd_priv *priv = rsnd_mod_to_priv(mod); + struct device *dev = rsnd_priv_to_dev(priv); + u32 status; + bool stop = false; + int id = rsnd_mod_id(mod); + int i; + + switch (id) { + case 0: + case 1: + case 2: + case 3: + case 4: + for (i = 0; i < 4; i++) { + status = rsnd_mod_read(mod, SSI_SYS_STATUS(i * 2)); + status &= 0xf << (id * 4); + + if (status) { + rsnd_dbg_irq_status(dev, "%s err status : 0x%08x\n", + rsnd_mod_name(mod), status); + rsnd_mod_write(mod, + SSI_SYS_STATUS(i * 2), + 0xf << (id * 4)); + stop = true; + } + } + break; + case 9: + for (i = 0; i < 4; i++) { + status = rsnd_mod_read(mod, SSI_SYS_STATUS((i * 2) + 1)); + status &= 0xf << 4; + + if (status) { + rsnd_dbg_irq_status(dev, "%s err status : 0x%08x\n", + rsnd_mod_name(mod), status); + rsnd_mod_write(mod, + SSI_SYS_STATUS((i * 2) + 1), + 0xf << 4); + stop = true; + } + } + break; + } + + return stop; +} + static void rsnd_ssi_config_init(struct rsnd_mod *mod, struct rsnd_dai_stream *io) { @@ -748,8 +797,6 @@ static void __rsnd_ssi_interrupt(struct rsnd_mod *mod, u32 status; bool elapsed = false; bool stop = false; - int id = rsnd_mod_id(mod); - int i; int is_tdm, is_tdm_split; is_tdm = rsnd_runtime_is_tdm(io); @@ -775,50 +822,8 @@ static void __rsnd_ssi_interrupt(struct rsnd_mod *mod, stop = true; } - status = 0; - - if (is_tdm || is_tdm_split) { - switch (id) { - case 0: - case 1: - case 2: - case 3: - case 4: - for (i = 0; i < 4; i++) { - status = rsnd_mod_read(mod, - SSI_SYS_STATUS(i * 2)); - status &= 0xf << (id * 4); - - if (status) { - rsnd_dbg_irq_status(dev, - "%s err status : 0x%08x\n", - rsnd_mod_name(mod), status); - rsnd_mod_write(mod, - SSI_SYS_STATUS(i * 2), - 0xf << (id * 4)); - stop = true; - } - } - break; - case 9: - for (i = 0; i < 4; i++) { - status = rsnd_mod_read(mod, - SSI_SYS_STATUS((i * 2) + 1)); - status &= 0xf << 4; - - if (status) { - rsnd_dbg_irq_status(dev, - "%s err status : 0x%08x\n", - rsnd_mod_name(mod), status); - rsnd_mod_write(mod, - SSI_SYS_STATUS((i * 2) + 1), - 0xf << 4); - stop = true; - } - } - break; - } - } + if (is_tdm || is_tdm_split) + stop |= rsnd_ssi_busif_err_status_clear(mod); rsnd_ssi_status_clear(mod); rsnd_ssi_interrupt_out: From 15c57ce07ce207069f1cd57ec117b11871f3afa6 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Thu, 8 Apr 2021 13:29:08 +0900 Subject: [PATCH 486/587] ASoC: rsnd: add rsnd_ssi_busif_err_irq_enable/disable() Current ssi.c has duplicated code to control BUSIF over/under run interrupt. This patch adds new rsnd_ssi_busif_err_irq_enable/disable() and share the code. Signed-off-by: Kuninori Morimoto Cc: Yongbo Zhang Cc: Chen Li Link: https://lore.kernel.org/r/871rbl1jsb.wl-kuninori.morimoto.gx@renesas.com Signed-off-by: Mark Brown --- sound/soc/sh/rcar/ssi.c | 112 ++++++++++++++++------------------------ 1 file changed, 45 insertions(+), 67 deletions(-) diff --git a/sound/soc/sh/rcar/ssi.c b/sound/soc/sh/rcar/ssi.c index 4af024917f03..e29482c26d6a 100644 --- a/sound/soc/sh/rcar/ssi.c +++ b/sound/soc/sh/rcar/ssi.c @@ -359,6 +359,47 @@ static void rsnd_ssi_master_clk_stop(struct rsnd_mod *mod, rsnd_adg_ssi_clk_stop(mod); } +/* enable busif buffer over/under run interrupt. */ +#define rsnd_ssi_busif_err_irq_enable(mod) rsnd_ssi_busif_err_irq_ctrl(mod, 1) +#define rsnd_ssi_busif_err_irq_disable(mod) rsnd_ssi_busif_err_irq_ctrl(mod, 0) +static void rsnd_ssi_busif_err_irq_ctrl(struct rsnd_mod *mod, int enable) +{ + u32 sys_int_enable = 0; + int id = rsnd_mod_id(mod); + int i; + + switch (id) { + case 0: + case 1: + case 2: + case 3: + case 4: + for (i = 0; i < 4; i++) { + sys_int_enable = rsnd_mod_read(mod, SSI_SYS_INT_ENABLE(i * 2)); + if (enable) + sys_int_enable |= 0xf << (id * 4); + else + sys_int_enable &= ~(0xf << (id * 4)); + rsnd_mod_write(mod, + SSI_SYS_INT_ENABLE(i * 2), + sys_int_enable); + } + break; + case 9: + for (i = 0; i < 4; i++) { + sys_int_enable = rsnd_mod_read(mod, SSI_SYS_INT_ENABLE((i * 2) + 1)); + if (enable) + sys_int_enable |= 0xf << 4; + else + sys_int_enable &= ~(0xf << 4); + rsnd_mod_write(mod, + SSI_SYS_INT_ENABLE((i * 2) + 1), + sys_int_enable); + } + break; + } +} + static bool rsnd_ssi_busif_err_status_clear(struct rsnd_mod *mod) { struct rsnd_priv *priv = rsnd_mod_to_priv(mod); @@ -421,9 +462,6 @@ static void rsnd_ssi_config_init(struct rsnd_mod *mod, u32 wsr = ssi->wsr; int width; int is_tdm, is_tdm_split; - int id = rsnd_mod_id(mod); - int i; - u32 sys_int_enable = 0; is_tdm = rsnd_runtime_is_tdm(io); is_tdm_split = rsnd_runtime_is_tdm_split(io); @@ -499,36 +537,8 @@ static void rsnd_ssi_config_init(struct rsnd_mod *mod, } /* enable busif buffer over/under run interrupt. */ - if (is_tdm || is_tdm_split) { - switch (id) { - case 0: - case 1: - case 2: - case 3: - case 4: - for (i = 0; i < 4; i++) { - sys_int_enable = rsnd_mod_read(mod, - SSI_SYS_INT_ENABLE(i * 2)); - sys_int_enable |= 0xf << (id * 4); - rsnd_mod_write(mod, - SSI_SYS_INT_ENABLE(i * 2), - sys_int_enable); - } - - break; - case 9: - for (i = 0; i < 4; i++) { - sys_int_enable = rsnd_mod_read(mod, - SSI_SYS_INT_ENABLE((i * 2) + 1)); - sys_int_enable |= 0xf << 4; - rsnd_mod_write(mod, - SSI_SYS_INT_ENABLE((i * 2) + 1), - sys_int_enable); - } - - break; - } - } + if (is_tdm || is_tdm_split) + rsnd_ssi_busif_err_irq_enable(mod); init_end: ssi->cr_own = cr_own; @@ -585,8 +595,6 @@ static int rsnd_ssi_quit(struct rsnd_mod *mod, struct rsnd_ssi *ssi = rsnd_mod_to_ssi(mod); struct device *dev = rsnd_priv_to_dev(priv); int is_tdm, is_tdm_split; - int id = rsnd_mod_id(mod); - u32 sys_int_enable = 0; is_tdm = rsnd_runtime_is_tdm(io); is_tdm_split = rsnd_runtime_is_tdm_split(io); @@ -612,38 +620,8 @@ static int rsnd_ssi_quit(struct rsnd_mod *mod, } /* disable busif buffer over/under run interrupt. */ - if (is_tdm || is_tdm_split) { - int i; - - switch (id) { - case 0: - case 1: - case 2: - case 3: - case 4: - for (i = 0; i < 4; i++) { - sys_int_enable = rsnd_mod_read(mod, - SSI_SYS_INT_ENABLE(i * 2)); - sys_int_enable &= ~(0xf << (id * 4)); - rsnd_mod_write(mod, - SSI_SYS_INT_ENABLE(i * 2), - sys_int_enable); - } - - break; - case 9: - for (i = 0; i < 4; i++) { - sys_int_enable = rsnd_mod_read(mod, - SSI_SYS_INT_ENABLE((i * 2) + 1)); - sys_int_enable &= ~(0xf << 4); - rsnd_mod_write(mod, - SSI_SYS_INT_ENABLE((i * 2) + 1), - sys_int_enable); - } - - break; - } - } + if (is_tdm || is_tdm_split) + rsnd_ssi_busif_err_irq_disable(mod); return 0; } From 63346d3d2f7cd96746149b9710a4cc5401c0cb5c Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Thu, 8 Apr 2021 13:29:15 +0900 Subject: [PATCH 487/587] ASoC: rsnd: add usage for SRC This patch add missing usage comment for SRC. Signed-off-by: Kuninori Morimoto Link: https://lore.kernel.org/r/87zgy9z9es.wl-kuninori.morimoto.gx@renesas.com Signed-off-by: Mark Brown --- sound/soc/sh/rcar/src.c | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/sound/soc/sh/rcar/src.c b/sound/soc/sh/rcar/src.c index 585ffba0244b..628af8f3920d 100644 --- a/sound/soc/sh/rcar/src.c +++ b/sound/soc/sh/rcar/src.c @@ -5,6 +5,15 @@ // Copyright (C) 2013 Renesas Solutions Corp. // Kuninori Morimoto +/* + * You can use Synchronous Sampling Rate Convert (if no DVC) + * + * amixer set "SRC Out Rate" on + * aplay xxx.wav & + * amixer set "SRC Out Rate" 96000 // convert rate to 96000Hz + * amixer set "SRC Out Rate" 22050 // convert rate to 22050Hz + */ + /* * you can enable below define if you don't need * SSI interrupt status debug message when debugging From 0b93bbc977af55fd10687f2c96c807cba95cb927 Mon Sep 17 00:00:00 2001 From: Shengjiu Wang Date: Wed, 14 Apr 2021 14:33:43 +0800 Subject: [PATCH 488/587] ASoC: ak5558: correct reset polarity Reset (aka power off) happens when the reset gpio is made active. The reset gpio is GPIO_ACTIVE_LOW Fixes: 920884777480 ("ASoC: ak5558: Add support for AK5558 ADC driver") Signed-off-by: Shengjiu Wang Link: https://lore.kernel.org/r/1618382024-31725-1-git-send-email-shengjiu.wang@nxp.com Signed-off-by: Mark Brown --- sound/soc/codecs/ak5558.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/sound/soc/codecs/ak5558.c b/sound/soc/codecs/ak5558.c index 8e4dca753f0b..f24d91b728dd 100644 --- a/sound/soc/codecs/ak5558.c +++ b/sound/soc/codecs/ak5558.c @@ -323,7 +323,7 @@ static void ak5558_power_off(struct ak5558_priv *ak5558) if (!ak5558->reset_gpiod) return; - gpiod_set_value_cansleep(ak5558->reset_gpiod, 0); + gpiod_set_value_cansleep(ak5558->reset_gpiod, 1); usleep_range(1000, 2000); } @@ -332,7 +332,7 @@ static void ak5558_power_on(struct ak5558_priv *ak5558) if (!ak5558->reset_gpiod) return; - gpiod_set_value_cansleep(ak5558->reset_gpiod, 1); + gpiod_set_value_cansleep(ak5558->reset_gpiod, 0); usleep_range(1000, 2000); } From 4d5d75ce2b32577afef26a233119d8ee1b764ea7 Mon Sep 17 00:00:00 2001 From: Shengjiu Wang Date: Wed, 14 Apr 2021 14:33:44 +0800 Subject: [PATCH 489/587] ASoC: ak5558: change function name to ak5558_reset Change function name to ak5558_reset to match devicetree property "reset-gpios". Signed-off-by: Shengjiu Wang Link: https://lore.kernel.org/r/1618382024-31725-2-git-send-email-shengjiu.wang@nxp.com Signed-off-by: Mark Brown --- sound/soc/codecs/ak5558.c | 23 +++++++---------------- 1 file changed, 7 insertions(+), 16 deletions(-) diff --git a/sound/soc/codecs/ak5558.c b/sound/soc/codecs/ak5558.c index f24d91b728dd..34aed80db0eb 100644 --- a/sound/soc/codecs/ak5558.c +++ b/sound/soc/codecs/ak5558.c @@ -318,21 +318,12 @@ static struct snd_soc_dai_driver ak5552_dai = { .ops = &ak5558_dai_ops, }; -static void ak5558_power_off(struct ak5558_priv *ak5558) +static void ak5558_reset(struct ak5558_priv *ak5558, bool active) { if (!ak5558->reset_gpiod) return; - gpiod_set_value_cansleep(ak5558->reset_gpiod, 1); - usleep_range(1000, 2000); -} - -static void ak5558_power_on(struct ak5558_priv *ak5558) -{ - if (!ak5558->reset_gpiod) - return; - - gpiod_set_value_cansleep(ak5558->reset_gpiod, 0); + gpiod_set_value_cansleep(ak5558->reset_gpiod, active); usleep_range(1000, 2000); } @@ -340,7 +331,7 @@ static int ak5558_probe(struct snd_soc_component *component) { struct ak5558_priv *ak5558 = snd_soc_component_get_drvdata(component); - ak5558_power_on(ak5558); + ak5558_reset(ak5558, false); return ak5558_set_mcki(component); } @@ -348,7 +339,7 @@ static void ak5558_remove(struct snd_soc_component *component) { struct ak5558_priv *ak5558 = snd_soc_component_get_drvdata(component); - ak5558_power_off(ak5558); + ak5558_reset(ak5558, true); } static int __maybe_unused ak5558_runtime_suspend(struct device *dev) @@ -356,7 +347,7 @@ static int __maybe_unused ak5558_runtime_suspend(struct device *dev) struct ak5558_priv *ak5558 = dev_get_drvdata(dev); regcache_cache_only(ak5558->regmap, true); - ak5558_power_off(ak5558); + ak5558_reset(ak5558, true); regulator_bulk_disable(ARRAY_SIZE(ak5558->supplies), ak5558->supplies); @@ -375,8 +366,8 @@ static int __maybe_unused ak5558_runtime_resume(struct device *dev) return ret; } - ak5558_power_off(ak5558); - ak5558_power_on(ak5558); + ak5558_reset(ak5558, true); + ak5558_reset(ak5558, false); regcache_cache_only(ak5558->regmap, false); regcache_mark_dirty(ak5558->regmap); From e42b6e813f4231d3c38362fd800724bd41040ef9 Mon Sep 17 00:00:00 2001 From: Yang Li Date: Wed, 14 Apr 2021 14:14:43 +0800 Subject: [PATCH 490/587] ASoC: cs35l35: remove unused including Fix the following versioncheck warning: ./sound/soc/codecs/cs35l35.c: 12 linux/version.h not needed. Reported-by: Abaci Robot Signed-off-by: Yang Li Link: https://lore.kernel.org/r/1618380883-114841-1-git-send-email-yang.lee@linux.alibaba.com Signed-off-by: Mark Brown --- sound/soc/codecs/cs35l35.c | 1 - 1 file changed, 1 deletion(-) diff --git a/sound/soc/codecs/cs35l35.c b/sound/soc/codecs/cs35l35.c index 7b9f5498f8a7..f20ed838b958 100644 --- a/sound/soc/codecs/cs35l35.c +++ b/sound/soc/codecs/cs35l35.c @@ -9,7 +9,6 @@ #include #include -#include #include #include #include From b5fb388da472a69858355560d803602e0ace1006 Mon Sep 17 00:00:00 2001 From: Nico Pache Date: Wed, 14 Apr 2021 04:58:04 -0400 Subject: [PATCH 491/587] ASoC: topology: adhere to KUNIT formatting standard Drop 'S' from end of SND_SOC_TOPOLOGY_KUNIT_TESTS inorder to adhear to the KUNIT *_KUNIT_TEST config name format. Signed-off-by: Nico Pache Link: https://lore.kernel.org/r/dcf79e592f9a7e14483dde32ac561f6af2632e50.1618388989.git.npache@redhat.com Signed-off-by: Mark Brown --- sound/soc/Kconfig | 2 +- sound/soc/Makefile | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/sound/soc/Kconfig b/sound/soc/Kconfig index 640494f76cbd..8a13462e1a63 100644 --- a/sound/soc/Kconfig +++ b/sound/soc/Kconfig @@ -37,7 +37,7 @@ config SND_SOC_COMPRESS config SND_SOC_TOPOLOGY bool -config SND_SOC_TOPOLOGY_KUNIT_TESTS +config SND_SOC_TOPOLOGY_KUNIT_TEST tristate "KUnit tests for SoC topology" depends on KUNIT depends on SND_SOC_TOPOLOGY diff --git a/sound/soc/Makefile b/sound/soc/Makefile index f56ad996eae8..a7b37c06dc43 100644 --- a/sound/soc/Makefile +++ b/sound/soc/Makefile @@ -7,9 +7,9 @@ ifneq ($(CONFIG_SND_SOC_TOPOLOGY),) snd-soc-core-objs += soc-topology.o endif -ifneq ($(CONFIG_SND_SOC_TOPOLOGY_KUNIT_TESTS),) +ifneq ($(CONFIG_SND_SOC_TOPOLOGY_KUNIT_TEST),) # snd-soc-test-objs := soc-topology-test.o -obj-$(CONFIG_SND_SOC_TOPOLOGY_KUNIT_TESTS) := soc-topology-test.o +obj-$(CONFIG_SND_SOC_TOPOLOGY_KUNIT_TEST) := soc-topology-test.o endif ifneq ($(CONFIG_SND_SOC_GENERIC_DMAENGINE_PCM),) From 8cbea89e2fba2f92937cd15211490b62f14a46ff Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Wed, 14 Apr 2021 08:19:55 +0900 Subject: [PATCH 492/587] ASoC: simple-card: remove unused variable from simple_parse_of() commit d9ffff696c5b4 ("ASoC: simple-card: Use snd_soc_of_parse_aux_devs()") switched to use snd_soc_of_parse_aux_devs() on simple_parse_of(). Thus noone is using *top anymore. Let's cleanup unused variable. Signed-off-by: Kuninori Morimoto Link: https://lore.kernel.org/r/87pmyxzs9w.wl-kuninori.morimoto.gx@renesas.com Signed-off-by: Mark Brown --- sound/soc/generic/simple-card.c | 5 ----- 1 file changed, 5 deletions(-) diff --git a/sound/soc/generic/simple-card.c b/sound/soc/generic/simple-card.c index bf5ddf1ea65f..7a87cd56d513 100644 --- a/sound/soc/generic/simple-card.c +++ b/sound/soc/generic/simple-card.c @@ -441,15 +441,10 @@ static int simple_for_each_link(struct asoc_simple_priv *priv, static int simple_parse_of(struct asoc_simple_priv *priv) { - struct device *dev = simple_priv_to_dev(priv); - struct device_node *top = dev->of_node; struct snd_soc_card *card = simple_priv_to_card(priv); struct link_info li; int ret; - if (!top) - return -EINVAL; - ret = asoc_simple_parse_widgets(card, PREFIX); if (ret < 0) return ret; From 5bb5ac71e3f4f85500b96ea03e54bf6e2d8be3f2 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Wed, 14 Apr 2021 08:20:04 +0900 Subject: [PATCH 493/587] ASoC: simple-card: use asoc_link_to_xxx() macro We shouldn't use dai_link->cpus/codecs/platforms directly, because these are array now to supporting multi CPU/Codec/Platform. This patch uses asoc_link_to_xxx() macro for it. Signed-off-by: Kuninori Morimoto Link: https://lore.kernel.org/r/87o8ehzs9n.wl-kuninori.morimoto.gx@renesas.com Signed-off-by: Mark Brown --- sound/soc/generic/simple-card.c | 35 ++++++++++++++++++--------------- 1 file changed, 19 insertions(+), 16 deletions(-) diff --git a/sound/soc/generic/simple-card.c b/sound/soc/generic/simple-card.c index 7a87cd56d513..9462b0d21486 100644 --- a/sound/soc/generic/simple-card.c +++ b/sound/soc/generic/simple-card.c @@ -122,9 +122,9 @@ static int simple_dai_link_of_dpcm(struct asoc_simple_priv *priv, struct snd_soc_dai_link *dai_link = simple_priv_to_link(priv, li->link); struct simple_dai_props *dai_props = simple_priv_to_props(priv, li->link); struct asoc_simple_dai *dai; - struct snd_soc_dai_link_component *cpus = dai_link->cpus; - struct snd_soc_dai_link_component *codecs = dai_link->codecs; - struct snd_soc_dai_link_component *platforms = dai_link->platforms; + struct snd_soc_dai_link_component *cpus = asoc_link_to_cpu(dai_link, 0); + struct snd_soc_dai_link_component *codecs = asoc_link_to_codec(dai_link, 0); + struct snd_soc_dai_link_component *platforms = asoc_link_to_platform(dai_link, 0); struct device_node *top = dev->of_node; struct device_node *node = of_get_parent(np); char *prefix = ""; @@ -149,11 +149,11 @@ static int simple_dai_link_of_dpcm(struct asoc_simple_priv *priv, dai = dai_props->cpu_dai; - ret = asoc_simple_parse_dai(np, dai_link->cpus, &is_single_links); + ret = asoc_simple_parse_dai(np, cpus, &is_single_links); if (ret) goto out_put_node; - ret = asoc_simple_parse_clk(dev, np, dai, dai_link->cpus); + ret = asoc_simple_parse_clk(dev, np, dai, cpus); if (ret < 0) goto out_put_node; @@ -177,11 +177,11 @@ static int simple_dai_link_of_dpcm(struct asoc_simple_priv *priv, dai = dai_props->codec_dai; cconf = dai_props->codec_conf; - ret = asoc_simple_parse_dai(np, dai_link->codecs, NULL); + ret = asoc_simple_parse_dai(np, codecs, NULL); if (ret < 0) goto out_put_node; - ret = asoc_simple_parse_clk(dev, np, dai, dai_link->codecs); + ret = asoc_simple_parse_clk(dev, np, dai, codecs); if (ret < 0) goto out_put_node; @@ -233,6 +233,9 @@ static int simple_dai_link_of(struct asoc_simple_priv *priv, struct simple_dai_props *dai_props = simple_priv_to_props(priv, li->link); struct asoc_simple_dai *cpu_dai = dai_props->cpu_dai; struct asoc_simple_dai *codec_dai = dai_props->codec_dai; + struct snd_soc_dai_link_component *cpus = asoc_link_to_cpu(dai_link, 0); + struct snd_soc_dai_link_component *codecs = asoc_link_to_codec(dai_link, 0); + struct snd_soc_dai_link_component *platforms = asoc_link_to_platform(dai_link, 0); struct device_node *top = dev->of_node; struct device_node *cpu = NULL; struct device_node *node = NULL; @@ -261,15 +264,15 @@ static int simple_dai_link_of(struct asoc_simple_priv *priv, simple_parse_mclk_fs(top, cpu, codec, dai_props, prefix); - ret = asoc_simple_parse_dai(cpu, dai_link->cpus, &single_cpu); + ret = asoc_simple_parse_dai(cpu, cpus, &single_cpu); if (ret < 0) goto dai_link_of_err; - ret = asoc_simple_parse_dai(codec, dai_link->codecs, NULL); + ret = asoc_simple_parse_dai(codec, codecs, NULL); if (ret < 0) goto dai_link_of_err; - ret = asoc_simple_parse_dai(plat, dai_link->platforms, NULL); + ret = asoc_simple_parse_dai(plat, platforms, NULL); if (ret < 0) goto dai_link_of_err; @@ -281,26 +284,26 @@ static int simple_dai_link_of(struct asoc_simple_priv *priv, if (ret < 0) goto dai_link_of_err; - ret = asoc_simple_parse_clk(dev, cpu, cpu_dai, dai_link->cpus); + ret = asoc_simple_parse_clk(dev, cpu, cpu_dai, cpus); if (ret < 0) goto dai_link_of_err; - ret = asoc_simple_parse_clk(dev, codec, codec_dai, dai_link->codecs); + ret = asoc_simple_parse_clk(dev, codec, codec_dai, codecs); if (ret < 0) goto dai_link_of_err; ret = asoc_simple_set_dailink_name(dev, dai_link, "%s-%s", - dai_link->cpus->dai_name, - dai_link->codecs->dai_name); + cpus->dai_name, + codecs->dai_name); if (ret < 0) goto dai_link_of_err; dai_link->ops = &simple_ops; dai_link->init = asoc_simple_dai_init; - asoc_simple_canonicalize_cpu(dai_link->cpus, single_cpu); - asoc_simple_canonicalize_platform(dai_link->platforms, dai_link->cpus); + asoc_simple_canonicalize_cpu(cpus, single_cpu); + asoc_simple_canonicalize_platform(platforms, cpus); dai_link_of_err: of_node_put(plat); From 2c33e20ffd68df097d61fad9b87dc6276354b139 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Wed, 14 Apr 2021 08:20:10 +0900 Subject: [PATCH 494/587] ASoC: simple-card: use simple_props_to_xxx() macro We shouldn't use dai_props->cpus/codecs directly, because these are array now to supporting multi CPU/Codec/Platform. This patch uses simple_props_to_xxx() macro for it. Signed-off-by: Kuninori Morimoto Link: https://lore.kernel.org/r/87mtu1zs9i.wl-kuninori.morimoto.gx@renesas.com Signed-off-by: Mark Brown --- sound/soc/generic/simple-card.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/sound/soc/generic/simple-card.c b/sound/soc/generic/simple-card.c index 9462b0d21486..5a686f82d1b4 100644 --- a/sound/soc/generic/simple-card.c +++ b/sound/soc/generic/simple-card.c @@ -147,7 +147,7 @@ static int simple_dai_link_of_dpcm(struct asoc_simple_priv *priv, dai_link->dynamic = 1; dai_link->dpcm_merged_format = 1; - dai = dai_props->cpu_dai; + dai = simple_props_to_dai_cpu(dai_props, 0); ret = asoc_simple_parse_dai(np, cpus, &is_single_links); if (ret) @@ -174,8 +174,8 @@ static int simple_dai_link_of_dpcm(struct asoc_simple_priv *priv, dai_link->no_pcm = 1; dai_link->be_hw_params_fixup = asoc_simple_be_hw_params_fixup; - dai = dai_props->codec_dai; - cconf = dai_props->codec_conf; + dai = simple_props_to_dai_codec(dai_props, 0); + cconf = simple_props_to_codec_conf(dai_props, 0); ret = asoc_simple_parse_dai(np, codecs, NULL); if (ret < 0) @@ -231,8 +231,8 @@ static int simple_dai_link_of(struct asoc_simple_priv *priv, struct device *dev = simple_priv_to_dev(priv); struct snd_soc_dai_link *dai_link = simple_priv_to_link(priv, li->link); struct simple_dai_props *dai_props = simple_priv_to_props(priv, li->link); - struct asoc_simple_dai *cpu_dai = dai_props->cpu_dai; - struct asoc_simple_dai *codec_dai = dai_props->codec_dai; + struct asoc_simple_dai *cpu_dai = simple_props_to_dai_cpu(dai_props, 0); + struct asoc_simple_dai *codec_dai = simple_props_to_dai_codec(dai_props, 0); struct snd_soc_dai_link_component *cpus = asoc_link_to_cpu(dai_link, 0); struct snd_soc_dai_link_component *codecs = asoc_link_to_codec(dai_link, 0); struct snd_soc_dai_link_component *platforms = asoc_link_to_platform(dai_link, 0); From 7ed5920995cea34d66e4af00c7f468cc933251cf Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Wed, 14 Apr 2021 08:20:15 +0900 Subject: [PATCH 495/587] ASoC: audio-graph: use asoc_link_to_xxx() macro We shouldn't use dai_link->cpus/codecs/platforms directly, because these are array now to supporting multi CPU/Codec/Platform. This patch uses asoc_link_to_xxx() macro for it. Signed-off-by: Kuninori Morimoto Link: https://lore.kernel.org/r/87lf9lzs9c.wl-kuninori.morimoto.gx@renesas.com Signed-off-by: Mark Brown --- sound/soc/generic/audio-graph-card.c | 33 +++++++++++++++------------- 1 file changed, 18 insertions(+), 15 deletions(-) diff --git a/sound/soc/generic/audio-graph-card.c b/sound/soc/generic/audio-graph-card.c index 0582fe296471..55384f1415b3 100644 --- a/sound/soc/generic/audio-graph-card.c +++ b/sound/soc/generic/audio-graph-card.c @@ -224,9 +224,9 @@ static int graph_dai_link_of_dpcm(struct asoc_simple_priv *priv, struct device_node *ports; struct device_node *node; struct asoc_simple_dai *dai; - struct snd_soc_dai_link_component *cpus = dai_link->cpus; - struct snd_soc_dai_link_component *codecs = dai_link->codecs; - struct snd_soc_dai_link_component *platforms = dai_link->platforms; + struct snd_soc_dai_link_component *cpus = asoc_link_to_cpu(dai_link, 0); + struct snd_soc_dai_link_component *codecs = asoc_link_to_codec(dai_link, 0); + struct snd_soc_dai_link_component *platforms = asoc_link_to_platform(dai_link, 0); int ret; port = of_get_parent(ep); @@ -248,11 +248,11 @@ static int graph_dai_link_of_dpcm(struct asoc_simple_priv *priv, dai = dai_props->cpu_dai; - ret = asoc_simple_parse_dai(ep, dai_link->cpus, &is_single_links); + ret = asoc_simple_parse_dai(ep, cpus, &is_single_links); if (ret) goto out_put_node; - ret = asoc_simple_parse_clk(dev, ep, dai, dai_link->cpus); + ret = asoc_simple_parse_clk(dev, ep, dai, cpus); if (ret < 0) goto out_put_node; @@ -291,11 +291,11 @@ static int graph_dai_link_of_dpcm(struct asoc_simple_priv *priv, dai = dai_props->codec_dai; cconf = dai_props->codec_conf; - ret = asoc_simple_parse_dai(ep, dai_link->codecs, NULL); + ret = asoc_simple_parse_dai(ep, codecs, NULL); if (ret < 0) goto out_put_node; - ret = asoc_simple_parse_clk(dev, ep, dai, dai_link->codecs); + ret = asoc_simple_parse_clk(dev, ep, dai, codecs); if (ret < 0) goto out_put_node; @@ -357,6 +357,9 @@ static int graph_dai_link_of(struct asoc_simple_priv *priv, struct device_node *top = dev->of_node; struct asoc_simple_dai *cpu_dai = dai_props->cpu_dai; struct asoc_simple_dai *codec_dai = dai_props->codec_dai; + struct snd_soc_dai_link_component *cpus = asoc_link_to_cpu(dai_link, 0); + struct snd_soc_dai_link_component *codecs = asoc_link_to_codec(dai_link, 0); + struct snd_soc_dai_link_component *platforms = asoc_link_to_platform(dai_link, 0); int ret, single_cpu = 0; dev_dbg(dev, "link_of (%pOF)\n", cpu_ep); @@ -372,11 +375,11 @@ static int graph_dai_link_of(struct asoc_simple_priv *priv, if (ret < 0) return ret; - ret = asoc_simple_parse_dai(cpu_ep, dai_link->cpus, &single_cpu); + ret = asoc_simple_parse_dai(cpu_ep, cpus, &single_cpu); if (ret < 0) return ret; - ret = asoc_simple_parse_dai(codec_ep, dai_link->codecs, NULL); + ret = asoc_simple_parse_dai(codec_ep, codecs, NULL); if (ret < 0) return ret; @@ -388,26 +391,26 @@ static int graph_dai_link_of(struct asoc_simple_priv *priv, if (ret < 0) return ret; - ret = asoc_simple_parse_clk(dev, cpu_ep, cpu_dai, dai_link->cpus); + ret = asoc_simple_parse_clk(dev, cpu_ep, cpu_dai, cpus); if (ret < 0) return ret; - ret = asoc_simple_parse_clk(dev, codec_ep, codec_dai, dai_link->codecs); + ret = asoc_simple_parse_clk(dev, codec_ep, codec_dai, codecs); if (ret < 0) return ret; ret = asoc_simple_set_dailink_name(dev, dai_link, "%s-%s", - dai_link->cpus->dai_name, - dai_link->codecs->dai_name); + cpus->dai_name, + codecs->dai_name); if (ret < 0) return ret; dai_link->ops = &graph_ops; dai_link->init = asoc_simple_dai_init; - asoc_simple_canonicalize_cpu(dai_link->cpus, single_cpu); - asoc_simple_canonicalize_platform(dai_link->platforms, dai_link->cpus); + asoc_simple_canonicalize_cpu(cpus, single_cpu); + asoc_simple_canonicalize_platform(platforms, cpus); return 0; } From ae0727ab77419d550d6f68b698ce37ef2bf315df Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Wed, 14 Apr 2021 08:20:20 +0900 Subject: [PATCH 496/587] ASoC: audio-graph: use simple_props_to_xxx() macro We shouldn't use dai_props->cpus/codecs directly, because these are array now to supporting multi CPU/Codec/Platform. This patch uses simple_props_to_xxx() macro for it. Signed-off-by: Kuninori Morimoto Link: https://lore.kernel.org/r/87k0p5zs97.wl-kuninori.morimoto.gx@renesas.com Signed-off-by: Mark Brown --- sound/soc/generic/audio-graph-card.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/sound/soc/generic/audio-graph-card.c b/sound/soc/generic/audio-graph-card.c index 55384f1415b3..36b2ad7dd283 100644 --- a/sound/soc/generic/audio-graph-card.c +++ b/sound/soc/generic/audio-graph-card.c @@ -246,7 +246,7 @@ static int graph_dai_link_of_dpcm(struct asoc_simple_priv *priv, dai_link->dynamic = 1; dai_link->dpcm_merged_format = 1; - dai = dai_props->cpu_dai; + dai = simple_props_to_dai_cpu(dai_props, 0); ret = asoc_simple_parse_dai(ep, cpus, &is_single_links); if (ret) @@ -288,8 +288,8 @@ static int graph_dai_link_of_dpcm(struct asoc_simple_priv *priv, dai_link->no_pcm = 1; dai_link->be_hw_params_fixup = asoc_simple_be_hw_params_fixup; - dai = dai_props->codec_dai; - cconf = dai_props->codec_conf; + dai = simple_props_to_dai_codec(dai_props, 0); + cconf = simple_props_to_codec_conf(dai_props, 0); ret = asoc_simple_parse_dai(ep, codecs, NULL); if (ret < 0) @@ -355,8 +355,8 @@ static int graph_dai_link_of(struct asoc_simple_priv *priv, struct snd_soc_dai_link *dai_link = simple_priv_to_link(priv, li->link); struct simple_dai_props *dai_props = simple_priv_to_props(priv, li->link); struct device_node *top = dev->of_node; - struct asoc_simple_dai *cpu_dai = dai_props->cpu_dai; - struct asoc_simple_dai *codec_dai = dai_props->codec_dai; + struct asoc_simple_dai *cpu_dai = simple_props_to_dai_cpu(dai_props, 0); + struct asoc_simple_dai *codec_dai = simple_props_to_dai_codec(dai_props, 0); struct snd_soc_dai_link_component *cpus = asoc_link_to_cpu(dai_link, 0); struct snd_soc_dai_link_component *codecs = asoc_link_to_codec(dai_link, 0); struct snd_soc_dai_link_component *platforms = asoc_link_to_platform(dai_link, 0); From 22ff9c4230bd09ade8971c05463b90ec1d513245 Mon Sep 17 00:00:00 2001 From: Guangqing Zhu Date: Thu, 15 Apr 2021 15:38:29 +0800 Subject: [PATCH 497/587] ASoC: codecs: wcd934x: Fix missing IRQF_ONESHOT as only threaded handler Coccinelle noticed: sound/soc/codecs/wcd934x.c:5041:7-32: ERROR: Threaded IRQ with no primary handler requested without IRQF_ONESHOT Signed-off-by: Guangqing Zhu Reviewed-by: Srinivas Kandagatla Link: https://lore.kernel.org/r/20210415073829.22750-1-zhuguangqing83@gmail.com Signed-off-by: Mark Brown --- sound/soc/codecs/wcd934x.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sound/soc/codecs/wcd934x.c b/sound/soc/codecs/wcd934x.c index 5fe403307b72..cddc49bbb7f6 100644 --- a/sound/soc/codecs/wcd934x.c +++ b/sound/soc/codecs/wcd934x.c @@ -5040,7 +5040,7 @@ static int wcd934x_codec_probe(struct platform_device *pdev) ret = devm_request_threaded_irq(dev, irq, NULL, wcd934x_slim_irq_handler, - IRQF_TRIGGER_RISING, + IRQF_TRIGGER_RISING | IRQF_ONESHOT, "slim", wcd); if (ret) { dev_err(dev, "Failed to request slimbus irq\n"); From a523ef731ac6674dc07574f31bf44cc5bfa14e4d Mon Sep 17 00:00:00 2001 From: Lukasz Majczak Date: Thu, 15 Apr 2021 14:43:47 +0200 Subject: [PATCH 498/587] ASoC: Intel: kbl_da7219_max98927: Fix kabylake_ssp_fixup function kabylake_ssp_fixup function uses snd_soc_dpcm to identify the codecs DAIs. The HW parameters are changed based on the codec DAI of the stream. The earlier approach to get snd_soc_dpcm was using container_of() macro on snd_pcm_hw_params. The structures have been modified over time and snd_soc_dpcm does not have snd_pcm_hw_params as a reference but as a copy. This causes the current driver to crash when used. This patch changes the way snd_soc_dpcm is extracted. snd_soc_pcm_runtime holds 2 dpcm instances (one for playback and one for capture). 2 codecs on the SSP are dmic (capture) and speakers (playback). Based on the stream direction, snd_soc_dpcm is extracted from snd_soc_pcm_runtime. Tested for all use cases of the driver. Based on similar fix in kbl_rt5663_rt5514_max98927.c from Harsha Priya and Vamshi Krishna Gopal Cc: # 5.4+ Signed-off-by: Lukasz Majczak Acked-by: Pierre-Louis Bossart Link: https://lore.kernel.org/r/20210415124347.475432-1-lma@semihalf.com Signed-off-by: Mark Brown --- sound/soc/intel/boards/kbl_da7219_max98927.c | 38 +++++++++++++++----- 1 file changed, 30 insertions(+), 8 deletions(-) diff --git a/sound/soc/intel/boards/kbl_da7219_max98927.c b/sound/soc/intel/boards/kbl_da7219_max98927.c index cc9a2509ace2..e0149cf6127d 100644 --- a/sound/soc/intel/boards/kbl_da7219_max98927.c +++ b/sound/soc/intel/boards/kbl_da7219_max98927.c @@ -282,11 +282,33 @@ static int kabylake_ssp_fixup(struct snd_soc_pcm_runtime *rtd, struct snd_interval *chan = hw_param_interval(params, SNDRV_PCM_HW_PARAM_CHANNELS); struct snd_mask *fmt = hw_param_mask(params, SNDRV_PCM_HW_PARAM_FORMAT); - struct snd_soc_dpcm *dpcm = container_of( - params, struct snd_soc_dpcm, hw_params); - struct snd_soc_dai_link *fe_dai_link = dpcm->fe->dai_link; - struct snd_soc_dai_link *be_dai_link = dpcm->be->dai_link; + struct snd_soc_dpcm *dpcm, *rtd_dpcm = NULL; + /* + * The following loop will be called only for playback stream + * In this platform, there is only one playback device on every SSP + */ + for_each_dpcm_fe(rtd, SNDRV_PCM_STREAM_PLAYBACK, dpcm) { + rtd_dpcm = dpcm; + break; + } + + /* + * This following loop will be called only for capture stream + * In this platform, there is only one capture device on every SSP + */ + for_each_dpcm_fe(rtd, SNDRV_PCM_STREAM_CAPTURE, dpcm) { + rtd_dpcm = dpcm; + break; + } + + if (!rtd_dpcm) + return -EINVAL; + + /* + * The above 2 loops are mutually exclusive based on the stream direction, + * thus rtd_dpcm variable will never be overwritten + */ /* * Topology for kblda7219m98373 & kblmax98373 supports only S24_LE, * where as kblda7219m98927 & kblmax98927 supports S16_LE by default. @@ -309,9 +331,9 @@ static int kabylake_ssp_fixup(struct snd_soc_pcm_runtime *rtd, /* * The ADSP will convert the FE rate to 48k, stereo, 24 bit */ - if (!strcmp(fe_dai_link->name, "Kbl Audio Port") || - !strcmp(fe_dai_link->name, "Kbl Audio Headset Playback") || - !strcmp(fe_dai_link->name, "Kbl Audio Capture Port")) { + if (!strcmp(rtd_dpcm->fe->dai_link->name, "Kbl Audio Port") || + !strcmp(rtd_dpcm->fe->dai_link->name, "Kbl Audio Headset Playback") || + !strcmp(rtd_dpcm->fe->dai_link->name, "Kbl Audio Capture Port")) { rate->min = rate->max = 48000; chan->min = chan->max = 2; snd_mask_none(fmt); @@ -322,7 +344,7 @@ static int kabylake_ssp_fixup(struct snd_soc_pcm_runtime *rtd, * The speaker on the SSP0 supports S16_LE and not S24_LE. * thus changing the mask here */ - if (!strcmp(be_dai_link->name, "SSP0-Codec")) + if (!strcmp(rtd_dpcm->be->dai_link->name, "SSP0-Codec")) snd_mask_set_format(fmt, SNDRV_PCM_FORMAT_S16_LE); return 0; From eea1d18e9b2d959df908746b193f66dba3078473 Mon Sep 17 00:00:00 2001 From: Ranjani Sridharan Date: Thu, 15 Apr 2021 11:21:07 -0500 Subject: [PATCH 499/587] ASoC: SOF: use current DAI config during resume Recently, the sof_pcm_dai_link_fixup() function was updated to match SSP config with the PCM hw_params and set the current_config for the DAI widget. But the sof_restore_pipelines() function still chooses the default config for the DAI widget upon resuming. Fix this to use the last used config when setting up the DAI widget during resume. Fixes: c943a586f6e49 ("ASoC: SOF: match SSP config with pcm hw params") Reviewed-by: Kai Vehmanen Signed-off-by: Ranjani Sridharan Signed-off-by: Pierre-Louis Bossart Link: https://lore.kernel.org/r/20210415162107.130963-1-pierre-louis.bossart@linux.intel.com Signed-off-by: Mark Brown --- sound/soc/sof/sof-audio.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sound/soc/sof/sof-audio.c b/sound/soc/sof/sof-audio.c index 0d0d47dc0246..510883cd9107 100644 --- a/sound/soc/sof/sof-audio.c +++ b/sound/soc/sof/sof-audio.c @@ -267,7 +267,7 @@ int sof_restore_pipelines(struct device *dev) /* restore dai links */ list_for_each_entry_reverse(dai, &sdev->dai_list, list) { struct sof_ipc_reply reply; - struct sof_ipc_dai_config *config = dai->dai_config; + struct sof_ipc_dai_config *config = &dai->dai_config[dai->current_config]; if (!config) { dev_err(dev, "error: no config for DAI %s\n", From 998f26f47e556f14cd124c508d76bceb2c3f6e6a Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Thu, 15 Apr 2021 15:18:56 +0200 Subject: [PATCH 500/587] ALSA: control: Fix racy management of user ctl memory size account We've got a report about the possible race in the user control element counts (card->user_ctl_count), and it was confirmed that the race wasn't serious in the old code up to 5.12. There, the value modification itself was exclusive and protected via a write semaphore, hence it's at most concurrent reads and evaluations before the increment. Since it's only about the soft-limit to avoid the exhausting memory usage, one-off isn't a big problem at all. Meanwhile, the relevant code has been largely modified recently, and now card->user_ctl_count was replaced with card->user_ctl_alloc_size, and a few more places were added to access this field. And, in this new code, it turned out to be more serious: the modifications are scattered in various places, and a few of them are without protection. It implies that it may lead to an inconsistent value by racy accesses. For addressing it, this patch extends the range covered by the card->controls_rwsem write lock at snd_ctl_elem_add() so that the all code paths that modify and refer to card->user_ctl_alloc_size are protected by the rwsem properly. The patch adds also comments in a couple of functions to indicate that they are under the rwsem lock. Fixes: 66c6d1ef86ff ("ALSA: control: Add memory consumption limit to user controls") Link: https://lore.kernel.org/r/FEEBF384-44BE-42CF-8FB3-93470933F64F@purdue.edu Link: https://lore.kernel.org/r/20210415131856.13113-1-tiwai@suse.de Signed-off-by: Takashi Iwai --- sound/core/control.c | 17 +++++++++++------ 1 file changed, 11 insertions(+), 6 deletions(-) diff --git a/sound/core/control.c b/sound/core/control.c index a076c08c21b6..498e3701514a 100644 --- a/sound/core/control.c +++ b/sound/core/control.c @@ -1337,6 +1337,7 @@ static int snd_ctl_elem_user_put(struct snd_kcontrol *kcontrol, return change; } +/* called in controls_rwsem write lock */ static int replace_user_tlv(struct snd_kcontrol *kctl, unsigned int __user *buf, unsigned int size) { @@ -1414,6 +1415,7 @@ static int snd_ctl_elem_user_tlv(struct snd_kcontrol *kctl, int op_flag, return read_user_tlv(kctl, buf, size); } +/* called in controls_rwsem write lock */ static int snd_ctl_elem_init_enum_names(struct user_element *ue) { char *names, *p; @@ -1529,8 +1531,11 @@ static int snd_ctl_elem_add(struct snd_ctl_file *file, private_size = value_sizes[info->type] * info->count; alloc_size = compute_user_elem_size(private_size, count); - if (check_user_elem_overflow(card, alloc_size)) - return -ENOMEM; + down_write(&card->controls_rwsem); + if (check_user_elem_overflow(card, alloc_size)) { + err = -ENOMEM; + goto unlock; + } /* * Keep memory object for this userspace control. After passing this @@ -1540,12 +1545,13 @@ static int snd_ctl_elem_add(struct snd_ctl_file *file, */ err = snd_ctl_new(&kctl, count, access, file); if (err < 0) - return err; + goto unlock; memcpy(&kctl->id, &info->id, sizeof(kctl->id)); ue = kzalloc(alloc_size, GFP_KERNEL); if (!ue) { kfree(kctl); - return -ENOMEM; + err = -ENOMEM; + goto unlock; } kctl->private_data = ue; kctl->private_free = snd_ctl_elem_user_free; @@ -1563,7 +1569,7 @@ static int snd_ctl_elem_add(struct snd_ctl_file *file, err = snd_ctl_elem_init_enum_names(ue); if (err < 0) { snd_ctl_free_one(kctl); - return err; + goto unlock; } } @@ -1580,7 +1586,6 @@ static int snd_ctl_elem_add(struct snd_ctl_file *file, kctl->tlv.c = snd_ctl_elem_user_tlv; /* This function manage to free the instance on failure. */ - down_write(&card->controls_rwsem); err = __snd_ctl_add_replace(card, kctl, CTL_ADD_EXCLUSIVE); if (err < 0) { snd_ctl_free_one(kctl); From d1ee66c5d3c5a0498dd5e3f2af5b8c219a98bba5 Mon Sep 17 00:00:00 2001 From: Phil Calvin Date: Thu, 15 Apr 2021 18:01:29 -0400 Subject: [PATCH 501/587] ALSA: hda/realtek: fix mic boost on Intel NUC 8 Fix two bugs with the Intel HDA Realtek ALC233 sound codec present in Intel NUC NUC8i7BEH and probably a few other similar NUC models. These codecs advertise a 4-level microphone input boost amplifier on pin 0x19, but the highest two boost settings do not work correctly, and produce only low analog noise that does not seem to contain any discernible signal. There is an existing fixup for this exact problem but for a different PCI subsystem ID, so we re-use that logic. Changing the boost level also triggers a DC spike in the input signal that bleeds off over about a second and overwhelms any input during that time. Thankfully, the existing fixup has the side effect of making the boost control show up in userspace as a mute/unmute switch, and this keeps (e.g.) PulseAudio from fiddling with it during normal input volume adjustments. Finally, the NUC hardware has built-in inverted stereo mics. This patch also enables the usual fixup for this so the two channels cancel noise instead of the actual signal. [ Re-ordered the quirk entry point by tiwai ] Signed-off-by: Phil Calvin Cc: Link: https://lore.kernel.org/r/80dc5663-7734-e7e5-25ef-15b5df24511a@philcalvin.com Signed-off-by: Takashi Iwai --- sound/pci/hda/patch_realtek.c | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/sound/pci/hda/patch_realtek.c b/sound/pci/hda/patch_realtek.c index 00a15e7cfdb9..50437ec1b9af 100644 --- a/sound/pci/hda/patch_realtek.c +++ b/sound/pci/hda/patch_realtek.c @@ -6422,6 +6422,8 @@ enum { ALC269_FIXUP_LEMOTE_A1802, ALC269_FIXUP_LEMOTE_A190X, ALC256_FIXUP_INTEL_NUC8_RUGGED, + ALC233_FIXUP_INTEL_NUC8_DMIC, + ALC233_FIXUP_INTEL_NUC8_BOOST, ALC256_FIXUP_INTEL_NUC10, ALC255_FIXUP_XIAOMI_HEADSET_MIC, ALC274_FIXUP_HP_MIC, @@ -7143,6 +7145,16 @@ static const struct hda_fixup alc269_fixups[] = { .type = HDA_FIXUP_FUNC, .v.func = alc233_fixup_lenovo_line2_mic_hotkey, }, + [ALC233_FIXUP_INTEL_NUC8_DMIC] = { + .type = HDA_FIXUP_FUNC, + .v.func = alc_fixup_inv_dmic, + .chained = true, + .chain_id = ALC233_FIXUP_INTEL_NUC8_BOOST, + }, + [ALC233_FIXUP_INTEL_NUC8_BOOST] = { + .type = HDA_FIXUP_FUNC, + .v.func = alc269_fixup_limit_int_mic_boost + }, [ALC255_FIXUP_DELL_SPK_NOISE] = { .type = HDA_FIXUP_FUNC, .v.func = alc_fixup_disable_aamix, @@ -8286,6 +8298,7 @@ static const struct snd_pci_quirk alc269_fixup_tbl[] = { SND_PCI_QUIRK(0x10ec, 0x118c, "Medion EE4254 MD62100", ALC256_FIXUP_MEDION_HEADSET_NO_PRESENCE), SND_PCI_QUIRK(0x1c06, 0x2013, "Lemote A1802", ALC269_FIXUP_LEMOTE_A1802), SND_PCI_QUIRK(0x1c06, 0x2015, "Lemote A190X", ALC269_FIXUP_LEMOTE_A190X), + SND_PCI_QUIRK(0x8086, 0x2074, "Intel NUC 8", ALC233_FIXUP_INTEL_NUC8_DMIC), SND_PCI_QUIRK(0x8086, 0x2080, "Intel NUC 8 Rugged", ALC256_FIXUP_INTEL_NUC8_RUGGED), SND_PCI_QUIRK(0x8086, 0x2081, "Intel NUC 10", ALC256_FIXUP_INTEL_NUC10), From 26928ca1f06aab4361eb5adbe7ef3b5c82f13cf2 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Fri, 16 Apr 2021 10:12:11 +0200 Subject: [PATCH 502/587] ALSA: hda/realtek: Add quirk for Lenovo Ideapad S740 Lenovo Ideapad S740 requires quite a few COEF setups to make its speakers working. The verb table was provided from Ryan Prescott as the result of investigation via qemu: https://github.com/ryanprescott/realtek-verb-tools/wiki/How-to-sniff-verbs-from-a-Windows-sound-driver BugLink: https://github.com/thesofproject/linux/issues/2748 Tested-by: Ryan Prescott Link: https://lore.kernel.org/r/20210416081211.20059-1-tiwai@suse.de Signed-off-by: Takashi Iwai --- sound/pci/hda/ideapad_s740_helper.c | 492 ++++++++++++++++++++++++++++ sound/pci/hda/patch_realtek.c | 11 + 2 files changed, 503 insertions(+) create mode 100644 sound/pci/hda/ideapad_s740_helper.c diff --git a/sound/pci/hda/ideapad_s740_helper.c b/sound/pci/hda/ideapad_s740_helper.c new file mode 100644 index 000000000000..564b9086e52d --- /dev/null +++ b/sound/pci/hda/ideapad_s740_helper.c @@ -0,0 +1,492 @@ +// SPDX-License-Identifier: GPL-2.0 +/* Fixes for Lenovo Ideapad S740, to be included from codec driver */ + +static const struct hda_verb alc285_ideapad_s740_coefs[] = { +{ 0x20, AC_VERB_SET_COEF_INDEX, 0x10 }, +{ 0x20, AC_VERB_SET_PROC_COEF, 0x0320 }, +{ 0x20, AC_VERB_SET_COEF_INDEX, 0x24 }, +{ 0x20, AC_VERB_SET_PROC_COEF, 0x0041 }, +{ 0x20, AC_VERB_SET_COEF_INDEX, 0x24 }, +{ 0x20, AC_VERB_SET_PROC_COEF, 0x0041 }, +{ 0x20, AC_VERB_SET_COEF_INDEX, 0x29 }, +{ 0x20, AC_VERB_SET_COEF_INDEX, 0x29 }, +{ 0x20, AC_VERB_SET_COEF_INDEX, 0x26 }, +{ 0x20, AC_VERB_SET_PROC_COEF, 0x0000 }, +{ 0x20, AC_VERB_SET_PROC_COEF, 0x0000 }, +{ 0x20, AC_VERB_SET_PROC_COEF, 0x0000 }, +{ 0x20, AC_VERB_SET_PROC_COEF, 0xb020 }, +{ 0x20, AC_VERB_SET_COEF_INDEX, 0x26 }, +{ 0x20, AC_VERB_SET_PROC_COEF, 0x0000 }, +{ 0x20, AC_VERB_SET_PROC_COEF, 0x0000 }, +{ 0x20, AC_VERB_SET_PROC_COEF, 0x0000 }, +{ 0x20, AC_VERB_SET_PROC_COEF, 0xb020 }, +{ 0x20, AC_VERB_SET_COEF_INDEX, 0x29 }, +{ 0x20, AC_VERB_SET_COEF_INDEX, 0x29 }, +{ 0x20, AC_VERB_SET_COEF_INDEX, 0x26 }, +{ 0x20, AC_VERB_SET_PROC_COEF, 0x007f }, +{ 0x20, AC_VERB_SET_PROC_COEF, 0x0000 }, +{ 0x20, AC_VERB_SET_PROC_COEF, 0x0000 }, +{ 0x20, AC_VERB_SET_PROC_COEF, 0xb020 }, +{ 0x20, AC_VERB_SET_COEF_INDEX, 0x26 }, +{ 0x20, AC_VERB_SET_PROC_COEF, 0x007f }, +{ 0x20, AC_VERB_SET_PROC_COEF, 0x0000 }, +{ 0x20, AC_VERB_SET_PROC_COEF, 0x0000 }, +{ 0x20, AC_VERB_SET_PROC_COEF, 0xb020 }, +{ 0x20, AC_VERB_SET_COEF_INDEX, 0x29 }, +{ 0x20, AC_VERB_SET_COEF_INDEX, 0x29 }, +{ 0x20, AC_VERB_SET_COEF_INDEX, 0x26 }, +{ 0x20, AC_VERB_SET_PROC_COEF, 0x0001 }, +{ 0x20, AC_VERB_SET_PROC_COEF, 0x0000 }, +{ 0x20, AC_VERB_SET_PROC_COEF, 0x0001 }, +{ 0x20, AC_VERB_SET_PROC_COEF, 0xb020 }, +{ 0x20, AC_VERB_SET_COEF_INDEX, 0x26 }, +{ 0x20, AC_VERB_SET_PROC_COEF, 0x0001 }, +{ 0x20, AC_VERB_SET_PROC_COEF, 0x0000 }, +{ 0x20, AC_VERB_SET_PROC_COEF, 0x0001 }, +{ 0x20, AC_VERB_SET_PROC_COEF, 0xb020 }, +{ 0x20, AC_VERB_SET_COEF_INDEX, 0x29 }, +{ 0x20, AC_VERB_SET_COEF_INDEX, 0x29 }, +{ 0x20, AC_VERB_SET_COEF_INDEX, 0x26 }, +{ 0x20, AC_VERB_SET_PROC_COEF, 0x003c }, +{ 0x20, AC_VERB_SET_PROC_COEF, 0x0000 }, +{ 0x20, AC_VERB_SET_PROC_COEF, 0x0011 }, +{ 0x20, AC_VERB_SET_PROC_COEF, 0xb020 }, +{ 0x20, AC_VERB_SET_COEF_INDEX, 0x26 }, +{ 0x20, AC_VERB_SET_PROC_COEF, 0x003c }, +{ 0x20, AC_VERB_SET_PROC_COEF, 0x0000 }, +{ 0x20, AC_VERB_SET_PROC_COEF, 0x0011 }, +{ 0x20, AC_VERB_SET_PROC_COEF, 0xb020 }, +{ 0x20, AC_VERB_SET_COEF_INDEX, 0x29 }, +{ 0x20, AC_VERB_SET_COEF_INDEX, 0x29 }, +{ 0x20, AC_VERB_SET_COEF_INDEX, 0x26 }, +{ 0x20, AC_VERB_SET_PROC_COEF, 0x000c }, +{ 0x20, AC_VERB_SET_PROC_COEF, 0x0000 }, +{ 0x20, AC_VERB_SET_PROC_COEF, 0x001a }, +{ 0x20, AC_VERB_SET_PROC_COEF, 0xb020 }, +{ 0x20, AC_VERB_SET_COEF_INDEX, 0x26 }, +{ 0x20, AC_VERB_SET_PROC_COEF, 0x000c }, +{ 0x20, AC_VERB_SET_PROC_COEF, 0x0000 }, +{ 0x20, AC_VERB_SET_PROC_COEF, 0x001a }, +{ 0x20, AC_VERB_SET_PROC_COEF, 0xb020 }, +{ 0x20, AC_VERB_SET_COEF_INDEX, 0x29 }, +{ 0x20, AC_VERB_SET_COEF_INDEX, 0x29 }, +{ 0x20, AC_VERB_SET_COEF_INDEX, 0x26 }, +{ 0x20, AC_VERB_SET_PROC_COEF, 0x000f }, +{ 0x20, AC_VERB_SET_PROC_COEF, 0x0000 }, +{ 0x20, AC_VERB_SET_PROC_COEF, 0x0042 }, +{ 0x20, AC_VERB_SET_PROC_COEF, 0xb020 }, +{ 0x20, AC_VERB_SET_COEF_INDEX, 0x26 }, +{ 0x20, AC_VERB_SET_PROC_COEF, 0x000f }, +{ 0x20, AC_VERB_SET_PROC_COEF, 0x0000 }, +{ 0x20, AC_VERB_SET_PROC_COEF, 0x0042 }, +{ 0x20, AC_VERB_SET_PROC_COEF, 0xb020 }, +{ 0x20, AC_VERB_SET_COEF_INDEX, 0x29 }, +{ 0x20, AC_VERB_SET_COEF_INDEX, 0x29 }, +{ 0x20, AC_VERB_SET_COEF_INDEX, 0x26 }, +{ 0x20, AC_VERB_SET_PROC_COEF, 0x0010 }, +{ 0x20, AC_VERB_SET_PROC_COEF, 0x0000 }, +{ 0x20, AC_VERB_SET_PROC_COEF, 0x0040 }, +{ 0x20, AC_VERB_SET_PROC_COEF, 0xb020 }, +{ 0x20, AC_VERB_SET_COEF_INDEX, 0x26 }, +{ 0x20, AC_VERB_SET_PROC_COEF, 0x0010 }, +{ 0x20, AC_VERB_SET_PROC_COEF, 0x0000 }, +{ 0x20, AC_VERB_SET_PROC_COEF, 0x0040 }, +{ 0x20, AC_VERB_SET_PROC_COEF, 0xb020 }, +{ 0x20, AC_VERB_SET_COEF_INDEX, 0x29 }, +{ 0x20, AC_VERB_SET_COEF_INDEX, 0x29 }, +{ 0x20, AC_VERB_SET_COEF_INDEX, 0x26 }, +{ 0x20, AC_VERB_SET_PROC_COEF, 0x0003 }, +{ 0x20, AC_VERB_SET_PROC_COEF, 0x0000 }, +{ 0x20, AC_VERB_SET_PROC_COEF, 0x0009 }, +{ 0x20, AC_VERB_SET_PROC_COEF, 0xb020 }, +{ 0x20, AC_VERB_SET_COEF_INDEX, 0x26 }, +{ 0x20, AC_VERB_SET_PROC_COEF, 0x0003 }, +{ 0x20, AC_VERB_SET_PROC_COEF, 0x0000 }, +{ 0x20, AC_VERB_SET_PROC_COEF, 0x0009 }, +{ 0x20, AC_VERB_SET_PROC_COEF, 0xb020 }, +{ 0x20, AC_VERB_SET_COEF_INDEX, 0x29 }, +{ 0x20, AC_VERB_SET_COEF_INDEX, 0x29 }, +{ 0x20, AC_VERB_SET_COEF_INDEX, 0x26 }, +{ 0x20, AC_VERB_SET_PROC_COEF, 0x001c }, +{ 0x20, AC_VERB_SET_PROC_COEF, 0x0000 }, +{ 0x20, AC_VERB_SET_PROC_COEF, 0x004c }, +{ 0x20, AC_VERB_SET_PROC_COEF, 0xb020 }, +{ 0x20, AC_VERB_SET_COEF_INDEX, 0x26 }, +{ 0x20, AC_VERB_SET_PROC_COEF, 0x001c }, +{ 0x20, AC_VERB_SET_PROC_COEF, 0x0000 }, +{ 0x20, AC_VERB_SET_PROC_COEF, 0x004c }, +{ 0x20, AC_VERB_SET_PROC_COEF, 0xb020 }, +{ 0x20, AC_VERB_SET_COEF_INDEX, 0x29 }, +{ 0x20, AC_VERB_SET_COEF_INDEX, 0x29 }, +{ 0x20, AC_VERB_SET_COEF_INDEX, 0x26 }, +{ 0x20, AC_VERB_SET_PROC_COEF, 0x001d }, +{ 0x20, AC_VERB_SET_PROC_COEF, 0x0000 }, +{ 0x20, AC_VERB_SET_PROC_COEF, 0x004e }, +{ 0x20, AC_VERB_SET_PROC_COEF, 0xb020 }, +{ 0x20, AC_VERB_SET_COEF_INDEX, 0x26 }, +{ 0x20, AC_VERB_SET_PROC_COEF, 0x001d }, +{ 0x20, AC_VERB_SET_PROC_COEF, 0x0000 }, +{ 0x20, AC_VERB_SET_PROC_COEF, 0x004e }, +{ 0x20, AC_VERB_SET_PROC_COEF, 0xb020 }, +{ 0x20, AC_VERB_SET_COEF_INDEX, 0x29 }, +{ 0x20, AC_VERB_SET_COEF_INDEX, 0x29 }, +{ 0x20, AC_VERB_SET_COEF_INDEX, 0x26 }, +{ 0x20, AC_VERB_SET_PROC_COEF, 0x001b }, +{ 0x20, AC_VERB_SET_PROC_COEF, 0x0000 }, +{ 0x20, AC_VERB_SET_PROC_COEF, 0x0001 }, +{ 0x20, AC_VERB_SET_PROC_COEF, 0xb020 }, +{ 0x20, AC_VERB_SET_COEF_INDEX, 0x26 }, +{ 0x20, AC_VERB_SET_PROC_COEF, 0x001b }, +{ 0x20, AC_VERB_SET_PROC_COEF, 0x0000 }, +{ 0x20, AC_VERB_SET_PROC_COEF, 0x0001 }, +{ 0x20, AC_VERB_SET_PROC_COEF, 0xb020 }, +{ 0x20, AC_VERB_SET_COEF_INDEX, 0x29 }, +{ 0x20, AC_VERB_SET_COEF_INDEX, 0x29 }, +{ 0x20, AC_VERB_SET_COEF_INDEX, 0x26 }, +{ 0x20, AC_VERB_SET_PROC_COEF, 0x0019 }, +{ 0x20, AC_VERB_SET_PROC_COEF, 0x0000 }, +{ 0x20, AC_VERB_SET_PROC_COEF, 0x0025 }, +{ 0x20, AC_VERB_SET_PROC_COEF, 0xb020 }, +{ 0x20, AC_VERB_SET_COEF_INDEX, 0x26 }, +{ 0x20, AC_VERB_SET_PROC_COEF, 0x0019 }, +{ 0x20, AC_VERB_SET_PROC_COEF, 0x0000 }, +{ 0x20, AC_VERB_SET_PROC_COEF, 0x0025 }, +{ 0x20, AC_VERB_SET_PROC_COEF, 0xb020 }, +{ 0x20, AC_VERB_SET_COEF_INDEX, 0x29 }, +{ 0x20, AC_VERB_SET_COEF_INDEX, 0x29 }, +{ 0x20, AC_VERB_SET_COEF_INDEX, 0x26 }, +{ 0x20, AC_VERB_SET_PROC_COEF, 0x0018 }, +{ 0x20, AC_VERB_SET_PROC_COEF, 0x0000 }, +{ 0x20, AC_VERB_SET_PROC_COEF, 0x0037 }, +{ 0x20, AC_VERB_SET_PROC_COEF, 0xb020 }, +{ 0x20, AC_VERB_SET_COEF_INDEX, 0x26 }, +{ 0x20, AC_VERB_SET_PROC_COEF, 0x0018 }, +{ 0x20, AC_VERB_SET_PROC_COEF, 0x0000 }, +{ 0x20, AC_VERB_SET_PROC_COEF, 0x0037 }, +{ 0x20, AC_VERB_SET_PROC_COEF, 0xb020 }, +{ 0x20, AC_VERB_SET_COEF_INDEX, 0x29 }, +{ 0x20, AC_VERB_SET_COEF_INDEX, 0x29 }, +{ 0x20, AC_VERB_SET_COEF_INDEX, 0x26 }, +{ 0x20, AC_VERB_SET_PROC_COEF, 0x001a }, +{ 0x20, AC_VERB_SET_PROC_COEF, 0x0000 }, +{ 0x20, AC_VERB_SET_PROC_COEF, 0x0040 }, +{ 0x20, AC_VERB_SET_PROC_COEF, 0xb020 }, +{ 0x20, AC_VERB_SET_COEF_INDEX, 0x26 }, +{ 0x20, AC_VERB_SET_PROC_COEF, 0x001a }, +{ 0x20, AC_VERB_SET_PROC_COEF, 0x0000 }, +{ 0x20, AC_VERB_SET_PROC_COEF, 0x0040 }, +{ 0x20, AC_VERB_SET_PROC_COEF, 0xb020 }, +{ 0x20, AC_VERB_SET_COEF_INDEX, 0x29 }, +{ 0x20, AC_VERB_SET_COEF_INDEX, 0x29 }, +{ 0x20, AC_VERB_SET_COEF_INDEX, 0x26 }, +{ 0x20, AC_VERB_SET_PROC_COEF, 0x0016 }, +{ 0x20, AC_VERB_SET_PROC_COEF, 0x0000 }, +{ 0x20, AC_VERB_SET_PROC_COEF, 0x0076 }, +{ 0x20, AC_VERB_SET_PROC_COEF, 0xb020 }, +{ 0x20, AC_VERB_SET_COEF_INDEX, 0x26 }, +{ 0x20, AC_VERB_SET_PROC_COEF, 0x0016 }, +{ 0x20, AC_VERB_SET_PROC_COEF, 0x0000 }, +{ 0x20, AC_VERB_SET_PROC_COEF, 0x0076 }, +{ 0x20, AC_VERB_SET_PROC_COEF, 0xb020 }, +{ 0x20, AC_VERB_SET_COEF_INDEX, 0x29 }, +{ 0x20, AC_VERB_SET_COEF_INDEX, 0x29 }, +{ 0x20, AC_VERB_SET_COEF_INDEX, 0x26 }, +{ 0x20, AC_VERB_SET_PROC_COEF, 0x0017 }, +{ 0x20, AC_VERB_SET_PROC_COEF, 0x0000 }, +{ 0x20, AC_VERB_SET_PROC_COEF, 0x0010 }, +{ 0x20, AC_VERB_SET_PROC_COEF, 0xb020 }, +{ 0x20, AC_VERB_SET_COEF_INDEX, 0x26 }, +{ 0x20, AC_VERB_SET_PROC_COEF, 0x0017 }, +{ 0x20, AC_VERB_SET_PROC_COEF, 0x0000 }, +{ 0x20, AC_VERB_SET_PROC_COEF, 0x0010 }, +{ 0x20, AC_VERB_SET_PROC_COEF, 0xb020 }, +{ 0x20, AC_VERB_SET_COEF_INDEX, 0x29 }, +{ 0x20, AC_VERB_SET_COEF_INDEX, 0x29 }, +{ 0x20, AC_VERB_SET_COEF_INDEX, 0x26 }, +{ 0x20, AC_VERB_SET_PROC_COEF, 0x0015 }, +{ 0x20, AC_VERB_SET_PROC_COEF, 0x0000 }, +{ 0x20, AC_VERB_SET_PROC_COEF, 0x0015 }, +{ 0x20, AC_VERB_SET_PROC_COEF, 0xb020 }, +{ 0x20, AC_VERB_SET_COEF_INDEX, 0x26 }, +{ 0x20, AC_VERB_SET_PROC_COEF, 0x0015 }, +{ 0x20, AC_VERB_SET_PROC_COEF, 0x0000 }, +{ 0x20, AC_VERB_SET_PROC_COEF, 0x0015 }, +{ 0x20, AC_VERB_SET_PROC_COEF, 0xb020 }, +{ 0x20, AC_VERB_SET_COEF_INDEX, 0x29 }, +{ 0x20, AC_VERB_SET_COEF_INDEX, 0x29 }, +{ 0x20, AC_VERB_SET_COEF_INDEX, 0x26 }, +{ 0x20, AC_VERB_SET_PROC_COEF, 0x0007 }, +{ 0x20, AC_VERB_SET_PROC_COEF, 0x0000 }, +{ 0x20, AC_VERB_SET_PROC_COEF, 0x0086 }, +{ 0x20, AC_VERB_SET_PROC_COEF, 0xb020 }, +{ 0x20, AC_VERB_SET_COEF_INDEX, 0x26 }, +{ 0x20, AC_VERB_SET_PROC_COEF, 0x0007 }, +{ 0x20, AC_VERB_SET_PROC_COEF, 0x0000 }, +{ 0x20, AC_VERB_SET_PROC_COEF, 0x0086 }, +{ 0x20, AC_VERB_SET_PROC_COEF, 0xb020 }, +{ 0x20, AC_VERB_SET_COEF_INDEX, 0x29 }, +{ 0x20, AC_VERB_SET_COEF_INDEX, 0x29 }, +{ 0x20, AC_VERB_SET_COEF_INDEX, 0x26 }, +{ 0x20, AC_VERB_SET_PROC_COEF, 0x0002 }, +{ 0x20, AC_VERB_SET_PROC_COEF, 0x0000 }, +{ 0x20, AC_VERB_SET_PROC_COEF, 0x0001 }, +{ 0x20, AC_VERB_SET_PROC_COEF, 0xb020 }, +{ 0x20, AC_VERB_SET_COEF_INDEX, 0x26 }, +{ 0x20, AC_VERB_SET_PROC_COEF, 0x0002 }, +{ 0x20, AC_VERB_SET_PROC_COEF, 0x0000 }, +{ 0x20, AC_VERB_SET_PROC_COEF, 0x0001 }, +{ 0x20, AC_VERB_SET_PROC_COEF, 0xb020 }, +{ 0x20, AC_VERB_SET_COEF_INDEX, 0x29 }, +{ 0x20, AC_VERB_SET_COEF_INDEX, 0x29 }, +{ 0x20, AC_VERB_SET_COEF_INDEX, 0x26 }, +{ 0x20, AC_VERB_SET_PROC_COEF, 0x0002 }, +{ 0x20, AC_VERB_SET_PROC_COEF, 0x0000 }, +{ 0x20, AC_VERB_SET_PROC_COEF, 0x0000 }, +{ 0x20, AC_VERB_SET_PROC_COEF, 0xb020 }, +{ 0x20, AC_VERB_SET_COEF_INDEX, 0x26 }, +{ 0x20, AC_VERB_SET_PROC_COEF, 0x0002 }, +{ 0x20, AC_VERB_SET_PROC_COEF, 0x0000 }, +{ 0x20, AC_VERB_SET_PROC_COEF, 0x0000 }, +{ 0x20, AC_VERB_SET_PROC_COEF, 0xb020 }, +{ 0x20, AC_VERB_SET_COEF_INDEX, 0x24 }, +{ 0x20, AC_VERB_SET_PROC_COEF, 0x0042 }, +{ 0x20, AC_VERB_SET_COEF_INDEX, 0x24 }, +{ 0x20, AC_VERB_SET_PROC_COEF, 0x0042 }, +{ 0x20, AC_VERB_SET_COEF_INDEX, 0x29 }, +{ 0x20, AC_VERB_SET_COEF_INDEX, 0x29 }, +{ 0x20, AC_VERB_SET_COEF_INDEX, 0x26 }, +{ 0x20, AC_VERB_SET_PROC_COEF, 0x0000 }, +{ 0x20, AC_VERB_SET_PROC_COEF, 0x0000 }, +{ 0x20, AC_VERB_SET_PROC_COEF, 0x0000 }, +{ 0x20, AC_VERB_SET_PROC_COEF, 0xb020 }, +{ 0x20, AC_VERB_SET_COEF_INDEX, 0x26 }, +{ 0x20, AC_VERB_SET_PROC_COEF, 0x0000 }, +{ 0x20, AC_VERB_SET_PROC_COEF, 0x0000 }, +{ 0x20, AC_VERB_SET_PROC_COEF, 0x0000 }, +{ 0x20, AC_VERB_SET_PROC_COEF, 0xb020 }, +{ 0x20, AC_VERB_SET_COEF_INDEX, 0x29 }, +{ 0x20, AC_VERB_SET_COEF_INDEX, 0x29 }, +{ 0x20, AC_VERB_SET_COEF_INDEX, 0x26 }, +{ 0x20, AC_VERB_SET_PROC_COEF, 0x007f }, +{ 0x20, AC_VERB_SET_PROC_COEF, 0x0000 }, +{ 0x20, AC_VERB_SET_PROC_COEF, 0x0000 }, +{ 0x20, AC_VERB_SET_PROC_COEF, 0xb020 }, +{ 0x20, AC_VERB_SET_COEF_INDEX, 0x26 }, +{ 0x20, AC_VERB_SET_PROC_COEF, 0x007f }, +{ 0x20, AC_VERB_SET_PROC_COEF, 0x0000 }, +{ 0x20, AC_VERB_SET_PROC_COEF, 0x0000 }, +{ 0x20, AC_VERB_SET_PROC_COEF, 0xb020 }, +{ 0x20, AC_VERB_SET_COEF_INDEX, 0x29 }, +{ 0x20, AC_VERB_SET_COEF_INDEX, 0x29 }, +{ 0x20, AC_VERB_SET_COEF_INDEX, 0x26 }, +{ 0x20, AC_VERB_SET_PROC_COEF, 0x0001 }, +{ 0x20, AC_VERB_SET_PROC_COEF, 0x0000 }, +{ 0x20, AC_VERB_SET_PROC_COEF, 0x0001 }, +{ 0x20, AC_VERB_SET_PROC_COEF, 0xb020 }, +{ 0x20, AC_VERB_SET_COEF_INDEX, 0x26 }, +{ 0x20, AC_VERB_SET_PROC_COEF, 0x0001 }, +{ 0x20, AC_VERB_SET_PROC_COEF, 0x0000 }, +{ 0x20, AC_VERB_SET_PROC_COEF, 0x0001 }, +{ 0x20, AC_VERB_SET_PROC_COEF, 0xb020 }, +{ 0x20, AC_VERB_SET_COEF_INDEX, 0x29 }, +{ 0x20, AC_VERB_SET_COEF_INDEX, 0x29 }, +{ 0x20, AC_VERB_SET_COEF_INDEX, 0x26 }, +{ 0x20, AC_VERB_SET_PROC_COEF, 0x003c }, +{ 0x20, AC_VERB_SET_PROC_COEF, 0x0000 }, +{ 0x20, AC_VERB_SET_PROC_COEF, 0x0011 }, +{ 0x20, AC_VERB_SET_PROC_COEF, 0xb020 }, +{ 0x20, AC_VERB_SET_COEF_INDEX, 0x26 }, +{ 0x20, AC_VERB_SET_PROC_COEF, 0x003c }, +{ 0x20, AC_VERB_SET_PROC_COEF, 0x0000 }, +{ 0x20, AC_VERB_SET_PROC_COEF, 0x0011 }, +{ 0x20, AC_VERB_SET_PROC_COEF, 0xb020 }, +{ 0x20, AC_VERB_SET_COEF_INDEX, 0x29 }, +{ 0x20, AC_VERB_SET_COEF_INDEX, 0x29 }, +{ 0x20, AC_VERB_SET_COEF_INDEX, 0x26 }, +{ 0x20, AC_VERB_SET_PROC_COEF, 0x000c }, +{ 0x20, AC_VERB_SET_PROC_COEF, 0x0000 }, +{ 0x20, AC_VERB_SET_PROC_COEF, 0x002a }, +{ 0x20, AC_VERB_SET_PROC_COEF, 0xb020 }, +{ 0x20, AC_VERB_SET_COEF_INDEX, 0x26 }, +{ 0x20, AC_VERB_SET_PROC_COEF, 0x000c }, +{ 0x20, AC_VERB_SET_PROC_COEF, 0x0000 }, +{ 0x20, AC_VERB_SET_PROC_COEF, 0x002a }, +{ 0x20, AC_VERB_SET_PROC_COEF, 0xb020 }, +{ 0x20, AC_VERB_SET_COEF_INDEX, 0x29 }, +{ 0x20, AC_VERB_SET_COEF_INDEX, 0x29 }, +{ 0x20, AC_VERB_SET_COEF_INDEX, 0x26 }, +{ 0x20, AC_VERB_SET_PROC_COEF, 0x000f }, +{ 0x20, AC_VERB_SET_PROC_COEF, 0x0000 }, +{ 0x20, AC_VERB_SET_PROC_COEF, 0x0046 }, +{ 0x20, AC_VERB_SET_PROC_COEF, 0xb020 }, +{ 0x20, AC_VERB_SET_COEF_INDEX, 0x26 }, +{ 0x20, AC_VERB_SET_PROC_COEF, 0x000f }, +{ 0x20, AC_VERB_SET_PROC_COEF, 0x0000 }, +{ 0x20, AC_VERB_SET_PROC_COEF, 0x0046 }, +{ 0x20, AC_VERB_SET_PROC_COEF, 0xb020 }, +{ 0x20, AC_VERB_SET_COEF_INDEX, 0x29 }, +{ 0x20, AC_VERB_SET_COEF_INDEX, 0x29 }, +{ 0x20, AC_VERB_SET_COEF_INDEX, 0x26 }, +{ 0x20, AC_VERB_SET_PROC_COEF, 0x0010 }, +{ 0x20, AC_VERB_SET_PROC_COEF, 0x0000 }, +{ 0x20, AC_VERB_SET_PROC_COEF, 0x0044 }, +{ 0x20, AC_VERB_SET_PROC_COEF, 0xb020 }, +{ 0x20, AC_VERB_SET_COEF_INDEX, 0x26 }, +{ 0x20, AC_VERB_SET_PROC_COEF, 0x0010 }, +{ 0x20, AC_VERB_SET_PROC_COEF, 0x0000 }, +{ 0x20, AC_VERB_SET_PROC_COEF, 0x0044 }, +{ 0x20, AC_VERB_SET_PROC_COEF, 0xb020 }, +{ 0x20, AC_VERB_SET_COEF_INDEX, 0x29 }, +{ 0x20, AC_VERB_SET_COEF_INDEX, 0x29 }, +{ 0x20, AC_VERB_SET_COEF_INDEX, 0x26 }, +{ 0x20, AC_VERB_SET_PROC_COEF, 0x0003 }, +{ 0x20, AC_VERB_SET_PROC_COEF, 0x0000 }, +{ 0x20, AC_VERB_SET_PROC_COEF, 0x0009 }, +{ 0x20, AC_VERB_SET_PROC_COEF, 0xb020 }, +{ 0x20, AC_VERB_SET_COEF_INDEX, 0x26 }, +{ 0x20, AC_VERB_SET_PROC_COEF, 0x0003 }, +{ 0x20, AC_VERB_SET_PROC_COEF, 0x0000 }, +{ 0x20, AC_VERB_SET_PROC_COEF, 0x0009 }, +{ 0x20, AC_VERB_SET_PROC_COEF, 0xb020 }, +{ 0x20, AC_VERB_SET_COEF_INDEX, 0x29 }, +{ 0x20, AC_VERB_SET_COEF_INDEX, 0x29 }, +{ 0x20, AC_VERB_SET_COEF_INDEX, 0x26 }, +{ 0x20, AC_VERB_SET_PROC_COEF, 0x001c }, +{ 0x20, AC_VERB_SET_PROC_COEF, 0x0000 }, +{ 0x20, AC_VERB_SET_PROC_COEF, 0x004c }, +{ 0x20, AC_VERB_SET_PROC_COEF, 0xb020 }, +{ 0x20, AC_VERB_SET_COEF_INDEX, 0x26 }, +{ 0x20, AC_VERB_SET_PROC_COEF, 0x001c }, +{ 0x20, AC_VERB_SET_PROC_COEF, 0x0000 }, +{ 0x20, AC_VERB_SET_PROC_COEF, 0x004c }, +{ 0x20, AC_VERB_SET_PROC_COEF, 0xb020 }, +{ 0x20, AC_VERB_SET_COEF_INDEX, 0x29 }, +{ 0x20, AC_VERB_SET_COEF_INDEX, 0x29 }, +{ 0x20, AC_VERB_SET_COEF_INDEX, 0x29 }, +{ 0x20, AC_VERB_SET_COEF_INDEX, 0x29 }, +{ 0x20, AC_VERB_SET_COEF_INDEX, 0x26 }, +{ 0x20, AC_VERB_SET_PROC_COEF, 0x001b }, +{ 0x20, AC_VERB_SET_PROC_COEF, 0x0000 }, +{ 0x20, AC_VERB_SET_PROC_COEF, 0x0001 }, +{ 0x20, AC_VERB_SET_PROC_COEF, 0xb020 }, +{ 0x20, AC_VERB_SET_COEF_INDEX, 0x26 }, +{ 0x20, AC_VERB_SET_PROC_COEF, 0x001b }, +{ 0x20, AC_VERB_SET_PROC_COEF, 0x0000 }, +{ 0x20, AC_VERB_SET_PROC_COEF, 0x0001 }, +{ 0x20, AC_VERB_SET_PROC_COEF, 0xb020 }, +{ 0x20, AC_VERB_SET_COEF_INDEX, 0x29 }, +{ 0x20, AC_VERB_SET_COEF_INDEX, 0x29 }, +{ 0x20, AC_VERB_SET_COEF_INDEX, 0x26 }, +{ 0x20, AC_VERB_SET_PROC_COEF, 0x0019 }, +{ 0x20, AC_VERB_SET_PROC_COEF, 0x0000 }, +{ 0x20, AC_VERB_SET_PROC_COEF, 0x0025 }, +{ 0x20, AC_VERB_SET_PROC_COEF, 0xb020 }, +{ 0x20, AC_VERB_SET_COEF_INDEX, 0x26 }, +{ 0x20, AC_VERB_SET_PROC_COEF, 0x0019 }, +{ 0x20, AC_VERB_SET_PROC_COEF, 0x0000 }, +{ 0x20, AC_VERB_SET_PROC_COEF, 0x0025 }, +{ 0x20, AC_VERB_SET_PROC_COEF, 0xb020 }, +{ 0x20, AC_VERB_SET_COEF_INDEX, 0x29 }, +{ 0x20, AC_VERB_SET_COEF_INDEX, 0x29 }, +{ 0x20, AC_VERB_SET_COEF_INDEX, 0x26 }, +{ 0x20, AC_VERB_SET_PROC_COEF, 0x0018 }, +{ 0x20, AC_VERB_SET_PROC_COEF, 0x0000 }, +{ 0x20, AC_VERB_SET_PROC_COEF, 0x0037 }, +{ 0x20, AC_VERB_SET_PROC_COEF, 0xb020 }, +{ 0x20, AC_VERB_SET_COEF_INDEX, 0x26 }, +{ 0x20, AC_VERB_SET_PROC_COEF, 0x0018 }, +{ 0x20, AC_VERB_SET_PROC_COEF, 0x0000 }, +{ 0x20, AC_VERB_SET_PROC_COEF, 0x0037 }, +{ 0x20, AC_VERB_SET_PROC_COEF, 0xb020 }, +{ 0x20, AC_VERB_SET_COEF_INDEX, 0x29 }, +{ 0x20, AC_VERB_SET_COEF_INDEX, 0x29 }, +{ 0x20, AC_VERB_SET_COEF_INDEX, 0x26 }, +{ 0x20, AC_VERB_SET_PROC_COEF, 0x001a }, +{ 0x20, AC_VERB_SET_PROC_COEF, 0x0000 }, +{ 0x20, AC_VERB_SET_PROC_COEF, 0x0040 }, +{ 0x20, AC_VERB_SET_PROC_COEF, 0xb020 }, +{ 0x20, AC_VERB_SET_COEF_INDEX, 0x26 }, +{ 0x20, AC_VERB_SET_PROC_COEF, 0x001a }, +{ 0x20, AC_VERB_SET_PROC_COEF, 0x0000 }, +{ 0x20, AC_VERB_SET_PROC_COEF, 0x0040 }, +{ 0x20, AC_VERB_SET_PROC_COEF, 0xb020 }, +{ 0x20, AC_VERB_SET_COEF_INDEX, 0x29 }, +{ 0x20, AC_VERB_SET_COEF_INDEX, 0x29 }, +{ 0x20, AC_VERB_SET_COEF_INDEX, 0x26 }, +{ 0x20, AC_VERB_SET_PROC_COEF, 0x0016 }, +{ 0x20, AC_VERB_SET_PROC_COEF, 0x0000 }, +{ 0x20, AC_VERB_SET_PROC_COEF, 0x0076 }, +{ 0x20, AC_VERB_SET_PROC_COEF, 0xb020 }, +{ 0x20, AC_VERB_SET_COEF_INDEX, 0x26 }, +{ 0x20, AC_VERB_SET_PROC_COEF, 0x0016 }, +{ 0x20, AC_VERB_SET_PROC_COEF, 0x0000 }, +{ 0x20, AC_VERB_SET_PROC_COEF, 0x0076 }, +{ 0x20, AC_VERB_SET_PROC_COEF, 0xb020 }, +{ 0x20, AC_VERB_SET_COEF_INDEX, 0x29 }, +{ 0x20, AC_VERB_SET_COEF_INDEX, 0x29 }, +{ 0x20, AC_VERB_SET_COEF_INDEX, 0x26 }, +{ 0x20, AC_VERB_SET_PROC_COEF, 0x0017 }, +{ 0x20, AC_VERB_SET_PROC_COEF, 0x0000 }, +{ 0x20, AC_VERB_SET_PROC_COEF, 0x0010 }, +{ 0x20, AC_VERB_SET_PROC_COEF, 0xb020 }, +{ 0x20, AC_VERB_SET_COEF_INDEX, 0x26 }, +{ 0x20, AC_VERB_SET_PROC_COEF, 0x0017 }, +{ 0x20, AC_VERB_SET_PROC_COEF, 0x0000 }, +{ 0x20, AC_VERB_SET_PROC_COEF, 0x0010 }, +{ 0x20, AC_VERB_SET_PROC_COEF, 0xb020 }, +{ 0x20, AC_VERB_SET_COEF_INDEX, 0x29 }, +{ 0x20, AC_VERB_SET_COEF_INDEX, 0x29 }, +{ 0x20, AC_VERB_SET_COEF_INDEX, 0x26 }, +{ 0x20, AC_VERB_SET_PROC_COEF, 0x0015 }, +{ 0x20, AC_VERB_SET_PROC_COEF, 0x0000 }, +{ 0x20, AC_VERB_SET_PROC_COEF, 0x0015 }, +{ 0x20, AC_VERB_SET_PROC_COEF, 0xb020 }, +{ 0x20, AC_VERB_SET_COEF_INDEX, 0x26 }, +{ 0x20, AC_VERB_SET_PROC_COEF, 0x0015 }, +{ 0x20, AC_VERB_SET_PROC_COEF, 0x0000 }, +{ 0x20, AC_VERB_SET_PROC_COEF, 0x0015 }, +{ 0x20, AC_VERB_SET_PROC_COEF, 0xb020 }, +{ 0x20, AC_VERB_SET_COEF_INDEX, 0x29 }, +{ 0x20, AC_VERB_SET_COEF_INDEX, 0x29 }, +{ 0x20, AC_VERB_SET_COEF_INDEX, 0x26 }, +{ 0x20, AC_VERB_SET_PROC_COEF, 0x0007 }, +{ 0x20, AC_VERB_SET_PROC_COEF, 0x0000 }, +{ 0x20, AC_VERB_SET_PROC_COEF, 0x0086 }, +{ 0x20, AC_VERB_SET_PROC_COEF, 0xb020 }, +{ 0x20, AC_VERB_SET_COEF_INDEX, 0x26 }, +{ 0x20, AC_VERB_SET_PROC_COEF, 0x0007 }, +{ 0x20, AC_VERB_SET_PROC_COEF, 0x0000 }, +{ 0x20, AC_VERB_SET_PROC_COEF, 0x0086 }, +{ 0x20, AC_VERB_SET_PROC_COEF, 0xb020 }, +{ 0x20, AC_VERB_SET_COEF_INDEX, 0x29 }, +{ 0x20, AC_VERB_SET_COEF_INDEX, 0x29 }, +{ 0x20, AC_VERB_SET_COEF_INDEX, 0x26 }, +{ 0x20, AC_VERB_SET_PROC_COEF, 0x0002 }, +{ 0x20, AC_VERB_SET_PROC_COEF, 0x0000 }, +{ 0x20, AC_VERB_SET_PROC_COEF, 0x0001 }, +{ 0x20, AC_VERB_SET_PROC_COEF, 0xb020 }, +{ 0x20, AC_VERB_SET_COEF_INDEX, 0x26 }, +{ 0x20, AC_VERB_SET_PROC_COEF, 0x0002 }, +{ 0x20, AC_VERB_SET_PROC_COEF, 0x0000 }, +{ 0x20, AC_VERB_SET_PROC_COEF, 0x0001 }, +{ 0x20, AC_VERB_SET_PROC_COEF, 0xb020 }, +{ 0x20, AC_VERB_SET_COEF_INDEX, 0x29 }, +{ 0x20, AC_VERB_SET_COEF_INDEX, 0x29 }, +{ 0x20, AC_VERB_SET_COEF_INDEX, 0x26 }, +{ 0x20, AC_VERB_SET_PROC_COEF, 0x0002 }, +{ 0x20, AC_VERB_SET_PROC_COEF, 0x0000 }, +{ 0x20, AC_VERB_SET_PROC_COEF, 0x0000 }, +{ 0x20, AC_VERB_SET_PROC_COEF, 0xb020 }, +{} +}; + +static void alc285_fixup_ideapad_s740_coef(struct hda_codec *codec, + const struct hda_fixup *fix, + int action) +{ + switch (action) { + case HDA_FIXUP_ACT_PRE_PROBE: + snd_hda_add_verbs(codec, alc285_ideapad_s740_coefs); + break; + } +} diff --git a/sound/pci/hda/patch_realtek.c b/sound/pci/hda/patch_realtek.c index 50437ec1b9af..1ef40f3ca259 100644 --- a/sound/pci/hda/patch_realtek.c +++ b/sound/pci/hda/patch_realtek.c @@ -6239,6 +6239,9 @@ static void alc_fixup_thinkpad_acpi(struct hda_codec *codec, /* for alc295_fixup_hp_top_speakers */ #include "hp_x360_helper.c" +/* for alc285_fixup_ideapad_s740_coef() */ +#include "ideapad_s740_helper.c" + enum { ALC269_FIXUP_GPIO2, ALC269_FIXUP_SONY_VAIO, @@ -6436,6 +6439,7 @@ enum { ALC282_FIXUP_ACER_DISABLE_LINEOUT, ALC255_FIXUP_ACER_LIMIT_INT_MIC_BOOST, ALC256_FIXUP_ACER_HEADSET_MIC, + ALC285_FIXUP_IDEAPAD_S740_COEF, }; static const struct hda_fixup alc269_fixups[] = { @@ -7920,6 +7924,12 @@ static const struct hda_fixup alc269_fixups[] = { .chained = true, .chain_id = ALC269_FIXUP_HEADSET_MODE_NO_HP_MIC }, + [ALC285_FIXUP_IDEAPAD_S740_COEF] = { + .type = HDA_FIXUP_FUNC, + .v.func = alc285_fixup_ideapad_s740_coef, + .chained = true, + .chain_id = ALC269_FIXUP_THINKPAD_ACPI, + }, }; static const struct snd_pci_quirk alc269_fixup_tbl[] = { @@ -8263,6 +8273,7 @@ static const struct snd_pci_quirk alc269_fixup_tbl[] = { SND_PCI_QUIRK(0x17aa, 0x3176, "ThinkCentre Station", ALC283_FIXUP_HEADSET_MIC), SND_PCI_QUIRK(0x17aa, 0x3178, "ThinkCentre Station", ALC283_FIXUP_HEADSET_MIC), SND_PCI_QUIRK(0x17aa, 0x3818, "Lenovo C940", ALC298_FIXUP_LENOVO_SPK_VOLUME), + SND_PCI_QUIRK(0x17aa, 0x3827, "Ideapad S740", ALC285_FIXUP_IDEAPAD_S740_COEF), SND_PCI_QUIRK(0x17aa, 0x3902, "Lenovo E50-80", ALC269_FIXUP_DMIC_THINKPAD_ACPI), SND_PCI_QUIRK(0x17aa, 0x3977, "IdeaPad S210", ALC283_FIXUP_INT_MIC), SND_PCI_QUIRK(0x17aa, 0x3978, "Lenovo B50-70", ALC269_FIXUP_DMIC_THINKPAD_ACPI), From 75b62ab65d2715ce6ff0794033d61ab9dc4a2dfc Mon Sep 17 00:00:00 2001 From: Jonas Witschel Date: Fri, 16 Apr 2021 12:58:54 +0200 Subject: [PATCH 503/587] ALSA: hda/realtek: fix mute/micmute LEDs for HP ProBook 445 G7 The HP ProBook 445 G7 (17T32ES) uses ALC236. Like ALC236_FIXUP_HP_GPIO_LED, COEF index 0x34 bit 5 is used to control the playback mute LED, but the microphone mute LED is controlled using pin VREF instead of a COEF index. AlsaInfo: https://alsa-project.org/db/?f=0d3f4d1af39cc359f9fea9b550727ee87e5cf45a Signed-off-by: Jonas Witschel Cc: Link: https://lore.kernel.org/r/20210416105852.52588-1-diabonas@archlinux.org Signed-off-by: Takashi Iwai --- sound/pci/hda/patch_realtek.c | 25 +++++++++++++++++++++++++ 1 file changed, 25 insertions(+) diff --git a/sound/pci/hda/patch_realtek.c b/sound/pci/hda/patch_realtek.c index 1ef40f3ca259..67aeed5d25b6 100644 --- a/sound/pci/hda/patch_realtek.c +++ b/sound/pci/hda/patch_realtek.c @@ -4445,6 +4445,25 @@ static void alc236_fixup_hp_mute_led(struct hda_codec *codec, alc236_fixup_hp_coef_micmute_led(codec, fix, action); } +static void alc236_fixup_hp_micmute_led_vref(struct hda_codec *codec, + const struct hda_fixup *fix, int action) +{ + struct alc_spec *spec = codec->spec; + + if (action == HDA_FIXUP_ACT_PRE_PROBE) { + spec->cap_mute_led_nid = 0x1a; + snd_hda_gen_add_micmute_led_cdev(codec, vref_micmute_led_set); + codec->power_filter = led_power_filter; + } +} + +static void alc236_fixup_hp_mute_led_micmute_vref(struct hda_codec *codec, + const struct hda_fixup *fix, int action) +{ + alc236_fixup_hp_mute_led_coefbit(codec, fix, action); + alc236_fixup_hp_micmute_led_vref(codec, fix, action); +} + #if IS_REACHABLE(CONFIG_INPUT) static void gpio2_mic_hotkey_event(struct hda_codec *codec, struct hda_jack_callback *event) @@ -6410,6 +6429,7 @@ enum { ALC285_FIXUP_HP_MUTE_LED, ALC236_FIXUP_HP_GPIO_LED, ALC236_FIXUP_HP_MUTE_LED, + ALC236_FIXUP_HP_MUTE_LED_MICMUTE_VREF, ALC298_FIXUP_SAMSUNG_HEADPHONE_VERY_QUIET, ALC295_FIXUP_ASUS_MIC_NO_PRESENCE, ALC269VC_FIXUP_ACER_VCOPPERBOX_PINS, @@ -7669,6 +7689,10 @@ static const struct hda_fixup alc269_fixups[] = { .type = HDA_FIXUP_FUNC, .v.func = alc236_fixup_hp_mute_led, }, + [ALC236_FIXUP_HP_MUTE_LED_MICMUTE_VREF] = { + .type = HDA_FIXUP_FUNC, + .v.func = alc236_fixup_hp_mute_led_micmute_vref, + }, [ALC298_FIXUP_SAMSUNG_HEADPHONE_VERY_QUIET] = { .type = HDA_FIXUP_VERBS, .v.verbs = (const struct hda_verb[]) { @@ -8092,6 +8116,7 @@ static const struct snd_pci_quirk alc269_fixup_tbl[] = { SND_PCI_QUIRK(0x103c, 0x869d, "HP", ALC236_FIXUP_HP_MUTE_LED), SND_PCI_QUIRK(0x103c, 0x8724, "HP EliteBook 850 G7", ALC285_FIXUP_HP_GPIO_LED), SND_PCI_QUIRK(0x103c, 0x8729, "HP", ALC285_FIXUP_HP_GPIO_LED), + SND_PCI_QUIRK(0x103c, 0x8730, "HP ProBook 445 G7", ALC236_FIXUP_HP_MUTE_LED_MICMUTE_VREF), SND_PCI_QUIRK(0x103c, 0x8736, "HP", ALC285_FIXUP_HP_GPIO_AMP_INIT), SND_PCI_QUIRK(0x103c, 0x8760, "HP", ALC285_FIXUP_HP_MUTE_LED), SND_PCI_QUIRK(0x103c, 0x877a, "HP", ALC285_FIXUP_HP_MUTE_LED), From 093b9dcb597611ce65f8c5610ee446616c0be304 Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Thu, 15 Apr 2021 12:50:05 -0500 Subject: [PATCH 504/587] ASoC: Intel: soc-acpi: add ADL SoundWire base configurations Add configurations ported over from TGL. The topology names need to include link information given all the hardware permutations. Signed-off-by: Pierre-Louis Bossart Reviewed-by: Rander Wang Reviewed-by: Libin Yang Link: https://lore.kernel.org/r/20210415175013.192862-2-pierre-louis.bossart@linux.intel.com Signed-off-by: Mark Brown --- .../intel/common/soc-acpi-intel-adl-match.c | 185 ++++++++++++++++++ 1 file changed, 185 insertions(+) diff --git a/sound/soc/intel/common/soc-acpi-intel-adl-match.c b/sound/soc/intel/common/soc-acpi-intel-adl-match.c index 0aca340ebc25..d935745322b6 100644 --- a/sound/soc/intel/common/soc-acpi-intel-adl-match.c +++ b/sound/soc/intel/common/soc-acpi-intel-adl-match.c @@ -15,6 +15,20 @@ static const struct snd_soc_acpi_endpoint single_endpoint = { .group_id = 0, }; +static const struct snd_soc_acpi_endpoint spk_l_endpoint = { + .num = 0, + .aggregated = 1, + .group_position = 0, + .group_id = 1, +}; + +static const struct snd_soc_acpi_endpoint spk_r_endpoint = { + .num = 0, + .aggregated = 1, + .group_position = 1, + .group_id = 1, +}; + static const struct snd_soc_acpi_adr_device rt711_0_adr[] = { { .adr = 0x000020025D071100, @@ -24,6 +38,159 @@ static const struct snd_soc_acpi_adr_device rt711_0_adr[] = { } }; +static const struct snd_soc_acpi_adr_device rt1308_1_group1_adr[] = { + { + .adr = 0x000120025D130800, + .num_endpoints = 1, + .endpoints = &spk_l_endpoint, + .name_prefix = "rt1308-1" + } +}; + +static const struct snd_soc_acpi_adr_device rt1308_2_group1_adr[] = { + { + .adr = 0x000220025D130800, + .num_endpoints = 1, + .endpoints = &spk_r_endpoint, + .name_prefix = "rt1308-2" + } +}; + +static const struct snd_soc_acpi_adr_device rt715_3_adr[] = { + { + .adr = 0x000320025D071500, + .num_endpoints = 1, + .endpoints = &single_endpoint, + .name_prefix = "rt715" + } +}; + +static const struct snd_soc_acpi_adr_device rt711_sdca_0_adr[] = { + { + .adr = 0x000030025D071101, + .num_endpoints = 1, + .endpoints = &single_endpoint, + .name_prefix = "rt711" + } +}; + +static const struct snd_soc_acpi_adr_device rt1316_1_group1_adr[] = { + { + .adr = 0x000131025D131601, /* unique ID is set for some reason */ + .num_endpoints = 1, + .endpoints = &spk_l_endpoint, + .name_prefix = "rt1316-1" + } +}; + +static const struct snd_soc_acpi_adr_device rt1316_2_group1_adr[] = { + { + .adr = 0x000230025D131601, + .num_endpoints = 1, + .endpoints = &spk_r_endpoint, + .name_prefix = "rt1316-2" + } +}; + +static const struct snd_soc_acpi_adr_device rt1316_3_group1_adr[] = { + { + .adr = 0x000330025D131601, + .num_endpoints = 1, + .endpoints = &spk_r_endpoint, + .name_prefix = "rt1316-2" + } +}; + +static const struct snd_soc_acpi_adr_device rt714_2_adr[] = { + { + .adr = 0x000230025D071401, + .num_endpoints = 1, + .endpoints = &single_endpoint, + .name_prefix = "rt714" + } +}; + +static const struct snd_soc_acpi_adr_device rt714_3_adr[] = { + { + .adr = 0x000330025D071401, + .num_endpoints = 1, + .endpoints = &single_endpoint, + .name_prefix = "rt714" + } +}; + +static const struct snd_soc_acpi_link_adr adl_default[] = { + { + .mask = BIT(0), + .num_adr = ARRAY_SIZE(rt711_0_adr), + .adr_d = rt711_0_adr, + }, + { + .mask = BIT(1), + .num_adr = ARRAY_SIZE(rt1308_1_group1_adr), + .adr_d = rt1308_1_group1_adr, + }, + { + .mask = BIT(2), + .num_adr = ARRAY_SIZE(rt1308_2_group1_adr), + .adr_d = rt1308_2_group1_adr, + }, + { + .mask = BIT(3), + .num_adr = ARRAY_SIZE(rt715_3_adr), + .adr_d = rt715_3_adr, + }, + {} +}; + +static const struct snd_soc_acpi_link_adr adl_sdca_default[] = { + { + .mask = BIT(0), + .num_adr = ARRAY_SIZE(rt711_sdca_0_adr), + .adr_d = rt711_sdca_0_adr, + }, + { + .mask = BIT(1), + .num_adr = ARRAY_SIZE(rt1316_1_group1_adr), + .adr_d = rt1316_1_group1_adr, + }, + { + .mask = BIT(2), + .num_adr = ARRAY_SIZE(rt1316_2_group1_adr), + .adr_d = rt1316_2_group1_adr, + }, + { + .mask = BIT(3), + .num_adr = ARRAY_SIZE(rt714_3_adr), + .adr_d = rt714_3_adr, + }, + {} +}; + +static const struct snd_soc_acpi_link_adr adl_sdca_3_in_1[] = { + { + .mask = BIT(0), + .num_adr = ARRAY_SIZE(rt711_sdca_0_adr), + .adr_d = rt711_sdca_0_adr, + }, + { + .mask = BIT(1), + .num_adr = ARRAY_SIZE(rt1316_1_group1_adr), + .adr_d = rt1316_1_group1_adr, + }, + { + .mask = BIT(2), + .num_adr = ARRAY_SIZE(rt714_2_adr), + .adr_d = rt714_2_adr, + }, + { + .mask = BIT(3), + .num_adr = ARRAY_SIZE(rt1316_3_group1_adr), + .adr_d = rt1316_3_group1_adr, + }, + {} +}; + static const struct snd_soc_acpi_link_adr adl_rvp[] = { { .mask = BIT(0), @@ -40,6 +207,24 @@ EXPORT_SYMBOL_GPL(snd_soc_acpi_intel_adl_machines); /* this table is used when there is no I2S codec present */ struct snd_soc_acpi_mach snd_soc_acpi_intel_adl_sdw_machines[] = { + { + .link_mask = 0xF, /* 4 active links required */ + .links = adl_default, + .drv_name = "sof_sdw", + .sof_tplg_filename = "sof-adl-rt711-l0-rt1308-l12-rt715-l3.tplg", + }, + { + .link_mask = 0xF, /* 4 active links required */ + .links = adl_sdca_default, + .drv_name = "sof_sdw", + .sof_tplg_filename = "sof-adl-rt711-l0-rt1316-l12-rt714-l3.tplg", + }, + { + .link_mask = 0xF, /* 4 active links required */ + .links = adl_sdca_3_in_1, + .drv_name = "sof_sdw", + .sof_tplg_filename = "sof-adl-rt711-l0-rt1316-l13-rt714-l2.tplg", + }, { .link_mask = 0x1, /* link0 required */ .links = adl_rvp, From 870dc42fe8311ef5b291ccb21eda3f7069b6f599 Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Thu, 15 Apr 2021 12:50:06 -0500 Subject: [PATCH 505/587] ASoC: Intel: soc-acpi: add ADL jack-less SoundWire configurations Add one configuration with no RT711. Signed-off-by: Pierre-Louis Bossart Reviewed-by: Rander Wang Reviewed-by: Libin Yang Link: https://lore.kernel.org/r/20210415175013.192862-3-pierre-louis.bossart@linux.intel.com Signed-off-by: Mark Brown --- .../intel/common/soc-acpi-intel-adl-match.c | 38 +++++++++++++++++++ 1 file changed, 38 insertions(+) diff --git a/sound/soc/intel/common/soc-acpi-intel-adl-match.c b/sound/soc/intel/common/soc-acpi-intel-adl-match.c index d935745322b6..692c4c479ed8 100644 --- a/sound/soc/intel/common/soc-acpi-intel-adl-match.c +++ b/sound/soc/intel/common/soc-acpi-intel-adl-match.c @@ -101,6 +101,24 @@ static const struct snd_soc_acpi_adr_device rt1316_3_group1_adr[] = { } }; +static const struct snd_soc_acpi_adr_device rt1316_2_single_adr[] = { + { + .adr = 0x000230025D131601, + .num_endpoints = 1, + .endpoints = &single_endpoint, + .name_prefix = "rt1316-1" + } +}; + +static const struct snd_soc_acpi_adr_device rt714_0_adr[] = { + { + .adr = 0x000030025D071401, + .num_endpoints = 1, + .endpoints = &single_endpoint, + .name_prefix = "rt714" + } +}; + static const struct snd_soc_acpi_adr_device rt714_2_adr[] = { { .adr = 0x000230025D071401, @@ -191,6 +209,20 @@ static const struct snd_soc_acpi_link_adr adl_sdca_3_in_1[] = { {} }; +static const struct snd_soc_acpi_link_adr adl_sdw_rt1316_link2_rt714_link0[] = { + { + .mask = BIT(2), + .num_adr = ARRAY_SIZE(rt1316_2_single_adr), + .adr_d = rt1316_2_single_adr, + }, + { + .mask = BIT(0), + .num_adr = ARRAY_SIZE(rt714_0_adr), + .adr_d = rt714_0_adr, + }, + {} +}; + static const struct snd_soc_acpi_link_adr adl_rvp[] = { { .mask = BIT(0), @@ -225,6 +257,12 @@ struct snd_soc_acpi_mach snd_soc_acpi_intel_adl_sdw_machines[] = { .drv_name = "sof_sdw", .sof_tplg_filename = "sof-adl-rt711-l0-rt1316-l13-rt714-l2.tplg", }, + { + .link_mask = 0x5, /* 2 active links required */ + .links = adl_sdw_rt1316_link2_rt714_link0, + .drv_name = "sof_sdw", + .sof_tplg_filename = "sof-adl-rt1316-l2-mono-rt714-l0.tplg", + }, { .link_mask = 0x1, /* link0 required */ .links = adl_rvp, From d25bbe80485f8bcbbeb91a2a6cd8798c124b27b7 Mon Sep 17 00:00:00 2001 From: Vamshi Krishna Gopal Date: Thu, 15 Apr 2021 12:50:09 -0500 Subject: [PATCH 506/587] ASoC: Intel: sof_sdw: add quirk for new ADL-P Rvp Add quirks for jack detection, rt711 DAI and DMIC Reviewed-by: Bard Liao Reviewed-by: Kai Vehmanen Signed-off-by: Vamshi Krishna Gopal Signed-off-by: Pierre-Louis Bossart Link: https://lore.kernel.org/r/20210415175013.192862-6-pierre-louis.bossart@linux.intel.com Signed-off-by: Mark Brown --- sound/soc/intel/boards/sof_sdw.c | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/sound/soc/intel/boards/sof_sdw.c b/sound/soc/intel/boards/sof_sdw.c index 8adce6417b02..ecd3f90f4bbe 100644 --- a/sound/soc/intel/boards/sof_sdw.c +++ b/sound/soc/intel/boards/sof_sdw.c @@ -187,6 +187,17 @@ static const struct dmi_system_id sof_sdw_quirk_table[] = { SOF_RT715_DAI_ID_FIX | SOF_SDW_FOUR_SPK), }, + /* AlderLake devices */ + { + .callback = sof_sdw_quirk_cb, + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "Intel Corporation"), + DMI_MATCH(DMI_PRODUCT_NAME, "Alder Lake Client Platform"), + }, + .driver_data = (void *)(SOF_RT711_JD_SRC_JD1 | + SOF_SDW_TGL_HDMI | + SOF_SDW_PCH_DMIC), + }, {} }; From d97140033948363ffdf5ed71dd2366f717e120e7 Mon Sep 17 00:00:00 2001 From: Daniel Baluta Date: Wed, 14 Apr 2021 13:12:12 +0300 Subject: [PATCH 507/587] ASoC: core: Don't set platform name when of_node is set A DAI link has 3 components: * CPU * platform * codec(s) A component is specified via: * name * of_node * dai_name In order to avoid confusion when building a sound card we disallow matching by both name and of_node (1). soc_check_tplg_fes allows overriding certain BE links by overriding BE link name. This doesn't work well if BE link was specified via DT, because we end up with a link with both name and of_node specified which is conflicting with (1). In order to fix this we need to: * override of_node if component was specified via DT * override name, otherwise. Signed-off-by: Daniel Baluta Link: https://lore.kernel.org/r/20210414101212.65573-1-daniel.baluta@oss.nxp.com Signed-off-by: Mark Brown --- sound/soc/soc-core.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/sound/soc/soc-core.c b/sound/soc/soc-core.c index 236e075b9e57..56bda3b9f691 100644 --- a/sound/soc/soc-core.c +++ b/sound/soc/soc-core.c @@ -1658,7 +1658,11 @@ match: dev_err(card->dev, "init platform error"); continue; } - dai_link->platforms->name = component->name; + + if (component->dev->of_node) + dai_link->platforms->of_node = component->dev->of_node; + else + dai_link->platforms->name = component->name; /* convert non BE into BE */ if (!dai_link->no_pcm) { From 1cacbac447d9b29a4057d7bbffe8c3d4125ec82a Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Fri, 16 Apr 2021 10:59:48 +0900 Subject: [PATCH 508/587] ASoC: soc-pcm: don't use "name" on __soc_pcm_params_symmetry() macro __soc_pcm_params_symmetry() macro is using "name" as parameter which will be exchanged to rate/channles/sample_bit, like below dai->name => dai->rate dai->name => dai->channels dai->name => dai->sample_bit But, dai itself has "name". This means 1) It is very confusable naming 2) It can't use dai->name This patch use "xxx" instead of "name" Signed-off-by: Kuninori Morimoto Link: https://lore.kernel.org/r/8735vryoob.wl-kuninori.morimoto.gx@renesas.com Signed-off-by: Mark Brown --- sound/soc/soc-pcm.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/sound/soc/soc-pcm.c b/sound/soc/soc-pcm.c index 02968a4e52b4..a3fc27fc156f 100644 --- a/sound/soc/soc-pcm.c +++ b/sound/soc/soc-pcm.c @@ -386,16 +386,16 @@ static int soc_pcm_params_symmetry(struct snd_pcm_substream *substream, soc_pcm_set_dai_params(&d, params); -#define __soc_pcm_params_symmetry(name) \ - symmetry = rtd->dai_link->symmetric_##name; \ +#define __soc_pcm_params_symmetry(xxx) \ + symmetry = rtd->dai_link->symmetric_##xxx; \ for_each_rtd_dais(rtd, i, dai) \ - symmetry |= dai->driver->symmetric_##name; \ + symmetry |= dai->driver->symmetric_##xxx; \ \ if (symmetry) \ for_each_rtd_cpu_dais(rtd, i, cpu_dai) \ - if (cpu_dai->name && cpu_dai->name != d.name) { \ + if (cpu_dai->xxx && cpu_dai->xxx != d.xxx) { \ dev_err(rtd->dev, "ASoC: unmatched %s symmetry: %d - %d\n", \ - #name, cpu_dai->name, d.name); \ + #xxx, cpu_dai->xxx, d.xxx); \ return -EINVAL; \ } From ee39d77ed91f220b1458137118dea158a095d5c5 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Fri, 16 Apr 2021 11:00:11 +0900 Subject: [PATCH 509/587] ASoC: soc-pcm: indicate DAI name if soc_pcm_params_symmetry() failed It indicates unmatched symmetry value, but not indicates on which DAI. This patch indicates it. Signed-off-by: Kuninori Morimoto Link: https://lore.kernel.org/r/871rbbyono.wl-kuninori.morimoto.gx@renesas.com Signed-off-by: Mark Brown --- sound/soc/soc-pcm.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/sound/soc/soc-pcm.c b/sound/soc/soc-pcm.c index a3fc27fc156f..72a797b2d1a7 100644 --- a/sound/soc/soc-pcm.c +++ b/sound/soc/soc-pcm.c @@ -384,6 +384,7 @@ static int soc_pcm_params_symmetry(struct snd_pcm_substream *substream, struct snd_soc_dai *cpu_dai; unsigned int symmetry, i; + d.name = __func__; soc_pcm_set_dai_params(&d, params); #define __soc_pcm_params_symmetry(xxx) \ @@ -394,8 +395,8 @@ static int soc_pcm_params_symmetry(struct snd_pcm_substream *substream, if (symmetry) \ for_each_rtd_cpu_dais(rtd, i, cpu_dai) \ if (cpu_dai->xxx && cpu_dai->xxx != d.xxx) { \ - dev_err(rtd->dev, "ASoC: unmatched %s symmetry: %d - %d\n", \ - #xxx, cpu_dai->xxx, d.xxx); \ + dev_err(rtd->dev, "ASoC: unmatched %s symmetry: %s:%d - %s:%d\n", \ + #xxx, cpu_dai->name, cpu_dai->xxx, d.name, d.xxx); \ return -EINVAL; \ } From 8f1a16818a08047c83bc6e29efc07b15fd11fa29 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Fri, 16 Apr 2021 11:00:26 +0900 Subject: [PATCH 510/587] ASoC: soc-utils: add snd_soc_component_is_dummy() There is snd_soc_dai_is_dummy(), but not for component. This patch adds it. Signed-off-by: Kuninori Morimoto Link: https://lore.kernel.org/r/87zgxzxa2t.wl-kuninori.morimoto.gx@renesas.com Signed-off-by: Mark Brown --- include/sound/soc-component.h | 1 + sound/soc/soc-core.c | 2 +- sound/soc/soc-utils.c | 6 ++++++ 3 files changed, 8 insertions(+), 1 deletion(-) diff --git a/include/sound/soc-component.h b/include/sound/soc-component.h index 722cfab28d29..8c4d6830597f 100644 --- a/include/sound/soc-component.h +++ b/include/sound/soc-component.h @@ -338,6 +338,7 @@ static inline int snd_soc_component_cache_sync( void snd_soc_component_set_aux(struct snd_soc_component *component, struct snd_soc_aux_dev *aux); int snd_soc_component_init(struct snd_soc_component *component); +int snd_soc_component_is_dummy(struct snd_soc_component *component); /* component IO */ unsigned int snd_soc_component_read(struct snd_soc_component *component, diff --git a/sound/soc/soc-core.c b/sound/soc/soc-core.c index 236e075b9e57..762fb5c23f21 100644 --- a/sound/soc/soc-core.c +++ b/sound/soc/soc-core.c @@ -1169,7 +1169,7 @@ static int soc_probe_component(struct snd_soc_card *card, int probed = 0; int ret; - if (!strcmp(component->name, "snd-soc-dummy")) + if (snd_soc_component_is_dummy(component)) return 0; if (component->card) { diff --git a/sound/soc/soc-utils.c b/sound/soc/soc-utils.c index f27f94ca064b..98383fd76224 100644 --- a/sound/soc/soc-utils.c +++ b/sound/soc/soc-utils.c @@ -131,6 +131,12 @@ int snd_soc_dai_is_dummy(struct snd_soc_dai *dai) return 0; } +int snd_soc_component_is_dummy(struct snd_soc_component *component) +{ + return ((component->driver == &dummy_platform) || + (component->driver == &dummy_codec)); +} + static int snd_soc_dummy_probe(struct platform_device *pdev) { int ret; From 9c2ae363f3347baacd2353a017eb62363420a1ea Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Fri, 16 Apr 2021 11:00:32 +0900 Subject: [PATCH 511/587] ASoC: soc-pcm: ignore dummy-DAI at soc_pcm_params_symmetry() soc_pcm_params_symmetry() checks CPU / Codec symmetry. Unfortunately there was bug on it (= A) which didn't check Codec. But is back by (B). A: v5.7: commit c840f7698d26 ("ASoC: soc-pcm: Merge for_each_rtd_cpu/codec_dais()") B: v5.12: commit 3a9067211122 ("ASoC: soc-pcm: cleanup soc_pcm_params_symmetry()") In total, old - v5.6 (= Generation-1): symmetric_rate : DAI_Link / CPU / Codec symmetric_channels : DAI_Link / CPU / Codec symmetric_sample_bits : DAI_Link / CPU / Codec v5.7 - v5.11 (= Generation-2): (= because of bug by (A)) symmetric_rate : DAI_Link / CPU symmetric_channels : DAI_Link / CPU / Codec symmetric_sample_bits : DAI_Link / CPU / Codec v5.12 - (= Generation-3): (= back by (B)) symmetric_rate : DAI_Link / CPU / Codec symmetric_channels : DAI_Link / CPU / Codec symmetric_sample_bits : DAI_Link / CPU / Codec OTOH, we can use DPCM which is configured by FE / BE. Both FE / BE uses dummy-DAI. FE: CPU <-> dummy-DAI BE: dummy-DAI <-> Codec One note is that we can use .be_hw_params_fixup in DPCM case. This means BE settings might be fixuped/updated by FE. This feature is used for example on MIXer case. It can be happen not only for rate, but for channels/sample_bits too. Because of these reasons, below issue happen on Generation-1 / Generation-3, if... 1) Sound Card used DPCM 2) It exchanges rate to 48kHz by using .be_hw_params_fixup() 3) Codec had symmetric_rate = 1 I didn't confirm, but maybe same things happen if it exchanged channels/sample_bits at Generation-1/2/3 too. # aplay 44100.wav # aplay 44100.wav => [kernel] be.ak4613-hifi: ASoC: unmatched rate symmetry: snd-soc-dummy-dai:44100 - soc_pcm_params_symmetry:48000 [kernel] be.ak4613-hifi: ASoC: hw_params BE failed -22 [kernel] fe.rsnd-dai.0: ASoC: hw_params BE failed -22 aplay: set_params:1407: Unable to install hw params: ACCESS: RW_INTERLEAVED FORMAT: S16_LE SUBFORMAT: STD SAMPLE_BITS: 16 FRAME_BITS: 32 CHANNELS: 2 RATE: 44100 PERIOD_TIME: (23219 23220) PERIOD_SIZE: 1024 PERIOD_BYTES: 4096 PERIODS: 4 BUFFER_TIME: (92879 92880) BUFFER_SIZE: 4096 BUFFER_BYTES: 16384 TICK_TIME: 0 soc_pcm_params_symmetry() checks by below if (symmetry) for_each_rtd_cpu_dais(rtd, i, cpu_dai) if (cpu_dai->xxx && cpu_dai->xxx != d.xxx) { dev_err(rtd->dev, "..."); return -EINVAL; } Because of above reason 3) (= Codec had symmetric_rate = 1) BE can't ignore "if (symmetric)". At 1st aplay, soc_pcm_params_symmetry() ignores it, because dummy-DAI->rate is 0. After this check, each DAI sets/keep settings. In above sample case, BE gets 48000 and FE gets 44100, and it happen BE -> FE order. Because DPCM is sharing *same* dummy-DAI, dummy-DAI sets as 48000 by BE, and is overwrote by 44100 by FE. This settings never be cleaned (= a) after 1st aplay, because dummy-DAI is used from FE/BE, never be last user (b). static int soc_pcm_hw_clean(...) { ... for_each_rtd_dais(rtd, i, dai) { ... (b) if (snd_soc_dai_active(dai) == 1) (a) soc_pcm_set_dai_params(dai, NULL); ... } ... } At 2nd aplay, BE gets 48000 but dummy-DAI is keeping 44100, soc_pcm_params_symmetry() checks will fail. To solve this issue, this patch ignores dummy-DAI at soc_pcm_params_symmetry() Link: https://lore.kernel.org/r/87a6q0z4xt.wl-kuninori.morimoto.gx@renesas.com Signed-off-by: Kuninori Morimoto Link: https://lore.kernel.org/r/87y2djxa2n.wl-kuninori.morimoto.gx@renesas.com Signed-off-by: Mark Brown --- sound/soc/soc-pcm.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/sound/soc/soc-pcm.c b/sound/soc/soc-pcm.c index 72a797b2d1a7..8659089a87a0 100644 --- a/sound/soc/soc-pcm.c +++ b/sound/soc/soc-pcm.c @@ -394,7 +394,8 @@ static int soc_pcm_params_symmetry(struct snd_pcm_substream *substream, \ if (symmetry) \ for_each_rtd_cpu_dais(rtd, i, cpu_dai) \ - if (cpu_dai->xxx && cpu_dai->xxx != d.xxx) { \ + if (!snd_soc_dai_is_dummy(cpu_dai) && \ + cpu_dai->xxx && cpu_dai->xxx != d.xxx) { \ dev_err(rtd->dev, "ASoC: unmatched %s symmetry: %s:%d - %s:%d\n", \ #xxx, cpu_dai->name, cpu_dai->xxx, d.name, d.xxx); \ return -EINVAL; \ From 0c37e2eb6b83e375e8a654d01598292d5591fc65 Mon Sep 17 00:00:00 2001 From: Kai Vehmanen Date: Fri, 16 Apr 2021 16:11:57 +0300 Subject: [PATCH 512/587] ALSA: hda/hdmi: fix race in handling acomp ELD notification at resume When snd-hda-codec-hdmi is used with ASoC HDA controller like SOF (acomp used for ELD notifications), display connection change done during suspend, can be lost due to following sequence of events: 1. system in S3 suspend 2. DP/HDMI receiver connected 3. system resumed 4. HDA controller resumed, but card->deferred_resume_work not complete 5. acomp eld_notify callback 6. eld_notify ignored as power state is not CTL_POWER_D0 7. HDA resume deferred work completed, power state set to CTL_POWER_D0 This results in losing the notification, and the jack state reported to user-space is not correct. The check on step 6 was added in commit 8ae743e82f0b ("ALSA: hda - Skip ELD notification during system suspend"). It would seem with the deferred resume logic in ASoC core, this check is not safe. Fix the issue by modifying the check to use "dev.power.power_state.event" instead of ALSA specific card power state variable. BugLink: https://github.com/thesofproject/linux/issues/2825 Suggested-by: Takashi Iwai Signed-off-by: Kai Vehmanen Link: https://lore.kernel.org/r/20210416131157.1881366-1-kai.vehmanen@linux.intel.com Signed-off-by: Takashi Iwai --- sound/pci/hda/patch_hdmi.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/sound/pci/hda/patch_hdmi.c b/sound/pci/hda/patch_hdmi.c index 5de3666a7101..4b2cc8cb55c4 100644 --- a/sound/pci/hda/patch_hdmi.c +++ b/sound/pci/hda/patch_hdmi.c @@ -2654,7 +2654,7 @@ static void generic_acomp_pin_eld_notify(void *audio_ptr, int port, int dev_id) /* skip notification during system suspend (but not in runtime PM); * the state will be updated at resume */ - if (snd_power_get_state(codec->card) != SNDRV_CTL_POWER_D0) + if (codec->core.dev.power.power_state.event == PM_EVENT_SUSPEND) return; /* ditto during suspend/resume process itself */ if (snd_hdac_is_in_pm(&codec->core)) @@ -2840,7 +2840,7 @@ static void intel_pin_eld_notify(void *audio_ptr, int port, int pipe) /* skip notification during system suspend (but not in runtime PM); * the state will be updated at resume */ - if (snd_power_get_state(codec->card) != SNDRV_CTL_POWER_D0) + if (codec->core.dev.power.power_state.event == PM_EVENT_SUSPEND) return; /* ditto during suspend/resume process itself */ if (snd_hdac_is_in_pm(&codec->core)) From 0f687d826736a5b4eee03170382fe54d413b912a Mon Sep 17 00:00:00 2001 From: Thierry Reding Date: Fri, 16 Apr 2021 09:11:46 +0200 Subject: [PATCH 513/587] ASoC: simple-card-utils: Propagate errors on too many links The DAI counting code doesn't propagate errors when the number of maximum links is exceeded, which causes subsequent initialization code to continue to run and that eventually leads to memory corruption with the code trying to access memory that is out of bounds. Fix this by propagating errors when the maximum number of links is reached, which ensures that the driver fails to load and prevents the memory corruption. Fixes: f2138aed231c ("ASoC: simple-card-utils: enable flexible CPU/Codec/Platform") Signed-off-by: Thierry Reding Link: https://lore.kernel.org/r/20210416071147.2149109-1-thierry.reding@gmail.com Reviewed-by: Jon Hunter Tested-by: Jon Hunter Signed-off-by: Mark Brown --- sound/soc/generic/audio-graph-card.c | 19 +++++++++++-------- sound/soc/generic/simple-card.c | 17 ++++++++++------- 2 files changed, 21 insertions(+), 15 deletions(-) diff --git a/sound/soc/generic/audio-graph-card.c b/sound/soc/generic/audio-graph-card.c index 36b2ad7dd283..080c1a22bfc2 100644 --- a/sound/soc/generic/audio-graph-card.c +++ b/sound/soc/generic/audio-graph-card.c @@ -542,8 +542,8 @@ static int graph_for_each_link(struct asoc_simple_priv *priv, return ret; } -static void graph_get_dais_count(struct asoc_simple_priv *priv, - struct link_info *li); +static int graph_get_dais_count(struct asoc_simple_priv *priv, + struct link_info *li); int audio_graph_parse_of(struct asoc_simple_priv *priv, struct device *dev) { @@ -555,7 +555,10 @@ int audio_graph_parse_of(struct asoc_simple_priv *priv, struct device *dev) card->dev = dev; memset(&li, 0, sizeof(li)); - graph_get_dais_count(priv, &li); + ret = graph_get_dais_count(priv, &li); + if (ret < 0) + return ret; + if (!li.link) return -EINVAL; @@ -660,8 +663,8 @@ static int graph_count_dpcm(struct asoc_simple_priv *priv, return 0; } -static void graph_get_dais_count(struct asoc_simple_priv *priv, - struct link_info *li) +static int graph_get_dais_count(struct asoc_simple_priv *priv, + struct link_info *li) { /* * link_num : number of links. @@ -709,9 +712,9 @@ static void graph_get_dais_count(struct asoc_simple_priv *priv, * => 4 DAIs = 2xCPU + 2xCodec * => 1 ccnf = 1xdummy-Codec */ - graph_for_each_link(priv, li, - graph_count_noml, - graph_count_dpcm); + return graph_for_each_link(priv, li, + graph_count_noml, + graph_count_dpcm); } int audio_graph_card_probe(struct snd_soc_card *card) diff --git a/sound/soc/generic/simple-card.c b/sound/soc/generic/simple-card.c index 5a686f82d1b4..e05539b5f997 100644 --- a/sound/soc/generic/simple-card.c +++ b/sound/soc/generic/simple-card.c @@ -524,8 +524,8 @@ static int simple_count_dpcm(struct asoc_simple_priv *priv, return 0; } -static void simple_get_dais_count(struct asoc_simple_priv *priv, - struct link_info *li) +static int simple_get_dais_count(struct asoc_simple_priv *priv, + struct link_info *li) { struct device *dev = simple_priv_to_dev(priv); struct device_node *top = dev->of_node; @@ -582,12 +582,12 @@ static void simple_get_dais_count(struct asoc_simple_priv *priv, li->num[0].platforms = 1; li->link = 1; - return; + return 0; } - simple_for_each_link(priv, li, - simple_count_noml, - simple_count_dpcm); + return simple_for_each_link(priv, li, + simple_count_noml, + simple_count_dpcm); } static int simple_soc_probe(struct snd_soc_card *card) @@ -626,7 +626,10 @@ static int asoc_simple_probe(struct platform_device *pdev) card->probe = simple_soc_probe; memset(&li, 0, sizeof(li)); - simple_get_dais_count(priv, &li); + ret = simple_get_dais_count(priv, &li); + if (ret < 0) + return ret; + if (!li.link) return -EINVAL; From 343e55e71877415a23372388b3e0c59a9bba42f6 Mon Sep 17 00:00:00 2001 From: Thierry Reding Date: Fri, 16 Apr 2021 09:11:47 +0200 Subject: [PATCH 514/587] ASoC: simple-card-utils: Increase maximum number of links to 128 On Tegra186 and later, the number of links can go up to 72, so bump the maximum number of links to the next power of two (128). Fixes: f2138aed231c ("ASoC: simple-card-utils: enable flexible CPU/Codec/Platform") Signed-off-by: Thierry Reding Link: https://lore.kernel.org/r/20210416071147.2149109-2-thierry.reding@gmail.com Reviewed-by: Jon Hunter Tested-by: Jon Hunter Signed-off-by: Mark Brown --- include/sound/simple_card_utils.h | 4 +++- sound/soc/generic/audio-graph-card.c | 4 ++-- sound/soc/generic/simple-card.c | 4 ++-- 3 files changed, 7 insertions(+), 5 deletions(-) diff --git a/include/sound/simple_card_utils.h b/include/sound/simple_card_utils.h index fac3b832d982..e318a2d4ac44 100644 --- a/include/sound/simple_card_utils.h +++ b/include/sound/simple_card_utils.h @@ -115,10 +115,12 @@ struct asoc_simple_priv { ((codec) = simple_props_to_dai_codec(props, i)); \ (i)++) +#define SNDRV_MAX_LINKS 128 + struct link_info { int link; /* number of link */ int cpu; /* turn for CPU / Codec */ - struct prop_nums num[SNDRV_MINOR_DEVICES]; + struct prop_nums num[SNDRV_MAX_LINKS]; }; int asoc_simple_parse_daifmt(struct device *dev, diff --git a/sound/soc/generic/audio-graph-card.c b/sound/soc/generic/audio-graph-card.c index 080c1a22bfc2..c7369beee805 100644 --- a/sound/soc/generic/audio-graph-card.c +++ b/sound/soc/generic/audio-graph-card.c @@ -619,7 +619,7 @@ static int graph_count_noml(struct asoc_simple_priv *priv, { struct device *dev = simple_priv_to_dev(priv); - if (li->link >= SNDRV_MINOR_DEVICES) { + if (li->link >= SNDRV_MAX_LINKS) { dev_err(dev, "too many links\n"); return -EINVAL; } @@ -642,7 +642,7 @@ static int graph_count_dpcm(struct asoc_simple_priv *priv, { struct device *dev = simple_priv_to_dev(priv); - if (li->link >= SNDRV_MINOR_DEVICES) { + if (li->link >= SNDRV_MAX_LINKS) { dev_err(dev, "too many links\n"); return -EINVAL; } diff --git a/sound/soc/generic/simple-card.c b/sound/soc/generic/simple-card.c index e05539b5f997..8b9964d25757 100644 --- a/sound/soc/generic/simple-card.c +++ b/sound/soc/generic/simple-card.c @@ -482,7 +482,7 @@ static int simple_count_noml(struct asoc_simple_priv *priv, struct device_node *codec, struct link_info *li, bool is_top) { - if (li->link >= SNDRV_MINOR_DEVICES) { + if (li->link >= SNDRV_MAX_LINKS) { struct device *dev = simple_priv_to_dev(priv); dev_err(dev, "too many links\n"); @@ -503,7 +503,7 @@ static int simple_count_dpcm(struct asoc_simple_priv *priv, struct device_node *codec, struct link_info *li, bool is_top) { - if (li->link >= SNDRV_MINOR_DEVICES) { + if (li->link >= SNDRV_MAX_LINKS) { struct device *dev = simple_priv_to_dev(priv); dev_err(dev, "too many links\n"); From a48f928e13a01d60c9c2a7a7ffab3afd1f7337bf Mon Sep 17 00:00:00 2001 From: Jack Yu Date: Mon, 29 Mar 2021 06:54:05 +0000 Subject: [PATCH 515/587] ASoC: rt715: modification for code simplicity Modification for code simplicity. Signed-off-by: Jack Yu Link: https://lore.kernel.org/r/340ee2df83ce47fcb1b59541b12ba7f4@realtek.com Signed-off-by: Mark Brown --- sound/soc/codecs/rt715.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/sound/soc/codecs/rt715.c b/sound/soc/codecs/rt715.c index f419d001a3fb..0f78ffbb03fd 100644 --- a/sound/soc/codecs/rt715.c +++ b/sound/soc/codecs/rt715.c @@ -57,14 +57,14 @@ static void rt715_get_gain(struct rt715_priv *rt715, unsigned int addr_h, { int ret; /* R Channel */ - *r_val = (val_h << 8); + *r_val = val_h << 8; ret = regmap_read(rt715->regmap, addr_l, r_val); if (ret < 0) pr_err("Failed to get R channel gain.\n"); /* L Channel */ val_h |= 0x20; - *l_val = (val_h << 8); + *l_val = val_h << 8; ret = regmap_read(rt715->regmap, addr_h, l_val); if (ret < 0) pr_err("Failed to get L channel gain.\n"); @@ -188,8 +188,8 @@ static int rt715_set_amp_gain_get(struct snd_kcontrol *kcontrol, if (mc->invert) { /* for mute status */ - read_ll = !((read_ll & 0x80) >> RT715_MUTE_SFT); - read_rl = !((read_rl & 0x80) >> RT715_MUTE_SFT); + read_ll = !(read_ll & 0x80); + read_rl = !(read_rl & 0x80); } else { /* for gain */ read_ll = read_ll & 0x7f; From dcca646c4977d885af3466b454df97b9cb0e0d26 Mon Sep 17 00:00:00 2001 From: Jack Yu Date: Mon, 29 Mar 2021 06:53:54 +0000 Subject: [PATCH 516/587] ASoC: rt715: add main capture switch and main capture volume Add main capture switch and main capture volume control. Main capture control has its own channel value respectivelly. Signed-off-by: Jack Yu Link: https://lore.kernel.org/r/dfd43a8db04e4d52a889d6f5c1262173@realtek.com Signed-off-by: Mark Brown --- sound/soc/codecs/rt715.c | 256 +++++++++++++++++++++++++++++++++++++++ sound/soc/codecs/rt715.h | 2 + 2 files changed, 258 insertions(+) diff --git a/sound/soc/codecs/rt715.c b/sound/soc/codecs/rt715.c index 0f78ffbb03fd..3849dd187de0 100644 --- a/sound/soc/codecs/rt715.c +++ b/sound/soc/codecs/rt715.c @@ -201,9 +201,246 @@ static int rt715_set_amp_gain_get(struct snd_kcontrol *kcontrol, return 0; } +static int rt715_set_main_switch_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_component *component = snd_kcontrol_chip(kcontrol); + struct snd_soc_dapm_context *dapm = + snd_soc_component_get_dapm(component); + struct rt715_priv *rt715 = snd_soc_component_get_drvdata(component); + unsigned int capture_reg_H[] = {RT715_SET_GAIN_MIC_ADC_H, + RT715_SET_GAIN_LINE_ADC_H, RT715_SET_GAIN_MIX_ADC_H, + RT715_SET_GAIN_MIX_ADC2_H}; + unsigned int capture_reg_L[] = {RT715_SET_GAIN_MIC_ADC_L, + RT715_SET_GAIN_LINE_ADC_L, RT715_SET_GAIN_MIX_ADC_L, + RT715_SET_GAIN_MIX_ADC2_L}; + unsigned int addr_h, addr_l, val_h = 0x0, val_ll, val_lr; + unsigned int k_shift = RT715_DIR_IN_SFT, k_changed = 0; + unsigned int read_ll, read_rl, i, j, loop_cnt = 4; + + for (i = 0; i < 8; i++) { + if (ucontrol->value.integer.value[i] != rt715->kctl_8ch_switch_ori[i]) + k_changed = 1; + } + + for (j = 0; j < loop_cnt; j++) { + /* Can't use update bit function, so read the original value first */ + addr_h = capture_reg_H[j]; + addr_l = capture_reg_L[j]; + rt715_get_gain(rt715, addr_h, addr_l, val_h, &read_rl, &read_ll); + + if (dapm->bias_level <= SND_SOC_BIAS_STANDBY) + regmap_write(rt715->regmap, + RT715_SET_AUDIO_POWER_STATE, AC_PWRST_D0); + + /* L Channel */ + /* for mute */ + rt715->kctl_8ch_switch_ori[j * 2] = + ucontrol->value.integer.value[j * 2]; + val_ll = (!ucontrol->value.integer.value[j * 2]) << 7; + /* keep gain */ + val_ll |= read_ll & 0x7f; + + /* R Channel */ + /* for mute */ + rt715->kctl_8ch_switch_ori[j * 2 + 1] = + ucontrol->value.integer.value[j * 2 + 1]; + val_lr = (!ucontrol->value.integer.value[j * 2 + 1]) << 7; + /* keep gain */ + val_lr |= read_rl & 0x7f; + + for (i = 0; i < 3; i++) { /* retry 3 times at most */ + + if (val_ll == val_lr) { + /* Set both L/R channels at the same time */ + val_h = (1 << k_shift) | (3 << 4); + regmap_write(rt715->regmap, addr_h, + (val_h << 8) | val_ll); + regmap_write(rt715->regmap, addr_l, + (val_h << 8) | val_ll); + } else { + /* Lch*/ + val_h = (1 << k_shift) | (1 << 5); + regmap_write(rt715->regmap, addr_h, + (val_h << 8) | val_ll); + /* Rch */ + val_h = (1 << k_shift) | (1 << 4); + regmap_write(rt715->regmap, addr_l, + (val_h << 8) | val_lr); + } + val_h = 0x0; + rt715_get_gain(rt715, addr_h, addr_l, val_h, + &read_rl, &read_ll); + if (read_rl == val_lr && read_ll == val_ll) + break; + } + } + + /* D0:power on state, D3: power saving mode */ + if (dapm->bias_level <= SND_SOC_BIAS_STANDBY) + regmap_write(rt715->regmap, + RT715_SET_AUDIO_POWER_STATE, AC_PWRST_D3); + return k_changed; +} + +static int rt715_set_main_switch_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_component *component = snd_kcontrol_chip(kcontrol); + struct rt715_priv *rt715 = snd_soc_component_get_drvdata(component); + unsigned int capture_reg_H[] = {RT715_SET_GAIN_MIC_ADC_H, + RT715_SET_GAIN_LINE_ADC_H, RT715_SET_GAIN_MIX_ADC_H, + RT715_SET_GAIN_MIX_ADC2_H}; + unsigned int capture_reg_L[] = {RT715_SET_GAIN_MIC_ADC_L, + RT715_SET_GAIN_LINE_ADC_L, RT715_SET_GAIN_MIX_ADC_L, + RT715_SET_GAIN_MIX_ADC2_L}; + unsigned int addr_h, addr_l, val_h = 0x0, i, loop_cnt = 4; + unsigned int read_ll, read_rl; + + for (i = 0; i < loop_cnt; i++) { + addr_h = capture_reg_H[i]; + addr_l = capture_reg_L[i]; + rt715_get_gain(rt715, addr_h, addr_l, val_h, &read_rl, &read_ll); + + ucontrol->value.integer.value[i * 2] = !(read_ll & 0x80); + ucontrol->value.integer.value[i * 2 + 1] = !(read_rl & 0x80); + } + + return 0; +} + +static int rt715_set_main_vol_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_component *component = snd_kcontrol_chip(kcontrol); + struct snd_soc_dapm_context *dapm = + snd_soc_component_get_dapm(component); + struct rt715_priv *rt715 = snd_soc_component_get_drvdata(component); + unsigned int capture_reg_H[] = {RT715_SET_GAIN_MIC_ADC_H, + RT715_SET_GAIN_LINE_ADC_H, RT715_SET_GAIN_MIX_ADC_H, + RT715_SET_GAIN_MIX_ADC2_H}; + unsigned int capture_reg_L[] = {RT715_SET_GAIN_MIC_ADC_L, + RT715_SET_GAIN_LINE_ADC_L, RT715_SET_GAIN_MIX_ADC_L, + RT715_SET_GAIN_MIX_ADC2_L}; + unsigned int addr_h, addr_l, val_h = 0x0, val_ll, val_lr; + unsigned int read_ll, read_rl, i, j, loop_cnt = 4, k_changed = 0; + unsigned int k_shift = RT715_DIR_IN_SFT, k_max = 0x3f; + + for (i = 0; i < 8; i++) { + if (ucontrol->value.integer.value[i] != rt715->kctl_8ch_vol_ori[i]) + k_changed = 1; + } + + for (j = 0; j < loop_cnt; j++) { + addr_h = capture_reg_H[j]; + addr_l = capture_reg_L[j]; + rt715_get_gain(rt715, addr_h, addr_l, val_h, &read_rl, &read_ll); + + if (dapm->bias_level <= SND_SOC_BIAS_STANDBY) + regmap_write(rt715->regmap, + RT715_SET_AUDIO_POWER_STATE, AC_PWRST_D0); + + /* L Channel */ + /* for gain */ + rt715->kctl_8ch_vol_ori[j * 2] = ucontrol->value.integer.value[j * 2]; + val_ll = ((ucontrol->value.integer.value[j * 2]) & 0x7f); + if (val_ll > k_max) + val_ll = k_max; + /* keep mute status */ + val_ll |= read_ll & 0x80; + + /* R Channel */ + /* for gain */ + rt715->kctl_8ch_vol_ori[j * 2 + 1] = + ucontrol->value.integer.value[j * 2 + 1]; + val_lr = ((ucontrol->value.integer.value[j * 2 + 1]) & 0x7f); + if (val_lr > k_max) + val_lr = k_max; + /* keep mute status */ + val_lr |= read_rl & 0x80; + + for (i = 0; i < 3; i++) { /* retry 3 times at most */ + if (val_ll == val_lr) { + /* Set both L/R channels at the same time */ + val_h = (1 << k_shift) | (3 << 4); + regmap_write(rt715->regmap, addr_h, + (val_h << 8) | val_ll); + regmap_write(rt715->regmap, addr_l, + (val_h << 8) | val_ll); + } else { + /* Lch*/ + val_h = (1 << k_shift) | (1 << 5); + regmap_write(rt715->regmap, addr_h, + (val_h << 8) | val_ll); + /* Rch */ + val_h = (1 << k_shift) | (1 << 4); + regmap_write(rt715->regmap, addr_l, + (val_h << 8) | val_lr); + } + val_h = 0x0; + rt715_get_gain(rt715, addr_h, addr_l, val_h, + &read_rl, &read_ll); + if (read_rl == val_lr && read_ll == val_ll) + break; + } + } + + /* D0:power on state, D3: power saving mode */ + if (dapm->bias_level <= SND_SOC_BIAS_STANDBY) + regmap_write(rt715->regmap, + RT715_SET_AUDIO_POWER_STATE, AC_PWRST_D3); + return k_changed; +} + +static int rt715_set_main_vol_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_component *component = snd_kcontrol_chip(kcontrol); + struct rt715_priv *rt715 = snd_soc_component_get_drvdata(component); + unsigned int capture_reg_H[] = {RT715_SET_GAIN_MIC_ADC_H, + RT715_SET_GAIN_LINE_ADC_H, RT715_SET_GAIN_MIX_ADC_H, + RT715_SET_GAIN_MIX_ADC2_H}; + unsigned int capture_reg_L[] = {RT715_SET_GAIN_MIC_ADC_L, + RT715_SET_GAIN_LINE_ADC_L, RT715_SET_GAIN_MIX_ADC_L, + RT715_SET_GAIN_MIX_ADC2_L}; + unsigned int addr_h, addr_l, val_h = 0x0, i, loop_cnt = 4; + unsigned int read_ll, read_rl; + + for (i = 0; i < loop_cnt; i++) { + addr_h = capture_reg_H[i]; + addr_l = capture_reg_L[i]; + rt715_get_gain(rt715, addr_h, addr_l, val_h, &read_rl, &read_ll); + + ucontrol->value.integer.value[i * 2] = read_ll & 0x7f; + ucontrol->value.integer.value[i * 2 + 1] = read_rl & 0x7f; + } + + return 0; +} + static const DECLARE_TLV_DB_SCALE(in_vol_tlv, -1725, 75, 0); static const DECLARE_TLV_DB_SCALE(mic_vol_tlv, 0, 1000, 0); +static int rt715_switch_info(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_info *uinfo) +{ + uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN; + uinfo->count = 8; + uinfo->value.integer.min = 0; + uinfo->value.integer.max = 1; + return 0; +} + +static int rt715_vol_info(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_info *uinfo) +{ + uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER; + uinfo->count = 8; + uinfo->value.integer.min = 0; + uinfo->value.integer.max = 0x3f; + return 0; +} + #define SOC_DOUBLE_R_EXT(xname, reg_left, reg_right, xshift, xmax, xinvert,\ xhandler_get, xhandler_put) \ { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = (xname), \ @@ -212,6 +449,21 @@ static const DECLARE_TLV_DB_SCALE(mic_vol_tlv, 0, 1000, 0); .private_value = SOC_DOUBLE_R_VALUE(reg_left, reg_right, xshift, \ xmax, xinvert) } +#define RT715_MAIN_SWITCH_EXT(xname, xhandler_get, xhandler_put) \ +{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = (xname), \ + .info = rt715_switch_info, \ + .get = xhandler_get, .put = xhandler_put, \ +} + +#define RT715_MAIN_VOL_EXT_TLV(xname, xhandler_get, xhandler_put, tlv_array) \ +{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = (xname), \ + .access = SNDRV_CTL_ELEM_ACCESS_TLV_READ | \ + SNDRV_CTL_ELEM_ACCESS_READWRITE, \ + .tlv.p = (tlv_array), \ + .info = rt715_vol_info, \ + .get = xhandler_get, .put = xhandler_put, \ +} + static const struct snd_kcontrol_new rt715_snd_controls[] = { /* Capture switch */ SOC_DOUBLE_R_EXT("ADC 07 Capture Switch", RT715_SET_GAIN_MIC_ADC_H, @@ -226,6 +478,8 @@ static const struct snd_kcontrol_new rt715_snd_controls[] = { SOC_DOUBLE_R_EXT("ADC 27 Capture Switch", RT715_SET_GAIN_MIX_ADC2_H, RT715_SET_GAIN_MIX_ADC2_L, RT715_DIR_IN_SFT, 1, 1, rt715_set_amp_gain_get, rt715_set_amp_gain_put), + RT715_MAIN_SWITCH_EXT("Capture Switch", + rt715_set_main_switch_get, rt715_set_main_switch_put), /* Volume Control */ SOC_DOUBLE_R_EXT_TLV("ADC 07 Capture Volume", RT715_SET_GAIN_MIC_ADC_H, RT715_SET_GAIN_MIC_ADC_L, RT715_DIR_IN_SFT, 0x3f, 0, @@ -243,6 +497,8 @@ static const struct snd_kcontrol_new rt715_snd_controls[] = { RT715_SET_GAIN_MIX_ADC2_L, RT715_DIR_IN_SFT, 0x3f, 0, rt715_set_amp_gain_get, rt715_set_amp_gain_put, in_vol_tlv), + RT715_MAIN_VOL_EXT_TLV("Capture Volume", + rt715_set_main_vol_get, rt715_set_main_vol_put, in_vol_tlv), /* MIC Boost Control */ SOC_DOUBLE_R_EXT_TLV("DMIC1 Boost", RT715_SET_GAIN_DMIC1_H, RT715_SET_GAIN_DMIC1_L, RT715_DIR_IN_SFT, 3, 0, diff --git a/sound/soc/codecs/rt715.h b/sound/soc/codecs/rt715.h index 009a8266f606..72c320bd35cb 100644 --- a/sound/soc/codecs/rt715.h +++ b/sound/soc/codecs/rt715.h @@ -22,6 +22,8 @@ struct rt715_priv { struct sdw_bus_params params; bool hw_init; bool first_hw_init; + unsigned int kctl_8ch_switch_ori[8]; + unsigned int kctl_8ch_vol_ori[8]; }; struct sdw_stream_data { From fa2f98378f941786a93f8e63696f59fb4ac7538b Mon Sep 17 00:00:00 2001 From: Jack Yu Date: Mon, 29 Mar 2021 06:54:00 +0000 Subject: [PATCH 517/587] ASoC: rt715: remove kcontrols which no longer be used Using new kcontrols "Capture Switch" and "Capture Volume" instead, remove kcontrols which no longer be used. Signed-off-by: Jack Yu Link: https://lore.kernel.org/r/5c314f5512654aca9fff0195f77264de@realtek.com Signed-off-by: Mark Brown --- sound/soc/codecs/rt715.c | 103 +++++++++++++-------------------------- sound/soc/codecs/rt715.h | 1 + 2 files changed, 36 insertions(+), 68 deletions(-) diff --git a/sound/soc/codecs/rt715.c b/sound/soc/codecs/rt715.c index 3849dd187de0..1352869cc086 100644 --- a/sound/soc/codecs/rt715.c +++ b/sound/soc/codecs/rt715.c @@ -81,12 +81,20 @@ static int rt715_set_amp_gain_put(struct snd_kcontrol *kcontrol, (struct soc_mixer_control *)kcontrol->private_value; struct rt715_priv *rt715 = snd_soc_component_get_drvdata(component); unsigned int addr_h, addr_l, val_h, val_ll, val_lr; - unsigned int read_ll, read_rl; - int i; + unsigned int read_ll, read_rl, i; + unsigned int k_vol_changed = 0; + + for (i = 0; i < 2; i++) { + if (ucontrol->value.integer.value[i] != rt715->kctl_2ch_vol_ori[i]) { + k_vol_changed = 1; + break; + } + } /* Can't use update bit function, so read the original value first */ addr_h = mc->reg; addr_l = mc->rreg; + if (mc->shift == RT715_DIR_OUT_SFT) /* output */ val_h = 0x80; else /* input */ @@ -94,41 +102,27 @@ static int rt715_set_amp_gain_put(struct snd_kcontrol *kcontrol, rt715_get_gain(rt715, addr_h, addr_l, val_h, &read_rl, &read_ll); + if (dapm->bias_level <= SND_SOC_BIAS_STANDBY) + regmap_write(rt715->regmap, + RT715_SET_AUDIO_POWER_STATE, AC_PWRST_D0); + /* L Channel */ - if (mc->invert) { - /* for mute */ - val_ll = (mc->max - ucontrol->value.integer.value[0]) << 7; - /* keep gain */ - read_ll = read_ll & 0x7f; - val_ll |= read_ll; - } else { - /* for gain */ - val_ll = ((ucontrol->value.integer.value[0]) & 0x7f); - if (val_ll > mc->max) - val_ll = mc->max; - /* keep mute status */ - read_ll = read_ll & 0x80; - val_ll |= read_ll; - } + rt715->kctl_2ch_vol_ori[0] = ucontrol->value.integer.value[0]; + /* for gain */ + val_ll = ((ucontrol->value.integer.value[0]) & 0x7f); + if (val_ll > mc->max) + val_ll = mc->max; + /* keep mute status */ + val_ll |= read_ll & 0x80; /* R Channel */ - if (mc->invert) { - regmap_write(rt715->regmap, - RT715_SET_AUDIO_POWER_STATE, AC_PWRST_D0); - /* for mute */ - val_lr = (mc->max - ucontrol->value.integer.value[1]) << 7; - /* keep gain */ - read_rl = read_rl & 0x7f; - val_lr |= read_rl; - } else { - /* for gain */ - val_lr = ((ucontrol->value.integer.value[1]) & 0x7f); - if (val_lr > mc->max) - val_lr = mc->max; - /* keep mute status */ - read_rl = read_rl & 0x80; - val_lr |= read_rl; - } + rt715->kctl_2ch_vol_ori[1] = ucontrol->value.integer.value[1]; + /* for gain */ + val_lr = ((ucontrol->value.integer.value[1]) & 0x7f); + if (val_lr > mc->max) + val_lr = mc->max; + /* keep mute status */ + val_lr |= read_rl & 0x80; for (i = 0; i < 3; i++) { /* retry 3 times at most */ @@ -136,18 +130,18 @@ static int rt715_set_amp_gain_put(struct snd_kcontrol *kcontrol, /* Set both L/R channels at the same time */ val_h = (1 << mc->shift) | (3 << 4); regmap_write(rt715->regmap, addr_h, - (val_h << 8 | val_ll)); + (val_h << 8) | val_ll); regmap_write(rt715->regmap, addr_l, - (val_h << 8 | val_ll)); + (val_h << 8) | val_ll); } else { /* Lch*/ val_h = (1 << mc->shift) | (1 << 5); regmap_write(rt715->regmap, addr_h, - (val_h << 8 | val_ll)); + (val_h << 8) | val_ll); /* Rch */ val_h = (1 << mc->shift) | (1 << 4); regmap_write(rt715->regmap, addr_l, - (val_h << 8 | val_lr)); + (val_h << 8) | val_lr); } /* check result */ if (mc->shift == RT715_DIR_OUT_SFT) /* output */ @@ -156,15 +150,16 @@ static int rt715_set_amp_gain_put(struct snd_kcontrol *kcontrol, val_h = 0x0; rt715_get_gain(rt715, addr_h, addr_l, val_h, - &read_rl, &read_ll); + &read_rl, &read_ll); if (read_rl == val_lr && read_ll == val_ll) break; } + /* D0:power on state, D3: power saving mode */ if (dapm->bias_level <= SND_SOC_BIAS_STANDBY) regmap_write(rt715->regmap, RT715_SET_AUDIO_POWER_STATE, AC_PWRST_D3); - return 0; + return k_vol_changed; } static int rt715_set_amp_gain_get(struct snd_kcontrol *kcontrol, @@ -466,37 +461,9 @@ static int rt715_vol_info(struct snd_kcontrol *kcontrol, static const struct snd_kcontrol_new rt715_snd_controls[] = { /* Capture switch */ - SOC_DOUBLE_R_EXT("ADC 07 Capture Switch", RT715_SET_GAIN_MIC_ADC_H, - RT715_SET_GAIN_MIC_ADC_L, RT715_DIR_IN_SFT, 1, 1, - rt715_set_amp_gain_get, rt715_set_amp_gain_put), - SOC_DOUBLE_R_EXT("ADC 08 Capture Switch", RT715_SET_GAIN_LINE_ADC_H, - RT715_SET_GAIN_LINE_ADC_L, RT715_DIR_IN_SFT, 1, 1, - rt715_set_amp_gain_get, rt715_set_amp_gain_put), - SOC_DOUBLE_R_EXT("ADC 09 Capture Switch", RT715_SET_GAIN_MIX_ADC_H, - RT715_SET_GAIN_MIX_ADC_L, RT715_DIR_IN_SFT, 1, 1, - rt715_set_amp_gain_get, rt715_set_amp_gain_put), - SOC_DOUBLE_R_EXT("ADC 27 Capture Switch", RT715_SET_GAIN_MIX_ADC2_H, - RT715_SET_GAIN_MIX_ADC2_L, RT715_DIR_IN_SFT, 1, 1, - rt715_set_amp_gain_get, rt715_set_amp_gain_put), RT715_MAIN_SWITCH_EXT("Capture Switch", rt715_set_main_switch_get, rt715_set_main_switch_put), /* Volume Control */ - SOC_DOUBLE_R_EXT_TLV("ADC 07 Capture Volume", RT715_SET_GAIN_MIC_ADC_H, - RT715_SET_GAIN_MIC_ADC_L, RT715_DIR_IN_SFT, 0x3f, 0, - rt715_set_amp_gain_get, rt715_set_amp_gain_put, - in_vol_tlv), - SOC_DOUBLE_R_EXT_TLV("ADC 08 Capture Volume", RT715_SET_GAIN_LINE_ADC_H, - RT715_SET_GAIN_LINE_ADC_L, RT715_DIR_IN_SFT, 0x3f, 0, - rt715_set_amp_gain_get, rt715_set_amp_gain_put, - in_vol_tlv), - SOC_DOUBLE_R_EXT_TLV("ADC 09 Capture Volume", RT715_SET_GAIN_MIX_ADC_H, - RT715_SET_GAIN_MIX_ADC_L, RT715_DIR_IN_SFT, 0x3f, 0, - rt715_set_amp_gain_get, rt715_set_amp_gain_put, - in_vol_tlv), - SOC_DOUBLE_R_EXT_TLV("ADC 27 Capture Volume", RT715_SET_GAIN_MIX_ADC2_H, - RT715_SET_GAIN_MIX_ADC2_L, RT715_DIR_IN_SFT, 0x3f, 0, - rt715_set_amp_gain_get, rt715_set_amp_gain_put, - in_vol_tlv), RT715_MAIN_VOL_EXT_TLV("Capture Volume", rt715_set_main_vol_get, rt715_set_main_vol_put, in_vol_tlv), /* MIC Boost Control */ diff --git a/sound/soc/codecs/rt715.h b/sound/soc/codecs/rt715.h index 72c320bd35cb..25dba61f1760 100644 --- a/sound/soc/codecs/rt715.h +++ b/sound/soc/codecs/rt715.h @@ -22,6 +22,7 @@ struct rt715_priv { struct sdw_bus_params params; bool hw_init; bool first_hw_init; + unsigned int kctl_2ch_vol_ori[2]; unsigned int kctl_8ch_switch_ori[8]; unsigned int kctl_8ch_vol_ori[8]; }; From d63f2a88d5cfaad025f26e1107f3807d579654c5 Mon Sep 17 00:00:00 2001 From: Rob Herring Date: Fri, 16 Apr 2021 13:01:18 -0500 Subject: [PATCH 518/587] ASoC: mt6359: Drop ASoC mt6359 ASoC accdet jack document This reverts commit e61c589587c772c5f672b22683c3e0b38be20702. The binding document has lots of schema errors and there's been no effort to fix them, so let's remove it. Cc: Argus Lin Cc: Mark Brown Cc: Liam Girdwood Cc: Matthias Brugger Cc: alsa-devel@alsa-project.org Cc: linux-arm-kernel@lists.infradead.org Cc: linux-mediatek@lists.infradead.org Signed-off-by: Rob Herring Link: https://lore.kernel.org/r/20210416180118.3662904-1-robh@kernel.org Signed-off-by: Mark Brown --- .../bindings/sound/mt6359-accdet.yaml | 164 ------------------ 1 file changed, 164 deletions(-) delete mode 100644 Documentation/devicetree/bindings/sound/mt6359-accdet.yaml diff --git a/Documentation/devicetree/bindings/sound/mt6359-accdet.yaml b/Documentation/devicetree/bindings/sound/mt6359-accdet.yaml deleted file mode 100644 index 7fb3e8dfb4c5..000000000000 --- a/Documentation/devicetree/bindings/sound/mt6359-accdet.yaml +++ /dev/null @@ -1,164 +0,0 @@ -# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) -%YAML 1.2 ---- -$id: http://devicetree.org/schemas/sound/mt6359-accdet.yaml# -$schema: http://devicetree.org/meta-schemas/core.yaml# - -title: Mediatek Technologies Inc. MT6359 ASoC accdet jack driver bindings - -maintainers: - - Chipeng Chang - -description: | - This binding describes the Mediatek Technologies MT6359 ASoC - accdet jack driver. - -properties: - mediatek,accdet-name: - maxItems: 1 - description: named as "mt6359-accdet" jack. - - mediatek,mic-vol: - maxItems: 1 - description: | - accdet micbias1 voltage. - - enum: - - 0x00 # 1.7v - micbias1 volage is 1.7v. - - 0x01 # 1.8v - micbias1 volage is 1.8v. - - 0x02 # 1.9v - micbias1 volage is 1.9v. - - 0x03 # 2.0v - micbias1 volage is 2.0v. - - 0x04 # 2.1v - micbias1 volage is 2.1v. - - 0x05 # 2.5v - micbias1 volage is 2.5v. - - 0x06 # 2.6v - micbias1 volage is 2.6v. - - 0x07 # 2.7v - micbias1 volage is 2.7v. - - 0x08 # 2.8v - micbias1 volage is 2.8v. - - 0x09 # 2.85v - micbias1 volage is 2.85v. - - mediatek,mic-mode: - maxItems: 1 - description: | - value as 1, 2, 6 to indicate ACC/DCC mode. default is DCC mode 2. - - enum: - - 0x01 # ACC - ACC mode. - - 0x02 # DCC - low cost without in bias. - - 0x06 # DCC - low cost with in bias. - - mediatek,pwm-deb-setting: - maxItems: 15 - description: | - headset-mode-setting : Indicates customized pwm, debounce setting - accdet pwm_width, pwm_thresh, fall_delay, rise_delay - debounce0, debounce1, debounce3, debounce4 - eint pwm_width, eint pwm_thresh - eint deb(debounce0, debounce1, debounce2, debounce3), inv_debounce. - - mediatek,eint-use-ap: - maxItems: 1 - description: | - indicates to use ap gpio. - - enum: - - 0x00 # MT6359 eint detection mode. - - 0x01 # SoC GPIO detection mode. - - mediatek,eint-detect-mode: - maxItems: 1 - description: | - indicates to use ap gpio. - - enum: - - 0x00 # detection mode with higher detection power. - - 0x01 # detection mode with lower detection power. - - 0x02 # detection mode with sw moisture detection mode. - - 0x03 # detection mode with hw moisture detection mode1. - - 0x04 # detection mode with hw moisture detection mode2. - - mediatek,eint-num: - maxItems: 1 - description: | - incicates pmic eint usage. - - enum: - - 0x0 # PMIC_EINT0 - use pmic eint0 to trigger plug interrupt. - - 0x1 # PMIC_EINT1 - use pmic eint1 to trigger plug interrupt. - - 0x2 # PMIC_BI_EINT - use pmic eint0/1 to trigger plug interrupt. - - mediatek,eint-trig-mode: - maxItems: 1 - description: | - incicates pmic eint trigger mode. - - enum: - - 0x0 # PMIC_GPIO - use pmic gpio to detect plug status. - - 0x1 # PMIC_INVERTER - use pmic inverter to detect plug status. - - mediatek,eint-use-ext-res: - maxItems: 1 - description: | - select HP_EINT pull up resistance, default 0 use internal resistance. - - enum: - - 0x0 # use internal resistor. - - 0x1 # use external resistor. - - mediatek,eint-comp-vth: - maxItems: 1 - description: | - indicates comparator detection voltage. - - enum: - - 0x00 # 2.8v. - - 0x01 # 2.4v. - - 0x02 # 2.0v. - - 0x03 # 0.7v. - - mediatek,key-mode: - maxItems: 1 - description: | - incicates key mode type. - - enum: - - 0x0 # THREE_KEY - support 3-key key mode. - - 0x1 # FOUR_KEY - support 4-key key mode. - - 0x2 # TRI_KEY_CDD - support 3-key google CDD key mode. - - mediatek,three-key-thr: - maxItems: 4 - description: | - 3 key device detection threshold: 0--MD_MAX--UP_MAX--DW_MAX. - - mediatek,tri-key-cdd-thr: - maxItems: 4 - description: | - 3 key CDD device detection threshold: 0--MD_MAX--UP_MAX--DW_MAX. - - mediatek,four-key-thr: - maxItems: 4 - description: | - 4 key device detection threshold: 0--MD_MAX--VOICE_MAX--UP_MAX--DW_MAX. - -additionalProperties: false - -examples: - - | - accdet: accdet { - mediatek,accdet-name = "mt6359-accdet"; - mediatek,mic-vol = <8>; - mediatek,mic-mode = <2>; - mediatek,pwm-deb-setting = <0x500 0x500 1 0x1f0 - 0x800 0x800 0x20 0x44 - 0x4 0x1 - 0x5 0x3 0x3 0x5 0xe>; - mediatek,eint-use-ap = <0>; - mediatek,eint-detect-mode = <4>; - mediatek,eint-num = <0>; - mediatek,eint-trig-mode = <1>; - mediatek,eint-use-ext-res = <0>; - mediatek,eint-comp-vth = <2>; - mediatek,key-mode = <0>; - mediatek,three-key-thr = <0 80 220 400>; - status = "okay"; - }; -... From d86f43b17ed4cd751f73d890ea63f818ffa5ef3d Mon Sep 17 00:00:00 2001 From: Lucas Endres Date: Fri, 16 Apr 2021 11:50:20 -0500 Subject: [PATCH 519/587] ALSA: usb-audio: Add support for many Roland devices' implicit feedback quirks It makes USB audio capture and playback possible and pristine on my Roland INTEGRA-7, Boutique D-05, and R-26, along with many more I've encountered people having had issues with over the last decade or so. Signed-off-by: Lucas Endres Link: https://lore.kernel.org/r/CAOsVg8rA61B=005_VyUwpw3piVwA7Bo5fs1GYEB054efyzGjLw@mail.gmail.com Signed-off-by: Takashi Iwai --- sound/usb/implicit.c | 59 ++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 59 insertions(+) diff --git a/sound/usb/implicit.c b/sound/usb/implicit.c index 4bd9c105a529..428e3a449f5d 100644 --- a/sound/usb/implicit.c +++ b/sound/usb/implicit.c @@ -79,13 +79,72 @@ static const struct snd_usb_implicit_fb_match playback_implicit_fb_quirks[] = { /* Implicit feedback quirk table for capture: only FIXED type */ static const struct snd_usb_implicit_fb_match capture_implicit_fb_quirks[] = { + IMPLICIT_FB_FIXED_DEV(0x0582, 0x00a6, 0x0d, 0x01), /* Roland JUNO-G */ + IMPLICIT_FB_FIXED_DEV(0x0582, 0x00a9, 0x0d, 0x01), /* Roland MC-808 */ + IMPLICIT_FB_FIXED_DEV(0x0582, 0x00ad, 0x0d, 0x01), /* Roland SH-201 */ + IMPLICIT_FB_FIXED_DEV(0x0582, 0x00b2, 0x0d, 0x01), /* Roland VG-99 */ + IMPLICIT_FB_FIXED_DEV(0x0582, 0x00b3, 0x0d, 0x01), /* Roland VG-99 */ + IMPLICIT_FB_FIXED_DEV(0x0582, 0x00c2, 0x0d, 0x01), /* Roland SonicCell */ + IMPLICIT_FB_FIXED_DEV(0x0582, 0x00c4, 0x0d, 0x01), /* Edirol M-16DX */ + IMPLICIT_FB_FIXED_DEV(0x0582, 0x00c5, 0x0d, 0x01), /* Roland SP-555 */ + IMPLICIT_FB_FIXED_DEV(0x0582, 0x00c7, 0x0d, 0x01), /* Roland V-Synth GT */ + IMPLICIT_FB_FIXED_DEV(0x0582, 0x00d1, 0x0d, 0x01), /* Roland Music Atelier */ + IMPLICIT_FB_FIXED_DEV(0x0582, 0x00da, 0x0d, 0x01), /* BOSS GT-10 */ + IMPLICIT_FB_FIXED_DEV(0x0582, 0x00db, 0x0d, 0x01), /* BOSS GT-10 Guitar Effects Processor */ + IMPLICIT_FB_FIXED_DEV(0x0582, 0x00dc, 0x0d, 0x01), /* BOSS GT-10B */ + IMPLICIT_FB_FIXED_DEV(0x0582, 0x00de, 0x0d, 0x01), /* Roland Fantom-G */ + IMPLICIT_FB_FIXED_DEV(0x0582, 0x00eb, 0x0d, 0x01), /* Roland VS-100 */ + IMPLICIT_FB_FIXED_DEV(0x0582, 0x00f8, 0x0d, 0x01), /* Roland JUNO Series */ + IMPLICIT_FB_FIXED_DEV(0x0582, 0x00fc, 0x0d, 0x01), /* Roland VS-700C */ + IMPLICIT_FB_FIXED_DEV(0x0582, 0x00fd, 0x0d, 0x01), /* Roland VS-700 */ + IMPLICIT_FB_FIXED_DEV(0x0582, 0x00fe, 0x0d, 0x01), /* Roland VS-700 M1 */ + IMPLICIT_FB_FIXED_DEV(0x0582, 0x00ff, 0x0d, 0x01), /* Roland VS-700 M2 */ + IMPLICIT_FB_FIXED_DEV(0x0582, 0x0100, 0x0d, 0x01), /* Roland VS-700 */ + IMPLICIT_FB_FIXED_DEV(0x0582, 0x0101, 0x0d, 0x01), /* Roland VS-700 M2 */ + IMPLICIT_FB_FIXED_DEV(0x0582, 0x0102, 0x0d, 0x01), /* Roland VB-99 */ + IMPLICIT_FB_BOTH_DEV(0x0582, 0x0109, 0x0d, 0x01), /* BOSS eBand JS-8 */ + IMPLICIT_FB_BOTH_DEV(0x0582, 0x0111, 0x0d, 0x01), /* Roland GAIA SH-01 */ + IMPLICIT_FB_FIXED_DEV(0x0582, 0x0113, 0x0d, 0x01), /* BOSS ME-25 */ + IMPLICIT_FB_FIXED_DEV(0x0582, 0x0114, 0x0d, 0x01), /* Roland SD-50 */ + IMPLICIT_FB_FIXED_DEV(0x0582, 0x0117, 0x0d, 0x01), /* Roland VS-20 */ + IMPLICIT_FB_FIXED_DEV(0x0582, 0x0119, 0x0d, 0x01), /* Roland OCTAPAD SPD-30 */ + IMPLICIT_FB_FIXED_DEV(0x0582, 0x011c, 0x0d, 0x01), /* Roland Lucina AX-09 */ + IMPLICIT_FB_FIXED_DEV(0x0582, 0x011e, 0x0d, 0x01), /* BOSS BR-800 */ + IMPLICIT_FB_FIXED_DEV(0x0582, 0x0120, 0x0d, 0x01), /* Roland OCTA-CAPTURE */ + IMPLICIT_FB_FIXED_DEV(0x0582, 0x0121, 0x0d, 0x01), /* Roland OCTA-CAPTURE */ + IMPLICIT_FB_FIXED_DEV(0x0582, 0x0123, 0x0d, 0x01), /* Roland JUNO-Gi */ + IMPLICIT_FB_FIXED_DEV(0x0582, 0x0124, 0x0d, 0x01), /* Roland M-300 */ + IMPLICIT_FB_BOTH_DEV(0x0582, 0x0127, 0x0d, 0x01), /* Roland GR-55 */ + IMPLICIT_FB_FIXED_DEV(0x0582, 0x012b, 0x0d, 0x01), /* Roland DUO-CAPTURE */ + IMPLICIT_FB_BOTH_DEV(0x0582, 0x012f, 0x0d, 0x01), /* Roland QUAD-CAPTURE */ IMPLICIT_FB_BOTH_DEV(0x0582, 0x0130, 0x0d, 0x01), /* BOSS BR-80 */ + IMPLICIT_FB_FIXED_DEV(0x0582, 0x0132, 0x0d, 0x01), /* Roland TRI-CAPTURE */ + IMPLICIT_FB_FIXED_DEV(0x0582, 0x0134, 0x0d, 0x01), /* Roland V-Mixer */ + IMPLICIT_FB_FIXED_DEV(0x0582, 0x0137, 0x0d, 0x01), /* Roland DUO-CAPTURE Advanced Mode */ + IMPLICIT_FB_BOTH_DEV(0x0582, 0x0138, 0x0d, 0x01), /* BOSS RC-300 */ + IMPLICIT_FB_FIXED_DEV(0x0582, 0x013a, 0x0d, 0x01), /* Roland JUPITER-80 */ + IMPLICIT_FB_BOTH_DEV(0x0582, 0x013e, 0x0d, 0x01), /* Roland R-26 */ + IMPLICIT_FB_FIXED_DEV(0x0582, 0x0145, 0x0d, 0x01), /* Roland SPD-SX */ + IMPLICIT_FB_FIXED_DEV(0x0582, 0x014b, 0x0d, 0x01), /* BOSS eBand JS-10 */ + IMPLICIT_FB_BOTH_DEV(0x0582, 0x014d, 0x0d, 0x01), /* BOSS GT-100 */ + IMPLICIT_FB_FIXED_DEV(0x0582, 0x0150, 0x0d, 0x01), /* Roland TD-15 */ + IMPLICIT_FB_FIXED_DEV(0x0582, 0x0151, 0x0d, 0x01), /* Roland TD-11 */ + IMPLICIT_FB_FIXED_DEV(0x0582, 0x0154, 0x0d, 0x01), /* Roland JUPITER-50 */ + IMPLICIT_FB_FIXED_DEV(0x0582, 0x0158, 0x0d, 0x01), /* Roland TD-30 */ + IMPLICIT_FB_FIXED_DEV(0x0582, 0x0159, 0x0d, 0x01), /* Roland DUO-CAPTURE EX */ + IMPLICIT_FB_BOTH_DEV(0x0582, 0x015b, 0x0d, 0x01), /* Roland INTEGRA-7 */ + IMPLICIT_FB_FIXED_DEV(0x0582, 0x015d, 0x0d, 0x01), /* Roland R-88 */ IMPLICIT_FB_BOTH_DEV(0x0582, 0x0171, 0x0d, 0x01), /* BOSS RC-505 */ + IMPLICIT_FB_FIXED_DEV(0x0582, 0x017a, 0x0d, 0x01), /* Roland VT-3 */ + IMPLICIT_FB_BOTH_DEV(0x0582, 0x017c, 0x0d, 0x01), /* Roland TR-8 */ IMPLICIT_FB_BOTH_DEV(0x0582, 0x0185, 0x0d, 0x01), /* BOSS GP-10 */ IMPLICIT_FB_BOTH_DEV(0x0582, 0x0189, 0x0d, 0x01), /* BOSS GT-100v2 */ + IMPLICIT_FB_BOTH_DEV(0x0582, 0x01b5, 0x0d, 0x01), /* Roland Boutique JP-08 */ IMPLICIT_FB_BOTH_DEV(0x0582, 0x01d6, 0x0d, 0x01), /* BOSS GT-1 */ IMPLICIT_FB_BOTH_DEV(0x0582, 0x01d8, 0x0d, 0x01), /* BOSS Katana */ IMPLICIT_FB_BOTH_DEV(0x0582, 0x01e5, 0x0d, 0x01), /* BOSS GT-001 */ + IMPLICIT_FB_BOTH_DEV(0x0582, 0x01fd, 0x0d, 0x01), /* Roland Boutique SH-01A */ + IMPLICIT_FB_BOTH_DEV(0x0582, 0x01ff, 0x0d, 0x01), /* Roland Boutique D-05 */ IMPLICIT_FB_BOTH_DEV(0x0582, 0x0203, 0x0d, 0x01), /* BOSS AD-10 */ {} /* terminator */ From 76fae6185f5456865ff1bcb647709d44fd987eb6 Mon Sep 17 00:00:00 2001 From: Luke D Jones Date: Mon, 19 Apr 2021 15:04:11 +1200 Subject: [PATCH 520/587] ALSA: hda/realtek: GA503 use same quirks as GA401 The GA503 has almost exactly the same default setup as the GA401 model with the same issues. The GA401 quirks solve all the issues so we will use the full quirk chain. Signed-off-by: Luke D Jones Cc: Link: https://lore.kernel.org/r/20210419030411.28304-1-luke@ljones.dev Signed-off-by: Takashi Iwai --- sound/pci/hda/patch_realtek.c | 1 + 1 file changed, 1 insertion(+) diff --git a/sound/pci/hda/patch_realtek.c b/sound/pci/hda/patch_realtek.c index 67aeed5d25b6..1ad1bb740c32 100644 --- a/sound/pci/hda/patch_realtek.c +++ b/sound/pci/hda/patch_realtek.c @@ -8167,6 +8167,7 @@ static const struct snd_pci_quirk alc269_fixup_tbl[] = { SND_PCI_QUIRK(0x1043, 0x1ccd, "ASUS X555UB", ALC256_FIXUP_ASUS_MIC), SND_PCI_QUIRK(0x1043, 0x1d4e, "ASUS TM420", ALC256_FIXUP_ASUS_HPE), SND_PCI_QUIRK(0x1043, 0x1e11, "ASUS Zephyrus G15", ALC289_FIXUP_ASUS_GA502), + SND_PCI_QUIRK(0x1043, 0x1e8e, "ASUS Zephyrus G15", ALC289_FIXUP_ASUS_GA401), SND_PCI_QUIRK(0x1043, 0x1f11, "ASUS Zephyrus G14", ALC289_FIXUP_ASUS_GA401), SND_PCI_QUIRK(0x1043, 0x1881, "ASUS Zephyrus S/M", ALC294_FIXUP_ASUS_GX502_PINS), SND_PCI_QUIRK(0x1043, 0x3030, "ASUS ZN270IE", ALC256_FIXUP_ASUS_AIO_GPIO2), From e7df7df5a3809d733888db6ce6592a644acaac19 Mon Sep 17 00:00:00 2001 From: Olivia Mackintosh Date: Sun, 18 Apr 2021 17:59:01 +0100 Subject: [PATCH 521/587] ALSA: usb-audio: DJM-750: ensure format is set Add case statement to set sample-rate for the DJM-750 Pioneer mixer. This was included as part of another patch but I think it has been archived on Patchwork and hasn't been merged. Signed-off-by: Olivia Mackintosh Cc: Link: https://lore.kernel.org/r/20210418165901.25776-1-livvy@base.nu Signed-off-by: Takashi Iwai --- sound/usb/quirks.c | 1 + 1 file changed, 1 insertion(+) diff --git a/sound/usb/quirks.c b/sound/usb/quirks.c index 63f27ce64bcb..8b8bee3c3dd6 100644 --- a/sound/usb/quirks.c +++ b/sound/usb/quirks.c @@ -1511,6 +1511,7 @@ void snd_usb_set_format_quirk(struct snd_usb_substream *subs, case USB_ID(0x2b73, 0x0013): /* Pioneer DJM-450 */ pioneer_djm_set_format_quirk(subs, 0x0082); break; + case USB_ID(0x08e4, 0x017f): /* Pioneer DJM-750 */ case USB_ID(0x08e4, 0x0163): /* Pioneer DJM-850 */ pioneer_djm_set_format_quirk(subs, 0x0086); break; From 59ce3233a538fc21c5c59ff38cafd784cbcd6de0 Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Fri, 16 Apr 2021 14:11:40 -0500 Subject: [PATCH 522/587] ASoC: soc-acpi: remove useless initialization cppcheck warning: value that is never used. [unreadVariable] acpi_status status = AE_OK; ^ sound/soc/soc-acpi.c:37:21: style: Variable 'status' is assigned a Signed-off-by: Pierre-Louis Bossart Reviewed-by: Daniel Baluta Reviewed-by: Guennadi Liakhovetski Link: https://lore.kernel.org/r/20210416191144.27006-2-pierre-louis.bossart@linux.intel.com Signed-off-by: Mark Brown --- sound/soc/soc-acpi.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sound/soc/soc-acpi.c b/sound/soc/soc-acpi.c index 444ce0602f76..395229bf5c51 100644 --- a/sound/soc/soc-acpi.c +++ b/sound/soc/soc-acpi.c @@ -34,7 +34,7 @@ static acpi_status snd_soc_acpi_find_package(acpi_handle handle, u32 level, void *context, void **ret) { struct acpi_device *adev; - acpi_status status = AE_OK; + acpi_status status; struct snd_soc_acpi_package_context *pkg_ctx = context; pkg_ctx->data_valid = false; From d3b47a888f0bc66a8590941cfa57ba015b288040 Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Fri, 16 Apr 2021 14:11:41 -0500 Subject: [PATCH 523/587] ASoC: soc-core: fix signed/unsigned issue cppcheck warning: sound/soc/soc-core.c:2237:13: warning: %x in format string (no. 1) requires 'unsigned int *' but the argument type is 'signed int *'. [invalidScanfArgType_int] } else if (sscanf(name, "%x-%x", &id1, &id2) == 2) { ^ sound/soc/soc-core.c:2237:13: warning: %x in format string (no. 2) requires 'unsigned int *' but the argument type is 'signed int *'. [invalidScanfArgType_int] } else if (sscanf(name, "%x-%x", &id1, &id2) == 2) { ^ Signed-off-by: Pierre-Louis Bossart Reviewed-by: Daniel Baluta Reviewed-by: Guennadi Liakhovetski Link: https://lore.kernel.org/r/20210416191144.27006-3-pierre-louis.bossart@linux.intel.com Signed-off-by: Mark Brown --- sound/soc/soc-core.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sound/soc/soc-core.c b/sound/soc/soc-core.c index 80374c82c501..fb6b3a6194ce 100644 --- a/sound/soc/soc-core.c +++ b/sound/soc/soc-core.c @@ -2219,7 +2219,7 @@ static char *fmt_single_name(struct device *dev, int *id) { const char *devname = dev_name(dev); char *found, *name; - int id1, id2; + unsigned int id1, id2; if (devname == NULL) return NULL; From e2290daefef3afa08135a0a65d4f0ce7fe23d5c0 Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Fri, 16 Apr 2021 14:11:42 -0500 Subject: [PATCH 524/587] ASoC: soc-core: fix always-false condition cppcheck warning: sound/soc/soc-core.c:2784:6: style: Condition '!num_routes' is always false [knownConditionTrueFalse] if (!num_routes) { ^ sound/soc/soc-core.c:2777:17: note: Assuming that condition 'num_routes<0' is not redundant if (num_routes < 0 || num_routes & 1) { ^ sound/soc/soc-core.c:2783:2: note: Compound assignment '/=', assigned value is 0 num_routes /= 2; ^ sound/soc/soc-core.c:2784:6: note: Condition '!num_routes' is always false if (!num_routes) { ^ The documentation for of_property_count_string reads " * Returns the number of strings on * success, -EINVAL if the property does not exist, -ENODATA if property * does not have a value, and -EILSEQ if the string is not null-terminated * within the length of the property data. " Since the case for num_routes == 0 is not possible, let's remove this test. Signed-off-by: Pierre-Louis Bossart Reviewed-by: Daniel Baluta Reviewed-by: Guennadi Liakhovetski Link: https://lore.kernel.org/r/20210416191144.27006-4-pierre-louis.bossart@linux.intel.com Signed-off-by: Mark Brown --- sound/soc/soc-core.c | 5 ----- 1 file changed, 5 deletions(-) diff --git a/sound/soc/soc-core.c b/sound/soc/soc-core.c index fb6b3a6194ce..1c0904acb935 100644 --- a/sound/soc/soc-core.c +++ b/sound/soc/soc-core.c @@ -2785,11 +2785,6 @@ int snd_soc_of_parse_audio_routing(struct snd_soc_card *card, return -EINVAL; } num_routes /= 2; - if (!num_routes) { - dev_err(card->dev, "ASoC: Property '%s's length is zero\n", - propname); - return -EINVAL; - } routes = devm_kcalloc(card->dev, num_routes, sizeof(*routes), GFP_KERNEL); From 36924a12c32021a098fec621fb5ea707a72cd5b5 Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Fri, 16 Apr 2021 14:11:43 -0500 Subject: [PATCH 525/587] ASoC: codecs: lpass-rx-macro: remove useless return cppcheck warning: sound/soc/codecs/lpass-rx-macro.c:1626:9: warning: Identical condition and return expression 'ret', return value is always 0 [identicalConditionAfterEarlyExit] return ret; ^ sound/soc/codecs/lpass-rx-macro.c:1623:6: note: If condition 'ret' is true, the function will return/exit if (ret) ^ sound/soc/codecs/lpass-rx-macro.c:1626:9: note: Returning identical expression 'ret' return ret; ^ Signed-off-by: Pierre-Louis Bossart Reviewed-by: Daniel Baluta Reviewed-by: Guennadi Liakhovetski Link: https://lore.kernel.org/r/20210416191144.27006-5-pierre-louis.bossart@linux.intel.com Signed-off-by: Mark Brown --- sound/soc/codecs/lpass-rx-macro.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/sound/soc/codecs/lpass-rx-macro.c b/sound/soc/codecs/lpass-rx-macro.c index 14c166506fb1..4f1b569d7c47 100644 --- a/sound/soc/codecs/lpass-rx-macro.c +++ b/sound/soc/codecs/lpass-rx-macro.c @@ -1620,8 +1620,6 @@ static int rx_macro_set_interpolator_rate(struct snd_soc_dai *dai, return ret; ret = rx_macro_set_mix_interpolator_rate(dai, rate_val, sample_rate); - if (ret) - return ret; return ret; } From 9726db36ed83670be93d053e05e150308e3ce743 Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Fri, 16 Apr 2021 14:11:44 -0500 Subject: [PATCH 526/587] ASoC: codecs: rt5682: clarify expression cppcheck warning: sound/soc/codecs/rt5682.c:2404:42: style: Boolean result is used in bitwise operation. Clarify expression with parentheses. [clarifyCondition] (pll_code.m_bp << RT5682_PLL_M_BP_SFT | RT5682_PLL_RST)); ^ Signed-off-by: Pierre-Louis Bossart Reviewed-by: Daniel Baluta Reviewed-by: Guennadi Liakhovetski Link: https://lore.kernel.org/r/20210416191144.27006-6-pierre-louis.bossart@linux.intel.com Signed-off-by: Mark Brown --- sound/soc/codecs/rt5682.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sound/soc/codecs/rt5682.c b/sound/soc/codecs/rt5682.c index 0e2a10ed11da..a5aacfe01a0d 100644 --- a/sound/soc/codecs/rt5682.c +++ b/sound/soc/codecs/rt5682.c @@ -2401,7 +2401,7 @@ static int rt5682_set_component_pll(struct snd_soc_component *component, (pll_code.n_code << RT5682_PLL_N_SFT) | pll_code.k_code); snd_soc_component_write(component, RT5682_PLL_CTRL_2, ((pll_code.m_bp ? 0 : pll_code.m_code) << RT5682_PLL_M_SFT) | - (pll_code.m_bp << RT5682_PLL_M_BP_SFT | RT5682_PLL_RST)); + ((pll_code.m_bp << RT5682_PLL_M_BP_SFT) | RT5682_PLL_RST)); } rt5682->pll_in[pll_id] = freq_in; From e86a53fb64ed0a4749eeac2eccc7a6412fd3c920 Mon Sep 17 00:00:00 2001 From: Viorel Suman Date: Mon, 19 Apr 2021 17:54:32 +0800 Subject: [PATCH 527/587] ASoC: ak4458: check reset control status check the return value of ak4458_rstn_control. Signed-off-by: Viorel Suman Signed-off-by: Shengjiu Wang Link: https://lore.kernel.org/r/1618826072-29344-1-git-send-email-shengjiu.wang@nxp.com Signed-off-by: Mark Brown --- sound/soc/codecs/ak4458.c | 21 ++++++++++++++++----- 1 file changed, 16 insertions(+), 5 deletions(-) diff --git a/sound/soc/codecs/ak4458.c b/sound/soc/codecs/ak4458.c index 85a1d00894a9..3088128816bb 100644 --- a/sound/soc/codecs/ak4458.c +++ b/sound/soc/codecs/ak4458.c @@ -334,7 +334,7 @@ static int ak4458_hw_params(struct snd_pcm_substream *substream, struct ak4458_priv *ak4458 = snd_soc_component_get_drvdata(component); int pcm_width = max(params_physical_width(params), ak4458->slot_width); u8 format, dsdsel0, dsdsel1; - int nfs1, dsd_bclk; + int nfs1, dsd_bclk, ret; nfs1 = params_rate(params); ak4458->fs = nfs1; @@ -419,8 +419,13 @@ static int ak4458_hw_params(struct snd_pcm_substream *substream, snd_soc_component_update_bits(component, AK4458_00_CONTROL1, AK4458_DIF_MASK, format); - ak4458_rstn_control(component, 0); - ak4458_rstn_control(component, 1); + ret = ak4458_rstn_control(component, 0); + if (ret) + return ret; + + ret = ak4458_rstn_control(component, 1); + if (ret) + return ret; return 0; } @@ -429,6 +434,7 @@ static int ak4458_set_dai_fmt(struct snd_soc_dai *dai, unsigned int fmt) { struct snd_soc_component *component = dai->component; struct ak4458_priv *ak4458 = snd_soc_component_get_drvdata(component); + int ret; switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) { case SND_SOC_DAIFMT_CBS_CFS: /* Slave Mode */ @@ -461,8 +467,13 @@ static int ak4458_set_dai_fmt(struct snd_soc_dai *dai, unsigned int fmt) ak4458->fmt == SND_SOC_DAIFMT_PDM ? AK4458_DP_MASK : 0); - ak4458_rstn_control(component, 0); - ak4458_rstn_control(component, 1); + ret = ak4458_rstn_control(component, 0); + if (ret) + return ret; + + ret = ak4458_rstn_control(component, 1); + if (ret) + return ret; return 0; } From fd9db1058c6c2a8c02f00707b26c4647d95e6acc Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Mon, 19 Apr 2021 17:39:18 +0200 Subject: [PATCH 528/587] ALSA: usb-audio: Re-apply implicit feedback mode to Pioneer devices Pioneer devices are supposed to be working with the implicit feedback mode, but so far the attempt to apply the implicit feedback caused issues, hence we explicitly skipped the implicit feedback mode for them. Recently, Geraldo discovered that the device actually works if you skip the generic matching of the sync EPs for the capture stream. That is, we should apply the implicit feedback setup for the playback like other similar devices, while we need to return 1 from audioformat_capture_quirk() so that no further matching will be done. And, later on, Olivia reported later that the fiddling with the capture quirk alone doesn't suffice for the test with speaker-test program. This seems to be a similar case like the recently fixed BOSS devices. Indeed, the problem could be addressed by setting playback_first flag, which indicates that the playback URBs have to be sent out at first even in the implicit feedback mode. This patch implements the application of the implicit feedback to Pioneer devices as described in the above. The former skip_pioneer_sync_ep() was dropped, and instead we provide is_pioneer_implicit_fb() to check the Pioneer devices that need the implicit feedback. In the audioformat_implicit_fb_quirk(), simply apply the implicit fb for playback and set chip->playback_first flag if matching, and in audioformat_capture_quirk()(), it returns 1 for skipping the generic EP sync handling. Reported-by: Geraldo Tested-by: Olivia Mackintosh Link: https://lore.kernel.org/r/s5ha6pygqfz.wl-tiwai@suse.de Link: https://lore.kernel.org/r/20210419153918.450-1-tiwai@suse.de Signed-off-by: Takashi Iwai --- sound/usb/implicit.c | 42 +++++++++++++++++++++++++++--------------- 1 file changed, 27 insertions(+), 15 deletions(-) diff --git a/sound/usb/implicit.c b/sound/usb/implicit.c index 428e3a449f5d..77ffcea294dd 100644 --- a/sound/usb/implicit.c +++ b/sound/usb/implicit.c @@ -230,18 +230,27 @@ static int add_roland_implicit_fb(struct snd_usb_audio *chip, ifnum, alts); } -/* Playback and capture EPs on Pioneer devices share the same iface/altset, - * but they don't seem working with the implicit fb mode well, hence we - * just return as if the sync were already set up. +/* Playback and capture EPs on Pioneer devices share the same iface/altset + * for the implicit feedback operation */ -static int skip_pioneer_sync_ep(struct snd_usb_audio *chip, - struct audioformat *fmt, - struct usb_host_interface *alts) +static bool is_pioneer_implicit_fb(struct snd_usb_audio *chip, + struct usb_host_interface *alts) + { struct usb_endpoint_descriptor *epd; + if (USB_ID_VENDOR(chip->usb_id) != 0x2b73 && + USB_ID_VENDOR(chip->usb_id) != 0x08e4) + return false; + if (alts->desc.bInterfaceClass != USB_CLASS_VENDOR_SPEC) + return false; if (alts->desc.bNumEndpoints != 2) - return 0; + return false; + + epd = get_endpoint(alts, 0); + if (!usb_endpoint_is_isoc_out(epd) || + (epd->bmAttributes & USB_ENDPOINT_SYNCTYPE) != USB_ENDPOINT_SYNC_ASYNC) + return false; epd = get_endpoint(alts, 1); if (!usb_endpoint_is_isoc_in(epd) || @@ -250,8 +259,9 @@ static int skip_pioneer_sync_ep(struct snd_usb_audio *chip, USB_ENDPOINT_USAGE_DATA && (epd->bmAttributes & USB_ENDPOINT_USAGE_MASK) != USB_ENDPOINT_USAGE_IMPLICIT_FB)) - return 0; - return 1; /* don't handle with the implicit fb, just skip sync EP */ + return false; + + return true; } static int __add_generic_implicit_fb(struct snd_usb_audio *chip, @@ -367,12 +377,12 @@ static int audioformat_implicit_fb_quirk(struct snd_usb_audio *chip, } /* Pioneer devices with vendor spec class */ - if (attr == USB_ENDPOINT_SYNC_ASYNC && - alts->desc.bInterfaceClass == USB_CLASS_VENDOR_SPEC && - (USB_ID_VENDOR(chip->usb_id) == 0x2b73 || /* Pioneer */ - USB_ID_VENDOR(chip->usb_id) == 0x08e4 /* Pioneer */)) { - if (skip_pioneer_sync_ep(chip, fmt, alts)) - return 1; + if (is_pioneer_implicit_fb(chip, alts)) { + chip->playback_first = 1; + return add_implicit_fb_sync_ep(chip, fmt, + get_endpoint(alts, 1)->bEndpointAddress, + 1, alts->desc.bInterfaceNumber, + alts); } /* Try the generic implicit fb if available */ @@ -394,6 +404,8 @@ static int audioformat_capture_quirk(struct snd_usb_audio *chip, if (p && (p->type == IMPLICIT_FB_FIXED || p->type == IMPLICIT_FB_BOTH)) return add_implicit_fb_sync_ep(chip, fmt, p->ep_num, 0, p->iface, NULL); + if (is_pioneer_implicit_fb(chip, alts)) + return 1; /* skip the quirk, also don't handle generic sync EP */ return 0; } From dfa7b01dbdc9723ced606425b47005bb583a8778 Mon Sep 17 00:00:00 2001 From: David Ward Date: Sun, 18 Apr 2021 09:46:54 -0400 Subject: [PATCH 529/587] ASoC: rt286: Fix upper byte in DMIC2 configuration This HDA verb sets the upper byte of the Configuration Default register, so only an 8-bit value should be used. For the rt298, the same fix was applied in commit f8f2dc4a7127 ("ASoC: rt298: fix wrong setting of gpio2_en"). Signed-off-by: David Ward Link: https://lore.kernel.org/r/20210418134658.4333-2-david.ward@gatech.edu Reviewed-by: Pierre-Louis Bossart Signed-off-by: Mark Brown --- sound/soc/codecs/rt286.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sound/soc/codecs/rt286.c b/sound/soc/codecs/rt286.c index 8abe232ca4a4..f9b29782b62a 100644 --- a/sound/soc/codecs/rt286.c +++ b/sound/soc/codecs/rt286.c @@ -1204,7 +1204,7 @@ static int rt286_i2c_probe(struct i2c_client *i2c, mdelay(10); if (!rt286->pdata.gpio2_en) - regmap_write(rt286->regmap, RT286_SET_DMIC2_DEFAULT, 0x4000); + regmap_write(rt286->regmap, RT286_SET_DMIC2_DEFAULT, 0x40); else regmap_write(rt286->regmap, RT286_SET_DMIC2_DEFAULT, 0); From cd8499d5c03ba260e3191e90236d0e5f6b147563 Mon Sep 17 00:00:00 2001 From: David Ward Date: Sun, 18 Apr 2021 09:46:57 -0400 Subject: [PATCH 530/587] ASoC: rt286: Make RT286_SET_GPIO_* readable and writable The GPIO configuration cannot be applied if the registers are inaccessible. This prevented the headset mic from working on the Dell XPS 13 9343. BugLink: https://bugzilla.kernel.org/show_bug.cgi?id=114171 Signed-off-by: David Ward Link: https://lore.kernel.org/r/20210418134658.4333-5-david.ward@gatech.edu Reviewed-by: Pierre-Louis Bossart Signed-off-by: Mark Brown --- sound/soc/codecs/rt286.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/sound/soc/codecs/rt286.c b/sound/soc/codecs/rt286.c index f9b29782b62a..e16e7237156f 100644 --- a/sound/soc/codecs/rt286.c +++ b/sound/soc/codecs/rt286.c @@ -171,6 +171,9 @@ static bool rt286_readable_register(struct device *dev, unsigned int reg) case RT286_PROC_COEF: case RT286_SET_AMP_GAIN_ADC_IN1: case RT286_SET_AMP_GAIN_ADC_IN2: + case RT286_SET_GPIO_MASK: + case RT286_SET_GPIO_DIRECTION: + case RT286_SET_GPIO_DATA: case RT286_SET_POWER(RT286_DAC_OUT1): case RT286_SET_POWER(RT286_DAC_OUT2): case RT286_SET_POWER(RT286_ADC_IN1): From 11a9b987611f17e6a95e9bb34c1f5f9aa0b6ae25 Mon Sep 17 00:00:00 2001 From: Niklas Carlsson Date: Mon, 19 Apr 2021 16:49:01 +0200 Subject: [PATCH 531/587] ASoC: sigmadsp: Disable cache mechanism for readbacks The ALSA control readback functionality only works for non-volatile controls, i.e. control values that does not change on their own without driver interaction. This doesn't work for readbacks since the DSP firmware updates the control value. Disable the cache mechanism in the driver if the control name matches the prefix used for readbacks to ensure that the control value is valid. Signed-off-by: Niklas Carlsson Link: https://lore.kernel.org/r/20210419144901.9441-1-Niklas.Carlsson@axis.com Signed-off-by: Mark Brown --- sound/soc/codecs/sigmadsp.c | 18 ++++++++++++++++-- 1 file changed, 16 insertions(+), 2 deletions(-) diff --git a/sound/soc/codecs/sigmadsp.c b/sound/soc/codecs/sigmadsp.c index 76c77dc8ecf7..b992216aee55 100644 --- a/sound/soc/codecs/sigmadsp.c +++ b/sound/soc/codecs/sigmadsp.c @@ -24,6 +24,8 @@ #define SIGMA_FW_CHUNK_TYPE_CONTROL 1 #define SIGMA_FW_CHUNK_TYPE_SAMPLERATES 2 +#define READBACK_CTRL_NAME "ReadBack" + struct sigmadsp_control { struct list_head head; uint32_t samplerates; @@ -31,6 +33,7 @@ struct sigmadsp_control { unsigned int num_bytes; const char *name; struct snd_kcontrol *kcontrol; + bool is_readback; bool cached; uint8_t cache[]; }; @@ -141,7 +144,8 @@ static int sigmadsp_ctrl_put(struct snd_kcontrol *kcontrol, if (ret == 0) { memcpy(ctrl->cache, data, ctrl->num_bytes); - ctrl->cached = true; + if (!ctrl->is_readback) + ctrl->cached = true; } mutex_unlock(&sigmadsp->lock); @@ -164,7 +168,8 @@ static int sigmadsp_ctrl_get(struct snd_kcontrol *kcontrol, } if (ret == 0) { - ctrl->cached = true; + if (!ctrl->is_readback) + ctrl->cached = true; memcpy(ucontrol->value.bytes.data, ctrl->cache, ctrl->num_bytes); } @@ -231,6 +236,15 @@ static int sigma_fw_load_control(struct sigmadsp *sigmadsp, name[name_len] = '\0'; ctrl->name = name; + /* + * Readbacks doesn't work with non-volatile controls, since the + * firmware updates the control value without driver interaction. Mark + * the readbacks to ensure that the values are not cached. + */ + if (ctrl->name && strncmp(ctrl->name, READBACK_CTRL_NAME, + (sizeof(READBACK_CTRL_NAME) - 1)) == 0) + ctrl->is_readback = true; + ctrl->addr = le16_to_cpu(ctrl_chunk->addr); ctrl->num_bytes = num_bytes; ctrl->samplerates = le32_to_cpu(chunk->samplerates); From b15c3ea7e0d2c53b33adc8ca0896de378d6df853 Mon Sep 17 00:00:00 2001 From: David Ward Date: Sun, 18 Apr 2021 09:46:55 -0400 Subject: [PATCH 532/587] ASoC: rt286: Configure combo jack for headphones During jack detection, the combo jack is configured for a CTIA headset, and then for an OMTP headset, while sensing the mic connection. If a mic is not found in either case, the combo jack should be re-configured for headphones only. This is consistent with the HDA driver behavior. Signed-off-by: David Ward Reviewed-by: Pierre-Louis Bossart Link: https://lore.kernel.org/r/20210418134658.4333-3-david.ward@gatech.edu Signed-off-by: Mark Brown --- sound/soc/codecs/rt286.c | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/sound/soc/codecs/rt286.c b/sound/soc/codecs/rt286.c index e16e7237156f..45e4a48ef5bf 100644 --- a/sound/soc/codecs/rt286.c +++ b/sound/soc/codecs/rt286.c @@ -255,11 +255,16 @@ static int rt286_jack_detect(struct rt286_priv *rt286, bool *hp, bool *mic) msleep(300); regmap_read(rt286->regmap, RT286_CBJ_CTRL2, &val); - if (0x0070 == (val & 0x0070)) + if (0x0070 == (val & 0x0070)) { *mic = true; - else + } else { *mic = false; + regmap_update_bits(rt286->regmap, + RT286_CBJ_CTRL1, + 0xfcc0, 0xc400); + } } + regmap_update_bits(rt286->regmap, RT286_DC_GAIN, 0x200, 0x0); From f3bd4dde9f048fa711e98626c8c3bc4d1eae3436 Mon Sep 17 00:00:00 2001 From: David Ward Date: Sun, 18 Apr 2021 09:46:56 -0400 Subject: [PATCH 533/587] ASoC: rt298: Configure combo jack for headphones During jack detection, the combo jack is configured for a CTIA headset, and then for an OMTP headset, while sensing the mic connection. If a mic is not found in either case, the combo jack should be re-configured for headphones only. This is consistent with the HDA driver behavior. Signed-off-by: David Ward Reviewed-by: Pierre-Louis Bossart Link: https://lore.kernel.org/r/20210418134658.4333-4-david.ward@gatech.edu Signed-off-by: Mark Brown --- sound/soc/codecs/rt298.c | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/sound/soc/codecs/rt298.c b/sound/soc/codecs/rt298.c index 32cc9b6287d2..c592c40a7ab3 100644 --- a/sound/soc/codecs/rt298.c +++ b/sound/soc/codecs/rt298.c @@ -267,11 +267,16 @@ static int rt298_jack_detect(struct rt298_priv *rt298, bool *hp, bool *mic) msleep(300); regmap_read(rt298->regmap, RT298_CBJ_CTRL2, &val); - if (0x0070 == (val & 0x0070)) + if (0x0070 == (val & 0x0070)) { *mic = true; - else + } else { *mic = false; + regmap_update_bits(rt298->regmap, + RT298_CBJ_CTRL1, + 0xfcc0, 0xc400); + } } + regmap_update_bits(rt298->regmap, RT298_DC_GAIN, 0x200, 0x0); From aa2f9c12821e6a4ba1df4fb34a3dbc6a2a1ee7fe Mon Sep 17 00:00:00 2001 From: David Ward Date: Sun, 18 Apr 2021 09:46:58 -0400 Subject: [PATCH 534/587] ASoC: rt286: Generalize support for ALC3263 codec The ALC3263 codec on the XPS 13 9343 is also found on the Latitude 13 7350 and Venue 11 Pro 7140. They require the same handling for the combo jack to work with a headset: GPIO pin 6 must be set. The HDA driver always sets this pin on the ALC3263, which it distinguishes by the codec vendor/device ID 0x10ec0288 and PCI subsystem vendor ID 0x1028 (Dell). The ASoC driver does not use PCI, so adapt this check to use DMI to determine if Dell is the system vendor. BugLink: https://bugzilla.kernel.org/show_bug.cgi?id=150601 BugLink: https://bugzilla.kernel.org/show_bug.cgi?id=205961 Signed-off-by: David Ward Reviewed-by: Pierre-Louis Bossart Link: https://lore.kernel.org/r/20210418134658.4333-6-david.ward@gatech.edu Signed-off-by: Mark Brown --- sound/soc/codecs/rt286.c | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/sound/soc/codecs/rt286.c b/sound/soc/codecs/rt286.c index 45e4a48ef5bf..802f4851c3df 100644 --- a/sound/soc/codecs/rt286.c +++ b/sound/soc/codecs/rt286.c @@ -1125,12 +1125,11 @@ static const struct dmi_system_id force_combo_jack_table[] = { { } }; -static const struct dmi_system_id dmi_dell_dino[] = { +static const struct dmi_system_id dmi_dell[] = { { - .ident = "Dell Dino", + .ident = "Dell", .matches = { DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."), - DMI_MATCH(DMI_PRODUCT_NAME, "XPS 13 9343") } }, { } @@ -1141,7 +1140,7 @@ static int rt286_i2c_probe(struct i2c_client *i2c, { struct rt286_platform_data *pdata = dev_get_platdata(&i2c->dev); struct rt286_priv *rt286; - int i, ret, val; + int i, ret, vendor_id; rt286 = devm_kzalloc(&i2c->dev, sizeof(*rt286), GFP_KERNEL); @@ -1157,14 +1156,15 @@ static int rt286_i2c_probe(struct i2c_client *i2c, } ret = regmap_read(rt286->regmap, - RT286_GET_PARAM(AC_NODE_ROOT, AC_PAR_VENDOR_ID), &val); + RT286_GET_PARAM(AC_NODE_ROOT, AC_PAR_VENDOR_ID), &vendor_id); if (ret != 0) { dev_err(&i2c->dev, "I2C error %d\n", ret); return ret; } - if (val != RT286_VENDOR_ID && val != RT288_VENDOR_ID) { + if (vendor_id != RT286_VENDOR_ID && vendor_id != RT288_VENDOR_ID) { dev_err(&i2c->dev, - "Device with ID register %#x is not rt286\n", val); + "Device with ID register %#x is not rt286\n", + vendor_id); return -ENODEV; } @@ -1188,8 +1188,8 @@ static int rt286_i2c_probe(struct i2c_client *i2c, if (pdata) rt286->pdata = *pdata; - if (dmi_check_system(force_combo_jack_table) || - dmi_check_system(dmi_dell_dino)) + if ((vendor_id == RT288_VENDOR_ID && dmi_check_system(dmi_dell)) || + dmi_check_system(force_combo_jack_table)) rt286->pdata.cbj_en = true; regmap_write(rt286->regmap, RT286_SET_AUDIO_POWER, AC_PWRST_D3); @@ -1228,7 +1228,7 @@ static int rt286_i2c_probe(struct i2c_client *i2c, regmap_update_bits(rt286->regmap, RT286_DEPOP_CTRL3, 0xf777, 0x4737); regmap_update_bits(rt286->regmap, RT286_DEPOP_CTRL4, 0x00ff, 0x003f); - if (dmi_check_system(dmi_dell_dino)) { + if (vendor_id == RT288_VENDOR_ID && dmi_check_system(dmi_dell)) { regmap_update_bits(rt286->regmap, RT286_SET_GPIO_MASK, 0x40, 0x40); regmap_update_bits(rt286->regmap, From 1c9d9dfd2d254211cb37b1513b1da3e6835b8f00 Mon Sep 17 00:00:00 2001 From: Kailang Yang Date: Tue, 20 Apr 2021 14:17:34 +0800 Subject: [PATCH 535/587] ALSA: hda/realtek - Headset Mic issue on HP platform Boot with plugged headset, the Headset Mic will be gone. Signed-off-by: Kailang Yang Cc: Link: https://lore.kernel.org/r/207eecfc3189466a820720bc0c409ea9@realtek.com Signed-off-by: Takashi Iwai --- sound/pci/hda/patch_realtek.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/sound/pci/hda/patch_realtek.c b/sound/pci/hda/patch_realtek.c index 1ad1bb740c32..77cb72fe3b1b 100644 --- a/sound/pci/hda/patch_realtek.c +++ b/sound/pci/hda/patch_realtek.c @@ -8104,6 +8104,8 @@ static const struct snd_pci_quirk alc269_fixup_tbl[] = { SND_PCI_QUIRK(0x103c, 0x221c, "HP EliteBook 755 G2", ALC280_FIXUP_HP_HEADSET_MIC), SND_PCI_QUIRK(0x103c, 0x802e, "HP Z240 SFF", ALC221_FIXUP_HP_MIC_NO_PRESENCE), SND_PCI_QUIRK(0x103c, 0x802f, "HP Z240", ALC221_FIXUP_HP_MIC_NO_PRESENCE), + SND_PCI_QUIRK(0x103c, 0x8077, "HP", ALC256_FIXUP_HP_HEADSET_MIC), + SND_PCI_QUIRK(0x103c, 0x8158, "HP", ALC256_FIXUP_HP_HEADSET_MIC), SND_PCI_QUIRK(0x103c, 0x820d, "HP Pavilion 15", ALC269_FIXUP_HP_MUTE_LED_MIC3), SND_PCI_QUIRK(0x103c, 0x8256, "HP", ALC221_FIXUP_HP_FRONT_MIC), SND_PCI_QUIRK(0x103c, 0x827e, "HP x360", ALC295_FIXUP_HP_X360), From bd15b15523fd3197d1bb46403e02e92877a4f412 Mon Sep 17 00:00:00 2001 From: Kai-Heng Feng Date: Tue, 20 Apr 2021 19:55:29 +0800 Subject: [PATCH 536/587] ALSA: hda/realtek: Enable mute/micmute LEDs and limit mic boost on EliteBook 845 G8 On HP EliteBook 845 G8, the audio LEDs can be enabled by ALC285_FIXUP_HP_MUTE_LED. So use it accordingly. In addition to that, the mic captures lots of noises, so also limits the mic boost. The quality of capture audio becomes crystal clear after limiting the mic boost. Signed-off-by: Kai-Heng Feng Link: https://lore.kernel.org/r/20210420115530.1349353-1-kai.heng.feng@canonical.com Signed-off-by: Takashi Iwai --- sound/pci/hda/patch_realtek.c | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/sound/pci/hda/patch_realtek.c b/sound/pci/hda/patch_realtek.c index 77cb72fe3b1b..97473e67716b 100644 --- a/sound/pci/hda/patch_realtek.c +++ b/sound/pci/hda/patch_realtek.c @@ -6460,6 +6460,7 @@ enum { ALC255_FIXUP_ACER_LIMIT_INT_MIC_BOOST, ALC256_FIXUP_ACER_HEADSET_MIC, ALC285_FIXUP_IDEAPAD_S740_COEF, + ALC285_FIXUP_HP_LIMIT_INT_MIC_BOOST, }; static const struct hda_fixup alc269_fixups[] = { @@ -7954,6 +7955,12 @@ static const struct hda_fixup alc269_fixups[] = { .chained = true, .chain_id = ALC269_FIXUP_THINKPAD_ACPI, }, + [ALC285_FIXUP_HP_LIMIT_INT_MIC_BOOST] = { + .type = HDA_FIXUP_FUNC, + .v.func = alc269_fixup_limit_int_mic_boost, + .chained = true, + .chain_id = ALC285_FIXUP_HP_MUTE_LED, + }, }; static const struct snd_pci_quirk alc269_fixup_tbl[] = { @@ -8135,6 +8142,7 @@ static const struct snd_pci_quirk alc269_fixup_tbl[] = { SND_PCI_QUIRK(0x103c, 0x87f7, "HP Spectre x360 14", ALC245_FIXUP_HP_X360_AMP), SND_PCI_QUIRK(0x103c, 0x8846, "HP EliteBook 850 G8 Notebook PC", ALC285_FIXUP_HP_GPIO_LED), SND_PCI_QUIRK(0x103c, 0x884c, "HP EliteBook 840 G8 Notebook PC", ALC285_FIXUP_HP_GPIO_LED), + SND_PCI_QUIRK(0x103c, 0x8898, "HP EliteBook 845 G8 Notebook PC", ALC285_FIXUP_HP_LIMIT_INT_MIC_BOOST), SND_PCI_QUIRK(0x1043, 0x103e, "ASUS X540SA", ALC256_FIXUP_ASUS_MIC), SND_PCI_QUIRK(0x1043, 0x103f, "ASUS TX300", ALC282_FIXUP_ASUS_TX300), SND_PCI_QUIRK(0x1043, 0x106d, "Asus K53BE", ALC269_FIXUP_LIMIT_INT_MIC_BOOST), From 7f51384f17b3e1039fbb2d3535cc777585dc3175 Mon Sep 17 00:00:00 2001 From: Jack Yu Date: Tue, 20 Apr 2021 09:30:48 +0000 Subject: [PATCH 537/587] ASoC: rt1015p: add support on format S32_LE Add support on format S32_LE for rt1015p. Signed-off-by: Jack Yu Link: https://lore.kernel.org/r/377f0ee05d514c66b567eb6385ac7753@realtek.com Signed-off-by: Mark Brown --- sound/soc/codecs/rt1015p.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/sound/soc/codecs/rt1015p.c b/sound/soc/codecs/rt1015p.c index 39f4c4ed2ab8..40f2063aefbe 100644 --- a/sound/soc/codecs/rt1015p.c +++ b/sound/soc/codecs/rt1015p.c @@ -96,7 +96,8 @@ static struct snd_soc_dai_driver rt1015p_dai_driver = { .name = "HiFi", .playback = { .stream_name = "HiFi Playback", - .formats = SNDRV_PCM_FMTBIT_S24, + .formats = SNDRV_PCM_FMTBIT_S24 | + SNDRV_PCM_FMTBIT_S32, .rates = SNDRV_PCM_RATE_48000, .channels_min = 1, .channels_max = 2, From ec1af6c64db94e4f24e53011a77b2bf2220ae000 Mon Sep 17 00:00:00 2001 From: Thierry Reding Date: Mon, 19 Apr 2021 18:41:17 +0200 Subject: [PATCH 538/587] ASoC: simple-card-utils: Allocate link info structure on heap struct link_info can grow fairly large and may cause the stack frame size to be exceeded when allocated on the stack. Some architectures such as 32-bit ARM, RISC-V or PowerPC have small stack frames where this causes a compiler warning, so allocate these structures on the heap instead of the stack. Fixes: 343e55e71877 ("ASoC: simple-card-utils: Increase maximum number of links to 128") Reported-by: Kuninori Morimoto Reported-by: Stephen Rothwell Reported-by: kernel test robot Signed-off-by: Thierry Reding Acked-by: Kuninori Morimoto Link: https://lore.kernel.org/r/20210419164117.1422242-1-thierry.reding@gmail.com Signed-off-by: Mark Brown --- sound/soc/generic/audio-graph-card.c | 18 +++++++++++------- sound/soc/generic/simple-card.c | 23 +++++++++++++---------- 2 files changed, 24 insertions(+), 17 deletions(-) diff --git a/sound/soc/generic/audio-graph-card.c b/sound/soc/generic/audio-graph-card.c index c7369beee805..e45a560aa9b0 100644 --- a/sound/soc/generic/audio-graph-card.c +++ b/sound/soc/generic/audio-graph-card.c @@ -548,21 +548,24 @@ static int graph_get_dais_count(struct asoc_simple_priv *priv, int audio_graph_parse_of(struct asoc_simple_priv *priv, struct device *dev) { struct snd_soc_card *card = simple_priv_to_card(priv); - struct link_info li; + struct link_info *li; int ret; + li = devm_kzalloc(dev, sizeof(*li), GFP_KERNEL); + if (!li) + return -ENOMEM; + card->owner = THIS_MODULE; card->dev = dev; - memset(&li, 0, sizeof(li)); - ret = graph_get_dais_count(priv, &li); + ret = graph_get_dais_count(priv, li); if (ret < 0) return ret; - if (!li.link) + if (!li->link) return -EINVAL; - ret = asoc_simple_init_priv(priv, &li); + ret = asoc_simple_init_priv(priv, li); if (ret < 0) return ret; @@ -581,8 +584,8 @@ int audio_graph_parse_of(struct asoc_simple_priv *priv, struct device *dev) if (ret < 0) return ret; - memset(&li, 0, sizeof(li)); - ret = graph_for_each_link(priv, &li, + memset(li, 0, sizeof(*li)); + ret = graph_for_each_link(priv, li, graph_dai_link_of, graph_dai_link_of_dpcm); if (ret < 0) @@ -600,6 +603,7 @@ int audio_graph_parse_of(struct asoc_simple_priv *priv, struct device *dev) if (ret < 0) goto err; + devm_kfree(dev, li); return 0; err: diff --git a/sound/soc/generic/simple-card.c b/sound/soc/generic/simple-card.c index 8b9964d25757..ca27cb9ff9e1 100644 --- a/sound/soc/generic/simple-card.c +++ b/sound/soc/generic/simple-card.c @@ -442,10 +442,9 @@ static int simple_for_each_link(struct asoc_simple_priv *priv, return ret; } -static int simple_parse_of(struct asoc_simple_priv *priv) +static int simple_parse_of(struct asoc_simple_priv *priv, struct link_info *li) { struct snd_soc_card *card = simple_priv_to_card(priv); - struct link_info li; int ret; ret = asoc_simple_parse_widgets(card, PREFIX); @@ -461,8 +460,8 @@ static int simple_parse_of(struct asoc_simple_priv *priv) return ret; /* Single/Muti DAI link(s) & New style of DT node */ - memset(&li, 0, sizeof(li)); - ret = simple_for_each_link(priv, &li, + memset(li, 0, sizeof(*li)); + ret = simple_for_each_link(priv, li, simple_dai_link_of, simple_dai_link_of_dpcm); if (ret < 0) @@ -612,7 +611,7 @@ static int asoc_simple_probe(struct platform_device *pdev) struct device *dev = &pdev->dev; struct device_node *np = dev->of_node; struct snd_soc_card *card; - struct link_info li; + struct link_info *li; int ret; /* Allocate the private data and the DAI link array */ @@ -625,21 +624,24 @@ static int asoc_simple_probe(struct platform_device *pdev) card->dev = dev; card->probe = simple_soc_probe; - memset(&li, 0, sizeof(li)); - ret = simple_get_dais_count(priv, &li); + li = devm_kzalloc(dev, sizeof(*li), GFP_KERNEL); + if (!li) + return -ENOMEM; + + ret = simple_get_dais_count(priv, li); if (ret < 0) return ret; - if (!li.link) + if (!li->link) return -EINVAL; - ret = asoc_simple_init_priv(priv, &li); + ret = asoc_simple_init_priv(priv, li); if (ret < 0) return ret; if (np && of_device_is_available(np)) { - ret = simple_parse_of(priv); + ret = simple_parse_of(priv, li); if (ret < 0) { if (ret != -EPROBE_DEFER) dev_err(dev, "parse error %d\n", ret); @@ -698,6 +700,7 @@ static int asoc_simple_probe(struct platform_device *pdev) if (ret < 0) goto err; + devm_kfree(dev, li); return 0; err: asoc_simple_clean_reference(card); From cfd577acb769301b19c31361d45ae1f145318b7a Mon Sep 17 00:00:00 2001 From: Colin Ian King Date: Tue, 20 Apr 2021 14:47:19 +0100 Subject: [PATCH 539/587] ALSA: usb: midi: don't return -ENOMEM when usb_urb_ep_type_check fails Currently when the call to usb_urb_ep_type_check fails (returning -EINVAL) the error return path returns -ENOMEM via the exit label "error". Other uses of the same error exit label set the err variable to -ENOMEM but this is not being used. I believe the original intent was for the error exit path to return the value in err rather than the hard coded -ENOMEM, so return this rather than the hard coded -ENOMEM. Addresses-Coverity: ("Unused value") Fixes: 738d9edcfd44 ("ALSA: usb-audio: Add sanity checks for invalid EPs") Signed-off-by: Colin Ian King Link: https://lore.kernel.org/r/20210420134719.381409-1-colin.king@canonical.com Signed-off-by: Takashi Iwai --- sound/usb/midi.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sound/usb/midi.c b/sound/usb/midi.c index 9efda4b06acb..a10ac75969a8 100644 --- a/sound/usb/midi.c +++ b/sound/usb/midi.c @@ -1316,7 +1316,7 @@ static int snd_usbmidi_in_endpoint_create(struct snd_usb_midi *umidi, error: snd_usbmidi_in_endpoint_delete(ep); - return -ENOMEM; + return err; } /* From 1a456b1c6be13514a8fc5c1a99e6763f491d17e9 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Mon, 19 Apr 2021 11:02:19 +0900 Subject: [PATCH 540/587] ASoC: audio-graph: move audio_graph_card_probe() to simple-card-utils.c audio-graph-card2 can reuse audio_graph_card_probe(). This patch moves it to simple-card-utils.c. Signed-off-by: Kuninori Morimoto Link: https://lore.kernel.org/r/87zgxv3uc4.wl-kuninori.morimoto.gx@renesas.com Signed-off-by: Mark Brown --- include/sound/graph_card.h | 2 -- include/sound/simple_card_utils.h | 3 +++ sound/soc/generic/audio-graph-card.c | 19 +------------------ sound/soc/generic/simple-card-utils.c | 17 +++++++++++++++++ sound/soc/tegra/tegra_audio_graph_card.c | 2 +- 5 files changed, 22 insertions(+), 21 deletions(-) diff --git a/include/sound/graph_card.h b/include/sound/graph_card.h index 013784467bec..9c2feb792742 100644 --- a/include/sound/graph_card.h +++ b/include/sound/graph_card.h @@ -9,8 +9,6 @@ #include -int audio_graph_card_probe(struct snd_soc_card *card); - int audio_graph_parse_of(struct asoc_simple_priv *priv, struct device *dev); int audio_graph_remove(struct platform_device *pdev); diff --git a/include/sound/simple_card_utils.h b/include/sound/simple_card_utils.h index e318a2d4ac44..656c7e30b6e4 100644 --- a/include/sound/simple_card_utils.h +++ b/include/sound/simple_card_utils.h @@ -178,6 +178,9 @@ int asoc_simple_init_jack(struct snd_soc_card *card, int asoc_simple_init_priv(struct asoc_simple_priv *priv, struct link_info *li); +int asoc_graph_card_probe(struct snd_soc_card *card); + + #ifdef DEBUG static inline void asoc_simple_debug_dai(struct asoc_simple_priv *priv, char *name, diff --git a/sound/soc/generic/audio-graph-card.c b/sound/soc/generic/audio-graph-card.c index e45a560aa9b0..6cac167a4e2b 100644 --- a/sound/soc/generic/audio-graph-card.c +++ b/sound/soc/generic/audio-graph-card.c @@ -721,23 +721,6 @@ static int graph_get_dais_count(struct asoc_simple_priv *priv, graph_count_dpcm); } -int audio_graph_card_probe(struct snd_soc_card *card) -{ - struct asoc_simple_priv *priv = snd_soc_card_get_drvdata(card); - int ret; - - ret = asoc_simple_init_hp(card, &priv->hp_jack, NULL); - if (ret < 0) - return ret; - - ret = asoc_simple_init_mic(card, &priv->mic_jack, NULL); - if (ret < 0) - return ret; - - return 0; -} -EXPORT_SYMBOL_GPL(audio_graph_card_probe); - static int graph_probe(struct platform_device *pdev) { struct asoc_simple_priv *priv; @@ -752,7 +735,7 @@ static int graph_probe(struct platform_device *pdev) card = simple_priv_to_card(priv); card->dapm_widgets = graph_dapm_widgets; card->num_dapm_widgets = ARRAY_SIZE(graph_dapm_widgets); - card->probe = audio_graph_card_probe; + card->probe = asoc_graph_card_probe; if (of_device_get_match_data(dev)) priv->dpcm_selectable = 1; diff --git a/sound/soc/generic/simple-card-utils.c b/sound/soc/generic/simple-card-utils.c index e1b7b30a4c8c..ed2cad6d9ac1 100644 --- a/sound/soc/generic/simple-card-utils.c +++ b/sound/soc/generic/simple-card-utils.c @@ -740,6 +740,23 @@ int asoc_simple_init_priv(struct asoc_simple_priv *priv, } EXPORT_SYMBOL_GPL(asoc_simple_init_priv); +int asoc_graph_card_probe(struct snd_soc_card *card) +{ + struct asoc_simple_priv *priv = snd_soc_card_get_drvdata(card); + int ret; + + ret = asoc_simple_init_hp(card, &priv->hp_jack, NULL); + if (ret < 0) + return ret; + + ret = asoc_simple_init_mic(card, &priv->mic_jack, NULL); + if (ret < 0) + return ret; + + return 0; +} +EXPORT_SYMBOL_GPL(asoc_graph_card_probe); + /* Module information */ MODULE_AUTHOR("Kuninori Morimoto "); MODULE_DESCRIPTION("ALSA SoC Simple Card Utils"); diff --git a/sound/soc/tegra/tegra_audio_graph_card.c b/sound/soc/tegra/tegra_audio_graph_card.c index 47b319504c8c..35d008b5d373 100644 --- a/sound/soc/tegra/tegra_audio_graph_card.c +++ b/sound/soc/tegra/tegra_audio_graph_card.c @@ -184,7 +184,7 @@ static int tegra_audio_graph_card_probe(struct snd_soc_card *card) return PTR_ERR(priv->clk_plla_out0); } - return audio_graph_card_probe(card); + return asoc_graph_card_probe(card); } static int tegra_audio_graph_probe(struct platform_device *pdev) From f6fcc820e0c96664e2f21c0d6bb60630243ef36a Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Mon, 19 Apr 2021 11:02:25 +0900 Subject: [PATCH 541/587] ASoC: audio-graph: move audio_graph_remove() to simple-card-utils.c audio-graph-card2 can reuse audio_graph_remove() / asoc_simple_remove(). This patch moves it to simple-card-utils.c. Signed-off-by: Kuninori Morimoto Link: https://lore.kernel.org/r/87y2df3uby.wl-kuninori.morimoto.gx@renesas.com Signed-off-by: Mark Brown --- include/sound/graph_card.h | 2 -- include/sound/simple_card_utils.h | 2 +- sound/soc/generic/audio-graph-card.c | 10 +--------- sound/soc/generic/simple-card-utils.c | 8 ++++++++ sound/soc/generic/simple-card.c | 7 ------- sound/soc/tegra/tegra_audio_graph_card.c | 2 +- 6 files changed, 11 insertions(+), 20 deletions(-) diff --git a/include/sound/graph_card.h b/include/sound/graph_card.h index 9c2feb792742..6f10bfb0d5ee 100644 --- a/include/sound/graph_card.h +++ b/include/sound/graph_card.h @@ -11,6 +11,4 @@ int audio_graph_parse_of(struct asoc_simple_priv *priv, struct device *dev); -int audio_graph_remove(struct platform_device *pdev); - #endif /* __GRAPH_CARD_H */ diff --git a/include/sound/simple_card_utils.h b/include/sound/simple_card_utils.h index 656c7e30b6e4..51b3b485a92e 100644 --- a/include/sound/simple_card_utils.h +++ b/include/sound/simple_card_utils.h @@ -177,10 +177,10 @@ int asoc_simple_init_jack(struct snd_soc_card *card, int is_hp, char *prefix, char *pin); int asoc_simple_init_priv(struct asoc_simple_priv *priv, struct link_info *li); +int asoc_simple_remove(struct platform_device *pdev); int asoc_graph_card_probe(struct snd_soc_card *card); - #ifdef DEBUG static inline void asoc_simple_debug_dai(struct asoc_simple_priv *priv, char *name, diff --git a/sound/soc/generic/audio-graph-card.c b/sound/soc/generic/audio-graph-card.c index 6cac167a4e2b..976c1ea31a98 100644 --- a/sound/soc/generic/audio-graph-card.c +++ b/sound/soc/generic/audio-graph-card.c @@ -743,14 +743,6 @@ static int graph_probe(struct platform_device *pdev) return audio_graph_parse_of(priv, dev); } -int audio_graph_remove(struct platform_device *pdev) -{ - struct snd_soc_card *card = platform_get_drvdata(pdev); - - return asoc_simple_clean_reference(card); -} -EXPORT_SYMBOL_GPL(audio_graph_remove); - static const struct of_device_id graph_of_match[] = { { .compatible = "audio-graph-card", }, { .compatible = "audio-graph-scu-card", @@ -766,7 +758,7 @@ static struct platform_driver graph_card = { .of_match_table = graph_of_match, }, .probe = graph_probe, - .remove = audio_graph_remove, + .remove = asoc_simple_remove, }; module_platform_driver(graph_card); diff --git a/sound/soc/generic/simple-card-utils.c b/sound/soc/generic/simple-card-utils.c index ed2cad6d9ac1..fa1247f0dda1 100644 --- a/sound/soc/generic/simple-card-utils.c +++ b/sound/soc/generic/simple-card-utils.c @@ -740,6 +740,14 @@ int asoc_simple_init_priv(struct asoc_simple_priv *priv, } EXPORT_SYMBOL_GPL(asoc_simple_init_priv); +int asoc_simple_remove(struct platform_device *pdev) +{ + struct snd_soc_card *card = platform_get_drvdata(pdev); + + return asoc_simple_clean_reference(card); +} +EXPORT_SYMBOL_GPL(asoc_simple_remove); + int asoc_graph_card_probe(struct snd_soc_card *card) { struct asoc_simple_priv *priv = snd_soc_card_get_drvdata(card); diff --git a/sound/soc/generic/simple-card.c b/sound/soc/generic/simple-card.c index ca27cb9ff9e1..a1373be4558f 100644 --- a/sound/soc/generic/simple-card.c +++ b/sound/soc/generic/simple-card.c @@ -708,13 +708,6 @@ err: return ret; } -static int asoc_simple_remove(struct platform_device *pdev) -{ - struct snd_soc_card *card = platform_get_drvdata(pdev); - - return asoc_simple_clean_reference(card); -} - static const struct of_device_id simple_of_match[] = { { .compatible = "simple-audio-card", }, { .compatible = "simple-scu-audio-card", diff --git a/sound/soc/tegra/tegra_audio_graph_card.c b/sound/soc/tegra/tegra_audio_graph_card.c index 35d008b5d373..1f2c5018bf5a 100644 --- a/sound/soc/tegra/tegra_audio_graph_card.c +++ b/sound/soc/tegra/tegra_audio_graph_card.c @@ -244,7 +244,7 @@ static struct platform_driver tegra_audio_graph_card = { .of_match_table = graph_of_tegra_match, }, .probe = tegra_audio_graph_probe, - .remove = audio_graph_remove, + .remove = asoc_simple_remove, }; module_platform_driver(tegra_audio_graph_card); From 6769ea1e4315999624ce4637c9c338b9d88a85e6 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Mon, 19 Apr 2021 11:02:29 +0900 Subject: [PATCH 542/587] ASoC: audio-graph: check ports if exists "endpoint" and "port" are always exists, but there is no guarantee for "ports". This patch checks "ports" if exists, otherwise, it might set un-expected settings. This patch also do align to 100 char in 1 line. Signed-off-by: Kuninori Morimoto Link: https://lore.kernel.org/r/87wnsz3ubu.wl-kuninori.morimoto.gx@renesas.com Signed-off-by: Mark Brown --- sound/soc/generic/audio-graph-card.c | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/sound/soc/generic/audio-graph-card.c b/sound/soc/generic/audio-graph-card.c index 976c1ea31a98..f3c278a4be21 100644 --- a/sound/soc/generic/audio-graph-card.c +++ b/sound/soc/generic/audio-graph-card.c @@ -182,7 +182,8 @@ static void graph_parse_convert(struct device *dev, asoc_simple_parse_convert(top, NULL, adata); asoc_simple_parse_convert(node, PREFIX, adata); - asoc_simple_parse_convert(ports, NULL, adata); + if (of_node_name_eq(ports, "ports")) + asoc_simple_parse_convert(ports, NULL, adata); asoc_simple_parse_convert(port, NULL, adata); asoc_simple_parse_convert(ep, NULL, adata); @@ -200,7 +201,8 @@ static void graph_parse_mclk_fs(struct device_node *top, struct device_node *node = of_graph_get_port_parent(ep); of_property_read_u32(top, "mclk-fs", &props->mclk_fs); - of_property_read_u32(ports, "mclk-fs", &props->mclk_fs); + if (of_node_name_eq(ports, "ports")) + of_property_read_u32(ports, "mclk-fs", &props->mclk_fs); of_property_read_u32(port, "mclk-fs", &props->mclk_fs); of_property_read_u32(ep, "mclk-fs", &props->mclk_fs); @@ -311,8 +313,8 @@ static int graph_dai_link_of_dpcm(struct asoc_simple_priv *priv, "prefix"); snd_soc_of_parse_node_prefix(node, cconf, codecs->of_node, PREFIX "prefix"); - snd_soc_of_parse_node_prefix(ports, cconf, codecs->of_node, - "prefix"); + if (of_node_name_eq(ports, "ports")) + snd_soc_of_parse_node_prefix(ports, cconf, codecs->of_node, "prefix"); snd_soc_of_parse_node_prefix(port, cconf, codecs->of_node, "prefix"); } From 14d78d74d7bc47c6ff3a66fb9d405084de7b6b02 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Mon, 19 Apr 2021 11:02:34 +0900 Subject: [PATCH 543/587] ASoC: audio-graph: remove "audio-graph-card, " preix support No upstream code is using "audio-graph-card," preix, and Yaml base Document doesn't indicate it. Let's remove it. Signed-off-by: Kuninori Morimoto Link: https://lore.kernel.org/r/87v98j3ubp.wl-kuninori.morimoto.gx@renesas.com Signed-off-by: Mark Brown --- sound/soc/generic/audio-graph-card.c | 5 ----- 1 file changed, 5 deletions(-) diff --git a/sound/soc/generic/audio-graph-card.c b/sound/soc/generic/audio-graph-card.c index f3c278a4be21..d5ab5c919311 100644 --- a/sound/soc/generic/audio-graph-card.c +++ b/sound/soc/generic/audio-graph-card.c @@ -22,8 +22,6 @@ #define DPCM_SELECTABLE 1 -#define PREFIX "audio-graph-card," - static int graph_outdrv_event(struct snd_soc_dapm_widget *w, struct snd_kcontrol *kcontrol, int event) @@ -181,7 +179,6 @@ static void graph_parse_convert(struct device *dev, struct device_node *node = of_graph_get_port_parent(ep); asoc_simple_parse_convert(top, NULL, adata); - asoc_simple_parse_convert(node, PREFIX, adata); if (of_node_name_eq(ports, "ports")) asoc_simple_parse_convert(ports, NULL, adata); asoc_simple_parse_convert(port, NULL, adata); @@ -311,8 +308,6 @@ static int graph_dai_link_of_dpcm(struct asoc_simple_priv *priv, /* check "prefix" from top node */ snd_soc_of_parse_node_prefix(top, cconf, codecs->of_node, "prefix"); - snd_soc_of_parse_node_prefix(node, cconf, codecs->of_node, - PREFIX "prefix"); if (of_node_name_eq(ports, "ports")) snd_soc_of_parse_node_prefix(ports, cconf, codecs->of_node, "prefix"); snd_soc_of_parse_node_prefix(port, cconf, codecs->of_node, From 67800ae93982eb4496f446cfd06f98ba7382ce36 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Mon, 19 Apr 2021 11:02:38 +0900 Subject: [PATCH 544/587] ASoC: audio-graph: remove unused "node" from graph_parse_mclk_fs() graph_parse_mclk_fs() has "node", but is not used. This patch removes unused "node" Signed-off-by: Kuninori Morimoto Link: https://lore.kernel.org/r/87tuo33ubl.wl-kuninori.morimoto.gx@renesas.com Signed-off-by: Mark Brown --- sound/soc/generic/audio-graph-card.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/sound/soc/generic/audio-graph-card.c b/sound/soc/generic/audio-graph-card.c index d5ab5c919311..6b38640773b3 100644 --- a/sound/soc/generic/audio-graph-card.c +++ b/sound/soc/generic/audio-graph-card.c @@ -195,7 +195,6 @@ static void graph_parse_mclk_fs(struct device_node *top, { struct device_node *port = of_get_parent(ep); struct device_node *ports = of_get_parent(port); - struct device_node *node = of_graph_get_port_parent(ep); of_property_read_u32(top, "mclk-fs", &props->mclk_fs); if (of_node_name_eq(ports, "ports")) @@ -205,7 +204,6 @@ static void graph_parse_mclk_fs(struct device_node *top, of_node_put(port); of_node_put(ports); - of_node_put(node); } static int graph_dai_link_of_dpcm(struct asoc_simple_priv *priv, From 63f2f9cceb09f8e5f668e36c1cf764eea468ebed Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Mon, 19 Apr 2021 11:02:43 +0900 Subject: [PATCH 545/587] ASoC: audio-graph: remove Platform support Platform was one of mandatory component on ASoC before, and audio-graph-card was assuming that CPU and Platform were same driver. But it is no longer mandatory on ASoC. Current ASoC will just ignore if Platform and CPU were same or doplicated component. Of course ASoC is supporting Platform, but current audio-graph-card doesn't support detecting it from DT. This means current audio-graph-card operation for Platform so far is 100% useless. This patch removes it. We can respawn it when we need it. Signed-off-by: Kuninori Morimoto Link: https://lore.kernel.org/r/87sg3n3ubg.wl-kuninori.morimoto.gx@renesas.com Signed-off-by: Mark Brown --- sound/soc/generic/audio-graph-card.c | 6 ------ 1 file changed, 6 deletions(-) diff --git a/sound/soc/generic/audio-graph-card.c b/sound/soc/generic/audio-graph-card.c index 6b38640773b3..44714a12fcd8 100644 --- a/sound/soc/generic/audio-graph-card.c +++ b/sound/soc/generic/audio-graph-card.c @@ -223,7 +223,6 @@ static int graph_dai_link_of_dpcm(struct asoc_simple_priv *priv, struct asoc_simple_dai *dai; struct snd_soc_dai_link_component *cpus = asoc_link_to_cpu(dai_link, 0); struct snd_soc_dai_link_component *codecs = asoc_link_to_codec(dai_link, 0); - struct snd_soc_dai_link_component *platforms = asoc_link_to_platform(dai_link, 0); int ret; port = of_get_parent(ep); @@ -275,7 +274,6 @@ static int graph_dai_link_of_dpcm(struct asoc_simple_priv *priv, /* card->num_links includes Codec */ asoc_simple_canonicalize_cpu(cpus, is_single_links); - asoc_simple_canonicalize_platform(platforms, cpus); } else { struct snd_soc_codec_conf *cconf; @@ -354,7 +352,6 @@ static int graph_dai_link_of(struct asoc_simple_priv *priv, struct asoc_simple_dai *codec_dai = simple_props_to_dai_codec(dai_props, 0); struct snd_soc_dai_link_component *cpus = asoc_link_to_cpu(dai_link, 0); struct snd_soc_dai_link_component *codecs = asoc_link_to_codec(dai_link, 0); - struct snd_soc_dai_link_component *platforms = asoc_link_to_platform(dai_link, 0); int ret, single_cpu = 0; dev_dbg(dev, "link_of (%pOF)\n", cpu_ep); @@ -405,7 +402,6 @@ static int graph_dai_link_of(struct asoc_simple_priv *priv, dai_link->init = asoc_simple_dai_init; asoc_simple_canonicalize_cpu(cpus, single_cpu); - asoc_simple_canonicalize_platform(platforms, cpus); return 0; } @@ -625,7 +621,6 @@ static int graph_count_noml(struct asoc_simple_priv *priv, li->num[li->link].cpus = 1; li->num[li->link].codecs = 1; - li->num[li->link].platforms = 1; li->link += 1; /* 1xCPU-Codec */ @@ -648,7 +643,6 @@ static int graph_count_dpcm(struct asoc_simple_priv *priv, if (li->cpu) { li->num[li->link].cpus = 1; - li->num[li->link].platforms = 1; li->link++; /* 1xCPU-dummy */ } else { From 7342db3cddcd1d8ff54f4dff8c942e04232f1d6d Mon Sep 17 00:00:00 2001 From: Viorel Suman Date: Tue, 20 Apr 2021 18:44:13 +0800 Subject: [PATCH 546/587] ASoC: ak4458: enable daisy chain Enable Daisy Chain if in TDM mode and the number of played channels is bigger than the maximum supported number of channels. Signed-off-by: Viorel Suman Signed-off-by: Shengjiu Wang Link: https://lore.kernel.org/r/1618915453-29445-1-git-send-email-shengjiu.wang@nxp.com Signed-off-by: Mark Brown --- sound/soc/codecs/ak4458.c | 47 ++++++++++++++++++++++++++------------- sound/soc/codecs/ak4458.h | 1 + 2 files changed, 32 insertions(+), 16 deletions(-) diff --git a/sound/soc/codecs/ak4458.c b/sound/soc/codecs/ak4458.c index 3088128816bb..29eb78702bf3 100644 --- a/sound/soc/codecs/ak4458.c +++ b/sound/soc/codecs/ak4458.c @@ -306,6 +306,20 @@ static const struct snd_soc_dapm_route ak4497_intercon[] = { }; +static int ak4458_get_tdm_mode(struct ak4458_priv *ak4458) +{ + switch (ak4458->slots * ak4458->slot_width) { + case 128: + return 1; + case 256: + return 2; + case 512: + return 3; + default: + return 0; + } +} + static int ak4458_rstn_control(struct snd_soc_component *component, int bit) { int ret; @@ -333,13 +347,16 @@ static int ak4458_hw_params(struct snd_pcm_substream *substream, struct snd_soc_component *component = dai->component; struct ak4458_priv *ak4458 = snd_soc_component_get_drvdata(component); int pcm_width = max(params_physical_width(params), ak4458->slot_width); - u8 format, dsdsel0, dsdsel1; - int nfs1, dsd_bclk, ret; + u8 format, dsdsel0, dsdsel1, dchn; + int nfs1, dsd_bclk, ret, channels, channels_max; nfs1 = params_rate(params); ak4458->fs = nfs1; /* calculate bit clock */ + channels = params_channels(params); + channels_max = dai->driver->playback.channels_max; + switch (params_format(params)) { case SNDRV_PCM_FORMAT_DSD_U8: case SNDRV_PCM_FORMAT_DSD_U16_LE: @@ -419,6 +436,17 @@ static int ak4458_hw_params(struct snd_pcm_substream *substream, snd_soc_component_update_bits(component, AK4458_00_CONTROL1, AK4458_DIF_MASK, format); + /* + * Enable/disable Daisy Chain if in TDM mode and the number of played + * channels is bigger than the maximum supported number of channels + */ + dchn = ak4458_get_tdm_mode(ak4458) && + (ak4458->fmt == SND_SOC_DAIFMT_DSP_B) && + (channels > channels_max) ? AK4458_DCHAIN_MASK : 0; + + snd_soc_component_update_bits(component, AK4458_0B_CONTROL7, + AK4458_DCHAIN_MASK, dchn); + ret = ak4458_rstn_control(component, 0); if (ret) return ret; @@ -519,20 +547,7 @@ static int ak4458_set_tdm_slot(struct snd_soc_dai *dai, unsigned int tx_mask, ak4458->slots = slots; ak4458->slot_width = slot_width; - switch (slots * slot_width) { - case 128: - mode = AK4458_MODE_TDM128; - break; - case 256: - mode = AK4458_MODE_TDM256; - break; - case 512: - mode = AK4458_MODE_TDM512; - break; - default: - mode = AK4458_MODE_NORMAL; - break; - } + mode = ak4458_get_tdm_mode(ak4458) << AK4458_MODE_SHIFT; snd_soc_component_update_bits(component, AK4458_0A_CONTROL6, AK4458_MODE_MASK, diff --git a/sound/soc/codecs/ak4458.h b/sound/soc/codecs/ak4458.h index 9548c5d78621..9ad869575f8d 100644 --- a/sound/soc/codecs/ak4458.h +++ b/sound/soc/codecs/ak4458.h @@ -82,6 +82,7 @@ * */ #define AK4458_ATS_SHIFT 6 #define AK4458_ATS_MASK GENMASK(7, 6) +#define AK4458_DCHAIN_MASK (0x1 << 1) #define AK4458_DSDSEL_MASK (0x1 << 0) #define AK4458_DP_MASK (0x1 << 7) From 1300c7037f0f08692008053e4b12a2fb6fbd185a Mon Sep 17 00:00:00 2001 From: Vijendar Mukunda Date: Wed, 21 Apr 2021 13:53:11 +0530 Subject: [PATCH 547/587] ASoC: amd: drop S24_LE format support AMD I2S Controller doesn't support S24_LE format. Remove S24_LE format support from ACP DMA driver and CPU DAI Driver. Signed-off-by: Vijendar Mukunda Link: https://lore.kernel.org/r/1618993402-10354-1-git-send-email-Vijendar.Mukunda@amd.com Signed-off-by: Mark Brown --- sound/soc/amd/raven/acp3x-i2s.c | 6 ++---- sound/soc/amd/raven/acp3x-pcm-dma.c | 6 ++---- 2 files changed, 4 insertions(+), 8 deletions(-) diff --git a/sound/soc/amd/raven/acp3x-i2s.c b/sound/soc/amd/raven/acp3x-i2s.c index 5bc028692fcf..2cd93887410c 100644 --- a/sound/soc/amd/raven/acp3x-i2s.c +++ b/sound/soc/amd/raven/acp3x-i2s.c @@ -264,8 +264,7 @@ static struct snd_soc_dai_driver acp3x_i2s_dai = { .playback = { .rates = SNDRV_PCM_RATE_8000_96000, .formats = SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S8 | - SNDRV_PCM_FMTBIT_U8 | SNDRV_PCM_FMTBIT_S24_LE | - SNDRV_PCM_FMTBIT_S32_LE, + SNDRV_PCM_FMTBIT_U8 | SNDRV_PCM_FMTBIT_S32_LE, .channels_min = 2, .channels_max = 8, .rate_min = 8000, @@ -274,8 +273,7 @@ static struct snd_soc_dai_driver acp3x_i2s_dai = { .capture = { .rates = SNDRV_PCM_RATE_8000_48000, .formats = SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S8 | - SNDRV_PCM_FMTBIT_U8 | SNDRV_PCM_FMTBIT_S24_LE | - SNDRV_PCM_FMTBIT_S32_LE, + SNDRV_PCM_FMTBIT_U8 | SNDRV_PCM_FMTBIT_S32_LE, .channels_min = 2, .channels_max = 2, .rate_min = 8000, diff --git a/sound/soc/amd/raven/acp3x-pcm-dma.c b/sound/soc/amd/raven/acp3x-pcm-dma.c index 417cda24030c..f22bb2bdf527 100644 --- a/sound/soc/amd/raven/acp3x-pcm-dma.c +++ b/sound/soc/amd/raven/acp3x-pcm-dma.c @@ -24,8 +24,7 @@ static const struct snd_pcm_hardware acp3x_pcm_hardware_playback = { SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_MMAP_VALID | SNDRV_PCM_INFO_PAUSE | SNDRV_PCM_INFO_RESUME, .formats = SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S8 | - SNDRV_PCM_FMTBIT_U8 | SNDRV_PCM_FMTBIT_S24_LE | - SNDRV_PCM_FMTBIT_S32_LE, + SNDRV_PCM_FMTBIT_U8 | SNDRV_PCM_FMTBIT_S32_LE, .channels_min = 2, .channels_max = 8, .rates = SNDRV_PCM_RATE_8000_96000, @@ -45,8 +44,7 @@ static const struct snd_pcm_hardware acp3x_pcm_hardware_capture = { SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_MMAP_VALID | SNDRV_PCM_INFO_PAUSE | SNDRV_PCM_INFO_RESUME, .formats = SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S8 | - SNDRV_PCM_FMTBIT_U8 | SNDRV_PCM_FMTBIT_S24_LE | - SNDRV_PCM_FMTBIT_S32_LE, + SNDRV_PCM_FMTBIT_U8 | SNDRV_PCM_FMTBIT_S32_LE, .channels_min = 2, .channels_max = 2, .rates = SNDRV_PCM_RATE_8000_48000, From 62bad12bceebd7d336ced4e44f408b702c151ba0 Mon Sep 17 00:00:00 2001 From: Sia Jee Heng Date: Wed, 21 Apr 2021 08:55:46 +0800 Subject: [PATCH 548/587] ASoC: Intel: KMB: Fix random noise at the HDMI output Random noise could be heard when playing audio to the HDMI output. This is due to the IEC conversion is invoked in the external loop. As a result, this additional loop takes up a lot of the processing cycle. hdmi_reformat_iec958() process the conversion using an internal loop, it is safe to move it out from the external loop to avoid unnecessary processing cycle been spent. Furthermore, ALSA IEC958 plugin works in 32bit format only. Signed-off-by: Sia Jee Heng Reviewed-by: Pierre-Louis Bossart Link: https://lore.kernel.org/r/20210421005546.7534-1-jee.heng.sia@intel.com Signed-off-by: Mark Brown --- sound/soc/intel/keembay/kmb_platform.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/sound/soc/intel/keembay/kmb_platform.c b/sound/soc/intel/keembay/kmb_platform.c index 0fd1e8f62c89..96741c7c0fba 100644 --- a/sound/soc/intel/keembay/kmb_platform.c +++ b/sound/soc/intel/keembay/kmb_platform.c @@ -105,14 +105,15 @@ static unsigned int kmb_pcm_tx_fn(struct kmb_i2s_info *kmb_i2s, void *buf = runtime->dma_area; int i; + if (kmb_i2s->iec958_fmt) + hdmi_reformat_iec958(runtime, kmb_i2s, tx_ptr); + /* KMB i2s uses two separate L/R FIFO */ for (i = 0; i < kmb_i2s->fifo_th; i++) { if (kmb_i2s->config.data_width == 16) { writel(((u16(*)[2])buf)[tx_ptr][0], i2s_base + LRBR_LTHR(0)); writel(((u16(*)[2])buf)[tx_ptr][1], i2s_base + RRBR_RTHR(0)); } else { - if (kmb_i2s->iec958_fmt) - hdmi_reformat_iec958(runtime, kmb_i2s, tx_ptr); writel(((u32(*)[2])buf)[tx_ptr][0], i2s_base + LRBR_LTHR(0)); writel(((u32(*)[2])buf)[tx_ptr][1], i2s_base + RRBR_RTHR(0)); } From 8859f809c7d5813c28ab90f5335f182e634d77af Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Wed, 21 Apr 2021 14:45:21 +0900 Subject: [PATCH 549/587] ASoC: audio-graph: add graph_parse_node() Parse mclk_fs/dai/tdm/clk are common for both CPU/Codec node. This patch creates graph_parse_node() for it and share the code. Signed-off-by: Kuninori Morimoto Link: https://lore.kernel.org/r/87fszki426.wl-kuninori.morimoto.gx@renesas.com Signed-off-by: Mark Brown --- sound/soc/generic/audio-graph-card.c | 108 ++++++++++++--------------- 1 file changed, 49 insertions(+), 59 deletions(-) diff --git a/sound/soc/generic/audio-graph-card.c b/sound/soc/generic/audio-graph-card.c index 44714a12fcd8..bfaeb208db46 100644 --- a/sound/soc/generic/audio-graph-card.c +++ b/sound/soc/generic/audio-graph-card.c @@ -206,6 +206,47 @@ static void graph_parse_mclk_fs(struct device_node *top, of_node_put(ports); } +static int graph_parse_node(struct asoc_simple_priv *priv, + struct device_node *ep, + struct link_info *li, + int is_cpu) +{ + struct device *dev = simple_priv_to_dev(priv); + struct device_node *top = dev->of_node; + struct snd_soc_dai_link *dai_link = simple_priv_to_link(priv, li->link); + struct simple_dai_props *dai_props = simple_priv_to_props(priv, li->link); + struct snd_soc_dai_link_component *dlc; + struct asoc_simple_dai *dai; + int ret, single = 0; + + if (is_cpu) { + dlc = asoc_link_to_cpu(dai_link, 0); + dai = simple_props_to_dai_cpu(dai_props, 0); + } else { + dlc = asoc_link_to_codec(dai_link, 0); + dai = simple_props_to_dai_codec(dai_props, 0); + } + + graph_parse_mclk_fs(top, ep, dai_props); + + ret = asoc_simple_parse_dai(ep, dlc, &single); + if (ret < 0) + return ret; + + ret = asoc_simple_parse_tdm(ep, dai); + if (ret < 0) + return ret; + + ret = asoc_simple_parse_clk(dev, ep, dai, dlc); + if (ret < 0) + return ret; + + if (is_cpu) + asoc_simple_canonicalize_cpu(dlc, single); + + return 0; +} + static int graph_dai_link_of_dpcm(struct asoc_simple_priv *priv, struct device_node *cpu_ep, struct device_node *codec_ep, @@ -219,39 +260,26 @@ static int graph_dai_link_of_dpcm(struct asoc_simple_priv *priv, struct device_node *ep = li->cpu ? cpu_ep : codec_ep; struct device_node *port; struct device_node *ports; - struct device_node *node; - struct asoc_simple_dai *dai; struct snd_soc_dai_link_component *cpus = asoc_link_to_cpu(dai_link, 0); struct snd_soc_dai_link_component *codecs = asoc_link_to_codec(dai_link, 0); int ret; port = of_get_parent(ep); ports = of_get_parent(port); - node = of_graph_get_port_parent(ep); - - li->link++; dev_dbg(dev, "link_of DPCM (%pOF)\n", ep); if (li->cpu) { - int is_single_links = 0; - /* Codec is dummy */ /* FE settings */ dai_link->dynamic = 1; dai_link->dpcm_merged_format = 1; - dai = simple_props_to_dai_cpu(dai_props, 0); - - ret = asoc_simple_parse_dai(ep, cpus, &is_single_links); + ret = graph_parse_node(priv, cpu_ep, li, 1); if (ret) goto out_put_node; - ret = asoc_simple_parse_clk(dev, ep, dai, cpus); - if (ret < 0) - goto out_put_node; - ret = asoc_simple_set_dailink_name(dev, dai_link, "fe.%pOFP.%s", cpus->of_node, @@ -271,9 +299,6 @@ static int graph_dai_link_of_dpcm(struct asoc_simple_priv *priv, */ if (card->component_chaining && !soc_component_is_pcm(cpus)) dai_link->no_pcm = 1; - - /* card->num_links includes Codec */ - asoc_simple_canonicalize_cpu(cpus, is_single_links); } else { struct snd_soc_codec_conf *cconf; @@ -283,14 +308,9 @@ static int graph_dai_link_of_dpcm(struct asoc_simple_priv *priv, dai_link->no_pcm = 1; dai_link->be_hw_params_fixup = asoc_simple_be_hw_params_fixup; - dai = simple_props_to_dai_codec(dai_props, 0); cconf = simple_props_to_codec_conf(dai_props, 0); - ret = asoc_simple_parse_dai(ep, codecs, NULL); - if (ret < 0) - goto out_put_node; - - ret = asoc_simple_parse_clk(dev, ep, dai, codecs); + ret = graph_parse_node(priv, codec_ep, li, 0); if (ret < 0) goto out_put_node; @@ -311,11 +331,6 @@ static int graph_dai_link_of_dpcm(struct asoc_simple_priv *priv, } graph_parse_convert(dev, ep, &dai_props->adata); - graph_parse_mclk_fs(top, ep, dai_props); - - ret = asoc_simple_parse_tdm(ep, dai); - if (ret) - goto out_put_node; ret = asoc_simple_parse_daifmt(dev, cpu_ep, codec_ep, NULL, &dai_link->dai_fmt); @@ -333,9 +348,10 @@ static int graph_dai_link_of_dpcm(struct asoc_simple_priv *priv, dai_link->init = asoc_simple_dai_init; out_put_node: + li->link++; + of_node_put(ports); of_node_put(port); - of_node_put(node); return ret; } @@ -346,48 +362,22 @@ static int graph_dai_link_of(struct asoc_simple_priv *priv, { struct device *dev = simple_priv_to_dev(priv); struct snd_soc_dai_link *dai_link = simple_priv_to_link(priv, li->link); - struct simple_dai_props *dai_props = simple_priv_to_props(priv, li->link); - struct device_node *top = dev->of_node; - struct asoc_simple_dai *cpu_dai = simple_props_to_dai_cpu(dai_props, 0); - struct asoc_simple_dai *codec_dai = simple_props_to_dai_codec(dai_props, 0); struct snd_soc_dai_link_component *cpus = asoc_link_to_cpu(dai_link, 0); struct snd_soc_dai_link_component *codecs = asoc_link_to_codec(dai_link, 0); - int ret, single_cpu = 0; + int ret; dev_dbg(dev, "link_of (%pOF)\n", cpu_ep); - li->link++; - - /* Factor to mclk, used in hw_params() */ - graph_parse_mclk_fs(top, cpu_ep, dai_props); - graph_parse_mclk_fs(top, codec_ep, dai_props); - ret = asoc_simple_parse_daifmt(dev, cpu_ep, codec_ep, NULL, &dai_link->dai_fmt); if (ret < 0) return ret; - ret = asoc_simple_parse_dai(cpu_ep, cpus, &single_cpu); + ret = graph_parse_node(priv, cpu_ep, li, 1); if (ret < 0) return ret; - ret = asoc_simple_parse_dai(codec_ep, codecs, NULL); - if (ret < 0) - return ret; - - ret = asoc_simple_parse_tdm(cpu_ep, cpu_dai); - if (ret < 0) - return ret; - - ret = asoc_simple_parse_tdm(codec_ep, codec_dai); - if (ret < 0) - return ret; - - ret = asoc_simple_parse_clk(dev, cpu_ep, cpu_dai, cpus); - if (ret < 0) - return ret; - - ret = asoc_simple_parse_clk(dev, codec_ep, codec_dai, codecs); + ret = graph_parse_node(priv, codec_ep, li, 0); if (ret < 0) return ret; @@ -401,7 +391,7 @@ static int graph_dai_link_of(struct asoc_simple_priv *priv, dai_link->ops = &graph_ops; dai_link->init = asoc_simple_dai_init; - asoc_simple_canonicalize_cpu(cpus, single_cpu); + li->link++; return 0; } From e51237b8d3052251421770468903fa6e4446d158 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Wed, 21 Apr 2021 14:45:43 +0900 Subject: [PATCH 550/587] ASoC: audio-graph: add graph_link_init() This patch adds graph_link_init() and share dai_link setting code. Signed-off-by: Kuninori Morimoto Link: https://lore.kernel.org/r/87eef4i41k.wl-kuninori.morimoto.gx@renesas.com Signed-off-by: Mark Brown --- sound/soc/generic/audio-graph-card.c | 70 +++++++++++++--------------- 1 file changed, 33 insertions(+), 37 deletions(-) diff --git a/sound/soc/generic/audio-graph-card.c b/sound/soc/generic/audio-graph-card.c index bfaeb208db46..2c8a2fcb7922 100644 --- a/sound/soc/generic/audio-graph-card.c +++ b/sound/soc/generic/audio-graph-card.c @@ -247,6 +247,29 @@ static int graph_parse_node(struct asoc_simple_priv *priv, return 0; } +static int graph_link_init(struct asoc_simple_priv *priv, + struct device_node *cpu_ep, + struct device_node *codec_ep, + struct link_info *li, + char *name) +{ + struct device *dev = simple_priv_to_dev(priv); + struct snd_soc_dai_link *dai_link = simple_priv_to_link(priv, li->link); + int ret; + + ret = asoc_simple_parse_daifmt(dev, cpu_ep, codec_ep, + NULL, &dai_link->dai_fmt); + if (ret < 0) + return ret; + + dai_link->init = asoc_simple_dai_init; + dai_link->ops = &graph_ops; + if (priv->ops) + dai_link->ops = priv->ops; + + return asoc_simple_set_dailink_name(dev, dai_link, name); +} + static int graph_dai_link_of_dpcm(struct asoc_simple_priv *priv, struct device_node *cpu_ep, struct device_node *codec_ep, @@ -262,6 +285,7 @@ static int graph_dai_link_of_dpcm(struct asoc_simple_priv *priv, struct device_node *ports; struct snd_soc_dai_link_component *cpus = asoc_link_to_cpu(dai_link, 0); struct snd_soc_dai_link_component *codecs = asoc_link_to_codec(dai_link, 0); + char dai_name[64]; int ret; port = of_get_parent(ep); @@ -280,13 +304,8 @@ static int graph_dai_link_of_dpcm(struct asoc_simple_priv *priv, if (ret) goto out_put_node; - ret = asoc_simple_set_dailink_name(dev, dai_link, - "fe.%pOFP.%s", - cpus->of_node, - cpus->dai_name); - if (ret < 0) - goto out_put_node; - + snprintf(dai_name, sizeof(dai_name), + "fe.%pOFP.%s", cpus->of_node, cpus->dai_name); /* * In BE<->BE connections it is not required to create * PCM devices at CPU end of the dai link and thus 'no_pcm' @@ -314,12 +333,8 @@ static int graph_dai_link_of_dpcm(struct asoc_simple_priv *priv, if (ret < 0) goto out_put_node; - ret = asoc_simple_set_dailink_name(dev, dai_link, - "be.%pOFP.%s", - codecs->of_node, - codecs->dai_name); - if (ret < 0) - goto out_put_node; + snprintf(dai_name, sizeof(dai_name), + "be.%pOFP.%s", codecs->of_node, codecs->dai_name); /* check "prefix" from top node */ snd_soc_of_parse_node_prefix(top, cconf, codecs->of_node, @@ -332,20 +347,9 @@ static int graph_dai_link_of_dpcm(struct asoc_simple_priv *priv, graph_parse_convert(dev, ep, &dai_props->adata); - ret = asoc_simple_parse_daifmt(dev, cpu_ep, codec_ep, - NULL, &dai_link->dai_fmt); - if (ret < 0) - goto out_put_node; - snd_soc_dai_link_set_capabilities(dai_link); - dai_link->ops = &graph_ops; - - /* Use custom snd_soc_ops callbacks if available */ - if (priv->ops) - dai_link->ops = priv->ops; - - dai_link->init = asoc_simple_dai_init; + ret = graph_link_init(priv, cpu_ep, codec_ep, li, dai_name); out_put_node: li->link++; @@ -364,15 +368,11 @@ static int graph_dai_link_of(struct asoc_simple_priv *priv, struct snd_soc_dai_link *dai_link = simple_priv_to_link(priv, li->link); struct snd_soc_dai_link_component *cpus = asoc_link_to_cpu(dai_link, 0); struct snd_soc_dai_link_component *codecs = asoc_link_to_codec(dai_link, 0); + char dai_name[64]; int ret; dev_dbg(dev, "link_of (%pOF)\n", cpu_ep); - ret = asoc_simple_parse_daifmt(dev, cpu_ep, codec_ep, - NULL, &dai_link->dai_fmt); - if (ret < 0) - return ret; - ret = graph_parse_node(priv, cpu_ep, li, 1); if (ret < 0) return ret; @@ -381,16 +381,12 @@ static int graph_dai_link_of(struct asoc_simple_priv *priv, if (ret < 0) return ret; - ret = asoc_simple_set_dailink_name(dev, dai_link, - "%s-%s", - cpus->dai_name, - codecs->dai_name); + snprintf(dai_name, sizeof(dai_name), + "%s-%s", cpus->dai_name, codecs->dai_name); + ret = graph_link_init(priv, cpu_ep, codec_ep, li, dai_name); if (ret < 0) return ret; - dai_link->ops = &graph_ops; - dai_link->init = asoc_simple_dai_init; - li->link++; return 0; From 59c35c44a9cf89a83a92a8d26749e59497d0317d Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Wed, 21 Apr 2021 14:45:48 +0900 Subject: [PATCH 551/587] ASoC: simple-card: add simple_parse_node() Parse dai/tdm/clk are common for both CPU/Codec node. This patch creates simple_parse_node() for it and share the code. Signed-off-by: Kuninori Morimoto Link: https://lore.kernel.org/r/87czuoi41f.wl-kuninori.morimoto.gx@renesas.com Signed-off-by: Mark Brown --- sound/soc/generic/simple-card.c | 119 ++++++++++++++++---------------- 1 file changed, 58 insertions(+), 61 deletions(-) diff --git a/sound/soc/generic/simple-card.c b/sound/soc/generic/simple-card.c index a1373be4558f..91af4eca9c86 100644 --- a/sound/soc/generic/simple-card.c +++ b/sound/soc/generic/simple-card.c @@ -93,12 +93,11 @@ static void simple_parse_convert(struct device *dev, } static void simple_parse_mclk_fs(struct device_node *top, - struct device_node *cpu, - struct device_node *codec, + struct device_node *np, struct simple_dai_props *props, char *prefix) { - struct device_node *node = of_get_parent(cpu); + struct device_node *node = of_get_parent(np); char prop[128]; snprintf(prop, sizeof(prop), "%smclk-fs", PREFIX); @@ -106,12 +105,57 @@ static void simple_parse_mclk_fs(struct device_node *top, snprintf(prop, sizeof(prop), "%smclk-fs", prefix); of_property_read_u32(node, prop, &props->mclk_fs); - of_property_read_u32(cpu, prop, &props->mclk_fs); - of_property_read_u32(codec, prop, &props->mclk_fs); + of_property_read_u32(np, prop, &props->mclk_fs); of_node_put(node); } +static int simple_parse_node(struct asoc_simple_priv *priv, + struct device_node *np, + struct link_info *li, + char *prefix, + int is_cpu) +{ + struct device *dev = simple_priv_to_dev(priv); + struct device_node *top = dev->of_node; + struct snd_soc_dai_link *dai_link = simple_priv_to_link(priv, li->link); + struct simple_dai_props *dai_props = simple_priv_to_props(priv, li->link); + struct snd_soc_dai_link_component *dlc; + struct asoc_simple_dai *dai; + int ret, single = 0; + + if (is_cpu) { + dlc = asoc_link_to_cpu(dai_link, 0); + dai = simple_props_to_dai_cpu(dai_props, 0); + } else { + dlc = asoc_link_to_codec(dai_link, 0); + dai = simple_props_to_dai_codec(dai_props, 0); + } + + simple_parse_mclk_fs(top, np, dai_props, prefix); + + ret = asoc_simple_parse_dai(np, dlc, &single); + if (ret) + return ret; + + ret = asoc_simple_parse_clk(dev, np, dai, dlc); + if (ret) + return ret; + + ret = asoc_simple_parse_tdm(np, dai); + if (ret) + return ret; + + if (is_cpu) { + struct snd_soc_dai_link_component *platforms = asoc_link_to_platform(dai_link, 0); + + asoc_simple_canonicalize_cpu(dlc, single); + asoc_simple_canonicalize_platform(platforms, dlc); + } + + return 0; +} + static int simple_dai_link_of_dpcm(struct asoc_simple_priv *priv, struct device_node *np, struct device_node *codec, @@ -121,10 +165,8 @@ static int simple_dai_link_of_dpcm(struct asoc_simple_priv *priv, struct device *dev = simple_priv_to_dev(priv); struct snd_soc_dai_link *dai_link = simple_priv_to_link(priv, li->link); struct simple_dai_props *dai_props = simple_priv_to_props(priv, li->link); - struct asoc_simple_dai *dai; struct snd_soc_dai_link_component *cpus = asoc_link_to_cpu(dai_link, 0); struct snd_soc_dai_link_component *codecs = asoc_link_to_codec(dai_link, 0); - struct snd_soc_dai_link_component *platforms = asoc_link_to_platform(dai_link, 0); struct device_node *top = dev->of_node; struct device_node *node = of_get_parent(np); char *prefix = ""; @@ -132,28 +174,18 @@ static int simple_dai_link_of_dpcm(struct asoc_simple_priv *priv, dev_dbg(dev, "link_of DPCM (%pOF)\n", np); - li->link++; - /* For single DAI link & old style of DT node */ if (is_top) prefix = PREFIX; if (li->cpu) { - int is_single_links = 0; - /* Codec is dummy */ /* FE settings */ dai_link->dynamic = 1; dai_link->dpcm_merged_format = 1; - dai = simple_props_to_dai_cpu(dai_props, 0); - - ret = asoc_simple_parse_dai(np, cpus, &is_single_links); - if (ret) - goto out_put_node; - - ret = asoc_simple_parse_clk(dev, np, dai, cpus); + ret = simple_parse_node(priv, np, li, prefix, 1); if (ret < 0) goto out_put_node; @@ -162,9 +194,6 @@ static int simple_dai_link_of_dpcm(struct asoc_simple_priv *priv, cpus->dai_name); if (ret < 0) goto out_put_node; - - asoc_simple_canonicalize_cpu(cpus, is_single_links); - asoc_simple_canonicalize_platform(platforms, cpus); } else { struct snd_soc_codec_conf *cconf; @@ -174,14 +203,9 @@ static int simple_dai_link_of_dpcm(struct asoc_simple_priv *priv, dai_link->no_pcm = 1; dai_link->be_hw_params_fixup = asoc_simple_be_hw_params_fixup; - dai = simple_props_to_dai_codec(dai_props, 0); cconf = simple_props_to_codec_conf(dai_props, 0); - ret = asoc_simple_parse_dai(np, codecs, NULL); - if (ret < 0) - goto out_put_node; - - ret = asoc_simple_parse_clk(dev, np, dai, codecs); + ret = simple_parse_node(priv, np, li, prefix, 0); if (ret < 0) goto out_put_node; @@ -201,11 +225,6 @@ static int simple_dai_link_of_dpcm(struct asoc_simple_priv *priv, } simple_parse_convert(dev, np, &dai_props->adata); - simple_parse_mclk_fs(top, np, codec, dai_props, prefix); - - ret = asoc_simple_parse_tdm(np, dai); - if (ret) - goto out_put_node; ret = asoc_simple_parse_daifmt(dev, node, codec, prefix, &dai_link->dai_fmt); @@ -218,6 +237,8 @@ static int simple_dai_link_of_dpcm(struct asoc_simple_priv *priv, dai_link->init = asoc_simple_dai_init; out_put_node: + li->link++; + of_node_put(node); return ret; } @@ -230,23 +251,18 @@ static int simple_dai_link_of(struct asoc_simple_priv *priv, { struct device *dev = simple_priv_to_dev(priv); struct snd_soc_dai_link *dai_link = simple_priv_to_link(priv, li->link); - struct simple_dai_props *dai_props = simple_priv_to_props(priv, li->link); - struct asoc_simple_dai *cpu_dai = simple_props_to_dai_cpu(dai_props, 0); - struct asoc_simple_dai *codec_dai = simple_props_to_dai_codec(dai_props, 0); struct snd_soc_dai_link_component *cpus = asoc_link_to_cpu(dai_link, 0); struct snd_soc_dai_link_component *codecs = asoc_link_to_codec(dai_link, 0); struct snd_soc_dai_link_component *platforms = asoc_link_to_platform(dai_link, 0); - struct device_node *top = dev->of_node; struct device_node *cpu = NULL; struct device_node *node = NULL; struct device_node *plat = NULL; char prop[128]; char *prefix = ""; - int ret, single_cpu = 0; + int ret; cpu = np; node = of_get_parent(np); - li->link++; dev_dbg(dev, "link_of (%pOF)\n", node); @@ -262,13 +278,11 @@ static int simple_dai_link_of(struct asoc_simple_priv *priv, if (ret < 0) goto dai_link_of_err; - simple_parse_mclk_fs(top, cpu, codec, dai_props, prefix); - - ret = asoc_simple_parse_dai(cpu, cpus, &single_cpu); + ret = simple_parse_node(priv, cpu, li, prefix, 1); if (ret < 0) goto dai_link_of_err; - ret = asoc_simple_parse_dai(codec, codecs, NULL); + ret = simple_parse_node(priv, codec, li, prefix, 0); if (ret < 0) goto dai_link_of_err; @@ -276,22 +290,6 @@ static int simple_dai_link_of(struct asoc_simple_priv *priv, if (ret < 0) goto dai_link_of_err; - ret = asoc_simple_parse_tdm(cpu, cpu_dai); - if (ret < 0) - goto dai_link_of_err; - - ret = asoc_simple_parse_tdm(codec, codec_dai); - if (ret < 0) - goto dai_link_of_err; - - ret = asoc_simple_parse_clk(dev, cpu, cpu_dai, cpus); - if (ret < 0) - goto dai_link_of_err; - - ret = asoc_simple_parse_clk(dev, codec, codec_dai, codecs); - if (ret < 0) - goto dai_link_of_err; - ret = asoc_simple_set_dailink_name(dev, dai_link, "%s-%s", cpus->dai_name, @@ -302,13 +300,12 @@ static int simple_dai_link_of(struct asoc_simple_priv *priv, dai_link->ops = &simple_ops; dai_link->init = asoc_simple_dai_init; - asoc_simple_canonicalize_cpu(cpus, single_cpu); - asoc_simple_canonicalize_platform(platforms, cpus); - dai_link_of_err: of_node_put(plat); of_node_put(node); + li->link++; + return ret; } From 434392271afcff350fe11730f12b831fffaf33eb Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Wed, 21 Apr 2021 14:45:52 +0900 Subject: [PATCH 552/587] ASoC: simple-card: add simple_link_init() This patch adds simple_link_init() and share dai_link setting code. Signed-off-by: Kuninori Morimoto Link: https://lore.kernel.org/r/87bla8i41b.wl-kuninori.morimoto.gx@renesas.com Signed-off-by: Mark Brown --- sound/soc/generic/simple-card.c | 59 +++++++++++++++++---------------- 1 file changed, 30 insertions(+), 29 deletions(-) diff --git a/sound/soc/generic/simple-card.c b/sound/soc/generic/simple-card.c index 91af4eca9c86..6a04632944b8 100644 --- a/sound/soc/generic/simple-card.c +++ b/sound/soc/generic/simple-card.c @@ -156,6 +156,28 @@ static int simple_parse_node(struct asoc_simple_priv *priv, return 0; } +static int simple_link_init(struct asoc_simple_priv *priv, + struct device_node *node, + struct device_node *codec, + struct link_info *li, + char *prefix, + char *name) +{ + struct device *dev = simple_priv_to_dev(priv); + struct snd_soc_dai_link *dai_link = simple_priv_to_link(priv, li->link); + int ret; + + ret = asoc_simple_parse_daifmt(dev, node, codec, + prefix, &dai_link->dai_fmt); + if (ret < 0) + return 0; + + dai_link->init = asoc_simple_dai_init; + dai_link->ops = &simple_ops; + + return asoc_simple_set_dailink_name(dev, dai_link, name); +} + static int simple_dai_link_of_dpcm(struct asoc_simple_priv *priv, struct device_node *np, struct device_node *codec, @@ -170,6 +192,7 @@ static int simple_dai_link_of_dpcm(struct asoc_simple_priv *priv, struct device_node *top = dev->of_node; struct device_node *node = of_get_parent(np); char *prefix = ""; + char dai_name[64]; int ret; dev_dbg(dev, "link_of DPCM (%pOF)\n", np); @@ -189,11 +212,7 @@ static int simple_dai_link_of_dpcm(struct asoc_simple_priv *priv, if (ret < 0) goto out_put_node; - ret = asoc_simple_set_dailink_name(dev, dai_link, - "fe.%s", - cpus->dai_name); - if (ret < 0) - goto out_put_node; + snprintf(dai_name, sizeof(dai_name), "fe.%s", cpus->dai_name); } else { struct snd_soc_codec_conf *cconf; @@ -209,11 +228,7 @@ static int simple_dai_link_of_dpcm(struct asoc_simple_priv *priv, if (ret < 0) goto out_put_node; - ret = asoc_simple_set_dailink_name(dev, dai_link, - "be.%s", - codecs->dai_name); - if (ret < 0) - goto out_put_node; + snprintf(dai_name, sizeof(dai_name), "be.%s", codecs->dai_name); /* check "prefix" from top node */ snd_soc_of_parse_node_prefix(top, cconf, codecs->of_node, @@ -226,15 +241,9 @@ static int simple_dai_link_of_dpcm(struct asoc_simple_priv *priv, simple_parse_convert(dev, np, &dai_props->adata); - ret = asoc_simple_parse_daifmt(dev, node, codec, - prefix, &dai_link->dai_fmt); - if (ret < 0) - goto out_put_node; - snd_soc_dai_link_set_capabilities(dai_link); - dai_link->ops = &simple_ops; - dai_link->init = asoc_simple_dai_init; + ret = simple_link_init(priv, node, codec, li, prefix, dai_name); out_put_node: li->link++; @@ -257,6 +266,7 @@ static int simple_dai_link_of(struct asoc_simple_priv *priv, struct device_node *cpu = NULL; struct device_node *node = NULL; struct device_node *plat = NULL; + char dai_name[64]; char prop[128]; char *prefix = ""; int ret; @@ -273,11 +283,6 @@ static int simple_dai_link_of(struct asoc_simple_priv *priv, snprintf(prop, sizeof(prop), "%splat", prefix); plat = of_get_child_by_name(node, prop); - ret = asoc_simple_parse_daifmt(dev, node, codec, - prefix, &dai_link->dai_fmt); - if (ret < 0) - goto dai_link_of_err; - ret = simple_parse_node(priv, cpu, li, prefix, 1); if (ret < 0) goto dai_link_of_err; @@ -290,16 +295,12 @@ static int simple_dai_link_of(struct asoc_simple_priv *priv, if (ret < 0) goto dai_link_of_err; - ret = asoc_simple_set_dailink_name(dev, dai_link, - "%s-%s", - cpus->dai_name, - codecs->dai_name); + snprintf(dai_name, sizeof(dai_name), + "%s-%s", cpus->dai_name, codecs->dai_name); + ret = simple_link_init(priv, node, codec, li, prefix, dai_name); if (ret < 0) goto dai_link_of_err; - dai_link->ops = &simple_ops; - dai_link->init = asoc_simple_dai_init; - dai_link_of_err: of_node_put(plat); of_node_put(node); From 73371bacf0475a20ab6f3e7b6310e378ec5b3023 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Wed, 21 Apr 2021 14:45:56 +0900 Subject: [PATCH 553/587] ASoC: audio-graph: tidyup graph_dai_link_of_dpcm() Use local variable at local area only. Signed-off-by: Kuninori Morimoto Link: https://lore.kernel.org/r/87a6psi417.wl-kuninori.morimoto.gx@renesas.com Signed-off-by: Mark Brown --- sound/soc/generic/audio-graph-card.c | 30 +++++++++++++--------------- 1 file changed, 14 insertions(+), 16 deletions(-) diff --git a/sound/soc/generic/audio-graph-card.c b/sound/soc/generic/audio-graph-card.c index 2c8a2fcb7922..0159a4576e9c 100644 --- a/sound/soc/generic/audio-graph-card.c +++ b/sound/soc/generic/audio-graph-card.c @@ -276,24 +276,19 @@ static int graph_dai_link_of_dpcm(struct asoc_simple_priv *priv, struct link_info *li) { struct device *dev = simple_priv_to_dev(priv); - struct snd_soc_card *card = simple_priv_to_card(priv); struct snd_soc_dai_link *dai_link = simple_priv_to_link(priv, li->link); struct simple_dai_props *dai_props = simple_priv_to_props(priv, li->link); struct device_node *top = dev->of_node; struct device_node *ep = li->cpu ? cpu_ep : codec_ep; - struct device_node *port; - struct device_node *ports; - struct snd_soc_dai_link_component *cpus = asoc_link_to_cpu(dai_link, 0); - struct snd_soc_dai_link_component *codecs = asoc_link_to_codec(dai_link, 0); char dai_name[64]; int ret; - port = of_get_parent(ep); - ports = of_get_parent(port); - dev_dbg(dev, "link_of DPCM (%pOF)\n", ep); if (li->cpu) { + struct snd_soc_card *card = simple_priv_to_card(priv); + struct snd_soc_dai_link_component *cpus = asoc_link_to_cpu(dai_link, 0); + /* Codec is dummy */ /* FE settings */ @@ -302,7 +297,7 @@ static int graph_dai_link_of_dpcm(struct asoc_simple_priv *priv, ret = graph_parse_node(priv, cpu_ep, li, 1); if (ret) - goto out_put_node; + return ret; snprintf(dai_name, sizeof(dai_name), "fe.%pOFP.%s", cpus->of_node, cpus->dai_name); @@ -319,7 +314,10 @@ static int graph_dai_link_of_dpcm(struct asoc_simple_priv *priv, if (card->component_chaining && !soc_component_is_pcm(cpus)) dai_link->no_pcm = 1; } else { - struct snd_soc_codec_conf *cconf; + struct snd_soc_codec_conf *cconf = simple_props_to_codec_conf(dai_props, 0); + struct snd_soc_dai_link_component *codecs = asoc_link_to_codec(dai_link, 0); + struct device_node *port; + struct device_node *ports; /* CPU is dummy */ @@ -327,22 +325,25 @@ static int graph_dai_link_of_dpcm(struct asoc_simple_priv *priv, dai_link->no_pcm = 1; dai_link->be_hw_params_fixup = asoc_simple_be_hw_params_fixup; - cconf = simple_props_to_codec_conf(dai_props, 0); - ret = graph_parse_node(priv, codec_ep, li, 0); if (ret < 0) - goto out_put_node; + return ret; snprintf(dai_name, sizeof(dai_name), "be.%pOFP.%s", codecs->of_node, codecs->dai_name); /* check "prefix" from top node */ + port = of_get_parent(ep); + ports = of_get_parent(port); snd_soc_of_parse_node_prefix(top, cconf, codecs->of_node, "prefix"); if (of_node_name_eq(ports, "ports")) snd_soc_of_parse_node_prefix(ports, cconf, codecs->of_node, "prefix"); snd_soc_of_parse_node_prefix(port, cconf, codecs->of_node, "prefix"); + + of_node_put(ports); + of_node_put(port); } graph_parse_convert(dev, ep, &dai_props->adata); @@ -351,11 +352,8 @@ static int graph_dai_link_of_dpcm(struct asoc_simple_priv *priv, ret = graph_link_init(priv, cpu_ep, codec_ep, li, dai_name); -out_put_node: li->link++; - of_node_put(ports); - of_node_put(port); return ret; } From a89f3a93cd20f77ac1f84089297258d4b409e280 Mon Sep 17 00:00:00 2001 From: Niklas Carlsson Date: Thu, 22 Apr 2021 15:02:26 +0200 Subject: [PATCH 554/587] ASoC: adau17x1: Avoid overwriting CHPF Configuring number of channels per LRCLK frame by using e.g. snd_soc_dai_set_tdm_slot before configuring DAI format was being overwritten by the latter due to a regmap_write which would write over the whole register. Signed-off-by: Niklas Carlsson Link: https://lore.kernel.org/r/20210422130226.15201-1-Niklas.Carlsson@axis.com Signed-off-by: Mark Brown --- sound/soc/codecs/adau17x1.c | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/sound/soc/codecs/adau17x1.c b/sound/soc/codecs/adau17x1.c index 546ee8178038..8aae7ab74091 100644 --- a/sound/soc/codecs/adau17x1.c +++ b/sound/soc/codecs/adau17x1.c @@ -553,6 +553,7 @@ static int adau17x1_set_dai_fmt(struct snd_soc_dai *dai, { struct adau *adau = snd_soc_component_get_drvdata(dai->component); unsigned int ctrl0, ctrl1; + unsigned int ctrl0_mask; int lrclk_pol; switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) { @@ -612,8 +613,16 @@ static int adau17x1_set_dai_fmt(struct snd_soc_dai *dai, if (lrclk_pol) ctrl0 |= ADAU17X1_SERIAL_PORT0_LRCLK_POL; - regmap_write(adau->regmap, ADAU17X1_SERIAL_PORT0, ctrl0); - regmap_write(adau->regmap, ADAU17X1_SERIAL_PORT1, ctrl1); + /* Set the mask to update all relevant bits in ADAU17X1_SERIAL_PORT0 */ + ctrl0_mask = ADAU17X1_SERIAL_PORT0_MASTER | + ADAU17X1_SERIAL_PORT0_LRCLK_POL | + ADAU17X1_SERIAL_PORT0_BCLK_POL | + ADAU17X1_SERIAL_PORT0_PULSE_MODE; + + regmap_update_bits(adau->regmap, ADAU17X1_SERIAL_PORT0, ctrl0_mask, + ctrl0); + regmap_update_bits(adau->regmap, ADAU17X1_SERIAL_PORT1, + ADAU17X1_SERIAL_PORT1_DELAY_MASK, ctrl1); adau->dai_fmt = fmt & SND_SOC_DAIFMT_FORMAT_MASK; From ccd4cc3ed0692aef8a3b4566391c37eb168d8d32 Mon Sep 17 00:00:00 2001 From: Arnd Bergmann Date: Thu, 22 Apr 2021 15:34:00 +0200 Subject: [PATCH 555/587] ASoC: tegra: mark runtime-pm functions as __maybe_unused A reorganization of the driver source led to two of them causing a compile time warning in some configurations: tegra/tegra20_spdif.c:36:12: error: 'tegra20_spdif_runtime_resume' defined but not used [-Werror=unused-function] 36 | static int tegra20_spdif_runtime_resume(struct device *dev) | ^~~~~~~~~~~~~~~~~~~~~~~~~~~~ tegra/tegra20_spdif.c:27:12: error: 'tegra20_spdif_runtime_suspend' defined but not used [-Werror=unused-function] 27 | static int tegra20_spdif_runtime_suspend(struct device *dev) | ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~ tegra/tegra30_ahub.c:64:12: error: 'tegra30_ahub_runtime_resume' defined but not used [-Werror=unused-function] 64 | static int tegra30_ahub_runtime_resume(struct device *dev) | ^~~~~~~~~~~~~~~~~~~~~~~~~~~ tegra/tegra30_ahub.c:43:12: error: 'tegra30_ahub_runtime_suspend' defined but not used [-Werror=unused-function] 43 | static int tegra30_ahub_runtime_suspend(struct device *dev) | ^~~~~~~~~~~~~~~~~~~~~~~~~~~~ Mark these functions as __maybe_unused to avoid this kind of warning. Fixes: b5571449e618 ("ASoC: tegra30: ahub: Remove handing of disabled runtime PM") Fixes: c53b396f0dd4 ("ASoC: tegra20: spdif: Remove handing of disabled runtime PM") Fixes: 80ec4a4cb36d ("ASoC: tegra20: i2s: Remove handing of disabled runtime PM") Fixes: b5f6f781fcb2 ("ASoC: tegra30: i2s: Remove handing of disabled runtime PM") Signed-off-by: Arnd Bergmann Link: https://lore.kernel.org/r/20210422133418.1757893-1-arnd@kernel.org Signed-off-by: Mark Brown --- sound/soc/tegra/tegra20_i2s.c | 4 ++-- sound/soc/tegra/tegra20_spdif.c | 4 ++-- sound/soc/tegra/tegra30_ahub.c | 4 ++-- sound/soc/tegra/tegra30_i2s.c | 4 ++-- 4 files changed, 8 insertions(+), 8 deletions(-) diff --git a/sound/soc/tegra/tegra20_i2s.c b/sound/soc/tegra/tegra20_i2s.c index 1b27f81c10fe..b280ebd72591 100644 --- a/sound/soc/tegra/tegra20_i2s.c +++ b/sound/soc/tegra/tegra20_i2s.c @@ -34,7 +34,7 @@ #define DRV_NAME "tegra20-i2s" -static int tegra20_i2s_runtime_suspend(struct device *dev) +static __maybe_unused int tegra20_i2s_runtime_suspend(struct device *dev) { struct tegra20_i2s *i2s = dev_get_drvdata(dev); @@ -45,7 +45,7 @@ static int tegra20_i2s_runtime_suspend(struct device *dev) return 0; } -static int tegra20_i2s_runtime_resume(struct device *dev) +static __maybe_unused int tegra20_i2s_runtime_resume(struct device *dev) { struct tegra20_i2s *i2s = dev_get_drvdata(dev); int ret; diff --git a/sound/soc/tegra/tegra20_spdif.c b/sound/soc/tegra/tegra20_spdif.c index 7b597ee63cb5..de698ff2a69c 100644 --- a/sound/soc/tegra/tegra20_spdif.c +++ b/sound/soc/tegra/tegra20_spdif.c @@ -24,7 +24,7 @@ #define DRV_NAME "tegra20-spdif" -static int tegra20_spdif_runtime_suspend(struct device *dev) +static __maybe_unused int tegra20_spdif_runtime_suspend(struct device *dev) { struct tegra20_spdif *spdif = dev_get_drvdata(dev); @@ -33,7 +33,7 @@ static int tegra20_spdif_runtime_suspend(struct device *dev) return 0; } -static int tegra20_spdif_runtime_resume(struct device *dev) +static __maybe_unused int tegra20_spdif_runtime_resume(struct device *dev) { struct tegra20_spdif *spdif = dev_get_drvdata(dev); int ret; diff --git a/sound/soc/tegra/tegra30_ahub.c b/sound/soc/tegra/tegra30_ahub.c index d1718f3af3cd..4692c70ed933 100644 --- a/sound/soc/tegra/tegra30_ahub.c +++ b/sound/soc/tegra/tegra30_ahub.c @@ -40,7 +40,7 @@ static inline void tegra30_audio_write(u32 reg, u32 val) regmap_write(ahub->regmap_ahub, reg, val); } -static int tegra30_ahub_runtime_suspend(struct device *dev) +static __maybe_unused int tegra30_ahub_runtime_suspend(struct device *dev) { regcache_cache_only(ahub->regmap_apbif, true); regcache_cache_only(ahub->regmap_ahub, true); @@ -61,7 +61,7 @@ static int tegra30_ahub_runtime_suspend(struct device *dev) * stopping streams should dynamically adjust the clock as required. However, * this is not yet implemented. */ -static int tegra30_ahub_runtime_resume(struct device *dev) +static __maybe_unused int tegra30_ahub_runtime_resume(struct device *dev) { int ret; diff --git a/sound/soc/tegra/tegra30_i2s.c b/sound/soc/tegra/tegra30_i2s.c index 8730ffa0f691..36344f0a64c1 100644 --- a/sound/soc/tegra/tegra30_i2s.c +++ b/sound/soc/tegra/tegra30_i2s.c @@ -36,7 +36,7 @@ #define DRV_NAME "tegra30-i2s" -static int tegra30_i2s_runtime_suspend(struct device *dev) +static __maybe_unused int tegra30_i2s_runtime_suspend(struct device *dev) { struct tegra30_i2s *i2s = dev_get_drvdata(dev); @@ -47,7 +47,7 @@ static int tegra30_i2s_runtime_suspend(struct device *dev) return 0; } -static int tegra30_i2s_runtime_resume(struct device *dev) +static __maybe_unused int tegra30_i2s_runtime_resume(struct device *dev) { struct tegra30_i2s *i2s = dev_get_drvdata(dev); int ret; From 37153cc5303aecd1ac7fc4b4b12bb93f634b4953 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Thu, 22 Apr 2021 14:04:12 +0200 Subject: [PATCH 556/587] Revert "ALSA: usb-audio: Add support for many Roland devices..." This reverts commit d86f43b17ed4 ("ALSA: usb-audio: Add support for many Roland devices' feedback quirks"). It turned out that many quirk entries there don't contain the proper EP values and/or the quirk types, which lead to the broken operations. As we're going to cover all Roland/BOSS devices in a more generic way rather the explicit lists, let's revert the previous additions at first. Fixes: d86f43b17ed4 ("ALSA: usb-audio: Add support for many Roland devices' implicit feedback quirks") Link: https://lore.kernel.org/r/20210422120413.457-1-tiwai@suse.de Signed-off-by: Takashi Iwai --- sound/usb/implicit.c | 59 -------------------------------------------- 1 file changed, 59 deletions(-) diff --git a/sound/usb/implicit.c b/sound/usb/implicit.c index 77ffcea294dd..94acfaa7f2ef 100644 --- a/sound/usb/implicit.c +++ b/sound/usb/implicit.c @@ -79,72 +79,13 @@ static const struct snd_usb_implicit_fb_match playback_implicit_fb_quirks[] = { /* Implicit feedback quirk table for capture: only FIXED type */ static const struct snd_usb_implicit_fb_match capture_implicit_fb_quirks[] = { - IMPLICIT_FB_FIXED_DEV(0x0582, 0x00a6, 0x0d, 0x01), /* Roland JUNO-G */ - IMPLICIT_FB_FIXED_DEV(0x0582, 0x00a9, 0x0d, 0x01), /* Roland MC-808 */ - IMPLICIT_FB_FIXED_DEV(0x0582, 0x00ad, 0x0d, 0x01), /* Roland SH-201 */ - IMPLICIT_FB_FIXED_DEV(0x0582, 0x00b2, 0x0d, 0x01), /* Roland VG-99 */ - IMPLICIT_FB_FIXED_DEV(0x0582, 0x00b3, 0x0d, 0x01), /* Roland VG-99 */ - IMPLICIT_FB_FIXED_DEV(0x0582, 0x00c2, 0x0d, 0x01), /* Roland SonicCell */ - IMPLICIT_FB_FIXED_DEV(0x0582, 0x00c4, 0x0d, 0x01), /* Edirol M-16DX */ - IMPLICIT_FB_FIXED_DEV(0x0582, 0x00c5, 0x0d, 0x01), /* Roland SP-555 */ - IMPLICIT_FB_FIXED_DEV(0x0582, 0x00c7, 0x0d, 0x01), /* Roland V-Synth GT */ - IMPLICIT_FB_FIXED_DEV(0x0582, 0x00d1, 0x0d, 0x01), /* Roland Music Atelier */ - IMPLICIT_FB_FIXED_DEV(0x0582, 0x00da, 0x0d, 0x01), /* BOSS GT-10 */ - IMPLICIT_FB_FIXED_DEV(0x0582, 0x00db, 0x0d, 0x01), /* BOSS GT-10 Guitar Effects Processor */ - IMPLICIT_FB_FIXED_DEV(0x0582, 0x00dc, 0x0d, 0x01), /* BOSS GT-10B */ - IMPLICIT_FB_FIXED_DEV(0x0582, 0x00de, 0x0d, 0x01), /* Roland Fantom-G */ - IMPLICIT_FB_FIXED_DEV(0x0582, 0x00eb, 0x0d, 0x01), /* Roland VS-100 */ - IMPLICIT_FB_FIXED_DEV(0x0582, 0x00f8, 0x0d, 0x01), /* Roland JUNO Series */ - IMPLICIT_FB_FIXED_DEV(0x0582, 0x00fc, 0x0d, 0x01), /* Roland VS-700C */ - IMPLICIT_FB_FIXED_DEV(0x0582, 0x00fd, 0x0d, 0x01), /* Roland VS-700 */ - IMPLICIT_FB_FIXED_DEV(0x0582, 0x00fe, 0x0d, 0x01), /* Roland VS-700 M1 */ - IMPLICIT_FB_FIXED_DEV(0x0582, 0x00ff, 0x0d, 0x01), /* Roland VS-700 M2 */ - IMPLICIT_FB_FIXED_DEV(0x0582, 0x0100, 0x0d, 0x01), /* Roland VS-700 */ - IMPLICIT_FB_FIXED_DEV(0x0582, 0x0101, 0x0d, 0x01), /* Roland VS-700 M2 */ - IMPLICIT_FB_FIXED_DEV(0x0582, 0x0102, 0x0d, 0x01), /* Roland VB-99 */ - IMPLICIT_FB_BOTH_DEV(0x0582, 0x0109, 0x0d, 0x01), /* BOSS eBand JS-8 */ - IMPLICIT_FB_BOTH_DEV(0x0582, 0x0111, 0x0d, 0x01), /* Roland GAIA SH-01 */ - IMPLICIT_FB_FIXED_DEV(0x0582, 0x0113, 0x0d, 0x01), /* BOSS ME-25 */ - IMPLICIT_FB_FIXED_DEV(0x0582, 0x0114, 0x0d, 0x01), /* Roland SD-50 */ - IMPLICIT_FB_FIXED_DEV(0x0582, 0x0117, 0x0d, 0x01), /* Roland VS-20 */ - IMPLICIT_FB_FIXED_DEV(0x0582, 0x0119, 0x0d, 0x01), /* Roland OCTAPAD SPD-30 */ - IMPLICIT_FB_FIXED_DEV(0x0582, 0x011c, 0x0d, 0x01), /* Roland Lucina AX-09 */ - IMPLICIT_FB_FIXED_DEV(0x0582, 0x011e, 0x0d, 0x01), /* BOSS BR-800 */ - IMPLICIT_FB_FIXED_DEV(0x0582, 0x0120, 0x0d, 0x01), /* Roland OCTA-CAPTURE */ - IMPLICIT_FB_FIXED_DEV(0x0582, 0x0121, 0x0d, 0x01), /* Roland OCTA-CAPTURE */ - IMPLICIT_FB_FIXED_DEV(0x0582, 0x0123, 0x0d, 0x01), /* Roland JUNO-Gi */ - IMPLICIT_FB_FIXED_DEV(0x0582, 0x0124, 0x0d, 0x01), /* Roland M-300 */ - IMPLICIT_FB_BOTH_DEV(0x0582, 0x0127, 0x0d, 0x01), /* Roland GR-55 */ - IMPLICIT_FB_FIXED_DEV(0x0582, 0x012b, 0x0d, 0x01), /* Roland DUO-CAPTURE */ - IMPLICIT_FB_BOTH_DEV(0x0582, 0x012f, 0x0d, 0x01), /* Roland QUAD-CAPTURE */ IMPLICIT_FB_BOTH_DEV(0x0582, 0x0130, 0x0d, 0x01), /* BOSS BR-80 */ - IMPLICIT_FB_FIXED_DEV(0x0582, 0x0132, 0x0d, 0x01), /* Roland TRI-CAPTURE */ - IMPLICIT_FB_FIXED_DEV(0x0582, 0x0134, 0x0d, 0x01), /* Roland V-Mixer */ - IMPLICIT_FB_FIXED_DEV(0x0582, 0x0137, 0x0d, 0x01), /* Roland DUO-CAPTURE Advanced Mode */ - IMPLICIT_FB_BOTH_DEV(0x0582, 0x0138, 0x0d, 0x01), /* BOSS RC-300 */ - IMPLICIT_FB_FIXED_DEV(0x0582, 0x013a, 0x0d, 0x01), /* Roland JUPITER-80 */ - IMPLICIT_FB_BOTH_DEV(0x0582, 0x013e, 0x0d, 0x01), /* Roland R-26 */ - IMPLICIT_FB_FIXED_DEV(0x0582, 0x0145, 0x0d, 0x01), /* Roland SPD-SX */ - IMPLICIT_FB_FIXED_DEV(0x0582, 0x014b, 0x0d, 0x01), /* BOSS eBand JS-10 */ - IMPLICIT_FB_BOTH_DEV(0x0582, 0x014d, 0x0d, 0x01), /* BOSS GT-100 */ - IMPLICIT_FB_FIXED_DEV(0x0582, 0x0150, 0x0d, 0x01), /* Roland TD-15 */ - IMPLICIT_FB_FIXED_DEV(0x0582, 0x0151, 0x0d, 0x01), /* Roland TD-11 */ - IMPLICIT_FB_FIXED_DEV(0x0582, 0x0154, 0x0d, 0x01), /* Roland JUPITER-50 */ - IMPLICIT_FB_FIXED_DEV(0x0582, 0x0158, 0x0d, 0x01), /* Roland TD-30 */ - IMPLICIT_FB_FIXED_DEV(0x0582, 0x0159, 0x0d, 0x01), /* Roland DUO-CAPTURE EX */ - IMPLICIT_FB_BOTH_DEV(0x0582, 0x015b, 0x0d, 0x01), /* Roland INTEGRA-7 */ - IMPLICIT_FB_FIXED_DEV(0x0582, 0x015d, 0x0d, 0x01), /* Roland R-88 */ IMPLICIT_FB_BOTH_DEV(0x0582, 0x0171, 0x0d, 0x01), /* BOSS RC-505 */ - IMPLICIT_FB_FIXED_DEV(0x0582, 0x017a, 0x0d, 0x01), /* Roland VT-3 */ - IMPLICIT_FB_BOTH_DEV(0x0582, 0x017c, 0x0d, 0x01), /* Roland TR-8 */ IMPLICIT_FB_BOTH_DEV(0x0582, 0x0185, 0x0d, 0x01), /* BOSS GP-10 */ IMPLICIT_FB_BOTH_DEV(0x0582, 0x0189, 0x0d, 0x01), /* BOSS GT-100v2 */ - IMPLICIT_FB_BOTH_DEV(0x0582, 0x01b5, 0x0d, 0x01), /* Roland Boutique JP-08 */ IMPLICIT_FB_BOTH_DEV(0x0582, 0x01d6, 0x0d, 0x01), /* BOSS GT-1 */ IMPLICIT_FB_BOTH_DEV(0x0582, 0x01d8, 0x0d, 0x01), /* BOSS Katana */ IMPLICIT_FB_BOTH_DEV(0x0582, 0x01e5, 0x0d, 0x01), /* BOSS GT-001 */ - IMPLICIT_FB_BOTH_DEV(0x0582, 0x01fd, 0x0d, 0x01), /* Roland Boutique SH-01A */ - IMPLICIT_FB_BOTH_DEV(0x0582, 0x01ff, 0x0d, 0x01), /* Roland Boutique D-05 */ IMPLICIT_FB_BOTH_DEV(0x0582, 0x0203, 0x0d, 0x01), /* BOSS AD-10 */ {} /* terminator */ From 316791b556f7c4aeb7a7fea8f400f4434e71d1bf Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Thu, 22 Apr 2021 14:04:13 +0200 Subject: [PATCH 557/587] ALSA: usb-audio: Generic application of implicit fb to Roland/BOSS devices Through the examinations and experiments with lots of Roland and BOSS USB-audio devices, we found out that the recently introduced full-duplex operations with the implicit feedback mode work fine for quite a few devices, while the others need only the capture-side quirk to enforce the full-duplex mode. The recent commit d86f43b17ed4 ("ALSA: usb-audio: Add support for many Roland devices' implicit feedback quirks") tried to add such quirk entries manually in the lists, but this turned out to be too many and error-prone, hence it was reverted again. This patch is another attempt to cover those missing Roland/BOSS devices but in a more generic way. It matches the devices with the vendor ID 0x0582, and checks whether they are with both ASYNC sync types or ASYNC is only for capture device. In the former case, it's the device with the implicit feedback mode, and applies accordingly. In both cases, the capture stream requires always the full-duplex mode, and we apply the known capture quirk for that, too. Basically the already existing BOSS device quirk entries become redundant after this generic matching, so those are removed. Although the capture_implicit_fb_quirks[] table became empty and superfluous, I keep it for now, so that people can put a special device easily at any time later again. Link: https://lore.kernel.org/r/CAOsVg8rA61B=005_VyUwpw3piVwA7Bo5fs1GYEB054efyzGjLw@mail.gmail.com Link: https://lore.kernel.org/r/20210414083255.9527-1-tiwai@suse.de BugLink: https://bugzilla.kernel.org/show_bug.cgi?id=212519 Tested-by: Lucas Endres Link: https://lore.kernel.org/r/20210422120413.457-2-tiwai@suse.de Signed-off-by: Takashi Iwai --- sound/usb/implicit.c | 94 +++++++++++++++++++++++++++++--------------- 1 file changed, 63 insertions(+), 31 deletions(-) diff --git a/sound/usb/implicit.c b/sound/usb/implicit.c index 94acfaa7f2ef..590a0dbba7a2 100644 --- a/sound/usb/implicit.c +++ b/sound/usb/implicit.c @@ -79,15 +79,6 @@ static const struct snd_usb_implicit_fb_match playback_implicit_fb_quirks[] = { /* Implicit feedback quirk table for capture: only FIXED type */ static const struct snd_usb_implicit_fb_match capture_implicit_fb_quirks[] = { - IMPLICIT_FB_BOTH_DEV(0x0582, 0x0130, 0x0d, 0x01), /* BOSS BR-80 */ - IMPLICIT_FB_BOTH_DEV(0x0582, 0x0171, 0x0d, 0x01), /* BOSS RC-505 */ - IMPLICIT_FB_BOTH_DEV(0x0582, 0x0185, 0x0d, 0x01), /* BOSS GP-10 */ - IMPLICIT_FB_BOTH_DEV(0x0582, 0x0189, 0x0d, 0x01), /* BOSS GT-100v2 */ - IMPLICIT_FB_BOTH_DEV(0x0582, 0x01d6, 0x0d, 0x01), /* BOSS GT-1 */ - IMPLICIT_FB_BOTH_DEV(0x0582, 0x01d8, 0x0d, 0x01), /* BOSS Katana */ - IMPLICIT_FB_BOTH_DEV(0x0582, 0x01e5, 0x0d, 0x01), /* BOSS GT-001 */ - IMPLICIT_FB_BOTH_DEV(0x0582, 0x0203, 0x0d, 0x01), /* BOSS AD-10 */ - {} /* terminator */ }; @@ -145,30 +136,70 @@ static int add_generic_uac2_implicit_fb(struct snd_usb_audio *chip, ifnum, alts); } -/* Like the function above, but specific to Roland with vendor class and hack */ -static int add_roland_implicit_fb(struct snd_usb_audio *chip, - struct audioformat *fmt, - unsigned int ifnum, - unsigned int altsetting) +static bool roland_sanity_check_iface(struct usb_host_interface *alts) { - struct usb_host_interface *alts; - struct usb_endpoint_descriptor *epd; - - alts = snd_usb_get_host_interface(chip, ifnum, altsetting); - if (!alts) - return 0; if (alts->desc.bInterfaceClass != USB_CLASS_VENDOR_SPEC || (alts->desc.bInterfaceSubClass != 2 && alts->desc.bInterfaceProtocol != 2) || alts->desc.bNumEndpoints < 1) + return false; + return true; +} + +/* Like the UAC2 case above, but specific to Roland with vendor class and hack */ +static int add_roland_implicit_fb(struct snd_usb_audio *chip, + struct audioformat *fmt, + struct usb_host_interface *alts) +{ + struct usb_endpoint_descriptor *epd; + + if (!roland_sanity_check_iface(alts)) + return 0; + /* only when both streams are with ASYNC type */ + epd = get_endpoint(alts, 0); + if (!usb_endpoint_is_isoc_out(epd) || + (epd->bmAttributes & USB_ENDPOINT_SYNCTYPE) != USB_ENDPOINT_SYNC_ASYNC) + return 0; + + /* check capture EP */ + alts = snd_usb_get_host_interface(chip, + alts->desc.bInterfaceNumber + 1, + alts->desc.bAlternateSetting); + if (!alts || !roland_sanity_check_iface(alts)) return 0; epd = get_endpoint(alts, 0); if (!usb_endpoint_is_isoc_in(epd) || - (epd->bmAttributes & USB_ENDPOINT_USAGE_MASK) != - USB_ENDPOINT_USAGE_IMPLICIT_FB) + (epd->bmAttributes & USB_ENDPOINT_SYNCTYPE) != USB_ENDPOINT_SYNC_ASYNC) + return 0; + chip->playback_first = 1; + return add_implicit_fb_sync_ep(chip, fmt, epd->bEndpointAddress, 0, + alts->desc.bInterfaceNumber, alts); +} + +/* capture quirk for Roland device; always full-duplex */ +static int add_roland_capture_quirk(struct snd_usb_audio *chip, + struct audioformat *fmt, + struct usb_host_interface *alts) +{ + struct usb_endpoint_descriptor *epd; + + if (!roland_sanity_check_iface(alts)) + return 0; + epd = get_endpoint(alts, 0); + if (!usb_endpoint_is_isoc_in(epd) || + (epd->bmAttributes & USB_ENDPOINT_SYNCTYPE) != USB_ENDPOINT_SYNC_ASYNC) + return 0; + + alts = snd_usb_get_host_interface(chip, + alts->desc.bInterfaceNumber - 1, + alts->desc.bAlternateSetting); + if (!alts || !roland_sanity_check_iface(alts)) + return 0; + epd = get_endpoint(alts, 0); + if (!usb_endpoint_is_isoc_out(epd)) return 0; return add_implicit_fb_sync_ep(chip, fmt, epd->bEndpointAddress, 0, - ifnum, alts); + alts->desc.bInterfaceNumber, alts); } /* Playback and capture EPs on Pioneer devices share the same iface/altset @@ -306,14 +337,8 @@ static int audioformat_implicit_fb_quirk(struct snd_usb_audio *chip, } /* Roland/BOSS implicit feedback with vendor spec class */ - if (attr == USB_ENDPOINT_SYNC_ASYNC && - alts->desc.bInterfaceClass == USB_CLASS_VENDOR_SPEC && - alts->desc.bInterfaceProtocol == 2 && - alts->desc.bNumEndpoints == 1 && - USB_ID_VENDOR(chip->usb_id) == 0x0582 /* Roland */) { - if (add_roland_implicit_fb(chip, fmt, - alts->desc.bInterfaceNumber + 1, - alts->desc.bAlternateSetting)) + if (USB_ID_VENDOR(chip->usb_id) == 0x0582) { + if (add_roland_implicit_fb(chip, fmt, alts) > 0) return 1; } @@ -345,6 +370,13 @@ static int audioformat_capture_quirk(struct snd_usb_audio *chip, if (p && (p->type == IMPLICIT_FB_FIXED || p->type == IMPLICIT_FB_BOTH)) return add_implicit_fb_sync_ep(chip, fmt, p->ep_num, 0, p->iface, NULL); + + /* Roland/BOSS need full-duplex streams */ + if (USB_ID_VENDOR(chip->usb_id) == 0x0582) { + if (add_roland_capture_quirk(chip, fmt, alts) > 0) + return 1; + } + if (is_pioneer_implicit_fb(chip, alts)) return 1; /* skip the quirk, also don't handle generic sync EP */ return 0; From 65d1cce726d4912793d0a84c55ecdb0ef5832130 Mon Sep 17 00:00:00 2001 From: Jerome Brunet Date: Wed, 21 Apr 2021 14:05:08 +0200 Subject: [PATCH 558/587] ASoC: stm32: properly get clk from the provider Instead of using the clk embedded in the clk_hw (which is meant to go away), a clock provider which need to interact with its own clock should request clk reference through the clock provider API. Reviewed-by: Stephen Boyd Signed-off-by: Jerome Brunet Link: https://lore.kernel.org/r/20210421120512.413057-2-jbrunet@baylibre.com Signed-off-by: Mark Brown --- sound/soc/stm/stm32_sai_sub.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/sound/soc/stm/stm32_sai_sub.c b/sound/soc/stm/stm32_sai_sub.c index 3aa1cf262402..c1561237ee24 100644 --- a/sound/soc/stm/stm32_sai_sub.c +++ b/sound/soc/stm/stm32_sai_sub.c @@ -484,7 +484,10 @@ static int stm32_sai_add_mclk_provider(struct stm32_sai_sub_data *sai) dev_err(dev, "mclk register returned %d\n", ret); return ret; } - sai->sai_mclk = hw->clk; + + sai->sai_mclk = devm_clk_hw_get_clk(dev, hw, NULL); + if (IS_ERR(sai->sai_mclk)) + return PTR_ERR(sai->sai_mclk); /* register mclk provider */ return devm_of_clk_add_hw_provider(dev, of_clk_hw_simple_get, hw); From 104c3a9ed07411288efcd34f08a577df318aafc0 Mon Sep 17 00:00:00 2001 From: Jerome Brunet Date: Wed, 21 Apr 2021 14:05:09 +0200 Subject: [PATCH 559/587] ASoC: wcd934x: use the clock provider API Clock providers should use the clk_hw API Reviewed-by: Stephen Boyd Signed-off-by: Jerome Brunet Link: https://lore.kernel.org/r/20210421120512.413057-3-jbrunet@baylibre.com Signed-off-by: Mark Brown --- sound/soc/codecs/wcd934x.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/sound/soc/codecs/wcd934x.c b/sound/soc/codecs/wcd934x.c index cddc49bbb7f6..046874ef490e 100644 --- a/sound/soc/codecs/wcd934x.c +++ b/sound/soc/codecs/wcd934x.c @@ -2116,11 +2116,13 @@ static struct clk *wcd934x_register_mclk_output(struct wcd934x_codec *wcd) wcd->hw.init = &init; hw = &wcd->hw; - ret = clk_hw_register(wcd->dev->parent, hw); + ret = devm_clk_hw_register(wcd->dev->parent, hw); if (ret) return ERR_PTR(ret); - of_clk_add_provider(np, of_clk_src_simple_get, hw->clk); + ret = devm_of_clk_add_hw_provider(dev, of_clk_hw_simple_get, hw); + if (ret) + return ERR_PTR(ret); return NULL; } From 8691743c511d6f92d7647d78ea1e5f5ef69937b1 Mon Sep 17 00:00:00 2001 From: Jerome Brunet Date: Wed, 21 Apr 2021 14:05:10 +0200 Subject: [PATCH 560/587] ASoC: rt5682: clock driver must use the clock provider API Clock drivers ops should not call the clk API but the clock provider (clk_hw) instead. Signed-off-by: Jerome Brunet Link: https://lore.kernel.org/r/20210421120512.413057-4-jbrunet@baylibre.com Signed-off-by: Mark Brown --- sound/soc/codecs/rt5682.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/sound/soc/codecs/rt5682.c b/sound/soc/codecs/rt5682.c index a5aacfe01a0d..e4c91571abae 100644 --- a/sound/soc/codecs/rt5682.c +++ b/sound/soc/codecs/rt5682.c @@ -2634,7 +2634,7 @@ static int rt5682_wclk_set_rate(struct clk_hw *hw, unsigned long rate, container_of(hw, struct rt5682_priv, dai_clks_hw[RT5682_DAI_WCLK_IDX]); struct snd_soc_component *component = rt5682->component; - struct clk *parent_clk; + struct clk_hw *parent_hw; const char * const clk_name = clk_hw_get_name(hw); int pre_div; unsigned int clk_pll2_out; @@ -2649,8 +2649,8 @@ static int rt5682_wclk_set_rate(struct clk_hw *hw, unsigned long rate, * * It will set the codec anyway by assuming mclk is 48MHz. */ - parent_clk = clk_get_parent(hw->clk); - if (!parent_clk) + parent_hw = clk_hw_get_parent(hw); + if (!parent_hw) dev_warn(component->dev, "Parent mclk of wclk not acquired in driver. Please ensure mclk was provided as %d Hz.\n", CLK_PLL2_FIN); From 27dc72b44e85997dfd5f3b120e5ec847c43c272a Mon Sep 17 00:00:00 2001 From: Jerome Brunet Date: Wed, 21 Apr 2021 14:05:11 +0200 Subject: [PATCH 561/587] ASoC: lpass: use the clock provider API Clock providers should be registered using the clk_hw API. Signed-off-by: Jerome Brunet Link: https://lore.kernel.org/r/20210421120512.413057-5-jbrunet@baylibre.com Signed-off-by: Mark Brown --- sound/soc/codecs/lpass-va-macro.c | 7 ++----- sound/soc/codecs/lpass-wsa-macro.c | 11 +++-------- 2 files changed, 5 insertions(+), 13 deletions(-) diff --git a/sound/soc/codecs/lpass-va-macro.c b/sound/soc/codecs/lpass-va-macro.c index 5294c57b2cd4..56c93f4465c9 100644 --- a/sound/soc/codecs/lpass-va-macro.c +++ b/sound/soc/codecs/lpass-va-macro.c @@ -1343,7 +1343,7 @@ static int va_macro_register_fsgen_output(struct va_macro *va) if (ret) return ret; - return of_clk_add_provider(np, of_clk_src_simple_get, va->hw.clk); + return devm_of_clk_add_hw_provider(dev, of_clk_hw_simple_get, &va->hw); } static int va_macro_validate_dmic_sample_rate(u32 dmic_sample_rate, @@ -1452,12 +1452,10 @@ static int va_macro_probe(struct platform_device *pdev) va_macro_dais, ARRAY_SIZE(va_macro_dais)); if (ret) - goto soc_err; + goto err; return ret; -soc_err: - of_clk_del_provider(pdev->dev.of_node); err: clk_bulk_disable_unprepare(VA_NUM_CLKS_MAX, va->clks); @@ -1468,7 +1466,6 @@ static int va_macro_remove(struct platform_device *pdev) { struct va_macro *va = dev_get_drvdata(&pdev->dev); - of_clk_del_provider(pdev->dev.of_node); clk_bulk_disable_unprepare(VA_NUM_CLKS_MAX, va->clks); return 0; diff --git a/sound/soc/codecs/lpass-wsa-macro.c b/sound/soc/codecs/lpass-wsa-macro.c index e79a70386b4b..1a7fa5492f28 100644 --- a/sound/soc/codecs/lpass-wsa-macro.c +++ b/sound/soc/codecs/lpass-wsa-macro.c @@ -2337,10 +2337,9 @@ static const struct clk_ops swclk_gate_ops = { .recalc_rate = swclk_recalc_rate, }; -static struct clk *wsa_macro_register_mclk_output(struct wsa_macro *wsa) +static int wsa_macro_register_mclk_output(struct wsa_macro *wsa) { struct device *dev = wsa->dev; - struct device_node *np = dev->of_node; const char *parent_clk_name; const char *clk_name = "mclk"; struct clk_hw *hw; @@ -2358,11 +2357,9 @@ static struct clk *wsa_macro_register_mclk_output(struct wsa_macro *wsa) hw = &wsa->hw; ret = clk_hw_register(wsa->dev, hw); if (ret) - return ERR_PTR(ret); + return ret; - of_clk_add_provider(np, of_clk_src_simple_get, hw->clk); - - return NULL; + return devm_of_clk_add_hw_provider(dev, of_clk_hw_simple_get, hw); } static const struct snd_soc_component_driver wsa_macro_component_drv = { @@ -2438,8 +2435,6 @@ static int wsa_macro_remove(struct platform_device *pdev) { struct wsa_macro *wsa = dev_get_drvdata(&pdev->dev); - of_clk_del_provider(pdev->dev.of_node); - clk_bulk_disable_unprepare(WSA_NUM_CLKS_MAX, wsa->clks); return 0; From 12f8127fe9e6154dd4197df97e44f3fd67583071 Mon Sep 17 00:00:00 2001 From: Jerome Brunet Date: Wed, 21 Apr 2021 14:05:12 +0200 Subject: [PATCH 562/587] ASoC: da7219: properly get clk from the provider Instead of using the clk embedded in the clk_hw (which is meant to go away), a clock provider which need to interact with its own clock should request clk reference through the clock provider API. Reviewed-by: Stephen Boyd Signed-off-by: Jerome Brunet Link: https://lore.kernel.org/r/20210421120512.413057-6-jbrunet@baylibre.com Signed-off-by: Mark Brown --- sound/soc/codecs/da7219.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/sound/soc/codecs/da7219.c b/sound/soc/codecs/da7219.c index 13009d08b09a..bd3c523a8617 100644 --- a/sound/soc/codecs/da7219.c +++ b/sound/soc/codecs/da7219.c @@ -2181,7 +2181,10 @@ static int da7219_register_dai_clks(struct snd_soc_component *component) ret); goto err; } - da7219->dai_clks[i] = dai_clk_hw->clk; + + da7219->dai_clks[i] = devm_clk_hw_get_clk(dev, dai_clk_hw, NULL); + if (IS_ERR(da7219->dai_clks[i])) + return PTR_ERR(da7219->dai_clks[i]); /* For DT setup onecell data, otherwise create lookup */ if (np) { From ca5118c0c00f6bc8b7d0c82c95485159db3a5584 Mon Sep 17 00:00:00 2001 From: Shuming Fan Date: Thu, 22 Apr 2021 18:32:20 +0800 Subject: [PATCH 563/587] ASoC: rt711-sdca: change capture switch controls The DAPM event and mixer control could mute/unmute the capture directly. That will be confused that capture still works if the user settings is unmute before the capture. Therefore, this patch uses the variables to record the capture switch status of DAPM and mixer. Signed-off-by: Shuming Fan Link: https://lore.kernel.org/r/20210422103220.21987-1-shumingf@realtek.com Signed-off-by: Mark Brown --- sound/soc/codecs/rt711-sdca.c | 168 +++++++++++++++++++++++++--------- sound/soc/codecs/rt711-sdca.h | 2 + 2 files changed, 127 insertions(+), 43 deletions(-) diff --git a/sound/soc/codecs/rt711-sdca.c b/sound/soc/codecs/rt711-sdca.c index bfb7f1c8ec8f..39848d2641c3 100644 --- a/sound/soc/codecs/rt711-sdca.c +++ b/sound/soc/codecs/rt711-sdca.c @@ -642,6 +642,114 @@ static int rt711_sdca_set_gain_get(struct snd_kcontrol *kcontrol, return 0; } +static int rt711_sdca_set_fu0f_capture_ctl(struct rt711_sdca_priv *rt711) +{ + int err; + unsigned int ch_l, ch_r; + + ch_l = (rt711->fu0f_dapm_mute || rt711->fu0f_mixer_l_mute) ? 0x01 : 0x00; + ch_r = (rt711->fu0f_dapm_mute || rt711->fu0f_mixer_r_mute) ? 0x01 : 0x00; + + err = regmap_write(rt711->regmap, + SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT711_SDCA_ENT_USER_FU0F, + RT711_SDCA_CTL_FU_MUTE, CH_L), ch_l); + if (err < 0) + return err; + + err = regmap_write(rt711->regmap, + SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT711_SDCA_ENT_USER_FU0F, + RT711_SDCA_CTL_FU_MUTE, CH_R), ch_r); + if (err < 0) + return err; + + return 0; +} + +static int rt711_sdca_set_fu1e_capture_ctl(struct rt711_sdca_priv *rt711) +{ + int err; + unsigned int ch_l, ch_r; + + ch_l = (rt711->fu1e_dapm_mute || rt711->fu1e_mixer_l_mute) ? 0x01 : 0x00; + ch_r = (rt711->fu1e_dapm_mute || rt711->fu1e_mixer_r_mute) ? 0x01 : 0x00; + + err = regmap_write(rt711->regmap, + SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT711_SDCA_ENT_USER_FU1E, + RT711_SDCA_CTL_FU_MUTE, CH_L), ch_l); + if (err < 0) + return err; + + err = regmap_write(rt711->regmap, + SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT711_SDCA_ENT_USER_FU1E, + RT711_SDCA_CTL_FU_MUTE, CH_R), ch_r); + if (err < 0) + return err; + + return 0; +} + +static int rt711_sdca_fu1e_capture_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_component *component = snd_kcontrol_chip(kcontrol); + struct rt711_sdca_priv *rt711 = snd_soc_component_get_drvdata(component); + + ucontrol->value.integer.value[0] = !rt711->fu1e_mixer_l_mute; + ucontrol->value.integer.value[1] = !rt711->fu1e_mixer_r_mute; + return 0; +} + +static int rt711_sdca_fu1e_capture_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_component *component = snd_kcontrol_chip(kcontrol); + struct rt711_sdca_priv *rt711 = snd_soc_component_get_drvdata(component); + int err, changed = 0; + + if (rt711->fu1e_mixer_l_mute != !ucontrol->value.integer.value[0] || + rt711->fu1e_mixer_r_mute != !ucontrol->value.integer.value[1]) + changed = 1; + + rt711->fu1e_mixer_l_mute = !ucontrol->value.integer.value[0]; + rt711->fu1e_mixer_r_mute = !ucontrol->value.integer.value[1]; + err = rt711_sdca_set_fu1e_capture_ctl(rt711); + if (err < 0) + return err; + + return changed; +} + +static int rt711_sdca_fu0f_capture_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_component *component = snd_kcontrol_chip(kcontrol); + struct rt711_sdca_priv *rt711 = snd_soc_component_get_drvdata(component); + + ucontrol->value.integer.value[0] = !rt711->fu0f_mixer_l_mute; + ucontrol->value.integer.value[1] = !rt711->fu0f_mixer_r_mute; + return 0; +} + +static int rt711_sdca_fu0f_capture_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_component *component = snd_kcontrol_chip(kcontrol); + struct rt711_sdca_priv *rt711 = snd_soc_component_get_drvdata(component); + int err, changed = 0; + + if (rt711->fu0f_mixer_l_mute != !ucontrol->value.integer.value[0] || + rt711->fu0f_mixer_r_mute != !ucontrol->value.integer.value[1]) + changed = 1; + + rt711->fu0f_mixer_l_mute = !ucontrol->value.integer.value[0]; + rt711->fu0f_mixer_r_mute = !ucontrol->value.integer.value[1]; + err = rt711_sdca_set_fu0f_capture_ctl(rt711); + if (err < 0) + return err; + + return changed; +} + static const DECLARE_TLV_DB_SCALE(out_vol_tlv, -6525, 75, 0); static const DECLARE_TLV_DB_SCALE(in_vol_tlv, -1725, 75, 0); static const DECLARE_TLV_DB_SCALE(mic_vol_tlv, 0, 1000, 0); @@ -652,14 +760,10 @@ static const struct snd_kcontrol_new rt711_sdca_snd_controls[] = { SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT711_SDCA_ENT_USER_FU05, RT711_SDCA_CTL_FU_VOLUME, CH_R), 0x57, 0x57, 0, rt711_sdca_set_gain_get, rt711_sdca_set_gain_put, out_vol_tlv), - SOC_DOUBLE_R("FU1E Capture Switch", - SDW_SDCA_CTL(FUNC_NUM_MIC_ARRAY, RT711_SDCA_ENT_USER_FU1E, RT711_SDCA_CTL_FU_MUTE, CH_L), - SDW_SDCA_CTL(FUNC_NUM_MIC_ARRAY, RT711_SDCA_ENT_USER_FU1E, RT711_SDCA_CTL_FU_MUTE, CH_R), - 0, 1, 1), - SOC_DOUBLE_R("FU0F Capture Switch", - SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT711_SDCA_ENT_USER_FU0F, RT711_SDCA_CTL_FU_MUTE, CH_L), - SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT711_SDCA_ENT_USER_FU0F, RT711_SDCA_CTL_FU_MUTE, CH_R), - 0, 1, 1), + SOC_DOUBLE_EXT("FU1E Capture Switch", SND_SOC_NOPM, 0, 1, 1, 0, + rt711_sdca_fu1e_capture_get, rt711_sdca_fu1e_capture_put), + SOC_DOUBLE_EXT("FU0F Capture Switch", SND_SOC_NOPM, 0, 1, 1, 0, + rt711_sdca_fu0f_capture_get, rt711_sdca_fu0f_capture_put), SOC_DOUBLE_R_EXT_TLV("FU1E Capture Volume", SDW_SDCA_CTL(FUNC_NUM_MIC_ARRAY, RT711_SDCA_ENT_USER_FU1E, RT711_SDCA_CTL_FU_VOLUME, CH_L), SDW_SDCA_CTL(FUNC_NUM_MIC_ARRAY, RT711_SDCA_ENT_USER_FU1E, RT711_SDCA_CTL_FU_VOLUME, CH_R), @@ -809,28 +913,15 @@ static int rt711_sdca_fu0f_event(struct snd_soc_dapm_widget *w, struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm); struct rt711_sdca_priv *rt711 = snd_soc_component_get_drvdata(component); - unsigned char unmute = 0x0, mute = 0x1; switch (event) { case SND_SOC_DAPM_POST_PMU: - regmap_write(rt711->regmap, - SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT711_SDCA_ENT_USER_FU0F, - RT711_SDCA_CTL_FU_MUTE, CH_L), - unmute); - regmap_write(rt711->regmap, - SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT711_SDCA_ENT_USER_FU0F, - RT711_SDCA_CTL_FU_MUTE, CH_R), - unmute); + rt711->fu0f_dapm_mute = false; + rt711_sdca_set_fu0f_capture_ctl(rt711); break; case SND_SOC_DAPM_PRE_PMD: - regmap_write(rt711->regmap, - SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT711_SDCA_ENT_USER_FU0F, - RT711_SDCA_CTL_FU_MUTE, CH_L), - mute); - regmap_write(rt711->regmap, - SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT711_SDCA_ENT_USER_FU0F, - RT711_SDCA_CTL_FU_MUTE, CH_R), - mute); + rt711->fu0f_dapm_mute = true; + rt711_sdca_set_fu0f_capture_ctl(rt711); break; } return 0; @@ -842,29 +933,16 @@ static int rt711_sdca_fu1e_event(struct snd_soc_dapm_widget *w, struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm); struct rt711_sdca_priv *rt711 = snd_soc_component_get_drvdata(component); - unsigned char unmute = 0x0, mute = 0x1; switch (event) { case SND_SOC_DAPM_POST_PMU: - regmap_write(rt711->regmap, - SDW_SDCA_CTL(FUNC_NUM_MIC_ARRAY, RT711_SDCA_ENT_USER_FU1E, - RT711_SDCA_CTL_FU_MUTE, CH_L), - unmute); - regmap_write(rt711->regmap, - SDW_SDCA_CTL(FUNC_NUM_MIC_ARRAY, RT711_SDCA_ENT_USER_FU1E, - RT711_SDCA_CTL_FU_MUTE, CH_R), - unmute); + rt711->fu1e_dapm_mute = false; + rt711_sdca_set_fu1e_capture_ctl(rt711); break; case SND_SOC_DAPM_PRE_PMD: - regmap_write(rt711->regmap, - SDW_SDCA_CTL(FUNC_NUM_MIC_ARRAY, RT711_SDCA_ENT_USER_FU1E, - RT711_SDCA_CTL_FU_MUTE, CH_L), - mute); - regmap_write(rt711->regmap, - SDW_SDCA_CTL(FUNC_NUM_MIC_ARRAY, RT711_SDCA_ENT_USER_FU1E, - RT711_SDCA_CTL_FU_MUTE, CH_R), - mute); - break; + rt711->fu1e_dapm_mute = true; + rt711_sdca_set_fu1e_capture_ctl(rt711); + break; } return 0; } @@ -1330,6 +1408,10 @@ int rt711_sdca_init(struct device *dev, struct regmap *regmap, */ rt711->hw_init = false; rt711->first_hw_init = false; + rt711->fu0f_dapm_mute = true; + rt711->fu1e_dapm_mute = true; + rt711->fu0f_mixer_l_mute = rt711->fu0f_mixer_r_mute = true; + rt711->fu1e_mixer_l_mute = rt711->fu1e_mixer_r_mute = true; /* JD source uses JD2 in default */ rt711->jd_src = RT711_JD2; diff --git a/sound/soc/codecs/rt711-sdca.h b/sound/soc/codecs/rt711-sdca.h index 98a022cec0bd..43ae82b7fdb3 100644 --- a/sound/soc/codecs/rt711-sdca.h +++ b/sound/soc/codecs/rt711-sdca.h @@ -30,6 +30,8 @@ struct rt711_sdca_priv { int jack_type, jd_src; unsigned int scp_sdca_stat1, scp_sdca_stat2; int hw_ver; + bool fu0f_dapm_mute, fu0f_mixer_l_mute, fu0f_mixer_r_mute; + bool fu1e_dapm_mute, fu1e_mixer_l_mute, fu1e_mixer_r_mute; }; struct sdw_stream_data { From a1aee7f7b71155595a06f21f2d021b6a58d04017 Mon Sep 17 00:00:00 2001 From: Shuming Fan Date: Thu, 22 Apr 2021 18:32:35 +0800 Subject: [PATCH 564/587] ASoC: rt711-sdca: add the notification when volume changed This patch adds the return value when the volume settings were changed. The userspace application might monitor the kcontrols to check which control changed. Signed-off-by: Shuming Fan Link: https://lore.kernel.org/r/20210422103235.22048-1-shumingf@realtek.com Signed-off-by: Mark Brown --- sound/soc/codecs/rt711-sdca.c | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/sound/soc/codecs/rt711-sdca.c b/sound/soc/codecs/rt711-sdca.c index 39848d2641c3..cc36739f7fcf 100644 --- a/sound/soc/codecs/rt711-sdca.c +++ b/sound/soc/codecs/rt711-sdca.c @@ -509,12 +509,16 @@ static int rt711_sdca_set_gain_put(struct snd_kcontrol *kcontrol, (struct soc_mixer_control *)kcontrol->private_value; struct rt711_sdca_priv *rt711 = snd_soc_component_get_drvdata(component); unsigned int read_l, read_r, gain_l_val, gain_r_val; - unsigned int i, adc_vol_flag = 0; + unsigned int i, adc_vol_flag = 0, changed = 0; + unsigned int lvalue, rvalue; if (strstr(ucontrol->id.name, "FU1E Capture Volume") || strstr(ucontrol->id.name, "FU0F Capture Volume")) adc_vol_flag = 1; + regmap_read(rt711->mbq_regmap, mc->reg, &lvalue); + regmap_read(rt711->mbq_regmap, mc->rreg, &rvalue); + /* control value to 2's complement value */ /* L Channel */ gain_l_val = ucontrol->value.integer.value[0]; @@ -560,6 +564,11 @@ static int rt711_sdca_set_gain_put(struct snd_kcontrol *kcontrol, gain_r_val &= 0xffff; } + if (lvalue != gain_l_val || rvalue != gain_r_val) + changed = 1; + else + return 0; + for (i = 0; i < 3; i++) { /* retry 3 times at most */ /* Lch*/ regmap_write(rt711->mbq_regmap, mc->reg, gain_l_val); @@ -573,7 +582,7 @@ static int rt711_sdca_set_gain_put(struct snd_kcontrol *kcontrol, break; } - return i == 3 ? -EIO : 0; + return i == 3 ? -EIO : changed; } static int rt711_sdca_set_gain_get(struct snd_kcontrol *kcontrol, From 25c4a9b614f101bb9f3e687960815db7dc439c0f Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Fri, 23 Apr 2021 18:07:54 +0100 Subject: [PATCH 565/587] ASoC: simple-card: Fix breakage on kontron-sl28-var3-ads2 A KernelCI bisection identified 59c35c44a9cf89 "ASoC: simple-card: add simple_parse_node()" as causing simple-card to fail to instantiate on kontron-sl28-var3-ads2 systems. Since the merge window is expected to open over the weekend drop that commit and subsequent ones which depend on it for now in case other systems are affected too. The boot log showed the error as: <4>[ 9.948821] sysfs: cannot create duplicate filename '/devices/platform/sound/(null)-wm8904-hifi' (backtrace) <3>[ 10.191982] kobject_add_internal failed for (null)-wm8904-hifi with -EEXIST, don't try to register things with the same name in the same directory. The dropped commits are: 73371bacf0475a20ab6 "ASoC: audio-graph: tidyup graph_dai_link_of_dpcm()" 434392271afcff350fe "ASoC: simple-card: add simple_link_init()" 59c35c44a9cf89a83a9 "ASoC: simple-card: add simple_parse_node()" Reported-by: Guillaume Tucker Reported-by: "kernelci.org bot" Signed-off-by: Mark Brown --- sound/soc/generic/audio-graph-card.c | 30 ++--- sound/soc/generic/simple-card.c | 178 ++++++++++++++------------- 2 files changed, 106 insertions(+), 102 deletions(-) diff --git a/sound/soc/generic/audio-graph-card.c b/sound/soc/generic/audio-graph-card.c index 0159a4576e9c..2c8a2fcb7922 100644 --- a/sound/soc/generic/audio-graph-card.c +++ b/sound/soc/generic/audio-graph-card.c @@ -276,19 +276,24 @@ static int graph_dai_link_of_dpcm(struct asoc_simple_priv *priv, struct link_info *li) { struct device *dev = simple_priv_to_dev(priv); + struct snd_soc_card *card = simple_priv_to_card(priv); struct snd_soc_dai_link *dai_link = simple_priv_to_link(priv, li->link); struct simple_dai_props *dai_props = simple_priv_to_props(priv, li->link); struct device_node *top = dev->of_node; struct device_node *ep = li->cpu ? cpu_ep : codec_ep; + struct device_node *port; + struct device_node *ports; + struct snd_soc_dai_link_component *cpus = asoc_link_to_cpu(dai_link, 0); + struct snd_soc_dai_link_component *codecs = asoc_link_to_codec(dai_link, 0); char dai_name[64]; int ret; + port = of_get_parent(ep); + ports = of_get_parent(port); + dev_dbg(dev, "link_of DPCM (%pOF)\n", ep); if (li->cpu) { - struct snd_soc_card *card = simple_priv_to_card(priv); - struct snd_soc_dai_link_component *cpus = asoc_link_to_cpu(dai_link, 0); - /* Codec is dummy */ /* FE settings */ @@ -297,7 +302,7 @@ static int graph_dai_link_of_dpcm(struct asoc_simple_priv *priv, ret = graph_parse_node(priv, cpu_ep, li, 1); if (ret) - return ret; + goto out_put_node; snprintf(dai_name, sizeof(dai_name), "fe.%pOFP.%s", cpus->of_node, cpus->dai_name); @@ -314,10 +319,7 @@ static int graph_dai_link_of_dpcm(struct asoc_simple_priv *priv, if (card->component_chaining && !soc_component_is_pcm(cpus)) dai_link->no_pcm = 1; } else { - struct snd_soc_codec_conf *cconf = simple_props_to_codec_conf(dai_props, 0); - struct snd_soc_dai_link_component *codecs = asoc_link_to_codec(dai_link, 0); - struct device_node *port; - struct device_node *ports; + struct snd_soc_codec_conf *cconf; /* CPU is dummy */ @@ -325,25 +327,22 @@ static int graph_dai_link_of_dpcm(struct asoc_simple_priv *priv, dai_link->no_pcm = 1; dai_link->be_hw_params_fixup = asoc_simple_be_hw_params_fixup; + cconf = simple_props_to_codec_conf(dai_props, 0); + ret = graph_parse_node(priv, codec_ep, li, 0); if (ret < 0) - return ret; + goto out_put_node; snprintf(dai_name, sizeof(dai_name), "be.%pOFP.%s", codecs->of_node, codecs->dai_name); /* check "prefix" from top node */ - port = of_get_parent(ep); - ports = of_get_parent(port); snd_soc_of_parse_node_prefix(top, cconf, codecs->of_node, "prefix"); if (of_node_name_eq(ports, "ports")) snd_soc_of_parse_node_prefix(ports, cconf, codecs->of_node, "prefix"); snd_soc_of_parse_node_prefix(port, cconf, codecs->of_node, "prefix"); - - of_node_put(ports); - of_node_put(port); } graph_parse_convert(dev, ep, &dai_props->adata); @@ -352,8 +351,11 @@ static int graph_dai_link_of_dpcm(struct asoc_simple_priv *priv, ret = graph_link_init(priv, cpu_ep, codec_ep, li, dai_name); +out_put_node: li->link++; + of_node_put(ports); + of_node_put(port); return ret; } diff --git a/sound/soc/generic/simple-card.c b/sound/soc/generic/simple-card.c index 6a04632944b8..a1373be4558f 100644 --- a/sound/soc/generic/simple-card.c +++ b/sound/soc/generic/simple-card.c @@ -93,11 +93,12 @@ static void simple_parse_convert(struct device *dev, } static void simple_parse_mclk_fs(struct device_node *top, - struct device_node *np, + struct device_node *cpu, + struct device_node *codec, struct simple_dai_props *props, char *prefix) { - struct device_node *node = of_get_parent(np); + struct device_node *node = of_get_parent(cpu); char prop[128]; snprintf(prop, sizeof(prop), "%smclk-fs", PREFIX); @@ -105,79 +106,12 @@ static void simple_parse_mclk_fs(struct device_node *top, snprintf(prop, sizeof(prop), "%smclk-fs", prefix); of_property_read_u32(node, prop, &props->mclk_fs); - of_property_read_u32(np, prop, &props->mclk_fs); + of_property_read_u32(cpu, prop, &props->mclk_fs); + of_property_read_u32(codec, prop, &props->mclk_fs); of_node_put(node); } -static int simple_parse_node(struct asoc_simple_priv *priv, - struct device_node *np, - struct link_info *li, - char *prefix, - int is_cpu) -{ - struct device *dev = simple_priv_to_dev(priv); - struct device_node *top = dev->of_node; - struct snd_soc_dai_link *dai_link = simple_priv_to_link(priv, li->link); - struct simple_dai_props *dai_props = simple_priv_to_props(priv, li->link); - struct snd_soc_dai_link_component *dlc; - struct asoc_simple_dai *dai; - int ret, single = 0; - - if (is_cpu) { - dlc = asoc_link_to_cpu(dai_link, 0); - dai = simple_props_to_dai_cpu(dai_props, 0); - } else { - dlc = asoc_link_to_codec(dai_link, 0); - dai = simple_props_to_dai_codec(dai_props, 0); - } - - simple_parse_mclk_fs(top, np, dai_props, prefix); - - ret = asoc_simple_parse_dai(np, dlc, &single); - if (ret) - return ret; - - ret = asoc_simple_parse_clk(dev, np, dai, dlc); - if (ret) - return ret; - - ret = asoc_simple_parse_tdm(np, dai); - if (ret) - return ret; - - if (is_cpu) { - struct snd_soc_dai_link_component *platforms = asoc_link_to_platform(dai_link, 0); - - asoc_simple_canonicalize_cpu(dlc, single); - asoc_simple_canonicalize_platform(platforms, dlc); - } - - return 0; -} - -static int simple_link_init(struct asoc_simple_priv *priv, - struct device_node *node, - struct device_node *codec, - struct link_info *li, - char *prefix, - char *name) -{ - struct device *dev = simple_priv_to_dev(priv); - struct snd_soc_dai_link *dai_link = simple_priv_to_link(priv, li->link); - int ret; - - ret = asoc_simple_parse_daifmt(dev, node, codec, - prefix, &dai_link->dai_fmt); - if (ret < 0) - return 0; - - dai_link->init = asoc_simple_dai_init; - dai_link->ops = &simple_ops; - - return asoc_simple_set_dailink_name(dev, dai_link, name); -} - static int simple_dai_link_of_dpcm(struct asoc_simple_priv *priv, struct device_node *np, struct device_node *codec, @@ -187,32 +121,50 @@ static int simple_dai_link_of_dpcm(struct asoc_simple_priv *priv, struct device *dev = simple_priv_to_dev(priv); struct snd_soc_dai_link *dai_link = simple_priv_to_link(priv, li->link); struct simple_dai_props *dai_props = simple_priv_to_props(priv, li->link); + struct asoc_simple_dai *dai; struct snd_soc_dai_link_component *cpus = asoc_link_to_cpu(dai_link, 0); struct snd_soc_dai_link_component *codecs = asoc_link_to_codec(dai_link, 0); + struct snd_soc_dai_link_component *platforms = asoc_link_to_platform(dai_link, 0); struct device_node *top = dev->of_node; struct device_node *node = of_get_parent(np); char *prefix = ""; - char dai_name[64]; int ret; dev_dbg(dev, "link_of DPCM (%pOF)\n", np); + li->link++; + /* For single DAI link & old style of DT node */ if (is_top) prefix = PREFIX; if (li->cpu) { + int is_single_links = 0; + /* Codec is dummy */ /* FE settings */ dai_link->dynamic = 1; dai_link->dpcm_merged_format = 1; - ret = simple_parse_node(priv, np, li, prefix, 1); + dai = simple_props_to_dai_cpu(dai_props, 0); + + ret = asoc_simple_parse_dai(np, cpus, &is_single_links); + if (ret) + goto out_put_node; + + ret = asoc_simple_parse_clk(dev, np, dai, cpus); if (ret < 0) goto out_put_node; - snprintf(dai_name, sizeof(dai_name), "fe.%s", cpus->dai_name); + ret = asoc_simple_set_dailink_name(dev, dai_link, + "fe.%s", + cpus->dai_name); + if (ret < 0) + goto out_put_node; + + asoc_simple_canonicalize_cpu(cpus, is_single_links); + asoc_simple_canonicalize_platform(platforms, cpus); } else { struct snd_soc_codec_conf *cconf; @@ -222,13 +174,22 @@ static int simple_dai_link_of_dpcm(struct asoc_simple_priv *priv, dai_link->no_pcm = 1; dai_link->be_hw_params_fixup = asoc_simple_be_hw_params_fixup; + dai = simple_props_to_dai_codec(dai_props, 0); cconf = simple_props_to_codec_conf(dai_props, 0); - ret = simple_parse_node(priv, np, li, prefix, 0); + ret = asoc_simple_parse_dai(np, codecs, NULL); if (ret < 0) goto out_put_node; - snprintf(dai_name, sizeof(dai_name), "be.%s", codecs->dai_name); + ret = asoc_simple_parse_clk(dev, np, dai, codecs); + if (ret < 0) + goto out_put_node; + + ret = asoc_simple_set_dailink_name(dev, dai_link, + "be.%s", + codecs->dai_name); + if (ret < 0) + goto out_put_node; /* check "prefix" from top node */ snd_soc_of_parse_node_prefix(top, cconf, codecs->of_node, @@ -240,14 +201,23 @@ static int simple_dai_link_of_dpcm(struct asoc_simple_priv *priv, } simple_parse_convert(dev, np, &dai_props->adata); + simple_parse_mclk_fs(top, np, codec, dai_props, prefix); + + ret = asoc_simple_parse_tdm(np, dai); + if (ret) + goto out_put_node; + + ret = asoc_simple_parse_daifmt(dev, node, codec, + prefix, &dai_link->dai_fmt); + if (ret < 0) + goto out_put_node; snd_soc_dai_link_set_capabilities(dai_link); - ret = simple_link_init(priv, node, codec, li, prefix, dai_name); + dai_link->ops = &simple_ops; + dai_link->init = asoc_simple_dai_init; out_put_node: - li->link++; - of_node_put(node); return ret; } @@ -260,19 +230,23 @@ static int simple_dai_link_of(struct asoc_simple_priv *priv, { struct device *dev = simple_priv_to_dev(priv); struct snd_soc_dai_link *dai_link = simple_priv_to_link(priv, li->link); + struct simple_dai_props *dai_props = simple_priv_to_props(priv, li->link); + struct asoc_simple_dai *cpu_dai = simple_props_to_dai_cpu(dai_props, 0); + struct asoc_simple_dai *codec_dai = simple_props_to_dai_codec(dai_props, 0); struct snd_soc_dai_link_component *cpus = asoc_link_to_cpu(dai_link, 0); struct snd_soc_dai_link_component *codecs = asoc_link_to_codec(dai_link, 0); struct snd_soc_dai_link_component *platforms = asoc_link_to_platform(dai_link, 0); + struct device_node *top = dev->of_node; struct device_node *cpu = NULL; struct device_node *node = NULL; struct device_node *plat = NULL; - char dai_name[64]; char prop[128]; char *prefix = ""; - int ret; + int ret, single_cpu = 0; cpu = np; node = of_get_parent(np); + li->link++; dev_dbg(dev, "link_of (%pOF)\n", node); @@ -283,11 +257,18 @@ static int simple_dai_link_of(struct asoc_simple_priv *priv, snprintf(prop, sizeof(prop), "%splat", prefix); plat = of_get_child_by_name(node, prop); - ret = simple_parse_node(priv, cpu, li, prefix, 1); + ret = asoc_simple_parse_daifmt(dev, node, codec, + prefix, &dai_link->dai_fmt); if (ret < 0) goto dai_link_of_err; - ret = simple_parse_node(priv, codec, li, prefix, 0); + simple_parse_mclk_fs(top, cpu, codec, dai_props, prefix); + + ret = asoc_simple_parse_dai(cpu, cpus, &single_cpu); + if (ret < 0) + goto dai_link_of_err; + + ret = asoc_simple_parse_dai(codec, codecs, NULL); if (ret < 0) goto dai_link_of_err; @@ -295,18 +276,39 @@ static int simple_dai_link_of(struct asoc_simple_priv *priv, if (ret < 0) goto dai_link_of_err; - snprintf(dai_name, sizeof(dai_name), - "%s-%s", cpus->dai_name, codecs->dai_name); - ret = simple_link_init(priv, node, codec, li, prefix, dai_name); + ret = asoc_simple_parse_tdm(cpu, cpu_dai); if (ret < 0) goto dai_link_of_err; + ret = asoc_simple_parse_tdm(codec, codec_dai); + if (ret < 0) + goto dai_link_of_err; + + ret = asoc_simple_parse_clk(dev, cpu, cpu_dai, cpus); + if (ret < 0) + goto dai_link_of_err; + + ret = asoc_simple_parse_clk(dev, codec, codec_dai, codecs); + if (ret < 0) + goto dai_link_of_err; + + ret = asoc_simple_set_dailink_name(dev, dai_link, + "%s-%s", + cpus->dai_name, + codecs->dai_name); + if (ret < 0) + goto dai_link_of_err; + + dai_link->ops = &simple_ops; + dai_link->init = asoc_simple_dai_init; + + asoc_simple_canonicalize_cpu(cpus, single_cpu); + asoc_simple_canonicalize_platform(platforms, cpus); + dai_link_of_err: of_node_put(plat); of_node_put(node); - li->link++; - return ret; } From 988cc17552606be67a956cf8cd6ff504cfc5d643 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Mon, 26 Apr 2021 08:33:49 +0200 Subject: [PATCH 566/587] ALSA: usb-audio: Fix implicit sync clearance at stopping stream The recent endpoint management change for implicit feedback mode added a clearance of ep->sync_sink (formerly ep->sync_slave) pointer at snd_usb_endpoint_stop() to assure no leftover for the feedback from the already stopped capture stream. This turned out to cause a regression, however, when full-duplex streams were running and only a capture was stopped. Because of the above clearance of ep->sync_sink pointer, no more feedback is done, hence the playback will stall. This patch fixes the ep->sync_sink clearance to be done only after all endpoints are released, for addressing the regression. Reported-and-tested-by: Lucas Endres Fixes: bf6313a0ff76 ("ALSA: usb-audio: Refactor endpoint management") Cc: Link: https://lore.kernel.org/r/20210426063349.18601-1-tiwai@suse.de Signed-off-by: Takashi Iwai --- sound/usb/endpoint.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/sound/usb/endpoint.c b/sound/usb/endpoint.c index f4c3d2b38abb..014c43862826 100644 --- a/sound/usb/endpoint.c +++ b/sound/usb/endpoint.c @@ -1443,11 +1443,11 @@ void snd_usb_endpoint_stop(struct snd_usb_endpoint *ep) if (snd_BUG_ON(!atomic_read(&ep->running))) return; - if (ep->sync_source) - WRITE_ONCE(ep->sync_source->sync_sink, NULL); - - if (!atomic_dec_return(&ep->running)) + if (!atomic_dec_return(&ep->running)) { + if (ep->sync_source) + WRITE_ONCE(ep->sync_source->sync_sink, NULL); stop_urbs(ep, false); + } } /** From 9bbb94e57df135ef61bef075d9c99b8d9e89e246 Mon Sep 17 00:00:00 2001 From: Sami Loone Date: Sun, 25 Apr 2021 22:37:12 +0200 Subject: [PATCH 567/587] ALSA: hda/realtek: fix static noise on ALC285 Lenovo laptops Remove a duplicate vendor+subvendor pin fixup entry as one is masking the other and making it unreachable. Consider the more specific newcomer as a second chance instead. The generic entry is made less strict to also match for laptops with slightly different 0x12 pin configuration. Tested on Lenovo Yoga 6 (AMD) where 0x12 is 0x40000000. Fixes: 607184cb1635 ("ALSA: hda/realtek - Add supported for more Lenovo ALC285 Headset Button") Signed-off-by: Sami Loone Cc: Link: https://lore.kernel.org/r/YIXS+GT/dGI/LtK6@yoga Signed-off-by: Takashi Iwai --- sound/pci/hda/patch_realtek.c | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/sound/pci/hda/patch_realtek.c b/sound/pci/hda/patch_realtek.c index 97473e67716b..f4c2b10aeb68 100644 --- a/sound/pci/hda/patch_realtek.c +++ b/sound/pci/hda/patch_realtek.c @@ -8800,12 +8800,7 @@ static const struct snd_hda_pin_quirk alc269_pin_fixup_tbl[] = { {0x12, 0x90a60130}, {0x19, 0x03a11020}, {0x21, 0x0321101f}), - SND_HDA_PIN_QUIRK(0x10ec0285, 0x17aa, "Lenovo", ALC285_FIXUP_THINKPAD_NO_BASS_SPK_HEADSET_JACK, - {0x14, 0x90170110}, - {0x19, 0x04a11040}, - {0x21, 0x04211020}), SND_HDA_PIN_QUIRK(0x10ec0285, 0x17aa, "Lenovo", ALC285_FIXUP_LENOVO_PC_BEEP_IN_NOISE, - {0x12, 0x90a60130}, {0x14, 0x90170110}, {0x19, 0x04a11040}, {0x21, 0x04211020}), @@ -8976,6 +8971,10 @@ static const struct snd_hda_pin_quirk alc269_fallback_pin_fixup_tbl[] = { SND_HDA_PIN_QUIRK(0x10ec0274, 0x1028, "Dell", ALC274_FIXUP_DELL_AIO_LINEOUT_VERB, {0x19, 0x40000000}, {0x1a, 0x40000000}), + SND_HDA_PIN_QUIRK(0x10ec0285, 0x17aa, "Lenovo", ALC285_FIXUP_THINKPAD_NO_BASS_SPK_HEADSET_JACK, + {0x14, 0x90170110}, + {0x19, 0x04a11040}, + {0x21, 0x04211020}), {} }; From 1c98f574403dbcf2eb832d5535a10d967333ef2d Mon Sep 17 00:00:00 2001 From: Lv Yunlong Date: Mon, 26 Apr 2021 06:11:29 -0700 Subject: [PATCH 568/587] ALSA: emu8000: Fix a use after free in snd_emu8000_create_mixer Our code analyzer reported a uaf. In snd_emu8000_create_mixer, the callee snd_ctl_add(..,emu->controls[i]) calls snd_ctl_add_replace(.., kcontrol,..). Inside snd_ctl_add_replace(), if error happens, kcontrol will be freed by snd_ctl_free_one(kcontrol). Then emu->controls[i] points to a freed memory, and the execution comes to __error branch of snd_emu8000_create_mixer. The freed emu->controls[i] is used in snd_ctl_remove(card, emu->controls[i]). My patch set emu->controls[i] to NULL if snd_ctl_add() failed to avoid the uaf. Signed-off-by: Lv Yunlong Cc: Link: https://lore.kernel.org/r/20210426131129.4796-1-lyl2019@mail.ustc.edu.cn Signed-off-by: Takashi Iwai --- sound/isa/sb/emu8000.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/sound/isa/sb/emu8000.c b/sound/isa/sb/emu8000.c index 0aa545ac6e60..1c90421a88dc 100644 --- a/sound/isa/sb/emu8000.c +++ b/sound/isa/sb/emu8000.c @@ -1029,8 +1029,10 @@ snd_emu8000_create_mixer(struct snd_card *card, struct snd_emu8000 *emu) memset(emu->controls, 0, sizeof(emu->controls)); for (i = 0; i < EMU8000_NUM_CONTROLS; i++) { - if ((err = snd_ctl_add(card, emu->controls[i] = snd_ctl_new1(mixer_defs[i], emu))) < 0) + if ((err = snd_ctl_add(card, emu->controls[i] = snd_ctl_new1(mixer_defs[i], emu))) < 0) { + emu->controls[i] = NULL; goto __error; + } } return 0; From 4fb44dd2c1dda18606348acdfdb97e8759dde9df Mon Sep 17 00:00:00 2001 From: Lv Yunlong Date: Mon, 26 Apr 2021 07:55:41 -0700 Subject: [PATCH 569/587] ALSA: sb: Fix two use after free in snd_sb_qsound_build In snd_sb_qsound_build, snd_ctl_add(..,p->qsound_switch...) and snd_ctl_add(..,p->qsound_space..) are called. But the second arguments of snd_ctl_add() could be freed via snd_ctl_add_replace() ->snd_ctl_free_one(). After the error code is returned, snd_sb_qsound_destroy(p) is called in __error branch. But in snd_sb_qsound_destroy(), the freed p->qsound_switch and p->qsound_space are still used by snd_ctl_remove(). My patch set p->qsound_switch and p->qsound_space to NULL if snd_ctl_add() failed to avoid the uaf bugs. But these codes need to further be improved with the code style. Signed-off-by: Lv Yunlong Cc: Link: https://lore.kernel.org/r/20210426145541.8070-1-lyl2019@mail.ustc.edu.cn Signed-off-by: Takashi Iwai --- sound/isa/sb/sb16_csp.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/sound/isa/sb/sb16_csp.c b/sound/isa/sb/sb16_csp.c index 8635a2b6b36b..4789345a8fdd 100644 --- a/sound/isa/sb/sb16_csp.c +++ b/sound/isa/sb/sb16_csp.c @@ -1045,10 +1045,14 @@ static int snd_sb_qsound_build(struct snd_sb_csp * p) spin_lock_init(&p->q_lock); - if ((err = snd_ctl_add(card, p->qsound_switch = snd_ctl_new1(&snd_sb_qsound_switch, p))) < 0) + if ((err = snd_ctl_add(card, p->qsound_switch = snd_ctl_new1(&snd_sb_qsound_switch, p))) < 0) { + p->qsound_switch = NULL; goto __error; - if ((err = snd_ctl_add(card, p->qsound_space = snd_ctl_new1(&snd_sb_qsound_space, p))) < 0) + } + if ((err = snd_ctl_add(card, p->qsound_space = snd_ctl_new1(&snd_sb_qsound_space, p))) < 0) { + p->qsound_space = NULL; goto __error; + } return 0; From 0e853a9c3937caa9f13fdde547d6202f92457c2b Mon Sep 17 00:00:00 2001 From: Stefan Binding Date: Mon, 26 Apr 2021 17:37:48 +0100 Subject: [PATCH 570/587] ALSA: hda/cirrus: Set Initial DMIC volume for Bullseye to -26 dB After booting for first time on Bullseye, the DMIC is currently muted. Instead, the DMIC volume should be set to a valid initial value. Tested on DELL Inspiron-3505, DELL Inspiron-3501, DELL Inspiron-3500 Signed-off-by: Stefan Binding Signed-off-by: Vitaly Rodionov BugLink: https://bugs.launchpad.net/ubuntu/+source/linux/+bug/1923557 Reported-and-tested-by: You-Sheng Yang Cc: Link: https://lore.kernel.org/r/20210426163749.196153-2-vitalyr@opensource.cirrus.com Signed-off-by: Takashi Iwai --- sound/pci/hda/patch_cirrus.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/sound/pci/hda/patch_cirrus.c b/sound/pci/hda/patch_cirrus.c index 5d57096b3a95..a4f82f147ff3 100644 --- a/sound/pci/hda/patch_cirrus.c +++ b/sound/pci/hda/patch_cirrus.c @@ -2172,6 +2172,11 @@ static void cs8409_cs42l42_fixups(struct hda_codec *codec, (get_wcaps(codec, CS8409_CS42L42_AMIC_PIN_NID) | AC_WCAP_UNSOL_CAP)); break; case HDA_FIXUP_ACT_PROBE: + + /* Set initial volume on Bullseye to -26 dB */ + if (codec->fixup_id == CS8409_BULLSEYE) + snd_hda_codec_amp_init_stereo(codec, CS8409_CS42L42_DMIC_ADC_PIN_NID, + HDA_INPUT, 0, 0xff, 0x19); snd_hda_gen_add_kctl(&spec->gen, NULL, &cs8409_cs42l42_hp_volume_mixer); snd_hda_gen_add_kctl(&spec->gen, From 45b14fe200ba0611b6c3874aa5bba584dc979fb9 Mon Sep 17 00:00:00 2001 From: Stefan Binding Date: Mon, 26 Apr 2021 17:37:49 +0100 Subject: [PATCH 571/587] ALSA: hda/cirrus: Use CS8409 filter to fix abnormal sounds on Bullseye Cracking noises have been reported on the built-in speaker for certain Bullseye platforms, when volume is > 80%. This issue is caused by the specific combination of Codec and AMP in this platform, and cannot be fixed by the AMP, so indead must be fixed at codec level, by adding attenuation to the volume. Tested on DELL Inspiron-3505, DELL Inspiron-3501, DELL Inspiron-3500 Signed-off-by: Stefan Binding Signed-off-by: Vitaly Rodionov BugLink: https://bugs.launchpad.net/ubuntu/+source/linux/+bug/1924997 Reported-and-tested-by: You-Sheng Yang Cc: Link: https://lore.kernel.org/r/20210426163749.196153-3-vitalyr@opensource.cirrus.com Signed-off-by: Takashi Iwai --- sound/pci/hda/patch_cirrus.c | 33 +++++++++++++++++++++++++++++++++ 1 file changed, 33 insertions(+) diff --git a/sound/pci/hda/patch_cirrus.c b/sound/pci/hda/patch_cirrus.c index a4f82f147ff3..726507d0b04c 100644 --- a/sound/pci/hda/patch_cirrus.c +++ b/sound/pci/hda/patch_cirrus.c @@ -1481,6 +1481,34 @@ static const struct cs8409_cir_param cs8409_cs42l42_hw_cfg[] = { {} /* Terminator */ }; +static const struct cs8409_cir_param cs8409_cs42l42_bullseye_atn[] = { + { 0x47, 0x65, 0x4000 }, /* EQ_SEL=1, EQ1/2_EN=0 */ + { 0x47, 0x64, 0x4000 }, /* +EQ_ACC */ + { 0x47, 0x65, 0x4010 }, /* +EQ2_EN */ + { 0x47, 0x63, 0x0647 }, /* EQ_DATA_HI=0x0647 */ + { 0x47, 0x64, 0xc0c7 }, /* +EQ_WRT, +EQ_ACC, EQ_ADR=0, EQ_DATA_LO=0x67 */ + { 0x47, 0x63, 0x0647 }, /* EQ_DATA_HI=0x0647 */ + { 0x47, 0x64, 0xc1c7 }, /* +EQ_WRT, +EQ_ACC, EQ_ADR=1, EQ_DATA_LO=0x67 */ + { 0x47, 0x63, 0xf370 }, /* EQ_DATA_HI=0xf370 */ + { 0x47, 0x64, 0xc271 }, /* +EQ_WRT, +EQ_ACC, EQ_ADR=2, EQ_DATA_LO=0x71 */ + { 0x47, 0x63, 0x1ef8 }, /* EQ_DATA_HI=0x1ef8 */ + { 0x47, 0x64, 0xc348 }, /* +EQ_WRT, +EQ_ACC, EQ_ADR=3, EQ_DATA_LO=0x48 */ + { 0x47, 0x63, 0xc110 }, /* EQ_DATA_HI=0xc110 */ + { 0x47, 0x64, 0xc45a }, /* +EQ_WRT, +EQ_ACC, EQ_ADR=4, EQ_DATA_LO=0x5a */ + { 0x47, 0x63, 0x1f29 }, /* EQ_DATA_HI=0x1f29 */ + { 0x47, 0x64, 0xc574 }, /* +EQ_WRT, +EQ_ACC, EQ_ADR=5, EQ_DATA_LO=0x74 */ + { 0x47, 0x63, 0x1d7a }, /* EQ_DATA_HI=0x1d7a */ + { 0x47, 0x64, 0xc653 }, /* +EQ_WRT, +EQ_ACC, EQ_ADR=6, EQ_DATA_LO=0x53 */ + { 0x47, 0x63, 0xc38c }, /* EQ_DATA_HI=0xc38c */ + { 0x47, 0x64, 0xc714 }, /* +EQ_WRT, +EQ_ACC, EQ_ADR=7, EQ_DATA_LO=0x14 */ + { 0x47, 0x63, 0x1ca3 }, /* EQ_DATA_HI=0x1ca3 */ + { 0x47, 0x64, 0xc8c7 }, /* +EQ_WRT, +EQ_ACC, EQ_ADR=8, EQ_DATA_LO=0xc7 */ + { 0x47, 0x63, 0xc38c }, /* EQ_DATA_HI=0xc38c */ + { 0x47, 0x64, 0xc914 }, /* +EQ_WRT, +EQ_ACC, EQ_ADR=9, EQ_DATA_LO=0x14 */ + { 0x47, 0x64, 0x0000 }, /* -EQ_ACC, -EQ_WRT */ + {} /* Terminator */ +}; + /** * cs8409_enable_i2c_clock - Enable I2C clocks * @codec: the codec instance @@ -2029,6 +2057,7 @@ static void cs8409_enable_ur(struct hda_codec *codec, int flag) static void cs8409_cs42l42_hw_init(struct hda_codec *codec) { const struct cs8409_cir_param *seq = cs8409_cs42l42_hw_cfg; + const struct cs8409_cir_param *seq_bullseye = cs8409_cs42l42_bullseye_atn; struct cs_spec *spec = codec->spec; if (spec->gpio_mask) { @@ -2043,6 +2072,10 @@ static void cs8409_cs42l42_hw_init(struct hda_codec *codec) for (; seq->nid; seq++) cs_vendor_coef_set(codec, seq->cir, seq->coeff); + if (codec->fixup_id == CS8409_BULLSEYE) + for (; seq_bullseye->nid; seq_bullseye++) + cs_vendor_coef_set(codec, seq_bullseye->cir, seq_bullseye->coeff); + /* Disable Unsolicited Response during boot */ cs8409_enable_ur(codec, 0); From e861431303d23428bf26e8496252d7bee260a956 Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Mon, 26 Apr 2021 16:39:02 -0500 Subject: [PATCH 572/587] ALSA: virtio: fix kernel-doc make W=1 warning: sound/virtio/virtio_ctl_msg.c:70: warning: expecting prototype for virtsnd_ctl_msg_request(). Prototype was for virtsnd_ctl_msg_response() instead Signed-off-by: Pierre-Louis Bossart Link: https://lore.kernel.org/r/20210426213902.234711-1-pierre-louis.bossart@linux.intel.com Signed-off-by: Takashi Iwai --- sound/virtio/virtio_ctl_msg.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sound/virtio/virtio_ctl_msg.c b/sound/virtio/virtio_ctl_msg.c index 26ff7e7cc041..18dc5aca2e0c 100644 --- a/sound/virtio/virtio_ctl_msg.c +++ b/sound/virtio/virtio_ctl_msg.c @@ -61,7 +61,7 @@ void *virtsnd_ctl_msg_request(struct virtio_snd_msg *msg) } /** - * virtsnd_ctl_msg_request() - Get a pointer to the response header. + * virtsnd_ctl_msg_response() - Get a pointer to the response header. * @msg: Control message. * * Context: Any context. From 970e3012c04c96351c413f193a9c909e6d871ce2 Mon Sep 17 00:00:00 2001 From: Eckhart Mohr Date: Tue, 27 Apr 2021 17:30:25 +0200 Subject: [PATCH 573/587] ALSA: hda/realtek: Add quirk for Intel Clevo PCx0Dx This applies a SND_PCI_QUIRK(...) to the Clevo PCx0Dx barebones. This fix enables audio output over the headset jack and ensures that a microphone connected via the headset combo jack is correctly recognized when pluged in. [ Rearranged the list entries in a sorted order -- tiwai ] Signed-off-by: Eckhart Mohr Co-developed-by: Werner Sembach Signed-off-by: Werner Sembach Cc: Link: https://lore.kernel.org/r/20210427153025.451118-1-wse@tuxedocomputers.com Signed-off-by: Takashi Iwai --- sound/pci/hda/patch_realtek.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/sound/pci/hda/patch_realtek.c b/sound/pci/hda/patch_realtek.c index f4c2b10aeb68..4a3939c45a12 100644 --- a/sound/pci/hda/patch_realtek.c +++ b/sound/pci/hda/patch_realtek.c @@ -2552,8 +2552,10 @@ static const struct snd_pci_quirk alc882_fixup_tbl[] = { SND_PCI_QUIRK(0x1558, 0x65d1, "Clevo PB51[ER][CDF]", ALC1220_FIXUP_CLEVO_PB51ED_PINS), SND_PCI_QUIRK(0x1558, 0x65d2, "Clevo PB51R[CDF]", ALC1220_FIXUP_CLEVO_PB51ED_PINS), SND_PCI_QUIRK(0x1558, 0x65e1, "Clevo PB51[ED][DF]", ALC1220_FIXUP_CLEVO_PB51ED_PINS), + SND_PCI_QUIRK(0x1558, 0x65e5, "Clevo PC50D[PRS](?:-D|-G)?", ALC1220_FIXUP_CLEVO_PB51ED_PINS), SND_PCI_QUIRK(0x1558, 0x67d1, "Clevo PB71[ER][CDF]", ALC1220_FIXUP_CLEVO_PB51ED_PINS), SND_PCI_QUIRK(0x1558, 0x67e1, "Clevo PB71[DE][CDF]", ALC1220_FIXUP_CLEVO_PB51ED_PINS), + SND_PCI_QUIRK(0x1558, 0x67e5, "Clevo PC70D[PRS](?:-D|-G)?", ALC1220_FIXUP_CLEVO_PB51ED_PINS), SND_PCI_QUIRK(0x1558, 0x70d1, "Clevo PC70[ER][CDF]", ALC1220_FIXUP_CLEVO_PB51ED_PINS), SND_PCI_QUIRK(0x1558, 0x7714, "Clevo X170", ALC1220_FIXUP_CLEVO_PB51ED_PINS), SND_PCI_QUIRK_VENDOR(0x1558, "Clevo laptop", ALC882_FIXUP_EAPD), From a3ffcebc87480664aef7c8283394d4cf2aec327c Mon Sep 17 00:00:00 2001 From: Jiapeng Chong Date: Tue, 27 Apr 2021 18:26:34 +0800 Subject: [PATCH 574/587] ALSA: usb-audio: Remove redundant assignment to len Variable len is set to zero but this value is never read as it is overwritten with a new value later on, hence it is a redundant assignment and can be removed. Cleans up the following clang-analyzer warning: sound/usb/mixer.c:2713:3: warning: Value stored to 'len' is never read [clang-analyzer-deadcode.DeadStores]. Reported-by: Abaci Robot Signed-off-by: Jiapeng Chong Link: https://lore.kernel.org/r/1619519194-57806-1-git-send-email-jiapeng.chong@linux.alibaba.com Signed-off-by: Takashi Iwai --- sound/usb/mixer.c | 1 - 1 file changed, 1 deletion(-) diff --git a/sound/usb/mixer.c b/sound/usb/mixer.c index 2faf5767c7f8..428d581f988f 100644 --- a/sound/usb/mixer.c +++ b/sound/usb/mixer.c @@ -2726,7 +2726,6 @@ static int parse_audio_selector_unit(struct mixer_build *state, int unitid, #define MAX_ITEM_NAME_LEN 64 for (i = 0; i < desc->bNrInPins; i++) { struct usb_audio_term iterm; - len = 0; namelist[i] = kmalloc(MAX_ITEM_NAME_LEN, GFP_KERNEL); if (!namelist[i]) { err = -ENOMEM; From b265047ac56bad8c4f3d0c8bf9cb4e828ee0d28e Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Wed, 28 Apr 2021 13:26:52 +0200 Subject: [PATCH 575/587] ALSA: hda/realtek: Re-order ALC882 Acer quirk table entries Just re-order the alc882_fixup_tbl[] entries for Acer devices for avoiding the oversight of the duplicated or unapplied item in future. No functional changes. Also Cc-to-stable for the further patch applications. Cc: Link: https://lore.kernel.org/r/20210428112704.23967-2-tiwai@suse.de Signed-off-by: Takashi Iwai --- sound/pci/hda/patch_realtek.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/sound/pci/hda/patch_realtek.c b/sound/pci/hda/patch_realtek.c index 4a3939c45a12..bc4136b2b82f 100644 --- a/sound/pci/hda/patch_realtek.c +++ b/sound/pci/hda/patch_realtek.c @@ -2470,13 +2470,13 @@ static const struct snd_pci_quirk alc882_fixup_tbl[] = { ALC882_FIXUP_ACER_ASPIRE_8930G), SND_PCI_QUIRK(0x1025, 0x0146, "Acer Aspire 6935G", ALC882_FIXUP_ACER_ASPIRE_8930G), + SND_PCI_QUIRK(0x1025, 0x0142, "Acer Aspire 7730G", + ALC882_FIXUP_ACER_ASPIRE_4930G), + SND_PCI_QUIRK(0x1025, 0x0155, "Packard-Bell M5120", ALC882_FIXUP_PB_M5210), SND_PCI_QUIRK(0x1025, 0x015e, "Acer Aspire 6930G", ALC882_FIXUP_ACER_ASPIRE_4930G), SND_PCI_QUIRK(0x1025, 0x0166, "Acer Aspire 6530G", ALC882_FIXUP_ACER_ASPIRE_4930G), - SND_PCI_QUIRK(0x1025, 0x0142, "Acer Aspire 7730G", - ALC882_FIXUP_ACER_ASPIRE_4930G), - SND_PCI_QUIRK(0x1025, 0x0155, "Packard-Bell M5120", ALC882_FIXUP_PB_M5210), SND_PCI_QUIRK(0x1025, 0x021e, "Acer Aspire 5739G", ALC882_FIXUP_ACER_ASPIRE_4930G), SND_PCI_QUIRK(0x1025, 0x0259, "Acer Aspire 5935", ALC889_FIXUP_DAC_ROUTE), From b7529c18feecb1af92f9db08c8e7fe446a82d96d Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Wed, 28 Apr 2021 13:26:53 +0200 Subject: [PATCH 576/587] ALSA: hda/realtek: Re-order ALC882 Sony quirk table entries Just re-order the alc882_fixup_tbl[] entries for Sony devices for avoiding the oversight of the duplicated or unapplied item in future. No functional changes. Also Cc-to-stable for the further patch applications. Cc: Link: https://lore.kernel.org/r/20210428112704.23967-3-tiwai@suse.de Signed-off-by: Takashi Iwai --- sound/pci/hda/patch_realtek.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/sound/pci/hda/patch_realtek.c b/sound/pci/hda/patch_realtek.c index bc4136b2b82f..61a7c2f7a648 100644 --- a/sound/pci/hda/patch_realtek.c +++ b/sound/pci/hda/patch_realtek.c @@ -2489,11 +2489,11 @@ static const struct snd_pci_quirk alc882_fixup_tbl[] = { SND_PCI_QUIRK(0x1043, 0x835f, "Asus Eee 1601", ALC888_FIXUP_EEE1601), SND_PCI_QUIRK(0x1043, 0x84bc, "ASUS ET2700", ALC887_FIXUP_ASUS_BASS), SND_PCI_QUIRK(0x1043, 0x8691, "ASUS ROG Ranger VIII", ALC882_FIXUP_GPIO3), + SND_PCI_QUIRK(0x104d, 0x9043, "Sony Vaio VGC-LN51JGB", ALC882_FIXUP_NO_PRIMARY_HP), + SND_PCI_QUIRK(0x104d, 0x9044, "Sony VAIO AiO", ALC882_FIXUP_NO_PRIMARY_HP), SND_PCI_QUIRK(0x104d, 0x9047, "Sony Vaio TT", ALC889_FIXUP_VAIO_TT), SND_PCI_QUIRK(0x104d, 0x905a, "Sony Vaio Z", ALC882_FIXUP_NO_PRIMARY_HP), SND_PCI_QUIRK(0x104d, 0x9060, "Sony Vaio VPCL14M1R", ALC882_FIXUP_NO_PRIMARY_HP), - SND_PCI_QUIRK(0x104d, 0x9043, "Sony Vaio VGC-LN51JGB", ALC882_FIXUP_NO_PRIMARY_HP), - SND_PCI_QUIRK(0x104d, 0x9044, "Sony VAIO AiO", ALC882_FIXUP_NO_PRIMARY_HP), /* All Apple entries are in codec SSIDs */ SND_PCI_QUIRK(0x106b, 0x00a0, "MacBookPro 3,1", ALC889_FIXUP_MBP_VREF), From 13e1a4cd490b959a4c72c9f4fb502ef56b190062 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Wed, 28 Apr 2021 13:26:54 +0200 Subject: [PATCH 577/587] ALSA: hda/realtek: Re-order ALC882 Clevo quirk table entries Just re-order the alc882_fixup_tbl[] entries for Clevo devices for avoiding the oversight of the duplicated or unapplied item in future. No functional changes. Also, user lower hex letters in the entry. Also Cc-to-stable for the further patch applications. Cc: Link: https://lore.kernel.org/r/20210428112704.23967-4-tiwai@suse.de Signed-off-by: Takashi Iwai --- sound/pci/hda/patch_realtek.c | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/sound/pci/hda/patch_realtek.c b/sound/pci/hda/patch_realtek.c index 61a7c2f7a648..5eee67d443c2 100644 --- a/sound/pci/hda/patch_realtek.c +++ b/sound/pci/hda/patch_realtek.c @@ -2536,18 +2536,6 @@ static const struct snd_pci_quirk alc882_fixup_tbl[] = { SND_PCI_QUIRK(0x1462, 0xda57, "MSI Z270-Gaming", ALC1220_FIXUP_GB_DUAL_CODECS), SND_PCI_QUIRK_VENDOR(0x1462, "MSI", ALC882_FIXUP_GPIO3), SND_PCI_QUIRK(0x147b, 0x107a, "Abit AW9D-MAX", ALC882_FIXUP_ABIT_AW9D_MAX), - SND_PCI_QUIRK(0x1558, 0x9501, "Clevo P950HR", ALC1220_FIXUP_CLEVO_P950), - SND_PCI_QUIRK(0x1558, 0x9506, "Clevo P955HQ", ALC1220_FIXUP_CLEVO_P950), - SND_PCI_QUIRK(0x1558, 0x950A, "Clevo P955H[PR]", ALC1220_FIXUP_CLEVO_P950), - SND_PCI_QUIRK(0x1558, 0x95e1, "Clevo P95xER", ALC1220_FIXUP_CLEVO_P950), - SND_PCI_QUIRK(0x1558, 0x95e2, "Clevo P950ER", ALC1220_FIXUP_CLEVO_P950), - SND_PCI_QUIRK(0x1558, 0x95e3, "Clevo P955[ER]T", ALC1220_FIXUP_CLEVO_P950), - SND_PCI_QUIRK(0x1558, 0x95e4, "Clevo P955ER", ALC1220_FIXUP_CLEVO_P950), - SND_PCI_QUIRK(0x1558, 0x95e5, "Clevo P955EE6", ALC1220_FIXUP_CLEVO_P950), - SND_PCI_QUIRK(0x1558, 0x95e6, "Clevo P950R[CDF]", ALC1220_FIXUP_CLEVO_P950), - SND_PCI_QUIRK(0x1558, 0x96e1, "Clevo P960[ER][CDFN]-K", ALC1220_FIXUP_CLEVO_P950), - SND_PCI_QUIRK(0x1558, 0x97e1, "Clevo P970[ER][CDFN]", ALC1220_FIXUP_CLEVO_P950), - SND_PCI_QUIRK(0x1558, 0x97e2, "Clevo P970RC-M", ALC1220_FIXUP_CLEVO_P950), SND_PCI_QUIRK(0x1558, 0x50d3, "Clevo PC50[ER][CDF]", ALC1220_FIXUP_CLEVO_PB51ED_PINS), SND_PCI_QUIRK(0x1558, 0x65d1, "Clevo PB51[ER][CDF]", ALC1220_FIXUP_CLEVO_PB51ED_PINS), SND_PCI_QUIRK(0x1558, 0x65d2, "Clevo PB51R[CDF]", ALC1220_FIXUP_CLEVO_PB51ED_PINS), @@ -2558,6 +2546,18 @@ static const struct snd_pci_quirk alc882_fixup_tbl[] = { SND_PCI_QUIRK(0x1558, 0x67e5, "Clevo PC70D[PRS](?:-D|-G)?", ALC1220_FIXUP_CLEVO_PB51ED_PINS), SND_PCI_QUIRK(0x1558, 0x70d1, "Clevo PC70[ER][CDF]", ALC1220_FIXUP_CLEVO_PB51ED_PINS), SND_PCI_QUIRK(0x1558, 0x7714, "Clevo X170", ALC1220_FIXUP_CLEVO_PB51ED_PINS), + SND_PCI_QUIRK(0x1558, 0x9501, "Clevo P950HR", ALC1220_FIXUP_CLEVO_P950), + SND_PCI_QUIRK(0x1558, 0x9506, "Clevo P955HQ", ALC1220_FIXUP_CLEVO_P950), + SND_PCI_QUIRK(0x1558, 0x950a, "Clevo P955H[PR]", ALC1220_FIXUP_CLEVO_P950), + SND_PCI_QUIRK(0x1558, 0x95e1, "Clevo P95xER", ALC1220_FIXUP_CLEVO_P950), + SND_PCI_QUIRK(0x1558, 0x95e2, "Clevo P950ER", ALC1220_FIXUP_CLEVO_P950), + SND_PCI_QUIRK(0x1558, 0x95e3, "Clevo P955[ER]T", ALC1220_FIXUP_CLEVO_P950), + SND_PCI_QUIRK(0x1558, 0x95e4, "Clevo P955ER", ALC1220_FIXUP_CLEVO_P950), + SND_PCI_QUIRK(0x1558, 0x95e5, "Clevo P955EE6", ALC1220_FIXUP_CLEVO_P950), + SND_PCI_QUIRK(0x1558, 0x95e6, "Clevo P950R[CDF]", ALC1220_FIXUP_CLEVO_P950), + SND_PCI_QUIRK(0x1558, 0x96e1, "Clevo P960[ER][CDFN]-K", ALC1220_FIXUP_CLEVO_P950), + SND_PCI_QUIRK(0x1558, 0x97e1, "Clevo P970[ER][CDFN]", ALC1220_FIXUP_CLEVO_P950), + SND_PCI_QUIRK(0x1558, 0x97e2, "Clevo P970RC-M", ALC1220_FIXUP_CLEVO_P950), SND_PCI_QUIRK_VENDOR(0x1558, "Clevo laptop", ALC882_FIXUP_EAPD), SND_PCI_QUIRK(0x161f, 0x2054, "Medion laptop", ALC883_FIXUP_EAPD), SND_PCI_QUIRK(0x17aa, 0x3a0d, "Lenovo Y530", ALC882_FIXUP_LENOVO_Y530), From 45461e3b554c75ddff9703539f3711cc3dfb0422 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Wed, 28 Apr 2021 13:26:55 +0200 Subject: [PATCH 578/587] ALSA: hda/realtek: Re-order ALC269 HP quirk table entries Just re-order the alc269_fixup_tbl[] entries for HP devices for avoiding the oversight of the duplicated or unapplied item in future. No functional changes. Formerly, some entries were grouped for the actual codec, but this doesn't seem reasonable to keep in that way. So now we simply keep the PCI SSID order for the whole. Also Cc-to-stable for the further patch applications. Cc: Link: https://lore.kernel.org/r/20210428112704.23967-5-tiwai@suse.de Signed-off-by: Takashi Iwai --- sound/pci/hda/patch_realtek.c | 44 +++++++++++++++++------------------ 1 file changed, 21 insertions(+), 23 deletions(-) diff --git a/sound/pci/hda/patch_realtek.c b/sound/pci/hda/patch_realtek.c index 5eee67d443c2..5c594b8b8723 100644 --- a/sound/pci/hda/patch_realtek.c +++ b/sound/pci/hda/patch_realtek.c @@ -8055,35 +8055,18 @@ static const struct snd_pci_quirk alc269_fixup_tbl[] = { SND_PCI_QUIRK(0x103c, 0x1586, "HP", ALC269_FIXUP_HP_MUTE_LED_MIC2), SND_PCI_QUIRK(0x103c, 0x18e6, "HP", ALC269_FIXUP_HP_GPIO_LED), SND_PCI_QUIRK(0x103c, 0x218b, "HP", ALC269_FIXUP_LIMIT_INT_MIC_BOOST_MUTE_LED), - SND_PCI_QUIRK(0x103c, 0x225f, "HP", ALC280_FIXUP_HP_GPIO2_MIC_HOTKEY), - /* ALC282 */ SND_PCI_QUIRK(0x103c, 0x21f9, "HP", ALC269_FIXUP_HP_MUTE_LED_MIC1), SND_PCI_QUIRK(0x103c, 0x2210, "HP", ALC269_FIXUP_HP_MUTE_LED_MIC1), SND_PCI_QUIRK(0x103c, 0x2214, "HP", ALC269_FIXUP_HP_MUTE_LED_MIC1), + SND_PCI_QUIRK(0x103c, 0x221b, "HP", ALC269_FIXUP_HP_GPIO_MIC1_LED), + SND_PCI_QUIRK(0x103c, 0x221c, "HP EliteBook 755 G2", ALC280_FIXUP_HP_HEADSET_MIC), + SND_PCI_QUIRK(0x103c, 0x2221, "HP", ALC269_FIXUP_HP_GPIO_MIC1_LED), + SND_PCI_QUIRK(0x103c, 0x2225, "HP", ALC269_FIXUP_HP_GPIO_MIC1_LED), SND_PCI_QUIRK(0x103c, 0x2236, "HP", ALC269_FIXUP_HP_LINE1_MIC1_LED), SND_PCI_QUIRK(0x103c, 0x2237, "HP", ALC269_FIXUP_HP_LINE1_MIC1_LED), SND_PCI_QUIRK(0x103c, 0x2238, "HP", ALC269_FIXUP_HP_LINE1_MIC1_LED), SND_PCI_QUIRK(0x103c, 0x2239, "HP", ALC269_FIXUP_HP_LINE1_MIC1_LED), SND_PCI_QUIRK(0x103c, 0x224b, "HP", ALC269_FIXUP_HP_LINE1_MIC1_LED), - SND_PCI_QUIRK(0x103c, 0x2268, "HP", ALC269_FIXUP_HP_MUTE_LED_MIC1), - SND_PCI_QUIRK(0x103c, 0x226a, "HP", ALC269_FIXUP_HP_MUTE_LED_MIC1), - SND_PCI_QUIRK(0x103c, 0x226b, "HP", ALC269_FIXUP_HP_MUTE_LED_MIC1), - SND_PCI_QUIRK(0x103c, 0x226e, "HP", ALC269_FIXUP_HP_MUTE_LED_MIC1), - SND_PCI_QUIRK(0x103c, 0x2271, "HP", ALC286_FIXUP_HP_GPIO_LED), - SND_PCI_QUIRK(0x103c, 0x2272, "HP", ALC280_FIXUP_HP_DOCK_PINS), - SND_PCI_QUIRK(0x103c, 0x2273, "HP", ALC280_FIXUP_HP_DOCK_PINS), - SND_PCI_QUIRK(0x103c, 0x229e, "HP", ALC269_FIXUP_HP_MUTE_LED_MIC1), - SND_PCI_QUIRK(0x103c, 0x22b2, "HP", ALC269_FIXUP_HP_MUTE_LED_MIC1), - SND_PCI_QUIRK(0x103c, 0x22b7, "HP", ALC269_FIXUP_HP_MUTE_LED_MIC1), - SND_PCI_QUIRK(0x103c, 0x22bf, "HP", ALC269_FIXUP_HP_MUTE_LED_MIC1), - SND_PCI_QUIRK(0x103c, 0x22cf, "HP", ALC269_FIXUP_HP_MUTE_LED_MIC1), - SND_PCI_QUIRK(0x103c, 0x22db, "HP", ALC280_FIXUP_HP_9480M), - SND_PCI_QUIRK(0x103c, 0x22dc, "HP", ALC269_FIXUP_HP_GPIO_MIC1_LED), - SND_PCI_QUIRK(0x103c, 0x22fb, "HP", ALC269_FIXUP_HP_GPIO_MIC1_LED), - /* ALC290 */ - SND_PCI_QUIRK(0x103c, 0x221b, "HP", ALC269_FIXUP_HP_GPIO_MIC1_LED), - SND_PCI_QUIRK(0x103c, 0x2221, "HP", ALC269_FIXUP_HP_GPIO_MIC1_LED), - SND_PCI_QUIRK(0x103c, 0x2225, "HP", ALC269_FIXUP_HP_GPIO_MIC1_LED), SND_PCI_QUIRK(0x103c, 0x2253, "HP", ALC269_FIXUP_HP_GPIO_MIC1_LED), SND_PCI_QUIRK(0x103c, 0x2254, "HP", ALC269_FIXUP_HP_GPIO_MIC1_LED), SND_PCI_QUIRK(0x103c, 0x2255, "HP", ALC269_FIXUP_HP_GPIO_MIC1_LED), @@ -8091,26 +8074,41 @@ static const struct snd_pci_quirk alc269_fixup_tbl[] = { SND_PCI_QUIRK(0x103c, 0x2257, "HP", ALC269_FIXUP_HP_GPIO_MIC1_LED), SND_PCI_QUIRK(0x103c, 0x2259, "HP", ALC269_FIXUP_HP_GPIO_MIC1_LED), SND_PCI_QUIRK(0x103c, 0x225a, "HP", ALC269_FIXUP_HP_DOCK_GPIO_MIC1_LED), + SND_PCI_QUIRK(0x103c, 0x225f, "HP", ALC280_FIXUP_HP_GPIO2_MIC_HOTKEY), SND_PCI_QUIRK(0x103c, 0x2260, "HP", ALC269_FIXUP_HP_MUTE_LED_MIC1), SND_PCI_QUIRK(0x103c, 0x2263, "HP", ALC269_FIXUP_HP_MUTE_LED_MIC1), SND_PCI_QUIRK(0x103c, 0x2264, "HP", ALC269_FIXUP_HP_MUTE_LED_MIC1), SND_PCI_QUIRK(0x103c, 0x2265, "HP", ALC269_FIXUP_HP_MUTE_LED_MIC1), + SND_PCI_QUIRK(0x103c, 0x2268, "HP", ALC269_FIXUP_HP_MUTE_LED_MIC1), + SND_PCI_QUIRK(0x103c, 0x226a, "HP", ALC269_FIXUP_HP_MUTE_LED_MIC1), + SND_PCI_QUIRK(0x103c, 0x226b, "HP", ALC269_FIXUP_HP_MUTE_LED_MIC1), + SND_PCI_QUIRK(0x103c, 0x226e, "HP", ALC269_FIXUP_HP_MUTE_LED_MIC1), + SND_PCI_QUIRK(0x103c, 0x2271, "HP", ALC286_FIXUP_HP_GPIO_LED), SND_PCI_QUIRK(0x103c, 0x2272, "HP", ALC269_FIXUP_HP_GPIO_MIC1_LED), + SND_PCI_QUIRK(0x103c, 0x2272, "HP", ALC280_FIXUP_HP_DOCK_PINS), SND_PCI_QUIRK(0x103c, 0x2273, "HP", ALC269_FIXUP_HP_GPIO_MIC1_LED), + SND_PCI_QUIRK(0x103c, 0x2273, "HP", ALC280_FIXUP_HP_DOCK_PINS), SND_PCI_QUIRK(0x103c, 0x2278, "HP", ALC269_FIXUP_HP_GPIO_MIC1_LED), SND_PCI_QUIRK(0x103c, 0x227f, "HP", ALC269_FIXUP_HP_MUTE_LED_MIC1), SND_PCI_QUIRK(0x103c, 0x2282, "HP", ALC269_FIXUP_HP_MUTE_LED_MIC1), SND_PCI_QUIRK(0x103c, 0x228b, "HP", ALC269_FIXUP_HP_MUTE_LED_MIC1), SND_PCI_QUIRK(0x103c, 0x228e, "HP", ALC269_FIXUP_HP_MUTE_LED_MIC1), + SND_PCI_QUIRK(0x103c, 0x229e, "HP", ALC269_FIXUP_HP_MUTE_LED_MIC1), + SND_PCI_QUIRK(0x103c, 0x22b2, "HP", ALC269_FIXUP_HP_MUTE_LED_MIC1), + SND_PCI_QUIRK(0x103c, 0x22b7, "HP", ALC269_FIXUP_HP_MUTE_LED_MIC1), + SND_PCI_QUIRK(0x103c, 0x22bf, "HP", ALC269_FIXUP_HP_MUTE_LED_MIC1), + SND_PCI_QUIRK(0x103c, 0x22c4, "HP", ALC269_FIXUP_HP_MUTE_LED_MIC1), SND_PCI_QUIRK(0x103c, 0x22c5, "HP", ALC269_FIXUP_HP_MUTE_LED_MIC1), SND_PCI_QUIRK(0x103c, 0x22c7, "HP", ALC269_FIXUP_HP_MUTE_LED_MIC1), SND_PCI_QUIRK(0x103c, 0x22c8, "HP", ALC269_FIXUP_HP_MUTE_LED_MIC1), - SND_PCI_QUIRK(0x103c, 0x22c4, "HP", ALC269_FIXUP_HP_MUTE_LED_MIC1), + SND_PCI_QUIRK(0x103c, 0x22cf, "HP", ALC269_FIXUP_HP_MUTE_LED_MIC1), + SND_PCI_QUIRK(0x103c, 0x22db, "HP", ALC280_FIXUP_HP_9480M), + SND_PCI_QUIRK(0x103c, 0x22dc, "HP", ALC269_FIXUP_HP_GPIO_MIC1_LED), + SND_PCI_QUIRK(0x103c, 0x22fb, "HP", ALC269_FIXUP_HP_GPIO_MIC1_LED), SND_PCI_QUIRK(0x103c, 0x2334, "HP", ALC269_FIXUP_HP_MUTE_LED_MIC1), SND_PCI_QUIRK(0x103c, 0x2335, "HP", ALC269_FIXUP_HP_MUTE_LED_MIC1), SND_PCI_QUIRK(0x103c, 0x2336, "HP", ALC269_FIXUP_HP_MUTE_LED_MIC1), SND_PCI_QUIRK(0x103c, 0x2337, "HP", ALC269_FIXUP_HP_MUTE_LED_MIC1), - SND_PCI_QUIRK(0x103c, 0x221c, "HP EliteBook 755 G2", ALC280_FIXUP_HP_HEADSET_MIC), SND_PCI_QUIRK(0x103c, 0x802e, "HP Z240 SFF", ALC221_FIXUP_HP_MIC_NO_PRESENCE), SND_PCI_QUIRK(0x103c, 0x802f, "HP Z240", ALC221_FIXUP_HP_MIC_NO_PRESENCE), SND_PCI_QUIRK(0x103c, 0x8077, "HP", ALC256_FIXUP_HP_HEADSET_MIC), From 433f894ec7fbd3b4bf1f3187b2ddd566078c4aef Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Wed, 28 Apr 2021 13:26:56 +0200 Subject: [PATCH 579/587] ALSA: hda/realtek: Re-order ALC269 Acer quirk table entries Just re-order the alc269_fixup_tbl[] entries for Acer devices for avoiding the oversight of the duplicated or unapplied item in future. No functional changes. Also Cc-to-stable for the further patch applications. Cc: Link: https://lore.kernel.org/r/20210428112704.23967-6-tiwai@suse.de Signed-off-by: Takashi Iwai --- sound/pci/hda/patch_realtek.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sound/pci/hda/patch_realtek.c b/sound/pci/hda/patch_realtek.c index 5c594b8b8723..fd7255490635 100644 --- a/sound/pci/hda/patch_realtek.c +++ b/sound/pci/hda/patch_realtek.c @@ -7971,12 +7971,12 @@ static const struct snd_pci_quirk alc269_fixup_tbl[] = { SND_PCI_QUIRK(0x1025, 0x0349, "Acer AOD260", ALC269_FIXUP_INV_DMIC), SND_PCI_QUIRK(0x1025, 0x047c, "Acer AC700", ALC269_FIXUP_ACER_AC700), SND_PCI_QUIRK(0x1025, 0x072d, "Acer Aspire V5-571G", ALC269_FIXUP_ASPIRE_HEADSET_MIC), - SND_PCI_QUIRK(0x1025, 0x080d, "Acer Aspire V5-122P", ALC269_FIXUP_ASPIRE_HEADSET_MIC), SND_PCI_QUIRK(0x1025, 0x0740, "Acer AO725", ALC271_FIXUP_HP_GATE_MIC_JACK), SND_PCI_QUIRK(0x1025, 0x0742, "Acer AO756", ALC271_FIXUP_HP_GATE_MIC_JACK), SND_PCI_QUIRK(0x1025, 0x0762, "Acer Aspire E1-472", ALC271_FIXUP_HP_GATE_MIC_JACK_E1_572), SND_PCI_QUIRK(0x1025, 0x0775, "Acer Aspire E1-572", ALC271_FIXUP_HP_GATE_MIC_JACK_E1_572), SND_PCI_QUIRK(0x1025, 0x079b, "Acer Aspire V5-573G", ALC282_FIXUP_ASPIRE_V5_PINS), + SND_PCI_QUIRK(0x1025, 0x080d, "Acer Aspire V5-122P", ALC269_FIXUP_ASPIRE_HEADSET_MIC), SND_PCI_QUIRK(0x1025, 0x0840, "Acer Aspire E1", ALC269VB_FIXUP_ASPIRE_E1_COEF), SND_PCI_QUIRK(0x1025, 0x101c, "Acer Veriton N2510G", ALC269_FIXUP_LIFEBOOK), SND_PCI_QUIRK(0x1025, 0x102b, "Acer Aspire C24-860", ALC286_FIXUP_ACER_AIO_MIC_NO_PRESENCE), From aa143ad39a52d968ac69e426d329bb74f270e6ca Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Wed, 28 Apr 2021 13:26:57 +0200 Subject: [PATCH 580/587] ALSA: hda/realtek: Re-order ALC269 Dell quirk table entries Just re-order the alc269_fixup_tbl[] entries for Dell devices for avoiding the oversight of the duplicated or unapplied item in future. No functional changes. Also Cc-to-stable for the further patch applications. Cc: Link: https://lore.kernel.org/r/20210428112704.23967-7-tiwai@suse.de Signed-off-by: Takashi Iwai --- sound/pci/hda/patch_realtek.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/sound/pci/hda/patch_realtek.c b/sound/pci/hda/patch_realtek.c index fd7255490635..7e1accdd990f 100644 --- a/sound/pci/hda/patch_realtek.c +++ b/sound/pci/hda/patch_realtek.c @@ -8032,8 +8032,8 @@ static const struct snd_pci_quirk alc269_fixup_tbl[] = { SND_PCI_QUIRK(0x1028, 0x0738, "Dell Precision 5820", ALC269_FIXUP_NO_SHUTUP), SND_PCI_QUIRK(0x1028, 0x075c, "Dell XPS 27 7760", ALC298_FIXUP_SPK_VOLUME), SND_PCI_QUIRK(0x1028, 0x075d, "Dell AIO", ALC298_FIXUP_SPK_VOLUME), - SND_PCI_QUIRK(0x1028, 0x07b0, "Dell Precision 7520", ALC295_FIXUP_DISABLE_DAC3), SND_PCI_QUIRK(0x1028, 0x0798, "Dell Inspiron 17 7000 Gaming", ALC256_FIXUP_DELL_INSPIRON_7559_SUBWOOFER), + SND_PCI_QUIRK(0x1028, 0x07b0, "Dell Precision 7520", ALC295_FIXUP_DISABLE_DAC3), SND_PCI_QUIRK(0x1028, 0x080c, "Dell WYSE", ALC225_FIXUP_DELL_WYSE_MIC_NO_PRESENCE), SND_PCI_QUIRK(0x1028, 0x084b, "Dell", ALC274_FIXUP_DELL_AIO_LINEOUT_VERB), SND_PCI_QUIRK(0x1028, 0x084e, "Dell", ALC274_FIXUP_DELL_AIO_LINEOUT_VERB), @@ -8043,8 +8043,8 @@ static const struct snd_pci_quirk alc269_fixup_tbl[] = { SND_PCI_QUIRK(0x1028, 0x08ad, "Dell WYSE AIO", ALC225_FIXUP_DELL_WYSE_AIO_MIC_NO_PRESENCE), SND_PCI_QUIRK(0x1028, 0x08ae, "Dell WYSE NB", ALC225_FIXUP_DELL1_MIC_NO_PRESENCE), SND_PCI_QUIRK(0x1028, 0x0935, "Dell", ALC274_FIXUP_DELL_AIO_LINEOUT_VERB), - SND_PCI_QUIRK(0x1028, 0x097e, "Dell Precision", ALC289_FIXUP_DUAL_SPK), SND_PCI_QUIRK(0x1028, 0x097d, "Dell Precision", ALC289_FIXUP_DUAL_SPK), + SND_PCI_QUIRK(0x1028, 0x097e, "Dell Precision", ALC289_FIXUP_DUAL_SPK), SND_PCI_QUIRK(0x1028, 0x098d, "Dell Precision", ALC233_FIXUP_ASUS_MIC_NO_PRESENCE), SND_PCI_QUIRK(0x1028, 0x09bf, "Dell Precision", ALC233_FIXUP_ASUS_MIC_NO_PRESENCE), SND_PCI_QUIRK(0x1028, 0x0a2e, "Dell", ALC236_FIXUP_DELL_AIO_HEADSET_MIC), From 3cd0ed636dd19e7fbe3ebe8de8476e1718d5a8f1 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Wed, 28 Apr 2021 13:26:58 +0200 Subject: [PATCH 581/587] ALSA: hda/realtek: Re-order ALC269 ASUS quirk table entries Just re-order the alc269_fixup_tbl[] entries for ASUS devices for avoiding the oversight of the duplicated or unapplied item in future. No functional changes. Also Cc-to-stable for the further patch applications. Cc: Link: https://lore.kernel.org/r/20210428112704.23967-8-tiwai@suse.de Signed-off-by: Takashi Iwai --- sound/pci/hda/patch_realtek.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/sound/pci/hda/patch_realtek.c b/sound/pci/hda/patch_realtek.c index 7e1accdd990f..d99666c706b7 100644 --- a/sound/pci/hda/patch_realtek.c +++ b/sound/pci/hda/patch_realtek.c @@ -8151,16 +8151,18 @@ static const struct snd_pci_quirk alc269_fixup_tbl[] = { SND_PCI_QUIRK(0x1043, 0x10d0, "ASUS X540LA/X540LJ", ALC255_FIXUP_ASUS_MIC_NO_PRESENCE), SND_PCI_QUIRK(0x1043, 0x115d, "Asus 1015E", ALC269_FIXUP_LIMIT_INT_MIC_BOOST), SND_PCI_QUIRK(0x1043, 0x11c0, "ASUS X556UR", ALC255_FIXUP_ASUS_MIC_NO_PRESENCE), + SND_PCI_QUIRK(0x1043, 0x125e, "ASUS Q524UQK", ALC255_FIXUP_ASUS_MIC_NO_PRESENCE), SND_PCI_QUIRK(0x1043, 0x1271, "ASUS X430UN", ALC256_FIXUP_ASUS_MIC_NO_PRESENCE), SND_PCI_QUIRK(0x1043, 0x1290, "ASUS X441SA", ALC233_FIXUP_EAPD_COEF_AND_MIC_NO_PRESENCE), SND_PCI_QUIRK(0x1043, 0x12a0, "ASUS X441UV", ALC233_FIXUP_EAPD_COEF_AND_MIC_NO_PRESENCE), - SND_PCI_QUIRK(0x1043, 0x12f0, "ASUS X541UV", ALC256_FIXUP_ASUS_MIC), SND_PCI_QUIRK(0x1043, 0x12e0, "ASUS X541SA", ALC256_FIXUP_ASUS_MIC), + SND_PCI_QUIRK(0x1043, 0x12f0, "ASUS X541UV", ALC256_FIXUP_ASUS_MIC), SND_PCI_QUIRK(0x1043, 0x13b0, "ASUS Z550SA", ALC256_FIXUP_ASUS_MIC), SND_PCI_QUIRK(0x1043, 0x1427, "Asus Zenbook UX31E", ALC269VB_FIXUP_ASUS_ZENBOOK), SND_PCI_QUIRK(0x1043, 0x1517, "Asus Zenbook UX31A", ALC269VB_FIXUP_ASUS_ZENBOOK_UX31A), SND_PCI_QUIRK(0x1043, 0x16e3, "ASUS UX50", ALC269_FIXUP_STEREO_DMIC), SND_PCI_QUIRK(0x1043, 0x17d1, "ASUS UX431FL", ALC294_FIXUP_ASUS_DUAL_SPK), + SND_PCI_QUIRK(0x1043, 0x1881, "ASUS Zephyrus S/M", ALC294_FIXUP_ASUS_GX502_PINS), SND_PCI_QUIRK(0x1043, 0x18b1, "Asus MJ401TA", ALC256_FIXUP_ASUS_HEADSET_MIC), SND_PCI_QUIRK(0x1043, 0x18f1, "Asus FX505DT", ALC256_FIXUP_ASUS_HEADSET_MIC), SND_PCI_QUIRK(0x1043, 0x194e, "ASUS UX563FD", ALC294_FIXUP_ASUS_HPE), @@ -8173,13 +8175,11 @@ static const struct snd_pci_quirk alc269_fixup_tbl[] = { SND_PCI_QUIRK(0x1043, 0x1b13, "Asus U41SV", ALC269_FIXUP_INV_DMIC), SND_PCI_QUIRK(0x1043, 0x1bbd, "ASUS Z550MA", ALC255_FIXUP_ASUS_MIC_NO_PRESENCE), SND_PCI_QUIRK(0x1043, 0x1c23, "Asus X55U", ALC269_FIXUP_LIMIT_INT_MIC_BOOST), - SND_PCI_QUIRK(0x1043, 0x125e, "ASUS Q524UQK", ALC255_FIXUP_ASUS_MIC_NO_PRESENCE), SND_PCI_QUIRK(0x1043, 0x1ccd, "ASUS X555UB", ALC256_FIXUP_ASUS_MIC), SND_PCI_QUIRK(0x1043, 0x1d4e, "ASUS TM420", ALC256_FIXUP_ASUS_HPE), SND_PCI_QUIRK(0x1043, 0x1e11, "ASUS Zephyrus G15", ALC289_FIXUP_ASUS_GA502), SND_PCI_QUIRK(0x1043, 0x1e8e, "ASUS Zephyrus G15", ALC289_FIXUP_ASUS_GA401), SND_PCI_QUIRK(0x1043, 0x1f11, "ASUS Zephyrus G14", ALC289_FIXUP_ASUS_GA401), - SND_PCI_QUIRK(0x1043, 0x1881, "ASUS Zephyrus S/M", ALC294_FIXUP_ASUS_GX502_PINS), SND_PCI_QUIRK(0x1043, 0x3030, "ASUS ZN270IE", ALC256_FIXUP_ASUS_AIO_GPIO2), SND_PCI_QUIRK(0x1043, 0x831a, "ASUS P901", ALC269_FIXUP_STEREO_DMIC), SND_PCI_QUIRK(0x1043, 0x834a, "ASUS S101", ALC269_FIXUP_STEREO_DMIC), From cab561f8d4bc9b196ae20c960aa5da89fd786ab5 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Wed, 28 Apr 2021 13:26:59 +0200 Subject: [PATCH 582/587] ALSA: hda/realtek: Re-order ALC269 Sony quirk table entries Just re-order the alc269_fixup_tbl[] entries for Sony devices for avoiding the oversight of the duplicated or unapplied item in future. No functional changes. Also Cc-to-stable for the further patch applications. Cc: Link: https://lore.kernel.org/r/20210428112704.23967-9-tiwai@suse.de Signed-off-by: Takashi Iwai --- sound/pci/hda/patch_realtek.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/sound/pci/hda/patch_realtek.c b/sound/pci/hda/patch_realtek.c index d99666c706b7..53967d50d382 100644 --- a/sound/pci/hda/patch_realtek.c +++ b/sound/pci/hda/patch_realtek.c @@ -8186,12 +8186,12 @@ static const struct snd_pci_quirk alc269_fixup_tbl[] = { SND_PCI_QUIRK(0x1043, 0x8398, "ASUS P1005", ALC269_FIXUP_STEREO_DMIC), SND_PCI_QUIRK(0x1043, 0x83ce, "ASUS P1005", ALC269_FIXUP_STEREO_DMIC), SND_PCI_QUIRK(0x1043, 0x8516, "ASUS X101CH", ALC269_FIXUP_ASUS_X101), - SND_PCI_QUIRK(0x104d, 0x90b5, "Sony VAIO Pro 11", ALC286_FIXUP_SONY_MIC_NO_PRESENCE), - SND_PCI_QUIRK(0x104d, 0x90b6, "Sony VAIO Pro 13", ALC286_FIXUP_SONY_MIC_NO_PRESENCE), SND_PCI_QUIRK(0x104d, 0x9073, "Sony VAIO", ALC275_FIXUP_SONY_VAIO_GPIO2), SND_PCI_QUIRK(0x104d, 0x907b, "Sony VAIO", ALC275_FIXUP_SONY_HWEQ), SND_PCI_QUIRK(0x104d, 0x9084, "Sony VAIO", ALC275_FIXUP_SONY_HWEQ), SND_PCI_QUIRK(0x104d, 0x9099, "Sony VAIO S13", ALC275_FIXUP_SONY_DISABLE_AAMIX), + SND_PCI_QUIRK(0x104d, 0x90b5, "Sony VAIO Pro 11", ALC286_FIXUP_SONY_MIC_NO_PRESENCE), + SND_PCI_QUIRK(0x104d, 0x90b6, "Sony VAIO Pro 13", ALC286_FIXUP_SONY_MIC_NO_PRESENCE), SND_PCI_QUIRK(0x10cf, 0x1475, "Lifebook", ALC269_FIXUP_LIFEBOOK), SND_PCI_QUIRK(0x10cf, 0x159f, "Lifebook E780", ALC269_FIXUP_LIFEBOOK_NO_HP_TO_LINEOUT), SND_PCI_QUIRK(0x10cf, 0x15dc, "Lifebook T731", ALC269_FIXUP_LIFEBOOK_HP_PIN), From f552ff54c2a700616a02b038e4bf3cbf859f65b7 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Wed, 28 Apr 2021 13:27:00 +0200 Subject: [PATCH 583/587] ALSA: hda/realtek: Re-order ALC269 Lenovo quirk table entries Just re-order the alc269_fixup_tbl[] entries for Lenovo devices for avoiding the oversight of the duplicated or unapplied item in future. No functional changes. Also Cc-to-stable for the further patch applications. Cc: Link: https://lore.kernel.org/r/20210428112704.23967-10-tiwai@suse.de Signed-off-by: Takashi Iwai --- sound/pci/hda/patch_realtek.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/sound/pci/hda/patch_realtek.c b/sound/pci/hda/patch_realtek.c index 53967d50d382..539bae66a4ba 100644 --- a/sound/pci/hda/patch_realtek.c +++ b/sound/pci/hda/patch_realtek.c @@ -8266,9 +8266,9 @@ static const struct snd_pci_quirk alc269_fixup_tbl[] = { SND_PCI_QUIRK(0x17aa, 0x21b8, "Thinkpad Edge 14", ALC269_FIXUP_SKU_IGNORE), SND_PCI_QUIRK(0x17aa, 0x21ca, "Thinkpad L412", ALC269_FIXUP_SKU_IGNORE), SND_PCI_QUIRK(0x17aa, 0x21e9, "Thinkpad Edge 15", ALC269_FIXUP_SKU_IGNORE), + SND_PCI_QUIRK(0x17aa, 0x21f3, "Thinkpad T430", ALC269_FIXUP_LENOVO_DOCK), SND_PCI_QUIRK(0x17aa, 0x21f6, "Thinkpad T530", ALC269_FIXUP_LENOVO_DOCK_LIMIT_BOOST), SND_PCI_QUIRK(0x17aa, 0x21fa, "Thinkpad X230", ALC269_FIXUP_LENOVO_DOCK), - SND_PCI_QUIRK(0x17aa, 0x21f3, "Thinkpad T430", ALC269_FIXUP_LENOVO_DOCK), SND_PCI_QUIRK(0x17aa, 0x21fb, "Thinkpad T430s", ALC269_FIXUP_LENOVO_DOCK), SND_PCI_QUIRK(0x17aa, 0x2203, "Thinkpad X230 Tablet", ALC269_FIXUP_LENOVO_DOCK), SND_PCI_QUIRK(0x17aa, 0x2208, "Thinkpad T431s", ALC269_FIXUP_LENOVO_DOCK), @@ -8313,6 +8313,7 @@ static const struct snd_pci_quirk alc269_fixup_tbl[] = { SND_PCI_QUIRK(0x17aa, 0x3902, "Lenovo E50-80", ALC269_FIXUP_DMIC_THINKPAD_ACPI), SND_PCI_QUIRK(0x17aa, 0x3977, "IdeaPad S210", ALC283_FIXUP_INT_MIC), SND_PCI_QUIRK(0x17aa, 0x3978, "Lenovo B50-70", ALC269_FIXUP_DMIC_THINKPAD_ACPI), + SND_PCI_QUIRK(0x17aa, 0x3bf8, "Quanta FL1", ALC269_FIXUP_PCM_44K), SND_PCI_QUIRK(0x17aa, 0x5013, "Thinkpad", ALC269_FIXUP_LIMIT_INT_MIC_BOOST), SND_PCI_QUIRK(0x17aa, 0x501a, "Thinkpad", ALC283_FIXUP_INT_MIC), SND_PCI_QUIRK(0x17aa, 0x501e, "Thinkpad L440", ALC292_FIXUP_TPT440_DOCK), @@ -8331,7 +8332,6 @@ static const struct snd_pci_quirk alc269_fixup_tbl[] = { SND_PCI_QUIRK(0x17aa, 0x5109, "Thinkpad", ALC269_FIXUP_LIMIT_INT_MIC_BOOST), SND_PCI_QUIRK(0x17aa, 0x511e, "Thinkpad", ALC298_FIXUP_TPT470_DOCK), SND_PCI_QUIRK(0x17aa, 0x511f, "Thinkpad", ALC298_FIXUP_TPT470_DOCK), - SND_PCI_QUIRK(0x17aa, 0x3bf8, "Quanta FL1", ALC269_FIXUP_PCM_44K), SND_PCI_QUIRK(0x17aa, 0x9e54, "LENOVO NB", ALC269_FIXUP_LENOVO_EAPD), SND_PCI_QUIRK(0x19e5, 0x3204, "Huawei MACH-WX9", ALC256_FIXUP_HUAWEI_MACH_WX9_PINS), SND_PCI_QUIRK(0x1b35, 0x1235, "CZC B20", ALC269_FIXUP_CZC_B20), From c656f747df151a0a89756a5312f4ca2116758ba4 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Wed, 28 Apr 2021 13:27:01 +0200 Subject: [PATCH 584/587] ALSA: hda/realtek: Re-order remaining ALC269 quirk table entries Just re-order the alc269_fixup_tbl[] entries for FSC, Medion, Samsung and Lemote devices for avoiding the oversight of the duplicated or unapplied item in future. No functional changes. Also Cc-to-stable for the further patch applications. Cc: Link: https://lore.kernel.org/r/20210428112704.23967-11-tiwai@suse.de Signed-off-by: Takashi Iwai --- sound/pci/hda/patch_realtek.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/sound/pci/hda/patch_realtek.c b/sound/pci/hda/patch_realtek.c index 539bae66a4ba..11f731b95eef 100644 --- a/sound/pci/hda/patch_realtek.c +++ b/sound/pci/hda/patch_realtek.c @@ -8195,10 +8195,11 @@ static const struct snd_pci_quirk alc269_fixup_tbl[] = { SND_PCI_QUIRK(0x10cf, 0x1475, "Lifebook", ALC269_FIXUP_LIFEBOOK), SND_PCI_QUIRK(0x10cf, 0x159f, "Lifebook E780", ALC269_FIXUP_LIFEBOOK_NO_HP_TO_LINEOUT), SND_PCI_QUIRK(0x10cf, 0x15dc, "Lifebook T731", ALC269_FIXUP_LIFEBOOK_HP_PIN), - SND_PCI_QUIRK(0x10cf, 0x1757, "Lifebook E752", ALC269_FIXUP_LIFEBOOK_HP_PIN), SND_PCI_QUIRK(0x10cf, 0x1629, "Lifebook U7x7", ALC255_FIXUP_LIFEBOOK_U7x7_HEADSET_MIC), + SND_PCI_QUIRK(0x10cf, 0x1757, "Lifebook E752", ALC269_FIXUP_LIFEBOOK_HP_PIN), SND_PCI_QUIRK(0x10cf, 0x1845, "Lifebook U904", ALC269_FIXUP_LIFEBOOK_EXTMIC), SND_PCI_QUIRK(0x10ec, 0x10f2, "Intel Reference board", ALC700_FIXUP_INTEL_REFERENCE), + SND_PCI_QUIRK(0x10ec, 0x118c, "Medion EE4254 MD62100", ALC256_FIXUP_MEDION_HEADSET_NO_PRESENCE), SND_PCI_QUIRK(0x10ec, 0x1230, "Intel Reference board", ALC295_FIXUP_CHROME_BOOK), SND_PCI_QUIRK(0x10ec, 0x1252, "Intel Reference board", ALC295_FIXUP_CHROME_BOOK), SND_PCI_QUIRK(0x10ec, 0x1254, "Intel Reference board", ALC295_FIXUP_CHROME_BOOK), @@ -8208,9 +8209,9 @@ static const struct snd_pci_quirk alc269_fixup_tbl[] = { SND_PCI_QUIRK(0x144d, 0xc176, "Samsung Notebook 9 Pro (NP930MBE-K04US)", ALC298_FIXUP_SAMSUNG_HEADPHONE_VERY_QUIET), SND_PCI_QUIRK(0x144d, 0xc189, "Samsung Galaxy Flex Book (NT950QCG-X716)", ALC298_FIXUP_SAMSUNG_HEADPHONE_VERY_QUIET), SND_PCI_QUIRK(0x144d, 0xc18a, "Samsung Galaxy Book Ion (NP930XCJ-K01US)", ALC298_FIXUP_SAMSUNG_HEADPHONE_VERY_QUIET), - SND_PCI_QUIRK(0x144d, 0xc830, "Samsung Galaxy Book Ion (NT950XCJ-X716A)", ALC298_FIXUP_SAMSUNG_HEADPHONE_VERY_QUIET), SND_PCI_QUIRK(0x144d, 0xc740, "Samsung Ativ book 8 (NP870Z5G)", ALC269_FIXUP_ATIV_BOOK_8), SND_PCI_QUIRK(0x144d, 0xc812, "Samsung Notebook Pen S (NT950SBE-X58)", ALC298_FIXUP_SAMSUNG_HEADPHONE_VERY_QUIET), + SND_PCI_QUIRK(0x144d, 0xc830, "Samsung Galaxy Book Ion (NT950XCJ-X716A)", ALC298_FIXUP_SAMSUNG_HEADPHONE_VERY_QUIET), SND_PCI_QUIRK(0x1458, 0xfa53, "Gigabyte BXBT-2807", ALC283_FIXUP_HEADSET_MIC), SND_PCI_QUIRK(0x1462, 0xb120, "MSI Cubi MS-B120", ALC283_FIXUP_HEADSET_MIC), SND_PCI_QUIRK(0x1462, 0xb171, "Cubi N 8GL (MS-B171)", ALC283_FIXUP_HEADSET_MIC), @@ -8338,13 +8339,12 @@ static const struct snd_pci_quirk alc269_fixup_tbl[] = { SND_PCI_QUIRK(0x1b35, 0x1236, "CZC TMI", ALC269_FIXUP_CZC_TMI), SND_PCI_QUIRK(0x1b35, 0x1237, "CZC L101", ALC269_FIXUP_CZC_L101), SND_PCI_QUIRK(0x1b7d, 0xa831, "Ordissimo EVE2 ", ALC269VB_FIXUP_ORDISSIMO_EVE2), /* Also known as Malata PC-B1303 */ + SND_PCI_QUIRK(0x1c06, 0x2013, "Lemote A1802", ALC269_FIXUP_LEMOTE_A1802), + SND_PCI_QUIRK(0x1c06, 0x2015, "Lemote A190X", ALC269_FIXUP_LEMOTE_A190X), SND_PCI_QUIRK(0x1d72, 0x1602, "RedmiBook", ALC255_FIXUP_XIAOMI_HEADSET_MIC), SND_PCI_QUIRK(0x1d72, 0x1701, "XiaomiNotebook Pro", ALC298_FIXUP_DELL1_MIC_NO_PRESENCE), SND_PCI_QUIRK(0x1d72, 0x1901, "RedmiBook 14", ALC256_FIXUP_ASUS_HEADSET_MIC), SND_PCI_QUIRK(0x1d72, 0x1947, "RedmiBook Air", ALC255_FIXUP_XIAOMI_HEADSET_MIC), - SND_PCI_QUIRK(0x10ec, 0x118c, "Medion EE4254 MD62100", ALC256_FIXUP_MEDION_HEADSET_NO_PRESENCE), - SND_PCI_QUIRK(0x1c06, 0x2013, "Lemote A1802", ALC269_FIXUP_LEMOTE_A1802), - SND_PCI_QUIRK(0x1c06, 0x2015, "Lemote A190X", ALC269_FIXUP_LEMOTE_A190X), SND_PCI_QUIRK(0x8086, 0x2074, "Intel NUC 8", ALC233_FIXUP_INTEL_NUC8_DMIC), SND_PCI_QUIRK(0x8086, 0x2080, "Intel NUC 8 Rugged", ALC256_FIXUP_INTEL_NUC8_RUGGED), SND_PCI_QUIRK(0x8086, 0x2081, "Intel NUC 10", ALC256_FIXUP_INTEL_NUC10), From 9edeb1109d05953b2f0e24e5b2341a98c3fa78d5 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Wed, 28 Apr 2021 13:27:02 +0200 Subject: [PATCH 585/587] ALSA: hda/realtek: Re-order ALC662 quirk table entries Just re-order the alc662_fixup_tbl[] entries for Acer and ASUS devices for avoiding the oversight of the duplicated or unapplied item in future. No functional changes. Also Cc-to-stable for the further patch applications. Cc: Link: https://lore.kernel.org/r/20210428112704.23967-12-tiwai@suse.de Signed-off-by: Takashi Iwai --- sound/pci/hda/patch_realtek.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/sound/pci/hda/patch_realtek.c b/sound/pci/hda/patch_realtek.c index 11f731b95eef..cbed3c610170 100644 --- a/sound/pci/hda/patch_realtek.c +++ b/sound/pci/hda/patch_realtek.c @@ -10086,6 +10086,7 @@ static const struct snd_pci_quirk alc662_fixup_tbl[] = { SND_PCI_QUIRK(0x1025, 0x0349, "eMachines eM250", ALC662_FIXUP_INV_DMIC), SND_PCI_QUIRK(0x1025, 0x034a, "Gateway LT27", ALC662_FIXUP_INV_DMIC), SND_PCI_QUIRK(0x1025, 0x038b, "Acer Aspire 8943G", ALC662_FIXUP_ASPIRE), + SND_PCI_QUIRK(0x1025, 0x0566, "Acer Aspire Ethos 8951G", ALC669_FIXUP_ACER_ASPIRE_ETHOS), SND_PCI_QUIRK(0x1025, 0x123c, "Acer Nitro N50-600", ALC662_FIXUP_ACER_NITRO_HEADSET_MODE), SND_PCI_QUIRK(0x1025, 0x124e, "Acer 2660G", ALC662_FIXUP_ACER_X2660G_HEADSET_MODE), SND_PCI_QUIRK(0x1028, 0x05d8, "Dell", ALC668_FIXUP_DELL_MIC_NO_PRESENCE), @@ -10102,9 +10103,9 @@ static const struct snd_pci_quirk alc662_fixup_tbl[] = { SND_PCI_QUIRK(0x103c, 0x873e, "HP", ALC671_FIXUP_HP_HEADSET_MIC2), SND_PCI_QUIRK(0x1043, 0x1080, "Asus UX501VW", ALC668_FIXUP_HEADSET_MODE), SND_PCI_QUIRK(0x1043, 0x11cd, "Asus N550", ALC662_FIXUP_ASUS_Nx50), - SND_PCI_QUIRK(0x1043, 0x13df, "Asus N550JX", ALC662_FIXUP_BASS_1A), SND_PCI_QUIRK(0x1043, 0x129d, "Asus N750", ALC662_FIXUP_ASUS_Nx50), SND_PCI_QUIRK(0x1043, 0x12ff, "ASUS G751", ALC668_FIXUP_ASUS_G751), + SND_PCI_QUIRK(0x1043, 0x13df, "Asus N550JX", ALC662_FIXUP_BASS_1A), SND_PCI_QUIRK(0x1043, 0x1477, "ASUS N56VZ", ALC662_FIXUP_BASS_MODE4_CHMAP), SND_PCI_QUIRK(0x1043, 0x15a7, "ASUS UX51VZH", ALC662_FIXUP_BASS_16), SND_PCI_QUIRK(0x1043, 0x177d, "ASUS N551", ALC668_FIXUP_ASUS_Nx51), @@ -10124,7 +10125,6 @@ static const struct snd_pci_quirk alc662_fixup_tbl[] = { SND_PCI_QUIRK(0x1b0a, 0x01b8, "ACER Veriton", ALC662_FIXUP_ACER_VERITON), SND_PCI_QUIRK(0x1b35, 0x1234, "CZC ET26", ALC662_FIXUP_CZC_ET26), SND_PCI_QUIRK(0x1b35, 0x2206, "CZC P10T", ALC662_FIXUP_CZC_P10T), - SND_PCI_QUIRK(0x1025, 0x0566, "Acer Aspire Ethos 8951G", ALC669_FIXUP_ACER_ASPIRE_ETHOS), #if 0 /* Below is a quirk table taken from the old code. From defce244b01ee12534910a4544e11be5eb927d25 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Wed, 28 Apr 2021 13:27:03 +0200 Subject: [PATCH 586/587] ALSA: hda/realtek: Remove redundant entry for ALC861 Haier/Uniwill devices The quirk entry for Uniwill ECS M31EI is with the PCI SSID device 0, which means matching with all. That is, it's essentially equivalent with SND_PCI_QUIRK_VENDOR(0x1584), which also matches with the previous entry for Haier W18 applying the very same quirk. Let's unify them with the single vendor-quirk entry. Cc: Link: https://lore.kernel.org/r/20210428112704.23967-13-tiwai@suse.de Signed-off-by: Takashi Iwai --- sound/pci/hda/patch_realtek.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/sound/pci/hda/patch_realtek.c b/sound/pci/hda/patch_realtek.c index cbed3c610170..bd7bfd7c9ee7 100644 --- a/sound/pci/hda/patch_realtek.c +++ b/sound/pci/hda/patch_realtek.c @@ -9290,8 +9290,7 @@ static const struct snd_pci_quirk alc861_fixup_tbl[] = { SND_PCI_QUIRK(0x1043, 0x1393, "ASUS A6Rp", ALC861_FIXUP_ASUS_A6RP), SND_PCI_QUIRK_VENDOR(0x1043, "ASUS laptop", ALC861_FIXUP_AMP_VREF_0F), SND_PCI_QUIRK(0x1462, 0x7254, "HP DX2200", ALC861_FIXUP_NO_JACK_DETECT), - SND_PCI_QUIRK(0x1584, 0x2b01, "Haier W18", ALC861_FIXUP_AMP_VREF_0F), - SND_PCI_QUIRK(0x1584, 0x0000, "Uniwill ECS M31EI", ALC861_FIXUP_AMP_VREF_0F), + SND_PCI_QUIRK_VENDOR(0x1584, "Haier/Uniwill", ALC861_FIXUP_AMP_VREF_0F), SND_PCI_QUIRK(0x1734, 0x10c7, "FSC Amilo Pi1505", ALC861_FIXUP_FSC_AMILO_PI1505), {} }; From 2e6a731296be9d356fdccee9fb6ae345dad96438 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Wed, 28 Apr 2021 13:27:04 +0200 Subject: [PATCH 587/587] ALSA: hda/conexant: Re-order CX5066 quirk table entries Just re-order the cx5066_fixups[] entries for HP devices for avoiding the oversight of the duplicated or unapplied item in future. No functional changes. Also Cc-to-stable for the further patch applications. Cc: Link: https://lore.kernel.org/r/20210428112704.23967-14-tiwai@suse.de Signed-off-by: Takashi Iwai --- sound/pci/hda/patch_conexant.c | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/sound/pci/hda/patch_conexant.c b/sound/pci/hda/patch_conexant.c index dfef9c17e140..d111258c6f45 100644 --- a/sound/pci/hda/patch_conexant.c +++ b/sound/pci/hda/patch_conexant.c @@ -930,18 +930,18 @@ static const struct snd_pci_quirk cxt5066_fixups[] = { SND_PCI_QUIRK(0x103c, 0x8079, "HP EliteBook 840 G3", CXT_FIXUP_HP_DOCK), SND_PCI_QUIRK(0x103c, 0x807C, "HP EliteBook 820 G3", CXT_FIXUP_HP_DOCK), SND_PCI_QUIRK(0x103c, 0x80FD, "HP ProBook 640 G2", CXT_FIXUP_HP_DOCK), + SND_PCI_QUIRK(0x103c, 0x8115, "HP Z1 Gen3", CXT_FIXUP_HP_GATE_MIC), + SND_PCI_QUIRK(0x103c, 0x814f, "HP ZBook 15u G3", CXT_FIXUP_MUTE_LED_GPIO), + SND_PCI_QUIRK(0x103c, 0x8174, "HP Spectre x360", CXT_FIXUP_HP_SPECTRE), + SND_PCI_QUIRK(0x103c, 0x822e, "HP ProBook 440 G4", CXT_FIXUP_MUTE_LED_GPIO), SND_PCI_QUIRK(0x103c, 0x828c, "HP EliteBook 840 G4", CXT_FIXUP_HP_DOCK), + SND_PCI_QUIRK(0x103c, 0x8299, "HP 800 G3 SFF", CXT_FIXUP_HP_MIC_NO_PRESENCE), + SND_PCI_QUIRK(0x103c, 0x829a, "HP 800 G3 DM", CXT_FIXUP_HP_MIC_NO_PRESENCE), + SND_PCI_QUIRK(0x103c, 0x836e, "HP ProBook 455 G5", CXT_FIXUP_MUTE_LED_GPIO), + SND_PCI_QUIRK(0x103c, 0x837f, "HP ProBook 470 G5", CXT_FIXUP_MUTE_LED_GPIO), SND_PCI_QUIRK(0x103c, 0x83b2, "HP EliteBook 840 G5", CXT_FIXUP_HP_DOCK), SND_PCI_QUIRK(0x103c, 0x83b3, "HP EliteBook 830 G5", CXT_FIXUP_HP_DOCK), SND_PCI_QUIRK(0x103c, 0x83d3, "HP ProBook 640 G4", CXT_FIXUP_HP_DOCK), - SND_PCI_QUIRK(0x103c, 0x8174, "HP Spectre x360", CXT_FIXUP_HP_SPECTRE), - SND_PCI_QUIRK(0x103c, 0x8115, "HP Z1 Gen3", CXT_FIXUP_HP_GATE_MIC), - SND_PCI_QUIRK(0x103c, 0x814f, "HP ZBook 15u G3", CXT_FIXUP_MUTE_LED_GPIO), - SND_PCI_QUIRK(0x103c, 0x822e, "HP ProBook 440 G4", CXT_FIXUP_MUTE_LED_GPIO), - SND_PCI_QUIRK(0x103c, 0x836e, "HP ProBook 455 G5", CXT_FIXUP_MUTE_LED_GPIO), - SND_PCI_QUIRK(0x103c, 0x837f, "HP ProBook 470 G5", CXT_FIXUP_MUTE_LED_GPIO), - SND_PCI_QUIRK(0x103c, 0x8299, "HP 800 G3 SFF", CXT_FIXUP_HP_MIC_NO_PRESENCE), - SND_PCI_QUIRK(0x103c, 0x829a, "HP 800 G3 DM", CXT_FIXUP_HP_MIC_NO_PRESENCE), SND_PCI_QUIRK(0x103c, 0x8402, "HP ProBook 645 G4", CXT_FIXUP_MUTE_LED_GPIO), SND_PCI_QUIRK(0x103c, 0x8427, "HP ZBook Studio G5", CXT_FIXUP_HP_ZBOOK_MUTE_LED), SND_PCI_QUIRK(0x103c, 0x844f, "HP ZBook Studio G5", CXT_FIXUP_HP_ZBOOK_MUTE_LED),