diff options
author | Otavio Salvador <otavio@ossystems.com.br> | 2017-12-13 18:16:19 -0200 |
---|---|---|
committer | Marcel Ziswiler <marcel.ziswiler@toradex.com> | 2017-12-21 15:01:33 +0100 |
commit | fb2d2dee504a963efdcb76517b5cdf25444cf535 (patch) | |
tree | f1b58594ba11c6c41c3acddde35890f68c42ea9e /sound/soc | |
parent | effee16e4c0cc8b570d372e33633e9f9bc8359c7 (diff) | |
parent | d9f7e5584f0e3e34a2c14825657a6b31e7184171 (diff) |
Merge pull request #21 from falstaff84/4.9-1.0.x-imx-fixes-stable-merge
4.9-1.0.x-imx stable 4.9.67 merge
Diffstat (limited to 'sound/soc')
31 files changed, 485 insertions, 139 deletions
diff --git a/sound/soc/atmel/atmel-classd.c b/sound/soc/atmel/atmel-classd.c index 89ac5f5a93eb..7ae46c2647d4 100644 --- a/sound/soc/atmel/atmel-classd.c +++ b/sound/soc/atmel/atmel-classd.c @@ -349,7 +349,7 @@ static int atmel_classd_codec_dai_digital_mute(struct snd_soc_dai *codec_dai, } #define CLASSD_ACLK_RATE_11M2896_MPY_8 (112896 * 100 * 8) -#define CLASSD_ACLK_RATE_12M288_MPY_8 (12228 * 1000 * 8) +#define CLASSD_ACLK_RATE_12M288_MPY_8 (12288 * 1000 * 8) static struct { int rate; diff --git a/sound/soc/codecs/adau17x1.c b/sound/soc/codecs/adau17x1.c index 439aa3ff1f99..79dcb1e34baa 100644 --- a/sound/soc/codecs/adau17x1.c +++ b/sound/soc/codecs/adau17x1.c @@ -91,6 +91,27 @@ static int adau17x1_pll_event(struct snd_soc_dapm_widget *w, return 0; } +static int adau17x1_adc_fixup(struct snd_soc_dapm_widget *w, + struct snd_kcontrol *kcontrol, int event) +{ + struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm); + struct adau *adau = snd_soc_codec_get_drvdata(codec); + + /* + * If we are capturing, toggle the ADOSR bit in Converter Control 0 to + * avoid losing SNR (workaround from ADI). This must be done after + * the ADC(s) have been enabled. According to the data sheet, it is + * normally illegal to set this bit when the sampling rate is 96 kHz, + * but according to ADI it is acceptable for this workaround. + */ + regmap_update_bits(adau->regmap, ADAU17X1_CONVERTER0, + ADAU17X1_CONVERTER0_ADOSR, ADAU17X1_CONVERTER0_ADOSR); + regmap_update_bits(adau->regmap, ADAU17X1_CONVERTER0, + ADAU17X1_CONVERTER0_ADOSR, 0); + + return 0; +} + static const char * const adau17x1_mono_stereo_text[] = { "Stereo", "Mono Left Channel (L+R)", @@ -122,7 +143,8 @@ static const struct snd_soc_dapm_widget adau17x1_dapm_widgets[] = { SND_SOC_DAPM_MUX("Right DAC Mode Mux", SND_SOC_NOPM, 0, 0, &adau17x1_dac_mode_mux), - SND_SOC_DAPM_ADC("Left Decimator", NULL, ADAU17X1_ADC_CONTROL, 0, 0), + SND_SOC_DAPM_ADC_E("Left Decimator", NULL, ADAU17X1_ADC_CONTROL, 0, 0, + adau17x1_adc_fixup, SND_SOC_DAPM_POST_PMU), SND_SOC_DAPM_ADC("Right Decimator", NULL, ADAU17X1_ADC_CONTROL, 1, 0), SND_SOC_DAPM_DAC("Left DAC", NULL, ADAU17X1_DAC_CONTROL0, 0, 0), SND_SOC_DAPM_DAC("Right DAC", NULL, ADAU17X1_DAC_CONTROL0, 1, 0), diff --git a/sound/soc/codecs/adau17x1.h b/sound/soc/codecs/adau17x1.h index bf04b7efee40..db350035fad7 100644 --- a/sound/soc/codecs/adau17x1.h +++ b/sound/soc/codecs/adau17x1.h @@ -129,5 +129,7 @@ bool adau17x1_has_dsp(struct adau *adau); #define ADAU17X1_CONVERTER0_CONVSR_MASK 0x7 +#define ADAU17X1_CONVERTER0_ADOSR BIT(3) + #endif diff --git a/sound/soc/codecs/cs4271.c b/sound/soc/codecs/cs4271.c index 8c0f3b89b5bc..e78b5f055f25 100644 --- a/sound/soc/codecs/cs4271.c +++ b/sound/soc/codecs/cs4271.c @@ -498,7 +498,7 @@ static int cs4271_reset(struct snd_soc_codec *codec) struct cs4271_private *cs4271 = snd_soc_codec_get_drvdata(codec); if (gpio_is_valid(cs4271->gpio_nreset)) { - gpio_set_value(cs4271->gpio_nreset, 0); + gpio_direction_output(cs4271->gpio_nreset, 0); mdelay(1); gpio_set_value(cs4271->gpio_nreset, 1); mdelay(1); diff --git a/sound/soc/codecs/nau8825.c b/sound/soc/codecs/nau8825.c index e643be91d762..f9f2737c4ad2 100644 --- a/sound/soc/codecs/nau8825.c +++ b/sound/soc/codecs/nau8825.c @@ -1928,7 +1928,8 @@ static void nau8825_fll_apply(struct nau8825 *nau8825, NAU8825_FLL_INTEGER_MASK, fll_param->fll_int); /* FLL pre-scaler */ regmap_update_bits(nau8825->regmap, NAU8825_REG_FLL4, - NAU8825_FLL_REF_DIV_MASK, fll_param->clk_ref_div); + NAU8825_FLL_REF_DIV_MASK, + fll_param->clk_ref_div << NAU8825_FLL_REF_DIV_SFT); /* select divided VCO input */ regmap_update_bits(nau8825->regmap, NAU8825_REG_FLL5, NAU8825_FLL_CLK_SW_MASK, NAU8825_FLL_CLK_SW_REF); diff --git a/sound/soc/codecs/nau8825.h b/sound/soc/codecs/nau8825.h index 1c63e2abafa9..574d6f936135 100644 --- a/sound/soc/codecs/nau8825.h +++ b/sound/soc/codecs/nau8825.h @@ -129,7 +129,8 @@ #define NAU8825_FLL_CLK_SRC_FS (0x3 << NAU8825_FLL_CLK_SRC_SFT) /* FLL4 (0x07) */ -#define NAU8825_FLL_REF_DIV_MASK (0x3 << 10) +#define NAU8825_FLL_REF_DIV_SFT 10 +#define NAU8825_FLL_REF_DIV_MASK (0x3 << NAU8825_FLL_REF_DIV_SFT) /* FLL5 (0x08) */ #define NAU8825_FLL_PDB_DAC_EN (0x1 << 15) diff --git a/sound/soc/codecs/rt286.c b/sound/soc/codecs/rt286.c index 9c365a7f758d..7899a2cdeb42 100644 --- a/sound/soc/codecs/rt286.c +++ b/sound/soc/codecs/rt286.c @@ -1108,6 +1108,13 @@ static const struct dmi_system_id force_combo_jack_table[] = { DMI_MATCH(DMI_PRODUCT_NAME, "Kabylake Client platform") } }, + { + .ident = "Thinkpad Helix 2nd", + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"), + DMI_MATCH(DMI_PRODUCT_VERSION, "ThinkPad Helix 2nd") + } + }, { } }; diff --git a/sound/soc/codecs/rt5514.c b/sound/soc/codecs/rt5514.c index f24b7cfd3a89..e024800213f5 100644 --- a/sound/soc/codecs/rt5514.c +++ b/sound/soc/codecs/rt5514.c @@ -395,14 +395,14 @@ static const char * const rt5514_dmic_src[] = { "DMIC1", "DMIC2" }; -static const SOC_ENUM_SINGLE_DECL( +static SOC_ENUM_SINGLE_DECL( rt5514_stereo1_dmic_enum, RT5514_DIG_SOURCE_CTRL, RT5514_AD0_DMIC_INPUT_SEL_SFT, rt5514_dmic_src); static const struct snd_kcontrol_new rt5514_sto1_dmic_mux = SOC_DAPM_ENUM("Stereo1 DMIC Source", rt5514_stereo1_dmic_enum); -static const SOC_ENUM_SINGLE_DECL( +static SOC_ENUM_SINGLE_DECL( rt5514_stereo2_dmic_enum, RT5514_DIG_SOURCE_CTRL, RT5514_AD1_DMIC_INPUT_SEL_SFT, rt5514_dmic_src); diff --git a/sound/soc/codecs/rt5645.c b/sound/soc/codecs/rt5645.c index 10c2a564a715..1ac96ef9ee20 100644 --- a/sound/soc/codecs/rt5645.c +++ b/sound/soc/codecs/rt5645.c @@ -3833,6 +3833,9 @@ static int rt5645_i2c_probe(struct i2c_client *i2c, } } + regmap_update_bits(rt5645->regmap, RT5645_ADDA_CLK1, + RT5645_I2S_PD1_MASK, RT5645_I2S_PD1_2); + if (rt5645->pdata.jd_invert) { regmap_update_bits(rt5645->regmap, RT5645_IRQ_CTRL2, RT5645_JD_1_1_MASK, RT5645_JD_1_1_INV); diff --git a/sound/soc/codecs/rt5659.c b/sound/soc/codecs/rt5659.c index db54550aed60..635818fcda00 100644 --- a/sound/soc/codecs/rt5659.c +++ b/sound/soc/codecs/rt5659.c @@ -1150,28 +1150,28 @@ static const char * const rt5659_data_select[] = { "L/R", "R/L", "L/L", "R/R" }; -static const SOC_ENUM_SINGLE_DECL(rt5659_if1_01_adc_enum, +static SOC_ENUM_SINGLE_DECL(rt5659_if1_01_adc_enum, RT5659_TDM_CTRL_2, RT5659_DS_ADC_SLOT01_SFT, rt5659_data_select); -static const SOC_ENUM_SINGLE_DECL(rt5659_if1_23_adc_enum, +static SOC_ENUM_SINGLE_DECL(rt5659_if1_23_adc_enum, RT5659_TDM_CTRL_2, RT5659_DS_ADC_SLOT23_SFT, rt5659_data_select); -static const SOC_ENUM_SINGLE_DECL(rt5659_if1_45_adc_enum, +static SOC_ENUM_SINGLE_DECL(rt5659_if1_45_adc_enum, RT5659_TDM_CTRL_2, RT5659_DS_ADC_SLOT45_SFT, rt5659_data_select); -static const SOC_ENUM_SINGLE_DECL(rt5659_if1_67_adc_enum, +static SOC_ENUM_SINGLE_DECL(rt5659_if1_67_adc_enum, RT5659_TDM_CTRL_2, RT5659_DS_ADC_SLOT67_SFT, rt5659_data_select); -static const SOC_ENUM_SINGLE_DECL(rt5659_if2_dac_enum, +static SOC_ENUM_SINGLE_DECL(rt5659_if2_dac_enum, RT5659_DIG_INF23_DATA, RT5659_IF2_DAC_SEL_SFT, rt5659_data_select); -static const SOC_ENUM_SINGLE_DECL(rt5659_if2_adc_enum, +static SOC_ENUM_SINGLE_DECL(rt5659_if2_adc_enum, RT5659_DIG_INF23_DATA, RT5659_IF2_ADC_SEL_SFT, rt5659_data_select); -static const SOC_ENUM_SINGLE_DECL(rt5659_if3_dac_enum, +static SOC_ENUM_SINGLE_DECL(rt5659_if3_dac_enum, RT5659_DIG_INF23_DATA, RT5659_IF3_DAC_SEL_SFT, rt5659_data_select); -static const SOC_ENUM_SINGLE_DECL(rt5659_if3_adc_enum, +static SOC_ENUM_SINGLE_DECL(rt5659_if3_adc_enum, RT5659_DIG_INF23_DATA, RT5659_IF3_ADC_SEL_SFT, rt5659_data_select); static const struct snd_kcontrol_new rt5659_if1_01_adc_swap_mux = @@ -1207,31 +1207,31 @@ static unsigned int rt5659_asrc_clk_map_values[] = { 0, 1, 2, 3, 5, 6, }; -static const SOC_VALUE_ENUM_SINGLE_DECL( +static SOC_VALUE_ENUM_SINGLE_DECL( rt5659_da_sto_asrc_enum, RT5659_ASRC_2, RT5659_DA_STO_T_SFT, 0x7, rt5659_asrc_clk_src, rt5659_asrc_clk_map_values); -static const SOC_VALUE_ENUM_SINGLE_DECL( +static SOC_VALUE_ENUM_SINGLE_DECL( rt5659_da_monol_asrc_enum, RT5659_ASRC_2, RT5659_DA_MONO_L_T_SFT, 0x7, rt5659_asrc_clk_src, rt5659_asrc_clk_map_values); -static const SOC_VALUE_ENUM_SINGLE_DECL( +static SOC_VALUE_ENUM_SINGLE_DECL( rt5659_da_monor_asrc_enum, RT5659_ASRC_2, RT5659_DA_MONO_R_T_SFT, 0x7, rt5659_asrc_clk_src, rt5659_asrc_clk_map_values); -static const SOC_VALUE_ENUM_SINGLE_DECL( +static SOC_VALUE_ENUM_SINGLE_DECL( rt5659_ad_sto1_asrc_enum, RT5659_ASRC_2, RT5659_AD_STO1_T_SFT, 0x7, rt5659_asrc_clk_src, rt5659_asrc_clk_map_values); -static const SOC_VALUE_ENUM_SINGLE_DECL( +static SOC_VALUE_ENUM_SINGLE_DECL( rt5659_ad_sto2_asrc_enum, RT5659_ASRC_3, RT5659_AD_STO2_T_SFT, 0x7, rt5659_asrc_clk_src, rt5659_asrc_clk_map_values); -static const SOC_VALUE_ENUM_SINGLE_DECL( +static SOC_VALUE_ENUM_SINGLE_DECL( rt5659_ad_monol_asrc_enum, RT5659_ASRC_3, RT5659_AD_MONO_L_T_SFT, 0x7, rt5659_asrc_clk_src, rt5659_asrc_clk_map_values); -static const SOC_VALUE_ENUM_SINGLE_DECL( +static SOC_VALUE_ENUM_SINGLE_DECL( rt5659_ad_monor_asrc_enum, RT5659_ASRC_3, RT5659_AD_MONO_R_T_SFT, 0x7, rt5659_asrc_clk_src, rt5659_asrc_clk_map_values); @@ -1930,14 +1930,14 @@ static const char * const rt5659_dac2_src[] = { "IF1 DAC2", "IF2 DAC", "IF3 DAC", "Mono ADC MIX" }; -static const SOC_ENUM_SINGLE_DECL( +static SOC_ENUM_SINGLE_DECL( rt5659_dac_l2_enum, RT5659_DAC_CTRL, RT5659_DAC_L2_SEL_SFT, rt5659_dac2_src); static const struct snd_kcontrol_new rt5659_dac_l2_mux = SOC_DAPM_ENUM("DAC L2 Source", rt5659_dac_l2_enum); -static const SOC_ENUM_SINGLE_DECL( +static SOC_ENUM_SINGLE_DECL( rt5659_dac_r2_enum, RT5659_DAC_CTRL, RT5659_DAC_R2_SEL_SFT, rt5659_dac2_src); @@ -1951,7 +1951,7 @@ static const char * const rt5659_sto1_adc1_src[] = { "DAC MIX", "ADC" }; -static const SOC_ENUM_SINGLE_DECL( +static SOC_ENUM_SINGLE_DECL( rt5659_sto1_adc1_enum, RT5659_STO1_ADC_MIXER, RT5659_STO1_ADC1_SRC_SFT, rt5659_sto1_adc1_src); @@ -1964,7 +1964,7 @@ static const char * const rt5659_sto1_adc_src[] = { "ADC1", "ADC2" }; -static const SOC_ENUM_SINGLE_DECL( +static SOC_ENUM_SINGLE_DECL( rt5659_sto1_adc_enum, RT5659_STO1_ADC_MIXER, RT5659_STO1_ADC_SRC_SFT, rt5659_sto1_adc_src); @@ -1977,7 +1977,7 @@ static const char * const rt5659_sto1_adc2_src[] = { "DAC MIX", "DMIC" }; -static const SOC_ENUM_SINGLE_DECL( +static SOC_ENUM_SINGLE_DECL( rt5659_sto1_adc2_enum, RT5659_STO1_ADC_MIXER, RT5659_STO1_ADC2_SRC_SFT, rt5659_sto1_adc2_src); @@ -1990,7 +1990,7 @@ static const char * const rt5659_sto1_dmic_src[] = { "DMIC1", "DMIC2" }; -static const SOC_ENUM_SINGLE_DECL( +static SOC_ENUM_SINGLE_DECL( rt5659_sto1_dmic_enum, RT5659_STO1_ADC_MIXER, RT5659_STO1_DMIC_SRC_SFT, rt5659_sto1_dmic_src); @@ -2004,7 +2004,7 @@ static const char * const rt5659_mono_adc_l2_src[] = { "Mono DAC MIXL", "DMIC" }; -static const SOC_ENUM_SINGLE_DECL( +static SOC_ENUM_SINGLE_DECL( rt5659_mono_adc_l2_enum, RT5659_MONO_ADC_MIXER, RT5659_MONO_ADC_L2_SRC_SFT, rt5659_mono_adc_l2_src); @@ -2018,7 +2018,7 @@ static const char * const rt5659_mono_adc_l1_src[] = { "Mono DAC MIXL", "ADC" }; -static const SOC_ENUM_SINGLE_DECL( +static SOC_ENUM_SINGLE_DECL( rt5659_mono_adc_l1_enum, RT5659_MONO_ADC_MIXER, RT5659_MONO_ADC_L1_SRC_SFT, rt5659_mono_adc_l1_src); @@ -2031,14 +2031,14 @@ static const char * const rt5659_mono_adc_src[] = { "ADC1 L", "ADC1 R", "ADC2 L", "ADC2 R" }; -static const SOC_ENUM_SINGLE_DECL( +static SOC_ENUM_SINGLE_DECL( rt5659_mono_adc_l_enum, RT5659_MONO_ADC_MIXER, RT5659_MONO_ADC_L_SRC_SFT, rt5659_mono_adc_src); static const struct snd_kcontrol_new rt5659_mono_adc_l_mux = SOC_DAPM_ENUM("Mono ADC L Source", rt5659_mono_adc_l_enum); -static const SOC_ENUM_SINGLE_DECL( +static SOC_ENUM_SINGLE_DECL( rt5659_mono_adcr_enum, RT5659_MONO_ADC_MIXER, RT5659_MONO_ADC_R_SRC_SFT, rt5659_mono_adc_src); @@ -2051,7 +2051,7 @@ static const char * const rt5659_mono_dmic_l_src[] = { "DMIC1 L", "DMIC2 L" }; -static const SOC_ENUM_SINGLE_DECL( +static SOC_ENUM_SINGLE_DECL( rt5659_mono_dmic_l_enum, RT5659_MONO_ADC_MIXER, RT5659_MONO_DMIC_L_SRC_SFT, rt5659_mono_dmic_l_src); @@ -2064,7 +2064,7 @@ static const char * const rt5659_mono_adc_r2_src[] = { "Mono DAC MIXR", "DMIC" }; -static const SOC_ENUM_SINGLE_DECL( +static SOC_ENUM_SINGLE_DECL( rt5659_mono_adc_r2_enum, RT5659_MONO_ADC_MIXER, RT5659_MONO_ADC_R2_SRC_SFT, rt5659_mono_adc_r2_src); @@ -2077,7 +2077,7 @@ static const char * const rt5659_mono_adc_r1_src[] = { "Mono DAC MIXR", "ADC" }; -static const SOC_ENUM_SINGLE_DECL( +static SOC_ENUM_SINGLE_DECL( rt5659_mono_adc_r1_enum, RT5659_MONO_ADC_MIXER, RT5659_MONO_ADC_R1_SRC_SFT, rt5659_mono_adc_r1_src); @@ -2090,7 +2090,7 @@ static const char * const rt5659_mono_dmic_r_src[] = { "DMIC1 R", "DMIC2 R" }; -static const SOC_ENUM_SINGLE_DECL( +static SOC_ENUM_SINGLE_DECL( rt5659_mono_dmic_r_enum, RT5659_MONO_ADC_MIXER, RT5659_MONO_DMIC_R_SRC_SFT, rt5659_mono_dmic_r_src); @@ -2104,14 +2104,14 @@ static const char * const rt5659_dac1_src[] = { "IF1 DAC1", "IF2 DAC", "IF3 DAC" }; -static const SOC_ENUM_SINGLE_DECL( +static SOC_ENUM_SINGLE_DECL( rt5659_dac_r1_enum, RT5659_AD_DA_MIXER, RT5659_DAC1_R_SEL_SFT, rt5659_dac1_src); static const struct snd_kcontrol_new rt5659_dac_r1_mux = SOC_DAPM_ENUM("DAC R1 Source", rt5659_dac_r1_enum); -static const SOC_ENUM_SINGLE_DECL( +static SOC_ENUM_SINGLE_DECL( rt5659_dac_l1_enum, RT5659_AD_DA_MIXER, RT5659_DAC1_L_SEL_SFT, rt5659_dac1_src); @@ -2124,14 +2124,14 @@ static const char * const rt5659_dig_dac_mix_src[] = { "Stereo DAC Mixer", "Mono DAC Mixer" }; -static const SOC_ENUM_SINGLE_DECL( +static SOC_ENUM_SINGLE_DECL( rt5659_dig_dac_mixl_enum, RT5659_DIG_MIXER, RT5659_DAC_MIX_L_SFT, rt5659_dig_dac_mix_src); static const struct snd_kcontrol_new rt5659_dig_dac_mixl_mux = SOC_DAPM_ENUM("DAC Digital Mixer L Source", rt5659_dig_dac_mixl_enum); -static const SOC_ENUM_SINGLE_DECL( +static SOC_ENUM_SINGLE_DECL( rt5659_dig_dac_mixr_enum, RT5659_DIG_MIXER, RT5659_DAC_MIX_R_SFT, rt5659_dig_dac_mix_src); @@ -2144,14 +2144,14 @@ static const char * const rt5659_alg_dac1_src[] = { "DAC", "Stereo DAC Mixer" }; -static const SOC_ENUM_SINGLE_DECL( +static SOC_ENUM_SINGLE_DECL( rt5659_alg_dac_l1_enum, RT5659_A_DAC_MUX, RT5659_A_DACL1_SFT, rt5659_alg_dac1_src); static const struct snd_kcontrol_new rt5659_alg_dac_l1_mux = SOC_DAPM_ENUM("Analog DACL1 Source", rt5659_alg_dac_l1_enum); -static const SOC_ENUM_SINGLE_DECL( +static SOC_ENUM_SINGLE_DECL( rt5659_alg_dac_r1_enum, RT5659_A_DAC_MUX, RT5659_A_DACR1_SFT, rt5659_alg_dac1_src); @@ -2164,14 +2164,14 @@ static const char * const rt5659_alg_dac2_src[] = { "Stereo DAC Mixer", "Mono DAC Mixer" }; -static const SOC_ENUM_SINGLE_DECL( +static SOC_ENUM_SINGLE_DECL( rt5659_alg_dac_l2_enum, RT5659_A_DAC_MUX, RT5659_A_DACL2_SFT, rt5659_alg_dac2_src); static const struct snd_kcontrol_new rt5659_alg_dac_l2_mux = SOC_DAPM_ENUM("Analog DAC L2 Source", rt5659_alg_dac_l2_enum); -static const SOC_ENUM_SINGLE_DECL( +static SOC_ENUM_SINGLE_DECL( rt5659_alg_dac_r2_enum, RT5659_A_DAC_MUX, RT5659_A_DACR2_SFT, rt5659_alg_dac2_src); @@ -2184,7 +2184,7 @@ static const char * const rt5659_if2_adc_in_src[] = { "IF_ADC1", "IF_ADC2", "DAC_REF", "IF_ADC3" }; -static const SOC_ENUM_SINGLE_DECL( +static SOC_ENUM_SINGLE_DECL( rt5659_if2_adc_in_enum, RT5659_DIG_INF23_DATA, RT5659_IF2_ADC_IN_SFT, rt5659_if2_adc_in_src); @@ -2197,7 +2197,7 @@ static const char * const rt5659_if3_adc_in_src[] = { "IF_ADC1", "IF_ADC2", "DAC_REF", "Stereo2_ADC_L/R" }; -static const SOC_ENUM_SINGLE_DECL( +static SOC_ENUM_SINGLE_DECL( rt5659_if3_adc_in_enum, RT5659_DIG_INF23_DATA, RT5659_IF3_ADC_IN_SFT, rt5659_if3_adc_in_src); @@ -2210,14 +2210,14 @@ static const char * const rt5659_pdm_src[] = { "Mono DAC", "Stereo DAC" }; -static const SOC_ENUM_SINGLE_DECL( +static SOC_ENUM_SINGLE_DECL( rt5659_pdm_l_enum, RT5659_PDM_OUT_CTRL, RT5659_PDM1_L_SFT, rt5659_pdm_src); static const struct snd_kcontrol_new rt5659_pdm_l_mux = SOC_DAPM_ENUM("PDM L Source", rt5659_pdm_l_enum); -static const SOC_ENUM_SINGLE_DECL( +static SOC_ENUM_SINGLE_DECL( rt5659_pdm_r_enum, RT5659_PDM_OUT_CTRL, RT5659_PDM1_R_SFT, rt5659_pdm_src); @@ -2230,7 +2230,7 @@ static const char * const rt5659_spdif_src[] = { "IF1_DAC1", "IF1_DAC2", "IF2_DAC", "IF3_DAC" }; -static const SOC_ENUM_SINGLE_DECL( +static SOC_ENUM_SINGLE_DECL( rt5659_spdif_enum, RT5659_SPDIF_CTRL, RT5659_SPDIF_SEL_SFT, rt5659_spdif_src); @@ -2250,7 +2250,7 @@ static const char * const rt5659_rx_adc_data_src[] = { "NUL:AD2:DAC:AD1", "NUL:DAC:DAC:AD2", "NUL:DAC:AD2:DAC" }; -static const SOC_ENUM_SINGLE_DECL( +static SOC_ENUM_SINGLE_DECL( rt5659_rx_adc_data_enum, RT5659_TDM_CTRL_2, RT5659_ADCDAT_SRC_SFT, rt5659_rx_adc_data_src); diff --git a/sound/soc/codecs/rt5660.c b/sound/soc/codecs/rt5660.c index 9f0933ced804..e396b7680fa1 100644 --- a/sound/soc/codecs/rt5660.c +++ b/sound/soc/codecs/rt5660.c @@ -526,10 +526,10 @@ static const char * const rt5660_data_select[] = { "L/R", "R/L", "L/L", "R/R" }; -static const SOC_ENUM_SINGLE_DECL(rt5660_if1_dac_enum, +static SOC_ENUM_SINGLE_DECL(rt5660_if1_dac_enum, RT5660_DIG_INF1_DATA, RT5660_IF1_DAC_IN_SFT, rt5660_data_select); -static const SOC_ENUM_SINGLE_DECL(rt5660_if1_adc_enum, +static SOC_ENUM_SINGLE_DECL(rt5660_if1_adc_enum, RT5660_DIG_INF1_DATA, RT5660_IF1_ADC_IN_SFT, rt5660_data_select); static const struct snd_kcontrol_new rt5660_if1_dac_swap_mux = diff --git a/sound/soc/codecs/rt5670.c b/sound/soc/codecs/rt5670.c index 49caf1393aeb..fdc14e50d3b9 100644 --- a/sound/soc/codecs/rt5670.c +++ b/sound/soc/codecs/rt5670.c @@ -2813,6 +2813,8 @@ MODULE_DEVICE_TABLE(i2c, rt5670_i2c_id); #ifdef CONFIG_ACPI static const struct acpi_device_id rt5670_acpi_match[] = { { "10EC5670", 0}, + { "10EC5672", 0}, + { "10EC5640", 0}, /* quirk */ { }, }; MODULE_DEVICE_TABLE(acpi, rt5670_acpi_match); diff --git a/sound/soc/codecs/tlv320aic3x.c b/sound/soc/codecs/tlv320aic3x.c index 5a8d96ec058c..fe45a16a5142 100644 --- a/sound/soc/codecs/tlv320aic3x.c +++ b/sound/soc/codecs/tlv320aic3x.c @@ -126,6 +126,16 @@ static const struct reg_default aic3x_reg[] = { { 108, 0x00 }, { 109, 0x00 }, }; +static bool aic3x_volatile_reg(struct device *dev, unsigned int reg) +{ + switch (reg) { + case AIC3X_RESET: + return true; + default: + return false; + } +} + static const struct regmap_config aic3x_regmap = { .reg_bits = 8, .val_bits = 8, @@ -133,6 +143,9 @@ static const struct regmap_config aic3x_regmap = { .max_register = DAC_ICC_ADJ, .reg_defaults = aic3x_reg, .num_reg_defaults = ARRAY_SIZE(aic3x_reg), + + .volatile_reg = aic3x_volatile_reg, + .cache_type = REGCACHE_RBTREE, }; diff --git a/sound/soc/codecs/wm_adsp.c b/sound/soc/codecs/wm_adsp.c index b943dde8dbe5..757af795cebd 100644 --- a/sound/soc/codecs/wm_adsp.c +++ b/sound/soc/codecs/wm_adsp.c @@ -789,7 +789,10 @@ static int wm_coeff_put(struct snd_kcontrol *kctl, mutex_lock(&ctl->dsp->pwr_lock); - memcpy(ctl->cache, p, ctl->len); + if (ctl->flags & WMFW_CTL_FLAG_VOLATILE) + ret = -EPERM; + else + memcpy(ctl->cache, p, ctl->len); ctl->set = 1; if (ctl->enabled && ctl->dsp->running) @@ -816,6 +819,8 @@ static int wm_coeff_tlv_put(struct snd_kcontrol *kctl, ctl->set = 1; if (ctl->enabled && ctl->dsp->running) ret = wm_coeff_write_control(ctl, ctl->cache, size); + else if (ctl->flags & WMFW_CTL_FLAG_VOLATILE) + ret = -EPERM; } mutex_unlock(&ctl->dsp->pwr_lock); @@ -1360,7 +1365,7 @@ static int wm_adsp_load(struct wm_adsp *dsp) const struct wmfw_region *region; const struct wm_adsp_region *mem; const char *region_name; - char *file, *text; + char *file, *text = NULL; struct wm_adsp_buf *buf; unsigned int reg; int regions = 0; @@ -1521,10 +1526,21 @@ static int wm_adsp_load(struct wm_adsp *dsp) regions, le32_to_cpu(region->len), offset, region_name); + if ((pos + le32_to_cpu(region->len) + sizeof(*region)) > + firmware->size) { + adsp_err(dsp, + "%s.%d: %s region len %d bytes exceeds file length %zu\n", + file, regions, region_name, + le32_to_cpu(region->len), firmware->size); + ret = -EINVAL; + goto out_fw; + } + if (text) { memcpy(text, region->data, le32_to_cpu(region->len)); adsp_info(dsp, "%s: %s\n", file, text); kfree(text); + text = NULL; } if (reg) { @@ -1569,6 +1585,7 @@ out_fw: regmap_async_complete(regmap); wm_adsp_buf_free(&buf_list); release_firmware(firmware); + kfree(text); out: kfree(file); @@ -2049,6 +2066,17 @@ static int wm_adsp_load_coeff(struct wm_adsp *dsp) } if (reg) { + if ((pos + le32_to_cpu(blk->len) + sizeof(*blk)) > + firmware->size) { + adsp_err(dsp, + "%s.%d: %s region len %d bytes exceeds file length %zu\n", + file, blocks, region_name, + le32_to_cpu(blk->len), + firmware->size); + ret = -EINVAL; + goto out_fw; + } + buf = wm_adsp_buf_alloc(blk->data, le32_to_cpu(blk->len), &buf_list); diff --git a/sound/soc/fsl/fsl_ssi.c b/sound/soc/fsl/fsl_ssi.c index 2f487874237f..9cd9da6ef0b5 100644 --- a/sound/soc/fsl/fsl_ssi.c +++ b/sound/soc/fsl/fsl_ssi.c @@ -227,6 +227,12 @@ struct fsl_ssi_soc_data { * @dbg_stats: Debugging statistics * * @soc: SoC specific data + * + * @fifo_watermark: the FIFO watermark setting. Notifies DMA when + * there are @fifo_watermark or fewer words in TX fifo or + * @fifo_watermark or more empty words in RX fifo. + * @dma_maxburst: max number of words to transfer in one go. So far, + * this is always the same as fifo_watermark. */ struct fsl_ssi_private { struct regmap *regs; @@ -266,6 +272,9 @@ struct fsl_ssi_private { const struct fsl_ssi_soc_data *soc; struct device *dev; + + u32 fifo_watermark; + u32 dma_maxburst; }; /* @@ -1069,21 +1078,7 @@ static int _fsl_ssi_set_dai_fmt(struct device *dev, regmap_write(regs, CCSR_SSI_SRCR, srcr); regmap_write(regs, CCSR_SSI_SCR, scr); - /* - * Set the watermark for transmit FIFI 0 and receive FIFO 0. We don't - * use FIFO 1. We program the transmit water to signal a DMA transfer - * if there are only two (or fewer) elements left in the FIFO. Two - * elements equals one frame (left channel, right channel). This value, - * however, depends on the depth of the transmit buffer. - * - * We set the watermark on the same level as the DMA burstsize. For - * fiq it is probably better to use the biggest possible watermark - * size. - */ - if (ssi_private->use_dma) - wm = ssi_private->fifo_depth - 2; - else - wm = ssi_private->fifo_depth; + wm = ssi_private->fifo_watermark; regmap_write(regs, CCSR_SSI_SFCSR, CCSR_SSI_SFCSR_TFWM0(wm) | CCSR_SSI_SFCSR_RFWM0(wm) | @@ -1392,12 +1387,8 @@ static int fsl_ssi_imx_probe(struct platform_device *pdev, dev_dbg(&pdev->dev, "could not get baud clock: %ld\n", PTR_ERR(ssi_private->baudclk)); - /* - * We have burstsize be "fifo_depth - 2" to match the SSI - * watermark setting in fsl_ssi_startup(). - */ - ssi_private->dma_params_tx.maxburst = ssi_private->fifo_depth - 2; - ssi_private->dma_params_rx.maxburst = ssi_private->fifo_depth - 2; + ssi_private->dma_params_tx.maxburst = ssi_private->dma_maxburst; + ssi_private->dma_params_rx.maxburst = ssi_private->dma_maxburst; ssi_private->dma_params_tx.addr = ssi_private->ssi_phys + CCSR_SSI_STX0; ssi_private->dma_params_rx.addr = ssi_private->ssi_phys + CCSR_SSI_SRX0; @@ -1565,6 +1556,47 @@ static int fsl_ssi_probe(struct platform_device *pdev) /* Older 8610 DTs didn't have the fifo-depth property */ ssi_private->fifo_depth = 8; + /* + * Set the watermark for transmit FIFO 0 and receive FIFO 0. We don't + * use FIFO 1 but set the watermark appropriately nontheless. + * We program the transmit water to signal a DMA transfer + * if there are N elements left in the FIFO. For chips with 15-deep + * FIFOs, set watermark to 8. This allows the SSI to operate at a + * high data rate without channel slipping. Behavior is unchanged + * for the older chips with a fifo depth of only 8. A value of 4 + * might be appropriate for the older chips, but is left at + * fifo_depth-2 until sombody has a chance to test. + * + * We set the watermark on the same level as the DMA burstsize. For + * fiq it is probably better to use the biggest possible watermark + * size. + */ + switch (ssi_private->fifo_depth) { + case 15: + /* + * 2 samples is not enough when running at high data + * rates (like 48kHz @ 16 bits/channel, 16 channels) + * 8 seems to split things evenly and leave enough time + * for the DMA to fill the FIFO before it's over/under + * run. + */ + ssi_private->fifo_watermark = 8; + ssi_private->dma_maxburst = 8; + break; + case 8: + default: + /* + * maintain old behavior for older chips. + * Keeping it the same because I don't have an older + * board to test with. + * I suspect this could be changed to be something to + * leave some more space in the fifo. + */ + ssi_private->fifo_watermark = ssi_private->fifo_depth - 2; + ssi_private->dma_maxburst = ssi_private->fifo_depth - 2; + break; + } + pm_runtime_enable(&pdev->dev); dev_set_drvdata(&pdev->dev, ssi_private); diff --git a/sound/soc/intel/Kconfig b/sound/soc/intel/Kconfig index fd5d1e091038..e18fe9d6f08f 100644 --- a/sound/soc/intel/Kconfig +++ b/sound/soc/intel/Kconfig @@ -33,11 +33,9 @@ config SND_SOC_INTEL_SST select SND_SOC_INTEL_SST_MATCH if ACPI depends on (X86 || COMPILE_TEST) -# firmware stuff depends DW_DMAC_CORE; since there is no depends-on from -# the reverse selection, each machine driver needs to select -# SND_SOC_INTEL_SST_FIRMWARE carefully depending on DW_DMAC_CORE config SND_SOC_INTEL_SST_FIRMWARE tristate + select DW_DMAC_CORE config SND_SOC_INTEL_SST_ACPI tristate @@ -47,16 +45,18 @@ config SND_SOC_INTEL_SST_MATCH config SND_SOC_INTEL_HASWELL tristate + select SND_SOC_INTEL_SST select SND_SOC_INTEL_SST_FIRMWARE config SND_SOC_INTEL_BAYTRAIL tristate + select SND_SOC_INTEL_SST + select SND_SOC_INTEL_SST_FIRMWARE config SND_SOC_INTEL_HASWELL_MACH tristate "ASoC Audio DSP support for Intel Haswell Lynxpoint" depends on X86_INTEL_LPSS && I2C && I2C_DESIGNWARE_PLATFORM - depends on DW_DMAC_CORE - select SND_SOC_INTEL_SST + depends on DMADEVICES select SND_SOC_INTEL_HASWELL select SND_SOC_RT5640 help @@ -99,9 +99,8 @@ config SND_SOC_INTEL_BXT_RT298_MACH config SND_SOC_INTEL_BYT_RT5640_MACH tristate "ASoC Audio driver for Intel Baytrail with RT5640 codec" depends on X86_INTEL_LPSS && I2C - depends on DW_DMAC_CORE && (SND_SST_IPC_ACPI = n) - select SND_SOC_INTEL_SST - select SND_SOC_INTEL_SST_FIRMWARE + depends on DMADEVICES + depends on SND_SST_IPC_ACPI = n select SND_SOC_INTEL_BAYTRAIL select SND_SOC_RT5640 help @@ -112,9 +111,8 @@ config SND_SOC_INTEL_BYT_RT5640_MACH config SND_SOC_INTEL_BYT_MAX98090_MACH tristate "ASoC Audio driver for Intel Baytrail with MAX98090 codec" depends on X86_INTEL_LPSS && I2C - depends on DW_DMAC_CORE && (SND_SST_IPC_ACPI = n) - select SND_SOC_INTEL_SST - select SND_SOC_INTEL_SST_FIRMWARE + depends on DMADEVICES + depends on SND_SST_IPC_ACPI = n select SND_SOC_INTEL_BAYTRAIL select SND_SOC_MAX98090 help @@ -123,9 +121,8 @@ config SND_SOC_INTEL_BYT_MAX98090_MACH config SND_SOC_INTEL_BDW_RT5677_MACH tristate "ASoC Audio driver for Intel Broadwell with RT5677 codec" - depends on X86_INTEL_LPSS && GPIOLIB && I2C && DW_DMAC - depends on DW_DMAC_CORE=y - select SND_SOC_INTEL_SST + depends on X86_INTEL_LPSS && GPIOLIB && I2C + depends on DMADEVICES select SND_SOC_INTEL_HASWELL select SND_SOC_RT5677 help @@ -134,10 +131,8 @@ config SND_SOC_INTEL_BDW_RT5677_MACH config SND_SOC_INTEL_BROADWELL_MACH tristate "ASoC Audio DSP support for Intel Broadwell Wildcatpoint" - depends on X86_INTEL_LPSS && I2C && DW_DMAC && \ - I2C_DESIGNWARE_PLATFORM - depends on DW_DMAC_CORE - select SND_SOC_INTEL_SST + depends on X86_INTEL_LPSS && I2C && I2C_DESIGNWARE_PLATFORM + depends on DMADEVICES select SND_SOC_INTEL_HASWELL select SND_SOC_RT286 help diff --git a/sound/soc/intel/atom/sst/sst_acpi.c b/sound/soc/intel/atom/sst/sst_acpi.c index 0a88537ca58a..0bfa68862460 100644 --- a/sound/soc/intel/atom/sst/sst_acpi.c +++ b/sound/soc/intel/atom/sst/sst_acpi.c @@ -400,6 +400,7 @@ static int sst_acpi_remove(struct platform_device *pdev) static unsigned long cht_machine_id; #define CHT_SURFACE_MACH 1 +#define BYT_THINKPAD_10 2 static int cht_surface_quirk_cb(const struct dmi_system_id *id) { @@ -407,6 +408,23 @@ static int cht_surface_quirk_cb(const struct dmi_system_id *id) return 1; } +static int byt_thinkpad10_quirk_cb(const struct dmi_system_id *id) +{ + cht_machine_id = BYT_THINKPAD_10; + return 1; +} + + +static const struct dmi_system_id byt_table[] = { + { + .callback = byt_thinkpad10_quirk_cb, + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"), + DMI_MATCH(DMI_PRODUCT_NAME, "20C3001VHH"), + }, + }, + { } +}; static const struct dmi_system_id cht_table[] = { { @@ -424,6 +442,10 @@ static struct sst_acpi_mach cht_surface_mach = { "10EC5640", "cht-bsw-rt5645", "intel/fw_sst_22a8.bin", "cht-bsw", NULL, &chv_platform_data }; +static struct sst_acpi_mach byt_thinkpad_10 = { + "10EC5640", "cht-bsw-rt5672", "intel/fw_sst_0f28.bin", "cht-bsw", NULL, + &byt_rvp_platform_data }; + static struct sst_acpi_mach *cht_quirk(void *arg) { struct sst_acpi_mach *mach = arg; @@ -436,8 +458,21 @@ static struct sst_acpi_mach *cht_quirk(void *arg) return mach; } +static struct sst_acpi_mach *byt_quirk(void *arg) +{ + struct sst_acpi_mach *mach = arg; + + dmi_check_system(byt_table); + + if (cht_machine_id == BYT_THINKPAD_10) + return &byt_thinkpad_10; + else + return mach; +} + + static struct sst_acpi_mach sst_acpi_bytcr[] = { - {"10EC5640", "bytcr_rt5640", "intel/fw_sst_0f28.bin", "bytcr_rt5640", NULL, + {"10EC5640", "bytcr_rt5640", "intel/fw_sst_0f28.bin", "bytcr_rt5640", byt_quirk, &byt_rvp_platform_data }, {"10EC5642", "bytcr_rt5640", "intel/fw_sst_0f28.bin", "bytcr_rt5640", NULL, &byt_rvp_platform_data }, diff --git a/sound/soc/intel/boards/bytcr_rt5640.c b/sound/soc/intel/boards/bytcr_rt5640.c index bff77a1f27fc..c17f262f0834 100644 --- a/sound/soc/intel/boards/bytcr_rt5640.c +++ b/sound/soc/intel/boards/bytcr_rt5640.c @@ -57,9 +57,7 @@ struct byt_rt5640_private { struct clk *mclk; }; -static unsigned long byt_rt5640_quirk = BYT_RT5640_DMIC1_MAP | - BYT_RT5640_DMIC_EN | - BYT_RT5640_MCLK_EN; +static unsigned long byt_rt5640_quirk = BYT_RT5640_MCLK_EN; static void log_quirks(struct device *dev) { @@ -144,7 +142,7 @@ static int platform_clock_control(struct snd_soc_dapm_widget *w, * for Jack detection and button press */ ret = snd_soc_dai_set_sysclk(codec_dai, RT5640_SCLK_S_RCCLK, - 0, + 48000 * 512, SND_SOC_CLOCK_IN); if (!ret) { if ((byt_rt5640_quirk & BYT_RT5640_MCLK_EN) && priv->mclk) @@ -389,6 +387,16 @@ static const struct dmi_system_id byt_rt5640_quirk_table[] = { BYT_RT5640_SSP0_AIF1), }, + { + .callback = byt_rt5640_quirk_cb, + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "Insyde"), + }, + .driver_data = (unsigned long *)(BYT_RT5640_IN3_MAP | + BYT_RT5640_MCLK_EN | + BYT_RT5640_SSP0_AIF1), + + }, {} }; @@ -613,7 +621,7 @@ static struct snd_soc_dai_link byt_rt5640_dais[] = { .codec_dai_name = "snd-soc-dummy-dai", .codec_name = "snd-soc-dummy", .platform_name = "sst-mfld-platform", - .ignore_suspend = 1, + .nonatomic = true, .dynamic = 1, .dpcm_playback = 1, .dpcm_capture = 1, @@ -626,7 +634,6 @@ static struct snd_soc_dai_link byt_rt5640_dais[] = { .codec_dai_name = "snd-soc-dummy-dai", .codec_name = "snd-soc-dummy", .platform_name = "sst-mfld-platform", - .ignore_suspend = 1, .nonatomic = true, .dynamic = 1, .dpcm_playback = 1, @@ -653,6 +660,7 @@ static struct snd_soc_dai_link byt_rt5640_dais[] = { | SND_SOC_DAIFMT_CBS_CFS, .be_hw_params_fixup = byt_rt5640_codec_fixup, .ignore_suspend = 1, + .nonatomic = true, .dpcm_playback = 1, .dpcm_capture = 1, .init = byt_rt5640_init, @@ -738,6 +746,13 @@ static int snd_byt_rt5640_mc_probe(struct platform_device *pdev) if (res_info->acpi_ipc_irq_index == 0) { byt_rt5640_quirk |= BYT_RT5640_SSP0_AIF2; } + + /* change defaults for Baytrail-CR capture */ + byt_rt5640_quirk |= BYT_RT5640_IN1_MAP; + byt_rt5640_quirk |= BYT_RT5640_DIFF_MIC; + } else { + byt_rt5640_quirk |= (BYT_RT5640_DMIC1_MAP | + BYT_RT5640_DMIC_EN); } /* check quirks before creating card */ @@ -792,7 +807,6 @@ static int snd_byt_rt5640_mc_probe(struct platform_device *pdev) static struct platform_driver snd_byt_rt5640_mc_driver = { .driver = { .name = "bytcr_rt5640", - .pm = &snd_soc_pm_ops, }, .probe = snd_byt_rt5640_mc_probe, }; diff --git a/sound/soc/intel/boards/bytcr_rt5651.c b/sound/soc/intel/boards/bytcr_rt5651.c index 35f591eab3c9..ae49f8199e45 100644 --- a/sound/soc/intel/boards/bytcr_rt5651.c +++ b/sound/soc/intel/boards/bytcr_rt5651.c @@ -235,7 +235,6 @@ static struct snd_soc_dai_link byt_rt5651_dais[] = { .codec_dai_name = "snd-soc-dummy-dai", .codec_name = "snd-soc-dummy", .platform_name = "sst-mfld-platform", - .ignore_suspend = 1, .nonatomic = true, .dynamic = 1, .dpcm_playback = 1, @@ -249,7 +248,6 @@ static struct snd_soc_dai_link byt_rt5651_dais[] = { .codec_dai_name = "snd-soc-dummy-dai", .codec_name = "snd-soc-dummy", .platform_name = "sst-mfld-platform", - .ignore_suspend = 1, .nonatomic = true, .dynamic = 1, .dpcm_playback = 1, @@ -319,7 +317,6 @@ static int snd_byt_rt5651_mc_probe(struct platform_device *pdev) static struct platform_driver snd_byt_rt5651_mc_driver = { .driver = { .name = "bytcr_rt5651", - .pm = &snd_soc_pm_ops, }, .probe = snd_byt_rt5651_mc_probe, }; diff --git a/sound/soc/intel/boards/cht_bsw_rt5645.c b/sound/soc/intel/boards/cht_bsw_rt5645.c index 16c94c45ce50..90525614c20a 100644 --- a/sound/soc/intel/boards/cht_bsw_rt5645.c +++ b/sound/soc/intel/boards/cht_bsw_rt5645.c @@ -24,6 +24,9 @@ #include <linux/acpi.h> #include <linux/platform_device.h> #include <linux/slab.h> +#include <asm/cpu_device_id.h> +#include <asm/platform_sst_audio.h> +#include <linux/clk.h> #include <sound/pcm.h> #include <sound/pcm_params.h> #include <sound/soc.h> @@ -45,6 +48,7 @@ struct cht_mc_private { struct snd_soc_jack jack; struct cht_acpi_card *acpi_card; char codec_name[16]; + struct clk *mclk; }; static inline struct snd_soc_dai *cht_get_codec_dai(struct snd_soc_card *card) @@ -65,6 +69,7 @@ static int platform_clock_control(struct snd_soc_dapm_widget *w, struct snd_soc_dapm_context *dapm = w->dapm; struct snd_soc_card *card = dapm->card; struct snd_soc_dai *codec_dai; + struct cht_mc_private *ctx = snd_soc_card_get_drvdata(card); int ret; codec_dai = cht_get_codec_dai(card); @@ -73,19 +78,30 @@ static int platform_clock_control(struct snd_soc_dapm_widget *w, return -EIO; } - if (!SND_SOC_DAPM_EVENT_OFF(event)) - return 0; + if (SND_SOC_DAPM_EVENT_ON(event)) { + if (ctx->mclk) { + ret = clk_prepare_enable(ctx->mclk); + if (ret < 0) { + dev_err(card->dev, + "could not configure MCLK state"); + return ret; + } + } + } else { + /* Set codec sysclk source to its internal clock because codec PLL will + * be off when idle and MCLK will also be off when codec is + * runtime suspended. Codec needs clock for jack detection and button + * press. MCLK is turned off with clock framework or ACPI. + */ + ret = snd_soc_dai_set_sysclk(codec_dai, RT5645_SCLK_S_RCCLK, + 48000 * 512, SND_SOC_CLOCK_IN); + if (ret < 0) { + dev_err(card->dev, "can't set codec sysclk: %d\n", ret); + return ret; + } - /* Set codec sysclk source to its internal clock because codec PLL will - * be off when idle and MCLK will also be off by ACPI when codec is - * runtime suspended. Codec needs clock for jack detection and button - * press. - */ - ret = snd_soc_dai_set_sysclk(codec_dai, RT5645_SCLK_S_RCCLK, - 0, SND_SOC_CLOCK_IN); - if (ret < 0) { - dev_err(card->dev, "can't set codec sysclk: %d\n", ret); - return ret; + if (ctx->mclk) + clk_disable_unprepare(ctx->mclk); } return 0; @@ -97,7 +113,7 @@ static const struct snd_soc_dapm_widget cht_dapm_widgets[] = { SND_SOC_DAPM_MIC("Int Mic", NULL), SND_SOC_DAPM_SPK("Ext Spk", NULL), SND_SOC_DAPM_SUPPLY("Platform Clock", SND_SOC_NOPM, 0, 0, - platform_clock_control, SND_SOC_DAPM_POST_PMD), + platform_clock_control, SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD), }; static const struct snd_soc_dapm_route cht_rt5645_audio_map[] = { @@ -225,6 +241,26 @@ static int cht_codec_init(struct snd_soc_pcm_runtime *runtime) rt5645_set_jack_detect(codec, &ctx->jack, &ctx->jack, &ctx->jack); + if (ctx->mclk) { + /* + * The firmware might enable the clock at + * boot (this information may or may not + * be reflected in the enable clock register). + * To change the rate we must disable the clock + * first to cover these cases. Due to common + * clock framework restrictions that do not allow + * to disable a clock that has not been enabled, + * we need to enable the clock first. + */ + ret = clk_prepare_enable(ctx->mclk); + if (!ret) + clk_disable_unprepare(ctx->mclk); + + ret = clk_set_rate(ctx->mclk, CHT_PLAT_CLK_3_HZ); + + if (ret) + dev_err(runtime->dev, "unable to set MCLK rate\n"); + } return ret; } @@ -349,6 +385,18 @@ static struct cht_acpi_card snd_soc_cards[] = { static char cht_rt5640_codec_name[16]; /* i2c-<HID>:00 with HID being 8 chars */ +static bool is_valleyview(void) +{ + static const struct x86_cpu_id cpu_ids[] = { + { X86_VENDOR_INTEL, 6, 55 }, /* Valleyview, Bay Trail */ + {} + }; + + if (!x86_match_cpu(cpu_ids)) + return false; + return true; +} + static int snd_cht_mc_probe(struct platform_device *pdev) { int ret_val = 0; @@ -358,22 +406,32 @@ static int snd_cht_mc_probe(struct platform_device *pdev) struct sst_acpi_mach *mach; const char *i2c_name = NULL; int dai_index = 0; + bool found = false; drv = devm_kzalloc(&pdev->dev, sizeof(*drv), GFP_ATOMIC); if (!drv) return -ENOMEM; + mach = (&pdev->dev)->platform_data; + for (i = 0; i < ARRAY_SIZE(snd_soc_cards); i++) { - if (acpi_dev_found(snd_soc_cards[i].codec_id)) { + if (acpi_dev_found(snd_soc_cards[i].codec_id) && + (!strncmp(snd_soc_cards[i].codec_id, mach->id, 8))) { dev_dbg(&pdev->dev, "found codec %s\n", snd_soc_cards[i].codec_id); card = snd_soc_cards[i].soc_card; drv->acpi_card = &snd_soc_cards[i]; + found = true; break; } } + + if (!found) { + dev_err(&pdev->dev, "No matching HID found in supported list\n"); + return -ENODEV; + } + card->dev = &pdev->dev; - mach = card->dev->platform_data; sprintf(drv->codec_name, "i2c-%s:00", drv->acpi_card->codec_id); /* set correct codec name */ @@ -391,6 +449,16 @@ static int snd_cht_mc_probe(struct platform_device *pdev) cht_dailink[dai_index].codec_name = cht_rt5640_codec_name; } + if (is_valleyview()) { + drv->mclk = devm_clk_get(&pdev->dev, "pmc_plt_clk_3"); + if (IS_ERR(drv->mclk)) { + dev_err(&pdev->dev, + "Failed to get MCLK from pmc_plt_clk_3: %ld\n", + PTR_ERR(drv->mclk)); + return PTR_ERR(drv->mclk); + } + } + snd_soc_card_set_drvdata(card, drv); ret_val = devm_snd_soc_register_card(&pdev->dev, card); if (ret_val) { diff --git a/sound/soc/intel/skylake/skl-sst.c b/sound/soc/intel/skylake/skl-sst.c index 8fc3178bc79c..b30bd384c8d3 100644 --- a/sound/soc/intel/skylake/skl-sst.c +++ b/sound/soc/intel/skylake/skl-sst.c @@ -515,6 +515,9 @@ EXPORT_SYMBOL_GPL(skl_sst_init_fw); void skl_sst_dsp_cleanup(struct device *dev, struct skl_sst *ctx) { + + if (ctx->dsp->fw) + release_firmware(ctx->dsp->fw); skl_clear_module_table(ctx->dsp); skl_freeup_uuid_list(ctx); skl_ipc_free(&ctx->ipc); diff --git a/sound/soc/intel/skylake/skl-topology.c b/sound/soc/intel/skylake/skl-topology.c index b5b1934d8550..bef8a4546c12 100644 --- a/sound/soc/intel/skylake/skl-topology.c +++ b/sound/soc/intel/skylake/skl-topology.c @@ -448,7 +448,7 @@ static int skl_tplg_set_module_init_data(struct snd_soc_dapm_widget *w) if (bc->set_params != SKL_PARAM_INIT) continue; - mconfig->formats_config.caps = (u32 *)&bc->params; + mconfig->formats_config.caps = (u32 *)bc->params; mconfig->formats_config.caps_size = bc->size; break; diff --git a/sound/soc/mediatek/Kconfig b/sound/soc/mediatek/Kconfig index 05cf809cf9e1..d7013bde6f45 100644 --- a/sound/soc/mediatek/Kconfig +++ b/sound/soc/mediatek/Kconfig @@ -13,7 +13,7 @@ config SND_SOC_MT2701 config SND_SOC_MT2701_CS42448 tristate "ASoc Audio driver for MT2701 with CS42448 codec" - depends on SND_SOC_MT2701 + depends on SND_SOC_MT2701 && I2C select SND_SOC_CS42XX8_I2C select SND_SOC_BT_SCO help diff --git a/sound/soc/sh/rcar/core.c b/sound/soc/sh/rcar/core.c index f18141098b50..91b444db575e 100644 --- a/sound/soc/sh/rcar/core.c +++ b/sound/soc/sh/rcar/core.c @@ -978,10 +978,8 @@ static int __rsnd_kctrl_new(struct rsnd_mod *mod, return -ENOMEM; ret = snd_ctl_add(card, kctrl); - if (ret < 0) { - snd_ctl_free_one(kctrl); + if (ret < 0) return ret; - } cfg->update = update; cfg->card = card; diff --git a/sound/soc/soc-compress.c b/sound/soc/soc-compress.c index bf7b52fce597..ff093edccea9 100644 --- a/sound/soc/soc-compress.c +++ b/sound/soc/soc-compress.c @@ -68,7 +68,8 @@ out: static int soc_compr_open_fe(struct snd_compr_stream *cstream) { struct snd_soc_pcm_runtime *fe = cstream->private_data; - struct snd_pcm_substream *fe_substream = fe->pcm->streams[0].substream; + struct snd_pcm_substream *fe_substream = + fe->pcm->streams[cstream->direction].substream; struct snd_soc_platform *platform = fe->platform; struct snd_soc_dpcm *dpcm; struct snd_soc_dapm_widget_list *list; @@ -414,7 +415,8 @@ static int soc_compr_set_params_fe(struct snd_compr_stream *cstream, struct snd_compr_params *params) { struct snd_soc_pcm_runtime *fe = cstream->private_data; - struct snd_pcm_substream *fe_substream = fe->pcm->streams[0].substream; + struct snd_pcm_substream *fe_substream = + fe->pcm->streams[cstream->direction].substream; struct snd_soc_platform *platform = fe->platform; int ret = 0, stream; diff --git a/sound/soc/soc-core.c b/sound/soc/soc-core.c index c0bbcd903261..4e3de566809c 100644 --- a/sound/soc/soc-core.c +++ b/sound/soc/soc-core.c @@ -2076,6 +2076,9 @@ static int soc_cleanup_card_resources(struct snd_soc_card *card) list_for_each_entry(rtd, &card->rtd_list, list) flush_delayed_work(&rtd->delayed_work); + /* free the ALSA card at first; this syncs with pending operations */ + snd_card_free(card->snd_card); + /* remove and free each DAI */ soc_remove_dai_links(card); soc_remove_pcm_runtimes(card); @@ -2090,9 +2093,7 @@ static int soc_cleanup_card_resources(struct snd_soc_card *card) if (card->remove) card->remove(card); - snd_card_free(card->snd_card); return 0; - } /* removes a socdev */ diff --git a/sound/soc/soc-dapm.c b/sound/soc/soc-dapm.c index 3bbe32ee4630..6780eba55ec2 100644 --- a/sound/soc/soc-dapm.c +++ b/sound/soc/soc-dapm.c @@ -358,6 +358,10 @@ static int dapm_kcontrol_data_alloc(struct snd_soc_dapm_widget *widget, snd_soc_dapm_new_control_unlocked(widget->dapm, &template); kfree(name); + if (IS_ERR(data->widget)) { + ret = PTR_ERR(data->widget); + goto err_data; + } if (!data->widget) { ret = -ENOMEM; goto err_data; @@ -392,6 +396,10 @@ static int dapm_kcontrol_data_alloc(struct snd_soc_dapm_widget *widget, data->widget = snd_soc_dapm_new_control_unlocked( widget->dapm, &template); kfree(name); + if (IS_ERR(data->widget)) { + ret = PTR_ERR(data->widget); + goto err_data; + } if (!data->widget) { ret = -ENOMEM; goto err_data; @@ -3311,11 +3319,22 @@ snd_soc_dapm_new_control(struct snd_soc_dapm_context *dapm, mutex_lock_nested(&dapm->card->dapm_mutex, SND_SOC_DAPM_CLASS_RUNTIME); w = snd_soc_dapm_new_control_unlocked(dapm, widget); + /* Do not nag about probe deferrals */ + if (IS_ERR(w)) { + int ret = PTR_ERR(w); + + if (ret != -EPROBE_DEFER) + dev_err(dapm->dev, + "ASoC: Failed to create DAPM control %s (%d)\n", + widget->name, ret); + goto out_unlock; + } if (!w) dev_err(dapm->dev, "ASoC: Failed to create DAPM control %s\n", widget->name); +out_unlock: mutex_unlock(&dapm->card->dapm_mutex); return w; } @@ -3338,6 +3357,8 @@ snd_soc_dapm_new_control_unlocked(struct snd_soc_dapm_context *dapm, w->regulator = devm_regulator_get(dapm->dev, w->name); if (IS_ERR(w->regulator)) { ret = PTR_ERR(w->regulator); + if (ret == -EPROBE_DEFER) + return ERR_PTR(ret); dev_err(dapm->dev, "ASoC: Failed to request %s: %d\n", w->name, ret); return NULL; @@ -3356,6 +3377,8 @@ snd_soc_dapm_new_control_unlocked(struct snd_soc_dapm_context *dapm, w->clk = devm_clk_get(dapm->dev, w->name); if (IS_ERR(w->clk)) { ret = PTR_ERR(w->clk); + if (ret == -EPROBE_DEFER) + return ERR_PTR(ret); dev_err(dapm->dev, "ASoC: Failed to request %s: %d\n", w->name, ret); return NULL; @@ -3474,6 +3497,16 @@ int snd_soc_dapm_new_controls(struct snd_soc_dapm_context *dapm, mutex_lock_nested(&dapm->card->dapm_mutex, SND_SOC_DAPM_CLASS_INIT); for (i = 0; i < num; i++) { w = snd_soc_dapm_new_control_unlocked(dapm, widget); + if (IS_ERR(w)) { + ret = PTR_ERR(w); + /* Do not nag about probe deferrals */ + if (ret == -EPROBE_DEFER) + break; + dev_err(dapm->dev, + "ASoC: Failed to create DAPM control %s (%d)\n", + widget->name, ret); + break; + } if (!w) { dev_err(dapm->dev, "ASoC: Failed to create DAPM control %s\n", @@ -3750,6 +3783,15 @@ int snd_soc_dapm_new_pcm(struct snd_soc_card *card, dev_dbg(card->dev, "ASoC: adding %s widget\n", link_name); w = snd_soc_dapm_new_control_unlocked(&card->dapm, &template); + if (IS_ERR(w)) { + ret = PTR_ERR(w); + /* Do not nag about probe deferrals */ + if (ret != -EPROBE_DEFER) + dev_err(card->dev, + "ASoC: Failed to create %s widget (%d)\n", + link_name, ret); + goto outfree_kcontrol_news; + } if (!w) { dev_err(card->dev, "ASoC: Failed to create %s widget\n", link_name); @@ -3801,6 +3843,16 @@ int snd_soc_dapm_new_dai_widgets(struct snd_soc_dapm_context *dapm, template.name); w = snd_soc_dapm_new_control_unlocked(dapm, &template); + if (IS_ERR(w)) { + int ret = PTR_ERR(w); + + /* Do not nag about probe deferrals */ + if (ret != -EPROBE_DEFER) + dev_err(dapm->dev, + "ASoC: Failed to create %s widget (%d)\n", + dai->driver->playback.stream_name, ret); + return ret; + } if (!w) { dev_err(dapm->dev, "ASoC: Failed to create %s widget\n", dai->driver->playback.stream_name); @@ -3820,6 +3872,16 @@ int snd_soc_dapm_new_dai_widgets(struct snd_soc_dapm_context *dapm, template.name); w = snd_soc_dapm_new_control_unlocked(dapm, &template); + if (IS_ERR(w)) { + int ret = PTR_ERR(w); + + /* Do not nag about probe deferrals */ + if (ret != -EPROBE_DEFER) + dev_err(dapm->dev, + "ASoC: Failed to create %s widget (%d)\n", + dai->driver->playback.stream_name, ret); + return ret; + } if (!w) { dev_err(dapm->dev, "ASoC: Failed to create %s widget\n", dai->driver->capture.stream_name); diff --git a/sound/soc/soc-pcm.c b/sound/soc/soc-pcm.c index 70f8eab7331e..7f0e36dc50aa 100644 --- a/sound/soc/soc-pcm.c +++ b/sound/soc/soc-pcm.c @@ -181,6 +181,10 @@ int dpcm_dapm_stream_event(struct snd_soc_pcm_runtime *fe, int dir, dev_dbg(be->dev, "ASoC: BE %s event %d dir %d\n", be->dai_link->name, event, dir); + if ((event == SND_SOC_DAPM_STREAM_STOP) && + (be->dpcm[dir].users >= 1)) + continue; + snd_soc_dapm_stream_event(be, dir, event); } @@ -2227,9 +2231,11 @@ static int dpcm_fe_dai_do_trigger(struct snd_pcm_substream *substream, int cmd) break; case SNDRV_PCM_TRIGGER_STOP: case SNDRV_PCM_TRIGGER_SUSPEND: - case SNDRV_PCM_TRIGGER_PAUSE_PUSH: fe->dpcm[stream].state = SND_SOC_DPCM_STATE_STOP; break; + case SNDRV_PCM_TRIGGER_PAUSE_PUSH: + fe->dpcm[stream].state = SND_SOC_DPCM_STATE_PAUSED; + break; } out: diff --git a/sound/soc/soc-topology.c b/sound/soc/soc-topology.c index 6b05047a4134..8a758c994506 100644 --- a/sound/soc/soc-topology.c +++ b/sound/soc/soc-topology.c @@ -1473,6 +1473,15 @@ widget: widget = snd_soc_dapm_new_control(dapm, &template); else widget = snd_soc_dapm_new_control_unlocked(dapm, &template); + if (IS_ERR(widget)) { + ret = PTR_ERR(widget); + /* Do not nag about probe deferrals */ + if (ret != -EPROBE_DEFER) + dev_err(tplg->dev, + "ASoC: failed to create widget %s controls (%d)\n", + w->name, ret); + goto hdr_err; + } if (widget == NULL) { dev_err(tplg->dev, "ASoC: failed to create widget %s controls\n", w->name); diff --git a/sound/soc/sunxi/sun4i-i2s.c b/sound/soc/sunxi/sun4i-i2s.c index 687a8f83dbe5..15c92400cea4 100644 --- a/sound/soc/sunxi/sun4i-i2s.c +++ b/sound/soc/sunxi/sun4i-i2s.c @@ -14,9 +14,11 @@ #include <linux/clk.h> #include <linux/dmaengine.h> #include <linux/module.h> +#include <linux/of_device.h> #include <linux/platform_device.h> #include <linux/pm_runtime.h> #include <linux/regmap.h> +#include <linux/reset.h> #include <sound/dmaengine_pcm.h> #include <sound/pcm_params.h> @@ -92,6 +94,7 @@ struct sun4i_i2s { struct clk *bus_clk; struct clk *mod_clk; struct regmap *regmap; + struct reset_control *rst; struct snd_dmaengine_dai_dma_data playback_dma_data; }; @@ -585,9 +588,22 @@ static int sun4i_i2s_runtime_suspend(struct device *dev) return 0; } +struct sun4i_i2s_quirks { + bool has_reset; +}; + +static const struct sun4i_i2s_quirks sun4i_a10_i2s_quirks = { + .has_reset = false, +}; + +static const struct sun4i_i2s_quirks sun6i_a31_i2s_quirks = { + .has_reset = true, +}; + static int sun4i_i2s_probe(struct platform_device *pdev) { struct sun4i_i2s *i2s; + const struct sun4i_i2s_quirks *quirks; struct resource *res; void __iomem *regs; int irq, ret; @@ -608,6 +624,12 @@ static int sun4i_i2s_probe(struct platform_device *pdev) return irq; } + quirks = of_device_get_match_data(&pdev->dev); + if (!quirks) { + dev_err(&pdev->dev, "Failed to determine the quirks to use\n"); + return -ENODEV; + } + i2s->bus_clk = devm_clk_get(&pdev->dev, "apb"); if (IS_ERR(i2s->bus_clk)) { dev_err(&pdev->dev, "Can't get our bus clock\n"); @@ -626,7 +648,24 @@ static int sun4i_i2s_probe(struct platform_device *pdev) dev_err(&pdev->dev, "Can't get our mod clock\n"); return PTR_ERR(i2s->mod_clk); } - + + if (quirks->has_reset) { + i2s->rst = devm_reset_control_get(&pdev->dev, NULL); + if (IS_ERR(i2s->rst)) { + dev_err(&pdev->dev, "Failed to get reset control\n"); + return PTR_ERR(i2s->rst); + } + } + + if (!IS_ERR(i2s->rst)) { + ret = reset_control_deassert(i2s->rst); + if (ret) { + dev_err(&pdev->dev, + "Failed to deassert the reset control\n"); + return -EINVAL; + } + } + i2s->playback_dma_data.addr = res->start + SUN4I_I2S_FIFO_TX_REG; i2s->playback_dma_data.maxburst = 4; @@ -658,23 +697,37 @@ err_suspend: sun4i_i2s_runtime_suspend(&pdev->dev); err_pm_disable: pm_runtime_disable(&pdev->dev); + if (!IS_ERR(i2s->rst)) + reset_control_assert(i2s->rst); return ret; } static int sun4i_i2s_remove(struct platform_device *pdev) { + struct sun4i_i2s *i2s = dev_get_drvdata(&pdev->dev); + snd_dmaengine_pcm_unregister(&pdev->dev); pm_runtime_disable(&pdev->dev); if (!pm_runtime_status_suspended(&pdev->dev)) sun4i_i2s_runtime_suspend(&pdev->dev); + if (!IS_ERR(i2s->rst)) + reset_control_assert(i2s->rst); + return 0; } static const struct of_device_id sun4i_i2s_match[] = { - { .compatible = "allwinner,sun4i-a10-i2s", }, + { + .compatible = "allwinner,sun4i-a10-i2s", + .data = &sun4i_a10_i2s_quirks, + }, + { + .compatible = "allwinner,sun6i-a31-i2s", + .data = &sun6i_a31_i2s_quirks, + }, {} }; MODULE_DEVICE_TABLE(of, sun4i_i2s_match); diff --git a/sound/soc/sunxi/sun4i-spdif.c b/sound/soc/sunxi/sun4i-spdif.c index 88fbb3a1e660..048de15d6937 100644 --- a/sound/soc/sunxi/sun4i-spdif.c +++ b/sound/soc/sunxi/sun4i-spdif.c @@ -403,14 +403,6 @@ static struct snd_soc_dai_driver sun4i_spdif_dai = { .name = "spdif", }; -static const struct snd_soc_dapm_widget dit_widgets[] = { - SND_SOC_DAPM_OUTPUT("spdif-out"), -}; - -static const struct snd_soc_dapm_route dit_routes[] = { - { "spdif-out", NULL, "Playback" }, -}; - static const struct of_device_id sun4i_spdif_of_match[] = { { .compatible = "allwinner,sun4i-a10-spdif", }, { .compatible = "allwinner,sun6i-a31-spdif", }, |